feat: 快进、快退、拖动时时间戳展示、关闭自动播放时处理、单p播放完成处理

This commit is contained in:
guozhigq
2023-08-01 22:51:33 +08:00
parent b947397333
commit e97abb545f
9 changed files with 585 additions and 40 deletions

View File

@ -2,14 +2,20 @@ import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:pilipala/common/widgets/app_bar_ani.dart';
import 'package:pilipala/plugin/pl_player/controller.dart';
import 'package:pilipala/plugin/pl_player/models/duration.dart';
import 'package:pilipala/plugin/pl_player/models/play_status.dart';
import 'package:pilipala/plugin/pl_player/utils.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'widgets/backward_seek.dart';
import 'widgets/bottom_control.dart';
import 'widgets/common_btn.dart';
import 'widgets/forward_seek.dart';
import 'widgets/play_pause_btn.dart';
class PLVideoPlayer extends StatefulWidget {
final PlPlayerController controller;
@ -32,6 +38,23 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
late AnimationController animationController;
late VideoController videoController;
bool _mountSeekBackwardButton = false;
bool _mountSeekForwardButton = false;
bool _hideSeekBackwardButton = false;
bool _hideSeekForwardButton = false;
void onDoubleTapSeekBackward() {
setState(() {
_mountSeekBackwardButton = true;
});
}
void onDoubleTapSeekForward() {
setState(() {
_mountSeekForwardButton = true;
});
}
@override
void initState() {
super.initState();
@ -59,10 +82,33 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
fontWeight: FontWeight.normal,
backgroundColor: Color(0xaa000000),
);
const textStyle = TextStyle(
color: Colors.white,
fontSize: 12,
);
return Stack(
clipBehavior: Clip.hardEdge,
fit: StackFit.passthrough,
children: [
// Wrap [Video] widget with [MaterialVideoControlsTheme].
// MaterialVideoControlsTheme(
// normal: MaterialVideoControlsThemeData(
// // Modify theme options:
// buttonBarButtonSize: 24.0,
// buttonBarButtonColor: Colors.white,
// ),
// fullscreen: const MaterialVideoControlsThemeData(
// // Modify theme options:
// displaySeekBar: false,
// automaticallyImplySkipNextButton: false,
// automaticallyImplySkipPreviousButton: false,
// ),
// child: Scaffold(
// body: Video(
// controller: videoController,
// ),
// ),
// ),
Video(
controller: videoController,
controls: NoVideoControls,
@ -78,11 +124,29 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
onTap: () {
_.controls = !_.showControls.value;
},
onDoubleTap: () {
if (_.playerStatus.status.value == PlayerStatus.playing) {
_.togglePlay();
// onDoubleTap: () {
// if (_.playerStatus.status.value == PlayerStatus.playing) {
// _.togglePlay();
// } else {
// _.play();
// }
// },
onDoubleTapDown: (details) {
final totalWidth = MediaQuery.of(context).size.width;
final tapPosition = details.localPosition.dx;
final sectionWidth = totalWidth / 3;
if (tapPosition < sectionWidth) {
// 双击左边区域 👈
onDoubleTapSeekBackward();
} else if (tapPosition < sectionWidth * 2) {
if (_.playerStatus.status.value == PlayerStatus.playing) {
_.togglePlay();
} else {
_.play();
}
} else {
_.play();
// 双击右边区域 👈
onDoubleTapSeekForward();
}
},
onLongPressStart: (detail) {
@ -112,7 +176,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
clipBehavior: Clip.hardEdge,
child: AppBarAni(
controller: animationController,
visible: !_.controlsClose.value && _.showControls.value,
visible: !_.controlsLock.value && _.showControls.value,
position: 'top',
child: widget.headerControl!,
),
@ -122,7 +186,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
clipBehavior: Clip.hardEdge,
child: AppBarAni(
controller: animationController,
visible: !_.controlsClose.value && _.showControls.value,
visible: !_.controlsLock.value && _.showControls.value,
position: 'bottom',
child: BottomControl(controller: widget.controller),
),
@ -140,7 +204,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
return Container();
}
return Positioned(
bottom: -4,
bottom: -3,
left: 0,
right: 0,
child: SlideTransition(
@ -161,22 +225,22 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
Theme.of(context).colorScheme.primary.withOpacity(0.4),
timeLabelLocation: TimeLabelLocation.none,
thumbColor: colorTheme,
barHeight: 3,
barHeight: 2,
thumbRadius: 0.0,
onDragStart: (duration) {
_.onChangedSliderStart();
},
onDragEnd: () {
_.onChangedSliderEnd();
},
// onDragStart: (duration) {
// _.onChangedSliderStart();
// },
// onDragEnd: () {
// _.onChangedSliderEnd();
// },
// onDragUpdate: (details) {
// print(details);
// },
onSeek: (duration) {
feedBack();
_.onChangedSlider(duration.inSeconds.toDouble());
_.seekTo(duration);
},
// onSeek: (duration) {
// feedBack();
// _.onChangedSlider(duration.inSeconds.toDouble());
// _.seekTo(duration);
// },
)),
);
},
@ -212,13 +276,13 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
visible: _.showControls.value,
child: ComBtn(
icon: Icon(
_.controlsClose.value
_.controlsLock.value
? FontAwesomeIcons.lock
: FontAwesomeIcons.lockOpen,
size: 15,
color: Colors.white,
),
fuc: () => _.onCloseControl(!_.controlsClose.value),
fuc: () => _.onLockControl(!_.controlsLock.value),
),
),
),
@ -237,6 +301,141 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
return Container();
}
}),
// 时间进度
/// TDDO 样式
Obx(
() => Align(
alignment: Alignment.topCenter,
child: FractionalTranslation(
translation: const Offset(0.0, 2.5), // 上下偏移量(负数向上偏移)
child: Visibility(
visible: _.isSliderMoving.value,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() {
return Text(
_.sliderTempPosition.value.inMinutes >= 60
? printDurationWithHours(_.sliderTempPosition.value)
: printDuration(_.sliderTempPosition.value),
style: textStyle,
);
}),
const SizedBox(width: 2),
const Text('/', style: textStyle),
const SizedBox(width: 2),
Obx(
() => Text(
_.duration.value.inMinutes >= 60
? printDurationWithHours(_.duration.value)
: printDuration(_.duration.value),
style: textStyle,
),
),
],
),
),
),
),
),
// 点击 快进/快退
if (_mountSeekBackwardButton || _mountSeekForwardButton)
Positioned.fill(
child: Row(
children: [
Expanded(
child: _mountSeekBackwardButton
? TweenAnimationBuilder<double>(
tween: Tween<double>(
begin: 0.0,
end: _hideSeekBackwardButton ? 0.0 : 1.0,
),
duration: const Duration(milliseconds: 500),
builder: (context, value, child) => Opacity(
opacity: value,
child: child,
),
onEnd: () {
if (_hideSeekBackwardButton) {
setState(() {
_hideSeekBackwardButton = false;
_mountSeekBackwardButton = false;
});
}
},
child: BackwardSeekIndicator(
onChanged: (value) {
print(value);
// _seekBarDeltaValueNotifier.value = -value;
},
onSubmitted: (value) {
setState(() {
_hideSeekBackwardButton = true;
});
Player player =
widget.controller.videoPlayerController!;
var result = player.state.position - value;
result = result.clamp(
Duration.zero,
player.state.duration,
);
player.seek(result);
widget.controller.play();
},
),
)
: const SizedBox(),
),
Expanded(
child: SizedBox(
width: MediaQuery.of(context).size.width / 4,
),
),
Expanded(
child: _mountSeekForwardButton
? TweenAnimationBuilder<double>(
tween: Tween<double>(
begin: 0.0,
end: _hideSeekForwardButton ? 0.0 : 1.0,
),
duration: const Duration(milliseconds: 500),
builder: (context, value, child) => Opacity(
opacity: value,
child: child,
),
onEnd: () {
if (_hideSeekForwardButton) {
setState(() {
_hideSeekForwardButton = false;
_mountSeekForwardButton = false;
});
}
},
child: ForwardSeekIndicator(
onChanged: (value) {
// _seekBarDeltaValueNotifier.value = value;
},
onSubmitted: (value) {
setState(() {
_hideSeekForwardButton = true;
});
Player player =
widget.controller.videoPlayerController!;
var result = player.state.position + value;
result = result.clamp(
Duration.zero,
player.state.duration,
);
player.seek(result);
widget.controller.play();
},
),
)
: const SizedBox(),
),
],
),
),
],
);
}
@ -256,5 +455,3 @@ class MSliderTrackShape extends RoundedRectSliderTrackShape {
return Rect.fromLTWH(trackLeft, -1, trackWidth, 3);
}
}
class PLPlayerCtr extends GetxController {}