Skip to content

Commit

Permalink
Merge pull request #623 from henri2h/temporized-buffering-status
Browse files Browse the repository at this point in the history
[Android] Add a delay before displaying progress indicator
  • Loading branch information
diegotori committed Jun 8, 2022
2 parents fde2eca + 491becd commit 7b3b839
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 5 deletions.
76 changes: 75 additions & 1 deletion example/lib/app/app.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:chewie/chewie.dart';
import 'package:chewie_example/app/theme.dart';
import 'package:flutter/material.dart';
Expand All @@ -23,6 +25,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
late VideoPlayerController _videoPlayerController1;
late VideoPlayerController _videoPlayerController2;
ChewieController? _chewieController;
int? bufferDelay;

@override
void initState() {
Expand All @@ -39,6 +42,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
}

List<String> srcs = [
"https://assets.mixkit.co/videos/preview/mixkit-spinning-around-the-earth-29351-large.mp4",
"https://assets.mixkit.co/videos/preview/mixkit-daytime-city-traffic-aerial-view-56-large.mp4",
"https://assets.mixkit.co/videos/preview/mixkit-a-girl-blowing-a-bubble-gum-at-an-amusement-park-1226-large.mp4"
];
Expand Down Expand Up @@ -110,6 +114,8 @@ class _ChewieDemoState extends State<ChewieDemo> {
videoPlayerController: _videoPlayerController1,
autoPlay: true,
looping: true,
progressIndicatorDelay:
bufferDelay != null ? Duration(milliseconds: bufferDelay!) : null,

additionalOptions: (context) {
return <OptionItem>[
Expand Down Expand Up @@ -155,7 +161,10 @@ class _ChewieDemoState extends State<ChewieDemo> {

Future<void> toggleVideo() async {
await _videoPlayerController1.pause();
currPlayIndex = currPlayIndex == 0 ? 1 : 0;
currPlayIndex += 1;
if (currPlayIndex >= srcs.length) {
currPlayIndex = 0;
}
await initializePlayer();
}

Expand Down Expand Up @@ -302,9 +311,74 @@ class _ChewieDemoState extends State<ChewieDemo> {
),
],
),
if (Platform.isAndroid)
ListTile(
title: const Text("Delay"),
subtitle: DelaySlider(
delay:
_chewieController?.progressIndicatorDelay?.inMilliseconds,
onSave: (delay) async {
if (delay != null) {
bufferDelay = delay == 0 ? null : delay;
await initializePlayer();
}
},
),
)
],
),
),
);
}
}

class DelaySlider extends StatefulWidget {
const DelaySlider({Key? key, required this.delay, required this.onSave})
: super(key: key);

final int? delay;
final void Function(int?) onSave;
@override
State<DelaySlider> createState() => _DelaySliderState();
}

class _DelaySliderState extends State<DelaySlider> {
int? delay;
bool saved = false;

@override
void initState() {
super.initState();
delay = widget.delay;
}

@override
Widget build(BuildContext context) {
const int max = 1000;
return ListTile(
title: Text(
"Progress indicator delay ${delay != null ? "${delay.toString()} MS" : ""}",
),
subtitle: Slider(
value: delay != null ? (delay! / max) : 0,
onChanged: (value) async {
delay = (value * max).toInt();
setState(() {
saved = false;
});
},
),
trailing: IconButton(
icon: const Icon(Icons.save),
onPressed: saved
? null
: () {
widget.onSave(delay);
setState(() {
saved = true;
});
},
),
);
}
}
7 changes: 7 additions & 0 deletions lib/src/chewie_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class ChewieController extends ChangeNotifier {
this.systemOverlaysAfterFullScreen = SystemUiOverlay.values,
this.deviceOrientationsAfterFullScreen = DeviceOrientation.values,
this.routePageBuilder,
this.progressIndicatorDelay,
this.hideControlsTimer = defaultHideControlsTimer,
}) : assert(
playbackSpeeds.every((speed) => speed > 0),
Expand Down Expand Up @@ -324,6 +325,7 @@ class ChewieController extends ChangeNotifier {
List<DeviceOrientation>? deviceOrientationsOnEnterFullScreen,
List<SystemUiOverlay>? systemOverlaysAfterFullScreen,
List<DeviceOrientation>? deviceOrientationsAfterFullScreen,
Duration? progressIndicatorDelay,
Widget Function(
BuildContext,
Animation<double>,
Expand Down Expand Up @@ -377,6 +379,8 @@ class ChewieController extends ChangeNotifier {
this.deviceOrientationsAfterFullScreen,
routePageBuilder: routePageBuilder ?? this.routePageBuilder,
hideControlsTimer: hideControlsTimer ?? this.hideControlsTimer,
progressIndicatorDelay:
progressIndicatorDelay ?? this.progressIndicatorDelay,
);
}

Expand Down Expand Up @@ -513,6 +517,9 @@ class ChewieController extends ChangeNotifier {
/// Defines a custom RoutePageBuilder for the fullscreen
final ChewieRoutePageBuilder? routePageBuilder;

/// Defines a delay in milliseconds between entering buffering state and displaying the loading spinner. Set null (default) to disable it.
final Duration? progressIndicatorDelay;

static ChewieController of(BuildContext context) {
final chewieControllerProvider =
context.dependOnInheritedWidgetOfExactType<ChewieControllerProvider>()!;
Expand Down
28 changes: 27 additions & 1 deletion lib/src/cupertino/cupertino_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class _CupertinoControlsState extends State<CupertinoControls>
bool _dragging = false;
Duration? _subtitlesPosition;
bool _subtitleOn = false;
Timer? _bufferingDisplayTimer;
bool _displayBufferingIndicator = false;

late VideoPlayerController controller;

Expand Down Expand Up @@ -91,7 +93,7 @@ class _CupertinoControlsState extends State<CupertinoControls>
absorbing: notifier.hideStuff,
child: Stack(
children: [
if (_latestValue.isBuffering)
if (_displayBufferingIndicator)
const Center(
child: CircularProgressIndicator(),
)
Expand Down Expand Up @@ -769,8 +771,32 @@ class _CupertinoControlsState extends State<CupertinoControls>
});
}

void _bufferingTimerTimeout() {
_displayBufferingIndicator = true;
if (mounted) {
setState(() {});
}
}

void _updateState() {
if (!mounted) return;

// display the progress bar indicator only after the buffering delay if it has been set
if (chewieController.progressIndicatorDelay != null) {
if (controller.value.isBuffering) {
_bufferingDisplayTimer ??= Timer(
chewieController.progressIndicatorDelay!,
_bufferingTimerTimeout,
);
} else {
_bufferingDisplayTimer?.cancel();
_bufferingDisplayTimer = null;
_displayBufferingIndicator = false;
}
} else {
_displayBufferingIndicator = controller.value.isBuffering;
}

setState(() {
_latestValue = controller.value;
_subtitlesPosition = controller.value.position;
Expand Down
28 changes: 27 additions & 1 deletion lib/src/material/material_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class _MaterialControlsState extends State<MaterialControls>
Timer? _showAfterExpandCollapseTimer;
bool _dragging = false;
bool _displayTapped = false;
Timer? _bufferingDisplayTimer;
bool _displayBufferingIndicator = false;

final barHeight = 48.0 * 1.5;
final marginSize = 5.0;
Expand Down Expand Up @@ -82,7 +84,7 @@ class _MaterialControlsState extends State<MaterialControls>
absorbing: notifier.hideStuff,
child: Stack(
children: [
if (_latestValue.isBuffering)
if (_displayBufferingIndicator)
const Center(
child: CircularProgressIndicator(),
)
Expand Down Expand Up @@ -550,8 +552,32 @@ class _MaterialControlsState extends State<MaterialControls>
});
}

void _bufferingTimerTimeout() {
_displayBufferingIndicator = true;
if (mounted) {
setState(() {});
}
}

void _updateState() {
if (!mounted) return;

// display the progress bar indicator only after the buffering delay if it has been set
if (chewieController.progressIndicatorDelay != null) {
if (controller.value.isBuffering) {
_bufferingDisplayTimer ??= Timer(
chewieController.progressIndicatorDelay!,
_bufferingTimerTimeout,
);
} else {
_bufferingDisplayTimer?.cancel();
_bufferingDisplayTimer = null;
_displayBufferingIndicator = false;
}
} else {
_displayBufferingIndicator = controller.value.isBuffering;
}

setState(() {
_latestValue = controller.value;
_subtitlesPosition = controller.value.position;
Expand Down
28 changes: 27 additions & 1 deletion lib/src/material/material_desktop_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
Timer? _showAfterExpandCollapseTimer;
bool _dragging = false;
bool _displayTapped = false;
Timer? _bufferingDisplayTimer;
bool _displayBufferingIndicator = false;

final barHeight = 48.0 * 1.5;
final marginSize = 5.0;
Expand Down Expand Up @@ -83,7 +85,7 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
absorbing: notifier.hideStuff,
child: Stack(
children: [
if (_latestValue.isBuffering)
if (_displayBufferingIndicator)
const Center(
child: CircularProgressIndicator(),
)
Expand Down Expand Up @@ -530,8 +532,32 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
});
}

void _bufferingTimerTimeout() {
_displayBufferingIndicator = true;
if (mounted) {
setState(() {});
}
}

void _updateState() {
if (!mounted) return;

// display the progress bar indicator only after the buffering delay if it has been set
if (chewieController.progressIndicatorDelay != null) {
if (controller.value.isBuffering) {
_bufferingDisplayTimer ??= Timer(
chewieController.progressIndicatorDelay!,
_bufferingTimerTimeout,
);
} else {
_bufferingDisplayTimer?.cancel();
_bufferingDisplayTimer = null;
_displayBufferingIndicator = false;
}
} else {
_displayBufferingIndicator = controller.value.isBuffering;
}

setState(() {
_latestValue = controller.value;
_subtitlesPosition = controller.value.position;
Expand Down
12 changes: 11 additions & 1 deletion lib/src/progress_bar.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:chewie/src/chewie_progress_colors.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
Expand Down Expand Up @@ -81,7 +83,15 @@ class _VideoProgressBarState extends State<VideoProgressBar> {
if (!controller.value.isInitialized) {
return;
}
_seekToRelativePosition(details.globalPosition);
// Should only seek if it's not running on Android, or if it is,
// then the VideoPlayerController cannot be buffering.
// On Android, we need to let the player buffer when scrolling
// in order to let the player buffer. https://github.com/flutter/flutter/issues/101409
final shouldSeekToRelativePosition =
!Platform.isAndroid || !controller.value.isBuffering;
if (shouldSeekToRelativePosition) {
_seekToRelativePosition(details.globalPosition);
}

widget.onDragUpdate?.call();
},
Expand Down

0 comments on commit 7b3b839

Please sign in to comment.