Update video controls
This commit is contained in:
parent
93ed21a444
commit
8b6685c3e2
3 changed files with 325 additions and 0 deletions
299
lib/ui/video_controls.dart
Normal file
299
lib/ui/video_controls.dart
Normal file
|
@ -0,0 +1,299 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:chewie/chewie.dart';
|
||||
import 'package:chewie/src/material_progress_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photos/utils/date_time_util.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
class VideoControls extends StatefulWidget {
|
||||
const VideoControls({Key key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _VideoControlsState();
|
||||
}
|
||||
}
|
||||
|
||||
class _VideoControlsState extends State<VideoControls> {
|
||||
VideoPlayerValue _latestValue;
|
||||
bool _hideStuff = true;
|
||||
Timer _hideTimer;
|
||||
Timer _initTimer;
|
||||
Timer _showAfterExpandCollapseTimer;
|
||||
bool _dragging = false;
|
||||
bool _displayTapped = false;
|
||||
|
||||
final barHeight = 48.0;
|
||||
final marginSize = 5.0;
|
||||
|
||||
VideoPlayerController controller;
|
||||
ChewieController chewieController;
|
||||
|
||||
@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(),
|
||||
child: AbsorbPointer(
|
||||
absorbing: _hideStuff,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
_latestValue != null &&
|
||||
!_latestValue.isPlaying &&
|
||||
_latestValue.duration == null ||
|
||||
_latestValue.isBuffering
|
||||
? const Expanded(
|
||||
child: const Center(
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: _buildHitArea(),
|
||||
_buildBottomBar(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _dispose() {
|
||||
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();
|
||||
}
|
||||
|
||||
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: Container(
|
||||
height: barHeight,
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
_buildCurrentPosition(iconColor),
|
||||
chewieController.isLive ? const SizedBox() : _buildProgressBar(),
|
||||
_buildTotalDuration(iconColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Expanded _buildHitArea() {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (_latestValue != null) {
|
||||
if (_displayTapped) {
|
||||
setState(() {
|
||||
_hideStuff = true;
|
||||
});
|
||||
} else
|
||||
_cancelAndRestartTimer();
|
||||
} else {
|
||||
_playPause();
|
||||
|
||||
setState(() {
|
||||
_hideStuff = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Center(
|
||||
child: AnimatedOpacity(
|
||||
opacity:
|
||||
_latestValue != null && !_hideStuff && !_dragging ? 1.0 : 0.0,
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: GestureDetector(
|
||||
onTap: _playPause,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12.0),
|
||||
child: Icon(
|
||||
_latestValue.isPlaying ? Icons.pause : Icons.play_arrow,
|
||||
size: 64.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCurrentPosition(Color iconColor) {
|
||||
final position = _latestValue != null && _latestValue.position != null
|
||||
? _latestValue.position
|
||||
: Duration.zero;
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.only(left: 20.0, right: 16.0),
|
||||
child: Text(
|
||||
'${formatDuration(position)}',
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTotalDuration(Color iconColor) {
|
||||
final duration = _latestValue != null && _latestValue.duration != null
|
||||
? _latestValue.duration
|
||||
: Duration.zero;
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: 20.0),
|
||||
child: Text(
|
||||
'${formatDuration(duration)}',
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _cancelAndRestartTimer() {
|
||||
_hideTimer?.cancel();
|
||||
_startHideTimer();
|
||||
|
||||
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 _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: 2), () {
|
||||
setState(() {
|
||||
_hideStuff = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _updateState() {
|
||||
setState(() {
|
||||
_latestValue = controller.value;
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildProgressBar() {
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 16.0),
|
||||
child: MaterialVideoProgressBar(
|
||||
controller,
|
||||
onDragStart: () {
|
||||
setState(() {
|
||||
_dragging = true;
|
||||
});
|
||||
|
||||
_hideTimer?.cancel();
|
||||
},
|
||||
onDragEnd: () {
|
||||
setState(() {
|
||||
_dragging = false;
|
||||
});
|
||||
|
||||
_startHideTimer();
|
||||
},
|
||||
colors: chewieController.materialProgressColors ??
|
||||
ChewieProgressColors(
|
||||
playedColor: Colors.white,
|
||||
handleColor: Colors.white,
|
||||
bufferedColor: Theme.of(context).backgroundColor,
|
||||
backgroundColor: Theme.of(context).disabledColor),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:chewie/chewie.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:photos/models/file.dart';
|
||||
import 'package:photos/ui/video_controls.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
import 'loading_widget.dart';
|
||||
|
@ -61,6 +63,7 @@ class _VideoWidgetState extends State<VideoWidget> {
|
|||
autoInitialize: true,
|
||||
looping: true,
|
||||
allowFullScreen: false,
|
||||
customControls: VideoControls(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,3 +64,26 @@ String getFormattedTime(DateTime dateTime) {
|
|||
" - " +
|
||||
getTime(dateTime);
|
||||
}
|
||||
|
||||
String formatDuration(Duration position) {
|
||||
final ms = position.inMilliseconds;
|
||||
|
||||
int seconds = ms ~/ 1000;
|
||||
final int hours = seconds ~/ 3600;
|
||||
seconds = seconds % 3600;
|
||||
var minutes = seconds ~/ 60;
|
||||
seconds = seconds % 60;
|
||||
|
||||
final hoursString = hours >= 10 ? '$hours' : hours == 0 ? '00' : '0$hours';
|
||||
|
||||
final minutesString =
|
||||
minutes >= 10 ? '$minutes' : minutes == 0 ? '00' : '0$minutes';
|
||||
|
||||
final secondsString =
|
||||
seconds >= 10 ? '$seconds' : seconds == 0 ? '00' : '0$seconds';
|
||||
|
||||
final formattedTime =
|
||||
'${hoursString == '00' ? '' : hoursString + ':'}$minutesString:$secondsString';
|
||||
|
||||
return formattedTime;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue