|
|
@@ -6,6 +6,8 @@ import 'package:chewie/src/material_progress_bar.dart';
|
|
|
import 'package:chewie/src/utils.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:flutter/services.dart';
|
|
|
+import 'package:screen/screen.dart';
|
|
|
+import 'package:sys_volume/flutter_volume.dart';
|
|
|
import 'package:video_player/video_player.dart';
|
|
|
|
|
|
class I2MaterialControls extends StatefulWidget {
|
|
|
@@ -18,6 +20,11 @@ class I2MaterialControls extends StatefulWidget {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+enum VerticalMode {
|
|
|
+ Volume,
|
|
|
+ Bright
|
|
|
+}
|
|
|
+
|
|
|
class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
VideoPlayerValue _latestValue;
|
|
|
double _latestVolume;
|
|
|
@@ -34,6 +41,20 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
VideoPlayerController controller;
|
|
|
ChewieController chewieController;
|
|
|
|
|
|
+ /// 横向视频进度拖动 BiLiBiLi的逻辑 duration > 90 ? 90s : duration * 0.8
|
|
|
+ double startDx;
|
|
|
+ double lastDx;
|
|
|
+ Duration dragDuration;
|
|
|
+ Duration updateDragDuration;
|
|
|
+ /// 竖向音量亮度拖动 100%调整的逻辑
|
|
|
+ double startDy;
|
|
|
+ double endDy;
|
|
|
+ VerticalMode _verticalMode;
|
|
|
+ double savedBright;
|
|
|
+ double currentBright;
|
|
|
+ double currentVolume;
|
|
|
+ String valueText;
|
|
|
+
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
if (_latestValue.hasError) {
|
|
|
@@ -57,6 +78,124 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
},
|
|
|
child: GestureDetector(
|
|
|
onTap: () => _cancelAndRestartTimer(),
|
|
|
+ onVerticalDragStart: (DragStartDetails details) async {
|
|
|
+ print("onVerticalDragStart ${details.globalPosition}");
|
|
|
+ // 判断距离 只响应2/5的左边和2/5的右边
|
|
|
+ if (details.globalPosition.dx < MediaQuery.of(context).size.width / 5 * 2) {
|
|
|
+ // 响应亮度
|
|
|
+ startDy = details.globalPosition.dy;
|
|
|
+ _verticalMode = VerticalMode.Bright;
|
|
|
+ currentBright = await Screen.brightness;
|
|
|
+ } else if (details.globalPosition.dx > MediaQuery.of(context).size.width / 5 * 3) {
|
|
|
+ // 响应音量
|
|
|
+ startDy = details.globalPosition.dy;
|
|
|
+ _verticalMode = VerticalMode.Volume;
|
|
|
+ currentVolume = await FlutterVolume.get();
|
|
|
+ } else {
|
|
|
+ // 中间位置不响应 reset
|
|
|
+ setState(() {
|
|
|
+ _verticalMode = null;
|
|
|
+ currentBright = null;
|
|
|
+ currentVolume = null;
|
|
|
+ startDy = null;
|
|
|
+ endDy = null;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onVerticalDragUpdate: (DragUpdateDetails details) async {
|
|
|
+ print("onVerticalDragUpdate ${details.globalPosition}");
|
|
|
+ if (_verticalMode != null) {
|
|
|
+ // 显示数值(百分比)
|
|
|
+ setState(() {
|
|
|
+ endDy = details.globalPosition.dy;
|
|
|
+ });
|
|
|
+ if (_verticalMode != null && endDy != null && startDy != null) {
|
|
|
+ double value;
|
|
|
+ if (_verticalMode == VerticalMode.Bright) {
|
|
|
+ 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 (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){
|
|
|
+ setState(() {
|
|
|
+ _verticalMode = null;
|
|
|
+ currentBright = null;
|
|
|
+ startDy = null;
|
|
|
+ endDy = null;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onHorizontalDragStart: (DragStartDetails detail) {
|
|
|
+ if (_latestValue.duration == null) return;
|
|
|
+ _cancelAndRestartTimer();
|
|
|
+ startDx = detail.localPosition.dx;
|
|
|
+ dragDuration = _latestValue.position;
|
|
|
+ },
|
|
|
+ onHorizontalDragUpdate: (DragUpdateDetails detail) {
|
|
|
+ if (_latestValue.duration == null) return;
|
|
|
+ _cancelAndRestartTimer();
|
|
|
+ lastDx = detail.localPosition.dx;
|
|
|
+ // update progress bar
|
|
|
+ Duration finalDuration = getDragDuration();
|
|
|
+
|
|
|
+ setState(() {
|
|
|
+ updateDragDuration = finalDuration;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onHorizontalDragCancel: (){
|
|
|
+ startDx = null;
|
|
|
+ lastDx = null;
|
|
|
+ dragDuration = null;
|
|
|
+ setState(() {
|
|
|
+ updateDragDuration = null;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onHorizontalDragEnd: (DragEndDetails detail) {
|
|
|
+ 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(
|
|
|
@@ -78,8 +217,10 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
),
|
|
|
Positioned(
|
|
|
child: _buildTopBar(context),
|
|
|
- top: 20,
|
|
|
+ top: MediaQuery.of(context).padding.top,
|
|
|
),
|
|
|
+ _buildDragProgress(),
|
|
|
+ _buildVerticalWidget(),
|
|
|
],
|
|
|
)
|
|
|
),
|
|
|
@@ -87,6 +228,17 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ super.initState();
|
|
|
+ _initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ void _initState() async {
|
|
|
+ savedBright = await Screen.brightness;
|
|
|
+ FlutterVolume.disableUI();
|
|
|
+ }
|
|
|
+
|
|
|
@override
|
|
|
void dispose() {
|
|
|
_dispose();
|
|
|
@@ -94,6 +246,7 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
}
|
|
|
|
|
|
void _dispose() async {
|
|
|
+ Screen.setBrightness(savedBright);
|
|
|
controller.removeListener(_updateState);
|
|
|
_hideTimer?.cancel();
|
|
|
_initTimer?.cancel();
|
|
|
@@ -114,6 +267,82 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
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: _verticalMode == 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(_verticalMode == VerticalMode.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,
|
|
|
@@ -301,9 +530,9 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
}
|
|
|
|
|
|
Widget _buildPosition(Color iconColor) {
|
|
|
- final position = _latestValue != null && _latestValue.position != null
|
|
|
+ final position = updateDragDuration ?? (_latestValue != null && _latestValue.position != null
|
|
|
? _latestValue.position
|
|
|
- : Duration.zero;
|
|
|
+ : Duration.zero);
|
|
|
final duration = _latestValue != null && _latestValue.duration != null
|
|
|
? _latestValue.duration
|
|
|
: Duration.zero;
|
|
|
@@ -461,6 +690,7 @@ class _MaterialControlsState extends State<I2MaterialControls> {
|
|
|
handleColor: Color(0xFFC7000B),
|
|
|
bufferedColor: Color(0x5AC7000B),
|
|
|
backgroundColor: Color(0x5AFFFFFF)),
|
|
|
+ millionSec: updateDragDuration?.inMilliseconds,
|
|
|
),
|
|
|
);
|
|
|
}
|