|
@@ -0,0 +1,747 @@
|
|
|
|
|
+import 'dart:async';
|
|
|
|
|
+
|
|
|
|
|
+import 'package:chewie/chewie.dart';
|
|
|
|
|
+import 'package:chewie/src/chewie_player.dart';
|
|
|
|
|
+import 'package:chewie/src/chewie_progress_colors.dart';
|
|
|
|
|
+import 'package:chewie/src/i2_control_event.dart';
|
|
|
|
|
+import 'package:chewie/src/material_progress_bar.dart';
|
|
|
|
|
+import 'package:chewie/src/utils.dart';
|
|
|
|
|
+import 'package:flutter/material.dart';
|
|
|
|
|
+import 'package:screen/screen.dart';
|
|
|
|
|
+import 'package:sys_volume/flutter_volume.dart';
|
|
|
|
|
+import 'package:video_player/video_player.dart';
|
|
|
|
|
+
|
|
|
|
|
+class CartoonMaterialControls extends StatefulWidget {
|
|
|
|
|
+ final bool enableQuickControl;
|
|
|
|
|
+ final List<MoreVideo> moreVideo;
|
|
|
|
|
+ final OnTapMoreVideo onTapMoreVideo;
|
|
|
|
|
+ final VoidCallback onTapNext;
|
|
|
|
|
+ final VoidCallback onTapPrevious;
|
|
|
|
|
+ final VoidCallback onTapLove;
|
|
|
|
|
+
|
|
|
|
|
+ const CartoonMaterialControls({Key key, this.enableQuickControl = false, this.moreVideo, this.onTapMoreVideo, this.onTapNext, this.onTapPrevious, this.onTapLove}) : super(key: key);
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ State<StatefulWidget> createState() {
|
|
|
|
|
+ return CartoonMaterialControlsState();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+enum CartoonVerticalMode {
|
|
|
|
|
+ Volume,
|
|
|
|
|
+ Bright
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+typedef void OnTapMoreVideo(int index);
|
|
|
|
|
+
|
|
|
|
|
+class CartoonMaterialControlsState extends State<CartoonMaterialControls> {
|
|
|
|
|
+ VideoPlayerValue _latestValue;
|
|
|
|
|
+ double _latestVolume;
|
|
|
|
|
+ bool _hideStuff = true;
|
|
|
|
|
+ Timer _hideTimer;
|
|
|
|
|
+ Timer _initTimer;
|
|
|
|
|
+ Timer _showAfterExpandCollapseTimer;
|
|
|
|
|
+ bool _dragging = false;
|
|
|
|
|
+ bool _displayTapped = false;
|
|
|
|
|
+
|
|
|
|
|
+ final barHeight = 36.0;
|
|
|
|
|
+ final marginSize = 5.0;
|
|
|
|
|
+
|
|
|
|
|
+ VideoPlayerController controller;
|
|
|
|
|
+ ChewieController chewieController;
|
|
|
|
|
+
|
|
|
|
|
+ /// 横向视频进度拖动 BiLiBiLi的逻辑 duration > 90 ? 90s : duration * 0.8
|
|
|
|
|
+ double startDx;
|
|
|
|
|
+ double lastDx;
|
|
|
|
|
+ Duration dragDuration;
|
|
|
|
|
+ Duration updateDragDuration;
|
|
|
|
|
+ /// 竖向音量亮度拖动 100%调整的逻辑
|
|
|
|
|
+ double startDy;
|
|
|
|
|
+ double endDy;
|
|
|
|
|
+ CartoonVerticalMode _CartoonVerticalMode;
|
|
|
|
|
+ double currentBright;
|
|
|
|
|
+ double currentVolume;
|
|
|
|
|
+ String valueText;
|
|
|
|
|
+ StreamSubscription _eventBusStreamSubscription;
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ Widget build(BuildContext context) {
|
|
|
|
|
+ if (_latestValue.hasError) {
|
|
|
|
|
+ return chewieController.errorBuilder != null
|
|
|
|
|
+ ? chewieController.errorBuilder(
|
|
|
|
|
+ context,
|
|
|
|
|
+ chewieController.videoPlayerController.value.errorDescription,
|
|
|
|
|
+ )
|
|
|
|
|
+ : Center(
|
|
|
|
|
+ child: Icon(
|
|
|
|
|
+ Icons.error,
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ size: 42,
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return MouseRegion(
|
|
|
|
|
+ onHover: (_) {
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+ },
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ onTap: () => _cancelAndRestartTimer(),
|
|
|
|
|
+ onVerticalDragStart: (DragStartDetails details) async {
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 判断距离 只响应2/5的左边和2/5的右边
|
|
|
|
|
+ if (details.globalPosition.dx < MediaQuery.of(context).size.width / 5 * 2) {
|
|
|
|
|
+ // 响应亮度
|
|
|
|
|
+ startDy = details.globalPosition.dy;
|
|
|
|
|
+ _CartoonVerticalMode = CartoonVerticalMode.Bright;
|
|
|
|
|
+ currentBright = await Screen.brightness;
|
|
|
|
|
+ } else if (details.globalPosition.dx > MediaQuery.of(context).size.width / 5 * 3) {
|
|
|
|
|
+ // 响应音量
|
|
|
|
|
+ startDy = details.globalPosition.dy;
|
|
|
|
|
+ _CartoonVerticalMode = CartoonVerticalMode.Volume;
|
|
|
|
|
+ currentVolume = await FlutterVolume.get();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 中间位置不响应 reset
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _CartoonVerticalMode = null;
|
|
|
|
|
+ currentBright = null;
|
|
|
|
|
+ currentVolume = null;
|
|
|
|
|
+ startDy = null;
|
|
|
|
|
+ endDy = null;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ onVerticalDragUpdate: (DragUpdateDetails details) async {
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (_CartoonVerticalMode != null) {
|
|
|
|
|
+ // 显示数值(百分比)
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ endDy = details.globalPosition.dy;
|
|
|
|
|
+ });
|
|
|
|
|
+ if (_CartoonVerticalMode != null && endDy != null && startDy != null) {
|
|
|
|
|
+ double value;
|
|
|
|
|
+ if (_CartoonVerticalMode == CartoonVerticalMode.Bright) {
|
|
|
|
|
+ if (currentBright == null) return;
|
|
|
|
|
+ if (endDy > startDy) {
|
|
|
|
|
+ // 降低操作 竖屏环境?????
|
|
|
|
|
+ value = (currentBright - (endDy - startDy) / MediaQuery.of(context).size.height) < 0
|
|
|
|
|
+ ? 0
|
|
|
|
|
+ : (currentBright - (endDy - startDy) / MediaQuery.of(context).size.height);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 拉高操作 竖屏环境?????
|
|
|
|
|
+ value = (currentBright + (startDy - endDy) / MediaQuery.of(context).size.height) >= 1
|
|
|
|
|
+ ? 1
|
|
|
|
|
+ : (currentBright + (startDy - endDy) / MediaQuery.of(context).size.height);
|
|
|
|
|
+ }
|
|
|
|
|
+ Screen.setBrightness(value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (currentVolume == null) return;
|
|
|
|
|
+ if (endDy > startDy) {
|
|
|
|
|
+ // 降低操作 竖屏环境?????
|
|
|
|
|
+ value = (currentVolume - (endDy - startDy) / MediaQuery.of(context).size.height) < 0
|
|
|
|
|
+ ? 0
|
|
|
|
|
+ : (currentVolume - (endDy - startDy) / MediaQuery.of(context).size.height);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 拉高操作 竖屏环境?????
|
|
|
|
|
+ value = (currentVolume + (startDy - endDy) / MediaQuery.of(context).size.height) >= 1
|
|
|
|
|
+ ? 1
|
|
|
|
|
+ : (currentVolume + (startDy - endDy) / MediaQuery.of(context).size.height);
|
|
|
|
|
+ }
|
|
|
|
|
+ FlutterVolume.set(value);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (value == 1 || value == 0) {
|
|
|
|
|
+ // reset dy
|
|
|
|
|
+ startDy = endDy;
|
|
|
|
|
+ currentBright = await Screen.brightness;
|
|
|
|
|
+ currentVolume = await FlutterVolume.get();
|
|
|
|
|
+ }
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ valueText = (value * 100).toStringAsFixed(0);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ onVerticalDragEnd: (DragEndDetails details){
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _CartoonVerticalMode = null;
|
|
|
|
|
+ currentBright = null;
|
|
|
|
|
+ startDy = null;
|
|
|
|
|
+ endDy = null;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ onHorizontalDragStart: (DragStartDetails detail) {
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (_latestValue.duration == null) return;
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+ startDx = detail.localPosition.dx;
|
|
|
|
|
+ dragDuration = _latestValue.position;
|
|
|
|
|
+ },
|
|
|
|
|
+ onHorizontalDragUpdate: (DragUpdateDetails detail) {
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (_latestValue.duration == null) return;
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+ lastDx = detail.localPosition.dx;
|
|
|
|
|
+ // update progress bar
|
|
|
|
|
+ Duration finalDuration = getDragDuration();
|
|
|
|
|
+
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ updateDragDuration = finalDuration;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ onHorizontalDragCancel: (){
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ startDx = null;
|
|
|
|
|
+ lastDx = null;
|
|
|
|
|
+ dragDuration = null;
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ updateDragDuration = null;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ onHorizontalDragEnd: (DragEndDetails detail) {
|
|
|
|
|
+ if (!widget.enableQuickControl) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (startDx != null && lastDx != null && _latestValue.duration != null && dragDuration != null) {
|
|
|
|
|
+ Duration finalDuration = getDragDuration();
|
|
|
|
|
+ chewieController.seekTo(finalDuration);
|
|
|
|
|
+ }
|
|
|
|
|
+ startDx = null;
|
|
|
|
|
+ lastDx = null;
|
|
|
|
|
+ dragDuration = null;
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ updateDragDuration = null;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ child: AbsorbPointer(
|
|
|
|
|
+ absorbing: _hideStuff,
|
|
|
|
|
+ child: Stack(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ Column(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ _latestValue != null &&
|
|
|
|
|
+ !_latestValue.isPlaying &&
|
|
|
|
|
+ _latestValue.duration == null ||
|
|
|
|
|
+ _latestValue.isBuffering
|
|
|
|
|
+ ? const Expanded(
|
|
|
|
|
+ child: const Center(
|
|
|
|
|
+ child: const CircularProgressIndicator(),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ : _buildHitArea(),
|
|
|
|
|
+ _buildBottomBar(context),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
|
|
+ _buildTopBar(context),
|
|
|
|
|
+ _buildDragProgress(),
|
|
|
|
|
+ _buildVerticalWidget(),
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ void initState() {
|
|
|
|
|
+ super.initState();
|
|
|
|
|
+ _initState();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _initState() async {
|
|
|
|
|
+ FlutterVolume.disableUI();
|
|
|
|
|
+ _eventBusStreamSubscription = i2ControlEventBus.on<I2ControllerEvent>().listen((event){
|
|
|
|
|
+ if (event == I2ControllerEvent.ShowControl) {
|
|
|
|
|
+ _showControlWithoutTimer();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ void dispose() {
|
|
|
|
|
+ _eventBusStreamSubscription.cancel();
|
|
|
|
|
+ Screen.resetAndroidBrightness();
|
|
|
|
|
+ _dispose();
|
|
|
|
|
+ super.dispose();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _dispose() async {
|
|
|
|
|
+ controller.removeListener(_updateState);
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ _initTimer?.cancel();
|
|
|
|
|
+ _showAfterExpandCollapseTimer?.cancel();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @override
|
|
|
|
|
+ void didChangeDependencies() {
|
|
|
|
|
+ final _oldController = chewieController;
|
|
|
|
|
+ chewieController = ChewieController.of(context);
|
|
|
|
|
+ controller = chewieController.videoPlayerController;
|
|
|
|
|
+
|
|
|
|
|
+ if (_oldController != chewieController) {
|
|
|
|
|
+ _dispose();
|
|
|
|
|
+ _initialize();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ super.didChangeDependencies();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Duration getDragDuration() {
|
|
|
|
|
+ if (lastDx - startDx > 0) {
|
|
|
|
|
+ // 前进
|
|
|
|
|
+ int forwardSec;
|
|
|
|
|
+ if (_latestValue.duration.inSeconds > 90) {
|
|
|
|
|
+ forwardSec = ((lastDx - startDx) / MediaQuery.of(context).size.width * 90).toInt();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ forwardSec = ((lastDx - startDx) / MediaQuery.of(context).size.width * _latestValue.duration.inSeconds * 0.8).toInt();
|
|
|
|
|
+ }
|
|
|
|
|
+ Duration duration = dragDuration + Duration(seconds: forwardSec);
|
|
|
|
|
+ return duration >= _latestValue.duration ? _latestValue.duration : duration;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 后退
|
|
|
|
|
+ int backwardSec;
|
|
|
|
|
+ if (_latestValue.duration.inSeconds > 90) {
|
|
|
|
|
+ backwardSec = ((lastDx - startDx) * -1 / MediaQuery.of(context).size.width * 90).toInt();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ backwardSec = ((lastDx - startDx) * -1 / MediaQuery.of(context).size.width * _latestValue.duration.inSeconds * 0.8).toInt();
|
|
|
|
|
+ }
|
|
|
|
|
+ Duration duration = (Duration(seconds: backwardSec) > dragDuration) ? Duration.zero : dragDuration - Duration(seconds: backwardSec);
|
|
|
|
|
+ return duration;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Widget _buildDragProgress() {
|
|
|
|
|
+ final position = updateDragDuration ?? (_latestValue != null && _latestValue.position != null
|
|
|
|
|
+ ? _latestValue.position
|
|
|
|
|
+ : Duration.zero);
|
|
|
|
|
+ return Offstage(
|
|
|
|
|
+ offstage: updateDragDuration == null,
|
|
|
|
|
+ child: Align(
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ width: 96,
|
|
|
|
|
+ height: 34,
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: Color(0xB0000000),
|
|
|
|
|
+ borderRadius: BorderRadius.circular(4),
|
|
|
|
|
+ ),
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ child: Text("${formatDuration(position)}/${formatDuration(_latestValue.duration)}", style: TextStyle(color: Colors.white, fontSize: 12),),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Widget _buildVerticalWidget() {
|
|
|
|
|
+// ((endDy - startDy) / widgetHeight * 100).toStringAsFixed(2)
|
|
|
|
|
+ // 正方圆角
|
|
|
|
|
+ return Offstage(
|
|
|
|
|
+ offstage: _CartoonVerticalMode == null,
|
|
|
|
|
+ child: Align(
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ width: 80,
|
|
|
|
|
+ height: 80,
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: Color(0xB0000000),
|
|
|
|
|
+ borderRadius: BorderRadius.circular(4),
|
|
|
|
|
+ ),
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ child: Column(
|
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
+ mainAxisSize: MainAxisSize.max,
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ Icon(_CartoonVerticalMode == CartoonVerticalMode.Volume ? Icons.volume_up : Icons.brightness_6, color: Colors.white, size: 24,),
|
|
|
|
|
+ Padding(
|
|
|
|
|
+ padding: const EdgeInsets.only(top: 10),
|
|
|
|
|
+ child: Text("${valueText}%", style: TextStyle(color: Colors.white, fontSize: 15,),),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ AnimatedOpacity _buildTopBar(
|
|
|
|
|
+ BuildContext context,
|
|
|
|
|
+ ) {
|
|
|
|
|
+ return AnimatedOpacity(
|
|
|
|
|
+ opacity: _hideStuff ? 0.0 : 1.0,
|
|
|
|
|
+ duration: Duration(milliseconds: 300),
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ borderRadius: BorderRadius.only(bottomRight: Radius.circular(10), bottomLeft: Radius.circular(10)),
|
|
|
|
|
+ ),
|
|
|
|
|
+// color: chewieController.isFullScreen ? Colors.black26 : Colors.transparent,
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ margin: EdgeInsets.only(left: (MediaQuery.of(context).size.width - 280) / 2),
|
|
|
|
|
+ width: 300,
|
|
|
|
|
+ height: 46,
|
|
|
|
|
+// margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top != 0 ? MediaQuery.of(context).padding.top : 0),
|
|
|
|
|
+ padding: EdgeInsets.only(left: 13,),
|
|
|
|
|
+ child: Row(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Image(image: AssetImage("assets/dub_user_play/back2.png", package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ onTap: onTapBack,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Image(image: AssetImage("assets/dub_user_play/rightyou.png", package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ onTap: widget.onTapPrevious,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Image(image: AssetImage(controller.value.isPlaying ? "assets/dub_user_play/top_stop.png" : "assets/dub_user_play/top_bof.png" , package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ onTap: _playPause,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Image(image: AssetImage("assets/dub_user_play/rightji.png", package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ onTap: widget.onTapNext,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Image(image: AssetImage("assets/dub_user_play/xin.png", package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ onTap: widget.onTapLove,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ AnimatedOpacity _buildBottomBar(
|
|
|
|
|
+ BuildContext context,
|
|
|
|
|
+ ) {
|
|
|
|
|
+ final iconColor = Theme.of(context).textTheme.button.color;
|
|
|
|
|
+
|
|
|
|
|
+ return AnimatedOpacity(
|
|
|
|
|
+ opacity: _hideStuff ? 0.0 : 1.0,
|
|
|
|
|
+ duration: Duration(milliseconds: 300),
|
|
|
|
|
+ child: Column(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ Container(
|
|
|
|
|
+ height: barHeight + (widget.moreVideo.length == 0 ? 0 : 80),
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ gradient: const LinearGradient(
|
|
|
|
|
+ colors: [Colors.black38, Colors.transparent], begin: Alignment.bottomCenter, end: Alignment.topCenter, stops: [0.0, 1]),
|
|
|
|
|
+ ),
|
|
|
|
|
+ child: Column(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ SizedBox(
|
|
|
|
|
+ height: barHeight,
|
|
|
|
|
+ child: Row(
|
|
|
|
|
+ children: <Widget>[
|
|
|
|
|
+ chewieController.isLive
|
|
|
|
|
+ ? Expanded(child: const Text('LIVE'))
|
|
|
|
|
+ : _buildPosition(iconColor),
|
|
|
|
|
+ chewieController.isLive ? const SizedBox() : _buildProgressBar(),
|
|
|
|
|
+ chewieController.isLive
|
|
|
|
|
+ ? const SizedBox()
|
|
|
|
|
+ : _buildFullPosition(iconColor),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ Offstage(
|
|
|
|
|
+ offstage: widget.moreVideo.length == 0,
|
|
|
|
|
+ child: SizedBox(
|
|
|
|
|
+ height: 80,
|
|
|
|
|
+ child: Listener(
|
|
|
|
|
+ child: ListView.builder(
|
|
|
|
|
+ scrollDirection: Axis.horizontal,
|
|
|
|
|
+ shrinkWrap: true,
|
|
|
|
|
+ itemCount: widget.moreVideo.length,
|
|
|
|
|
+ itemBuilder: (ctx, index){
|
|
|
|
|
+ return GestureDetector(
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ width: 100,
|
|
|
|
|
+ height: 60,
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ borderRadius: BorderRadius.circular(15),
|
|
|
|
|
+ border: widget.moreVideo[index].isSelect ? Border.all(color: Color(0xFFEF765E), width: 3) : null,
|
|
|
|
|
+ ),
|
|
|
|
|
+ margin: EdgeInsets.only(left: 10, right: 10, bottom: 10),
|
|
|
|
|
+ child: ClipRRect(
|
|
|
|
|
+ borderRadius: BorderRadius.circular(15),
|
|
|
|
|
+ child: Image.network(widget.moreVideo[index].imageUrl, fit: BoxFit.fill,),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ onTap: () {
|
|
|
|
|
+ widget?.onTapMoreVideo(index);
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+ ),
|
|
|
|
|
+ onPointerDown: onMoreVideoPointerDown,
|
|
|
|
|
+ onPointerUp: onMoreVideoPointerUp,
|
|
|
|
|
+ )
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ )
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ GestureDetector _buildExpandButton() {
|
|
|
|
|
+ return GestureDetector(
|
|
|
|
|
+ onTap: _onExpandCollapse,
|
|
|
|
|
+ child: AnimatedOpacity(
|
|
|
|
|
+ opacity: _hideStuff ? 0.0 : 1.0,
|
|
|
|
|
+ duration: Duration(milliseconds: 300),
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ height: barHeight,
|
|
|
|
|
+ margin: EdgeInsets.only(right: 12.0),
|
|
|
|
|
+ padding: EdgeInsets.only(
|
|
|
|
|
+ left: 8.0,
|
|
|
|
|
+ right: 8.0,
|
|
|
|
|
+ ),
|
|
|
|
|
+ child: Center(
|
|
|
|
|
+ child: Image(image: AssetImage("assets/dub_user_play/${chewieController.isFullScreen ? "shousuo.png" : "fangda.png"}", package: 'chewie'), width: 20, height: 20,),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Expanded _buildHitArea() {
|
|
|
|
|
+ return Expanded(
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ onTap: () {
|
|
|
|
|
+ if (_latestValue != null && _latestValue.isPlaying) {
|
|
|
|
|
+ if (_displayTapped) {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ } else
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _playPause();
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ color: Colors.transparent,
|
|
|
|
|
+ child: Center(
|
|
|
|
|
+ child: AnimatedOpacity(
|
|
|
|
|
+ opacity:
|
|
|
|
|
+ _latestValue != null && !_latestValue.isPlaying && !_dragging
|
|
|
|
|
+ ? 1.0
|
|
|
|
|
+ : 0.0,
|
|
|
|
|
+ duration: Duration(milliseconds: 300),
|
|
|
|
|
+ child: GestureDetector(
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: Theme.of(context).dialogBackgroundColor,
|
|
|
|
|
+ borderRadius: BorderRadius.circular(48.0),
|
|
|
|
|
+ ),
|
|
|
|
|
+ child: Padding(
|
|
|
|
|
+ padding: EdgeInsets.all(12.0),
|
|
|
|
|
+ child: Icon(Icons.play_arrow, size: 32.0, color: Colors.black,),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Widget _buildPosition(Color iconColor) {
|
|
|
|
|
+ final position = updateDragDuration ?? (_latestValue != null && _latestValue.position != null
|
|
|
|
|
+ ? _latestValue.position
|
|
|
|
|
+ : Duration.zero);
|
|
|
|
|
+ final duration = _latestValue != null && _latestValue.duration != null
|
|
|
|
|
+ ? _latestValue.duration
|
|
|
|
|
+ : Duration.zero;
|
|
|
|
|
+
|
|
|
|
|
+ return Padding(
|
|
|
|
|
+ padding: EdgeInsets.only(left: 20.0, right: 14.0),
|
|
|
|
|
+ child: Text(
|
|
|
|
|
+ '${formatDuration(position)}',
|
|
|
|
|
+ style: TextStyle(
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ fontSize: 12.0,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Widget _buildFullPosition(Color iconColor) {
|
|
|
|
|
+ final position = _latestValue != null && _latestValue.position != null
|
|
|
|
|
+ ? _latestValue.position
|
|
|
|
|
+ : Duration.zero;
|
|
|
|
|
+ final duration = _latestValue != null && _latestValue.duration != null
|
|
|
|
|
+ ? _latestValue.duration
|
|
|
|
|
+ : Duration.zero;
|
|
|
|
|
+
|
|
|
|
|
+ return Padding(
|
|
|
|
|
+ padding: EdgeInsets.only(left: 14.0, right: 20.0),
|
|
|
|
|
+ child: Text(
|
|
|
|
|
+ '${formatDuration(duration)}',
|
|
|
|
|
+ style: TextStyle(
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ fontSize: 12.0,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _cancelAndRestartTimer() {
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ _startHideTimer();
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = false;
|
|
|
|
|
+ _displayTapped = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _showControlWithoutTimer() {
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = false;
|
|
|
|
|
+ _displayTapped = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Future<Null> _initialize() async {
|
|
|
|
|
+ controller.addListener(_updateState);
|
|
|
|
|
+
|
|
|
|
|
+ _updateState();
|
|
|
|
|
+
|
|
|
|
|
+ if ((controller.value != null && controller.value.isPlaying) ||
|
|
|
|
|
+ chewieController.autoPlay) {
|
|
|
|
|
+ _startHideTimer();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (chewieController.showControlsOnInitialize) {
|
|
|
|
|
+ _initTimer = Timer(Duration(milliseconds: 200), () {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _onExpandCollapse() {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = true;
|
|
|
|
|
+ chewieController.toggleFullScreen();
|
|
|
|
|
+ _showAfterExpandCollapseTimer = Timer(Duration(milliseconds: 300), () {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _playPause() {
|
|
|
|
|
+ bool isFinished = _latestValue.position >= _latestValue.duration;
|
|
|
|
|
+
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ if (controller.value.isPlaying) {
|
|
|
|
|
+ _hideStuff = false;
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ controller.pause();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ _cancelAndRestartTimer();
|
|
|
|
|
+
|
|
|
|
|
+ if (!controller.value.initialized) {
|
|
|
|
|
+ controller.initialize().then((_) {
|
|
|
|
|
+ controller.play();
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (isFinished) {
|
|
|
|
|
+ controller.seekTo(Duration(seconds: 0));
|
|
|
|
|
+ }
|
|
|
|
|
+ controller.play();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _startHideTimer() {
|
|
|
|
|
+ _hideTimer = Timer(const Duration(seconds: 3), () {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _hideStuff = true;
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _updateState() {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _latestValue = controller.value;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Widget _buildProgressBar() {
|
|
|
|
|
+ return Expanded(
|
|
|
|
|
+ child: MaterialVideoProgressBar(
|
|
|
|
|
+ controller,
|
|
|
|
|
+ onDragStart: () {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _dragging = true;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ },
|
|
|
|
|
+ onDragEnd: () {
|
|
|
|
|
+ setState(() {
|
|
|
|
|
+ _dragging = false;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ _startHideTimer();
|
|
|
|
|
+ },
|
|
|
|
|
+ colors: chewieController.materialProgressColors ??
|
|
|
|
|
+ ChewieProgressColors(
|
|
|
|
|
+ playedColor: Color(0xFFC7000B),
|
|
|
|
|
+ handleColor: Color(0xFFC7000B),
|
|
|
|
|
+ bufferedColor: Color(0x5AC7000B),
|
|
|
|
|
+ backgroundColor: Color(0x5AFFFFFF)),
|
|
|
|
|
+ millionSec: updateDragDuration?.inMilliseconds,
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void onTapBack() {
|
|
|
|
|
+ print("onTapBack");
|
|
|
|
|
+ chewieController.exitFullScreen();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void onMoreVideoPointerDown(PointerDownEvent event) {
|
|
|
|
|
+ _hideTimer?.cancel();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void onMoreVideoPointerUp(PointerUpEvent event) {
|
|
|
|
|
+ _startHideTimer();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|