mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-20 00:56:31 +08:00
@@ -14,7 +14,6 @@ import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/view.dart';
|
||||
import 'package:PiliPlus/services/service_locator.dart';
|
||||
import 'package:PiliPlus/utils/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/duration_util.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
@@ -113,20 +112,39 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
}
|
||||
}
|
||||
|
||||
late double maxWidth;
|
||||
late double maxHeight;
|
||||
late EdgeInsets padding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isPortrait = context.isPortrait;
|
||||
padding = MediaQuery.paddingOf(context);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
maxWidth = constraints.maxWidth;
|
||||
maxHeight = constraints.maxHeight;
|
||||
final isPortrait = maxHeight >= maxWidth;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
return Floating().isPipMode
|
||||
? videoPlayerPanel(isFullScreen, isPipMode: true)
|
||||
? videoPlayerPanel(
|
||||
isFullScreen,
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
isPipMode: true,
|
||||
)
|
||||
: childWhenDisabled(isPortrait);
|
||||
} else {
|
||||
return childWhenDisabled(isPortrait);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget videoPlayerPanel(
|
||||
bool isFullScreen, {
|
||||
required double width,
|
||||
required double height,
|
||||
bool isPipMode = false,
|
||||
Color? fill,
|
||||
Alignment? alignment,
|
||||
@@ -144,6 +162,8 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
final roomInfoH5 = _liveRoomController.roomInfoH5.value;
|
||||
return PLVideoPlayer(
|
||||
key: playerKey,
|
||||
maxWidth: width,
|
||||
maxHeight: height,
|
||||
fill: fill,
|
||||
alignment: alignment,
|
||||
plPlayerController: plPlayerController,
|
||||
@@ -212,11 +232,10 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
?.appBackground;
|
||||
Widget child;
|
||||
if (appBackground?.isNotEmpty == true) {
|
||||
final size = Get.size;
|
||||
child = CachedNetworkImage(
|
||||
fit: BoxFit.cover,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
width: maxWidth,
|
||||
height: maxHeight,
|
||||
imageUrl: appBackground!.http2https,
|
||||
);
|
||||
} else {
|
||||
@@ -254,14 +273,18 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
|
||||
Widget get _buildPH {
|
||||
final isFullScreen = this.isFullScreen;
|
||||
final size = Get.size;
|
||||
final height = isFullScreen ? maxHeight : maxWidth * 9 / 16;
|
||||
return Column(
|
||||
children: [
|
||||
if (!isFullScreen) _buildAppBar,
|
||||
SizedBox(
|
||||
width: size.width,
|
||||
height: isFullScreen ? size.height : size.width * 9 / 16,
|
||||
child: videoPlayerPanel(isFullScreen),
|
||||
width: maxWidth,
|
||||
height: height,
|
||||
child: videoPlayerPanel(
|
||||
isFullScreen,
|
||||
width: maxWidth,
|
||||
height: height,
|
||||
),
|
||||
),
|
||||
..._buildBottomWidget,
|
||||
],
|
||||
@@ -270,11 +293,17 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
|
||||
Widget get _buildPP {
|
||||
final isFullScreen = this.isFullScreen;
|
||||
final bottomHeight = 85.0 + padding.bottom;
|
||||
final height = isFullScreen
|
||||
? maxHeight
|
||||
: maxHeight - padding.top - kToolbarHeight - bottomHeight;
|
||||
Widget child = Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: videoPlayerPanel(
|
||||
width: maxWidth,
|
||||
height: height,
|
||||
isFullScreen,
|
||||
alignment: isFullScreen ? null : Alignment.topCenter,
|
||||
needDm: isFullScreen,
|
||||
@@ -288,7 +317,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
maintainState: true,
|
||||
visible: !isFullScreen,
|
||||
child: SizedBox(
|
||||
height: Get.height * 0.32,
|
||||
height: maxHeight * 0.32,
|
||||
child: _buildChatWidget(true),
|
||||
),
|
||||
),
|
||||
@@ -302,7 +331,10 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
children: [
|
||||
_buildAppBar,
|
||||
Expanded(child: child),
|
||||
_buildInputWidget,
|
||||
SizedBox(
|
||||
height: bottomHeight,
|
||||
child: _buildInputWidget,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -471,23 +503,23 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
|
||||
Widget get _buildBodyH {
|
||||
double videoWidth =
|
||||
clampDouble(context.height / context.width * 1.08, 0.58, 0.75) *
|
||||
context.width;
|
||||
clampDouble(maxHeight / maxWidth * 1.08, 0.58, 0.75) * maxWidth;
|
||||
return Obx(
|
||||
() {
|
||||
final isFullScreen = this.isFullScreen;
|
||||
final size = Get.size;
|
||||
final width = isFullScreen ? maxWidth : videoWidth;
|
||||
final height = isFullScreen ? maxHeight : maxWidth * 9 / 16;
|
||||
Widget child = Row(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
width: isFullScreen ? size.width : videoWidth,
|
||||
height: isFullScreen ? size.height : size.width * 9 / 16,
|
||||
margin: EdgeInsets.only(bottom: padding.bottom),
|
||||
width: width,
|
||||
height: height,
|
||||
child: videoPlayerPanel(
|
||||
isFullScreen,
|
||||
fill: Colors.transparent,
|
||||
width: width,
|
||||
height: height,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -531,7 +563,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
top: 5,
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 15 + MediaQuery.paddingOf(context).bottom,
|
||||
bottom: 15 + padding.bottom,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
|
||||
@@ -665,8 +665,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
showStatusBar();
|
||||
}
|
||||
}
|
||||
return SizedBox(
|
||||
height: !isPortrait || isFullScreen
|
||||
final height = !isPortrait || isFullScreen
|
||||
? maxHeight -
|
||||
(!isPortrait || removeSafeArea
|
||||
? 0
|
||||
@@ -674,16 +673,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
: videoDetailController.isExpanding ||
|
||||
videoDetailController.isCollapsing
|
||||
? animHeight
|
||||
: videoDetailController.videoHeight,
|
||||
: videoDetailController.videoHeight;
|
||||
return SizedBox(
|
||||
width: maxWidth,
|
||||
height: height,
|
||||
child: videoPlayer(
|
||||
maxWidth,
|
||||
!isPortrait || isFullScreen
|
||||
? maxHeight
|
||||
: videoDetailController.isExpanding ||
|
||||
videoDetailController.isCollapsing
|
||||
? animHeight
|
||||
: videoDetailController.videoHeight,
|
||||
width: maxWidth,
|
||||
height: height,
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -964,14 +960,18 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
if (videoDetailController.isVertical.value && enableVerticalExpand) {
|
||||
final double videoHeight =
|
||||
maxHeight - (removeSafeArea ? 0 : padding.vertical);
|
||||
final double videoWidth = videoHeight * 9 / 16;
|
||||
final double width = videoHeight * 9 / 16;
|
||||
final videoWidth = isFullScreen ? maxWidth : width;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
width: isFullScreen ? maxWidth : videoWidth,
|
||||
child: videoPlayer(videoWidth, videoHeight),
|
||||
child: videoPlayer(
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Scaffold(
|
||||
@@ -986,7 +986,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
controller: videoDetailController.tabCtr,
|
||||
children: [
|
||||
videoIntro(
|
||||
width: maxWidth - videoWidth,
|
||||
width: maxWidth - width,
|
||||
height: maxHeight,
|
||||
),
|
||||
if (videoDetailController.showReply)
|
||||
@@ -1002,16 +1002,20 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
],
|
||||
);
|
||||
}
|
||||
final double videoHeight = maxHeight / 2.5;
|
||||
final shouldShowSeasonPanel = _shouldShowSeasonPanel;
|
||||
final double height = maxHeight / 2.5;
|
||||
final videoHeight = isFullScreen
|
||||
? maxHeight - (removeSafeArea ? 0 : padding.vertical)
|
||||
: height;
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: maxWidth,
|
||||
height: isFullScreen
|
||||
? maxHeight - (removeSafeArea ? 0 : padding.vertical)
|
||||
: videoHeight,
|
||||
child: videoPlayer(maxWidth, videoHeight),
|
||||
height: videoHeight,
|
||||
child: videoPlayer(
|
||||
width: maxWidth,
|
||||
height: videoHeight,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Scaffold(
|
||||
@@ -1032,7 +1036,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
if (shouldShowSeasonPanel) flex++;
|
||||
return maxWidth / flex;
|
||||
}(),
|
||||
height: maxHeight - videoHeight,
|
||||
height: maxHeight - height,
|
||||
),
|
||||
),
|
||||
if (videoDetailController.showReply)
|
||||
@@ -1056,20 +1060,24 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
if (videoDetailController.isVertical.value && enableVerticalExpand) {
|
||||
final double videoHeight =
|
||||
maxHeight - (removeSafeArea ? 0 : padding.top);
|
||||
final double videoWidth = videoHeight * 9 / 16;
|
||||
final double width = videoHeight * 9 / 16;
|
||||
final videoWidth = isFullScreen ? maxWidth : width;
|
||||
return Row(
|
||||
children: [
|
||||
if (!isFullScreen)
|
||||
Expanded(
|
||||
child: videoIntro(
|
||||
width: (maxWidth - videoWidth) / 2,
|
||||
width: (maxWidth - width) / 2,
|
||||
height: maxHeight,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
width: isFullScreen ? maxWidth : videoWidth,
|
||||
child: videoPlayer(videoWidth, videoHeight),
|
||||
child: videoPlayer(
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Scaffold(
|
||||
@@ -1096,12 +1104,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
],
|
||||
);
|
||||
}
|
||||
double videoWidth =
|
||||
double width =
|
||||
clampDouble(maxHeight / maxWidth * 1.08, 0.5, 0.7) * maxWidth;
|
||||
if (maxWidth >= 560) {
|
||||
videoWidth = min(videoWidth, maxWidth - 280);
|
||||
width = min(width, maxWidth - 280);
|
||||
}
|
||||
final double videoHeight = videoWidth * 9 / 16;
|
||||
final videoWidth = isFullScreen ? maxWidth : width;
|
||||
final double videoHeight = isFullScreen ? maxHeight : width * 9 / 16;
|
||||
final introHeight =
|
||||
maxHeight - videoHeight - (removeSafeArea ? 0 : padding.top);
|
||||
return Row(
|
||||
@@ -1109,17 +1118,20 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: isFullScreen ? maxWidth : videoWidth,
|
||||
height: isFullScreen ? maxHeight : videoHeight,
|
||||
child: videoPlayer(videoWidth, videoHeight),
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
child: videoPlayer(
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: isFullScreen,
|
||||
child: SizedBox(
|
||||
width: videoWidth,
|
||||
width: width,
|
||||
height: introHeight,
|
||||
child: videoIntro(
|
||||
width: videoWidth,
|
||||
width: width,
|
||||
height: introHeight,
|
||||
needRelated: false,
|
||||
needCtr: false,
|
||||
@@ -1132,9 +1144,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
offstage: isFullScreen,
|
||||
child: SizedBox(
|
||||
width:
|
||||
maxWidth -
|
||||
videoWidth -
|
||||
(removeSafeArea ? 0 : padding.horizontal),
|
||||
maxWidth - width - (removeSafeArea ? 0 : padding.horizontal),
|
||||
height: maxHeight - (removeSafeArea ? 0 : padding.top),
|
||||
child: Scaffold(
|
||||
key: videoDetailController.childKey,
|
||||
@@ -1372,7 +1382,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
return const SizedBox.shrink();
|
||||
});
|
||||
|
||||
Widget plPlayer([bool isPipMode = false]) => Obx(
|
||||
Widget plPlayer({
|
||||
required double width,
|
||||
required double height,
|
||||
bool isPipMode = false,
|
||||
}) => Obx(
|
||||
key: videoPlayerKey,
|
||||
() =>
|
||||
videoDetailController.videoState.value is! Success ||
|
||||
@@ -1381,6 +1395,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
? const SizedBox.shrink()
|
||||
: PLVideoPlayer(
|
||||
key: playerKey,
|
||||
maxWidth: width,
|
||||
maxHeight: height,
|
||||
plPlayerController: plPlayerController!,
|
||||
videoDetailController: videoDetailController,
|
||||
introController: videoDetailController.isUgc
|
||||
@@ -1410,7 +1426,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
|
||||
Widget autoChoose(Widget childWhenDisabled) {
|
||||
if (Platform.isAndroid) {
|
||||
return Floating().isPipMode ? plPlayer(true) : childWhenDisabled;
|
||||
return Floating().isPipMode
|
||||
? plPlayer(width: maxWidth, height: maxHeight, isPipMode: true)
|
||||
: childWhenDisabled;
|
||||
}
|
||||
return childWhenDisabled;
|
||||
}
|
||||
@@ -1428,7 +1446,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
builder: (context, constraints) {
|
||||
maxWidth = constraints.maxWidth;
|
||||
maxHeight = constraints.maxHeight;
|
||||
isPortrait = maxHeight > maxWidth;
|
||||
isPortrait = maxHeight >= maxWidth;
|
||||
|
||||
if (!videoDetailController.horizontalScreen) {
|
||||
return autoChoose(childWhenDisabled);
|
||||
@@ -1599,7 +1617,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
);
|
||||
}
|
||||
|
||||
Widget videoPlayer(double videoWidth, double videoHeight) {
|
||||
Widget videoPlayer({required double width, required double height}) {
|
||||
final isFullScreen = this.isFullScreen;
|
||||
return PopScope(
|
||||
canPop:
|
||||
@@ -1611,7 +1629,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
children: [
|
||||
const Positioned.fill(child: ColoredBox(color: Colors.black)),
|
||||
|
||||
if (isShowing) plPlayer(),
|
||||
if (isShowing) plPlayer(width: width, height: height),
|
||||
|
||||
Obx(() {
|
||||
if (!videoDetailController.autoPlay.value) {
|
||||
@@ -1621,12 +1639,12 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
child: Obx(
|
||||
() => CachedNetworkImage(
|
||||
imageUrl: videoDetailController.cover.value.http2https,
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
width: width,
|
||||
height: height,
|
||||
fit: BoxFit.cover,
|
||||
fadeOutDuration: const Duration(milliseconds: 120),
|
||||
fadeInDuration: const Duration(milliseconds: 120),
|
||||
memCacheWidth: videoWidth.cacheSize(context),
|
||||
memCacheWidth: width.cacheSize(context),
|
||||
placeholder: (context, url) => Center(
|
||||
child: Image.asset('assets/images/loading.png'),
|
||||
),
|
||||
|
||||
@@ -46,6 +46,8 @@ import 'package:screen_brightness/screen_brightness.dart';
|
||||
|
||||
class PLVideoPlayer extends StatefulWidget {
|
||||
const PLVideoPlayer({
|
||||
required this.maxWidth,
|
||||
required this.maxHeight,
|
||||
required this.plPlayerController,
|
||||
this.videoDetailController,
|
||||
this.introController,
|
||||
@@ -61,6 +63,8 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
super.key,
|
||||
});
|
||||
|
||||
final double maxWidth;
|
||||
final double maxHeight;
|
||||
final PlPlayerController plPlayerController;
|
||||
final VideoDetailController? videoDetailController;
|
||||
final CommonIntroController? introController;
|
||||
@@ -244,7 +248,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
|
||||
// 动态构建底部控制条
|
||||
Widget buildBottomControl() {
|
||||
Widget buildBottomControl(double maxWidth) {
|
||||
final videoDetail = introController.videoDetail.value;
|
||||
final isSeason = videoDetail.ugcSeason != null;
|
||||
final isPart = videoDetail.pages != null && videoDetail.pages!.length > 1;
|
||||
@@ -659,12 +663,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
children: [
|
||||
...userSpecifyItemLeft.map(progressWidget),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => FittedBox(
|
||||
child: FittedBox(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: constraints.maxWidth,
|
||||
),
|
||||
constraints: BoxConstraints(minWidth: maxWidth),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: userSpecifyItemRight.map(progressWidget).toList(),
|
||||
@@ -672,7 +673,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -691,10 +691,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
);
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxWidth = constraints.maxWidth;
|
||||
final maxHeight = constraints.maxHeight;
|
||||
|
||||
final maxWidth = widget.maxWidth;
|
||||
final maxHeight = widget.maxHeight;
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.passthrough,
|
||||
key: _playerKey,
|
||||
@@ -739,8 +739,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
if (interacting || _initialFocalPoint == Offset.zero) return;
|
||||
Offset cumulativeDelta =
|
||||
details.localFocalPoint - _initialFocalPoint;
|
||||
if (details.pointerCount == 2 &&
|
||||
cumulativeDelta.distance < 1.5) {
|
||||
if (details.pointerCount == 2 && cumulativeDelta.distance < 1.5) {
|
||||
interacting = true;
|
||||
_gestureType = null;
|
||||
return;
|
||||
@@ -751,8 +750,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
if (_gestureType == null) {
|
||||
if (cumulativeDelta.distance < 1) return;
|
||||
if (cumulativeDelta.dx.abs() >
|
||||
3 * cumulativeDelta.dy.abs()) {
|
||||
if (cumulativeDelta.dx.abs() > 3 * cumulativeDelta.dy.abs()) {
|
||||
_gestureType = GestureType.horizontal;
|
||||
} else if (cumulativeDelta.dy.abs() >
|
||||
3 * cumulativeDelta.dx.abs()) {
|
||||
@@ -910,8 +908,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
'setVolume',
|
||||
const Duration(milliseconds: 20),
|
||||
() {
|
||||
final double volume =
|
||||
_volumeValue.value - delta.dy / level;
|
||||
final double volume = _volumeValue.value - delta.dy / level;
|
||||
final double result = volume.clamp(0.0, 1.0);
|
||||
setVolume(result);
|
||||
},
|
||||
@@ -1087,9 +1084,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
translation: const Offset(0.0, 0.3), // 上下偏移量(负数向上偏移)
|
||||
child: AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: plPlayerController.longPressStatus.value
|
||||
? 1.0
|
||||
: 0.0,
|
||||
opacity: plPlayerController.longPressStatus.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
@@ -1126,9 +1121,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: Obx(
|
||||
() => AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: plPlayerController.isSliderMoving.value
|
||||
? 1.0
|
||||
: 0.0,
|
||||
opacity: plPlayerController.isSliderMoving.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: IntrinsicWidth(
|
||||
child: Container(
|
||||
@@ -1302,6 +1295,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
BottomControl(
|
||||
controller: plPlayerController,
|
||||
buildBottomControl: buildBottomControl,
|
||||
maxWidth: maxWidth,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1328,8 +1322,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
// ),
|
||||
Obx(
|
||||
() =>
|
||||
showRestoreScaleBtn.value &&
|
||||
plPlayerController.showControls.value
|
||||
showRestoreScaleBtn.value && plPlayerController.showControls.value
|
||||
? Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
@@ -1337,9 +1330,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
backgroundColor: theme
|
||||
.colorScheme
|
||||
.secondaryContainer
|
||||
backgroundColor: theme.colorScheme.secondaryContainer
|
||||
.withValues(alpha: 0.8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: const EdgeInsets.all(15),
|
||||
@@ -1384,10 +1375,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
/// 进度条 live模式下禁用
|
||||
Obx(
|
||||
() {
|
||||
final int value =
|
||||
plPlayerController.sliderPositionSeconds.value;
|
||||
final int max =
|
||||
plPlayerController.durationSeconds.value.inSeconds;
|
||||
final int value = plPlayerController.sliderPositionSeconds.value;
|
||||
final int max = plPlayerController.durationSeconds.value.inSeconds;
|
||||
final int buffer = plPlayerController.bufferedSeconds.value;
|
||||
if (plPlayerController.showControls.value) {
|
||||
return const SizedBox.shrink();
|
||||
@@ -1433,7 +1422,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
buildDmChart(theme, plPlayerController),
|
||||
if (plPlayerController.viewPointList.isNotEmpty &&
|
||||
plPlayerController.showVP.value)
|
||||
buildViewPointWidget(plPlayerController, 4.25),
|
||||
buildViewPointWidget(
|
||||
plPlayerController,
|
||||
4.25,
|
||||
maxWidth,
|
||||
),
|
||||
IgnorePointer(
|
||||
child: ProgressBar(
|
||||
progress: Duration(seconds: value),
|
||||
@@ -1445,9 +1438,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
timeLabelLocation: TimeLabelLocation.none,
|
||||
thumbColor: primary,
|
||||
barHeight: 3.5,
|
||||
thumbRadius: draggingFixedProgressBar.value
|
||||
? 7
|
||||
: 2.5,
|
||||
thumbRadius: draggingFixedProgressBar.value ? 7 : 2.5,
|
||||
// onDragStart: (duration) {
|
||||
// feedBack();
|
||||
// plPlayerController.onChangedSliderStart();
|
||||
@@ -1500,8 +1491,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: CustomPaint(
|
||||
size: const Size(double.infinity, 3.5),
|
||||
painter: SegmentProgressBar(
|
||||
segmentColors:
|
||||
plPlayerController.viewPointList,
|
||||
segmentColors: plPlayerController.viewPointList,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1511,7 +1501,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 12,
|
||||
child: buildSeekPreviewWidget(plPlayerController),
|
||||
child: buildSeekPreviewWidget(
|
||||
plPlayerController,
|
||||
maxWidth,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1541,8 +1534,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: Visibility(
|
||||
visible:
|
||||
plPlayerController.showControls.value &&
|
||||
(isFullScreen ||
|
||||
plPlayerController.controlsLock.value),
|
||||
(isFullScreen || plPlayerController.controlsLock.value),
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x45000000),
|
||||
@@ -1553,8 +1545,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
plPlayerController.controlsLock.value
|
||||
? FontAwesomeIcons.lock
|
||||
: FontAwesomeIcons.lockOpen,
|
||||
semanticLabel:
|
||||
plPlayerController.controlsLock.value
|
||||
semanticLabel: plPlayerController.controlsLock.value
|
||||
? '解锁'
|
||||
: '锁定',
|
||||
size: 15,
|
||||
@@ -1611,7 +1602,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
8,
|
||||
),
|
||||
insetPadding: EdgeInsets.only(
|
||||
left: context.width / 2,
|
||||
left: maxWidth / 2,
|
||||
),
|
||||
//移除圆角
|
||||
shape: const RoundedRectangleBorder(),
|
||||
@@ -1719,9 +1710,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
/// 点击 快进/快退
|
||||
Obx(
|
||||
() =>
|
||||
_mountSeekBackwardButton.value ||
|
||||
_mountSeekForwardButton.value
|
||||
() => _mountSeekBackwardButton.value || _mountSeekForwardButton.value
|
||||
? Positioned.fill(
|
||||
child: Row(
|
||||
children: [
|
||||
@@ -1735,15 +1724,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: child,
|
||||
),
|
||||
child: BackwardSeekIndicator(
|
||||
duration: plPlayerController
|
||||
.fastForBackwardDuration,
|
||||
duration:
|
||||
plPlayerController.fastForBackwardDuration,
|
||||
onSubmitted: (Duration value) {
|
||||
_mountSeekBackwardButton.value = false;
|
||||
final Player player = widget
|
||||
.plPlayerController
|
||||
.videoPlayerController!;
|
||||
Duration result =
|
||||
player.state.position - value;
|
||||
Duration result = player.state.position - value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
@@ -1766,15 +1754,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
child: child,
|
||||
),
|
||||
child: ForwardSeekIndicator(
|
||||
duration: plPlayerController
|
||||
.fastForBackwardDuration,
|
||||
duration:
|
||||
plPlayerController.fastForBackwardDuration,
|
||||
onSubmitted: (Duration value) {
|
||||
_mountSeekForwardButton.value = false;
|
||||
final Player player = widget
|
||||
.plPlayerController
|
||||
.videoPlayerController!;
|
||||
Duration result =
|
||||
player.state.position + value;
|
||||
Duration result = player.state.position + value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
@@ -1793,8 +1780,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1851,7 +1836,10 @@ Widget buildDmChart(
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildSeekPreviewWidget(PlPlayerController plPlayerController) {
|
||||
Widget buildSeekPreviewWidget(
|
||||
PlPlayerController plPlayerController,
|
||||
double maxWidth,
|
||||
) {
|
||||
return Obx(
|
||||
() {
|
||||
if (!plPlayerController.showPreview.value ||
|
||||
@@ -1864,8 +1852,6 @@ Widget buildSeekPreviewWidget(PlPlayerController plPlayerController) {
|
||||
|
||||
VideoShotData data = plPlayerController.videoShot!['data'];
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
try {
|
||||
double scale =
|
||||
plPlayerController.isFullScreen.value &&
|
||||
@@ -1874,7 +1860,7 @@ Widget buildSeekPreviewWidget(PlPlayerController plPlayerController) {
|
||||
: 2.5;
|
||||
// offset
|
||||
double left = (plPlayerController.previewDx.value - 48 * scale / 2)
|
||||
.clamp(8, constraints.maxWidth - 48 * scale - 8);
|
||||
.clamp(8, maxWidth - 48 * scale - 8);
|
||||
|
||||
// index
|
||||
// int index = plPlayerController.sliderPositionSeconds.value ~/ 5;
|
||||
@@ -1883,8 +1869,7 @@ Widget buildSeekPreviewWidget(PlPlayerController plPlayerController) {
|
||||
(data.index!
|
||||
.where(
|
||||
(item) =>
|
||||
item <=
|
||||
plPlayerController.sliderPositionSeconds.value,
|
||||
item <= plPlayerController.sliderPositionSeconds.value,
|
||||
)
|
||||
.length -
|
||||
2),
|
||||
@@ -1933,16 +1918,13 @@ Widget buildSeekPreviewWidget(PlPlayerController plPlayerController) {
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildViewPointWidget(
|
||||
PlPlayerController plPlayerController,
|
||||
double offset,
|
||||
double maxWidth,
|
||||
) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Container(
|
||||
height: 16,
|
||||
margin: EdgeInsets.only(bottom: offset),
|
||||
@@ -1950,7 +1932,7 @@ Widget buildViewPointWidget(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPointerDown: (event) {
|
||||
try {
|
||||
double seg = event.localPosition.dx / constraints.maxWidth;
|
||||
double seg = event.localPosition.dx / maxWidth;
|
||||
Segment item = plPlayerController.viewPointList
|
||||
.where((item) => item.start >= seg)
|
||||
.reduce((a, b) => a.start < b.start ? a : b);
|
||||
@@ -1966,6 +1948,4 @@ Widget buildViewPointWidget(
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,14 +10,17 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class BottomControl extends StatelessWidget {
|
||||
final PlPlayerController controller;
|
||||
final Function buildBottomControl;
|
||||
const BottomControl({
|
||||
required this.controller,
|
||||
required this.buildBottomControl,
|
||||
required this.maxWidth,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final PlPlayerController controller;
|
||||
final Widget Function(double maxWidth) buildBottomControl;
|
||||
final double maxWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
@@ -51,7 +54,7 @@ class BottomControl extends StatelessWidget {
|
||||
buildDmChart(theme, controller, 4.5),
|
||||
if (controller.viewPointList.isNotEmpty &&
|
||||
controller.showVP.value)
|
||||
buildViewPointWidget(controller, 8.75),
|
||||
buildViewPointWidget(controller, 8.75, maxWidth),
|
||||
ProgressBar(
|
||||
progress: Duration(seconds: value),
|
||||
buffered: Duration(seconds: buffer),
|
||||
@@ -146,7 +149,7 @@ class BottomControl extends StatelessWidget {
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 18,
|
||||
child: buildSeekPreviewWidget(controller),
|
||||
child: buildSeekPreviewWidget(controller, maxWidth),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -154,7 +157,7 @@ class BottomControl extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
buildBottomControl(),
|
||||
buildBottomControl(maxWidth),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user