feat: 快进、快退、拖动时时间戳展示、关闭自动播放时处理、单p播放完成处理
This commit is contained in:
@ -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 {}
|
||||
|
Reference in New Issue
Block a user