-
Notifications
You must be signed in to change notification settings - Fork 309
lightbox test: Add video player regression tests #694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8ff5f7f
44c734c
71d679e
8f018d4
1e2143c
97109a0
b9065e8
ff029af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -248,6 +248,31 @@ class _ImageLightboxPageState extends State<_ImageLightboxPage> { | |
} | ||
} | ||
|
||
class VideoDurationLabel extends StatelessWidget { | ||
const VideoDurationLabel(this.duration, { | ||
super.key, | ||
this.semanticsLabel, | ||
}); | ||
|
||
final Duration duration; | ||
final String? semanticsLabel; | ||
|
||
@visibleForTesting | ||
static String formatDuration(Duration value) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh speaking of which, this should get a |
||
final hours = value.inHours.toString().padLeft(2, '0'); | ||
final minutes = value.inMinutes.remainder(60).toString().padLeft(2, '0'); | ||
final seconds = value.inSeconds.remainder(60).toString().padLeft(2, '0'); | ||
return '${hours == '00' ? '' : '$hours:'}$minutes:$seconds'; | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Text(formatDuration(duration), | ||
semanticsLabel: semanticsLabel, | ||
style: const TextStyle(color: Colors.white)); | ||
} | ||
} | ||
|
||
class _VideoPositionSliderControl extends StatefulWidget { | ||
final VideoPlayerController controller; | ||
|
||
|
@@ -277,27 +302,7 @@ class _VideoPositionSliderControlState extends State<_VideoPositionSliderControl | |
} | ||
|
||
void _handleVideoControllerUpdate() { | ||
setState(() { | ||
// After 'controller.seekTo' is called in 'Slider.onChangeEnd' the | ||
// position indicator switches back to the actual controller's position | ||
// but since the call 'seekTo' completes before the actual controller | ||
// updates are notified, the position indicator that switches to controller's | ||
// position can show the older position before the call to 'seekTo' for a | ||
// single frame, resulting in a glichty UX. | ||
// | ||
// To avoid that, we delay the position indicator switch from '_sliderValue' to | ||
// happen when we are notified of the controller update. | ||
if (_isSliderDragging && _sliderValue == widget.controller.value.position) { | ||
_isSliderDragging = false; | ||
} | ||
}); | ||
} | ||
|
||
static String _formatDuration(Duration value) { | ||
final hours = value.inHours.toString().padLeft(2, '0'); | ||
final minutes = value.inMinutes.remainder(60).toString().padLeft(2, '0'); | ||
final seconds = value.inSeconds.remainder(60).toString().padLeft(2, '0'); | ||
return '${hours == '00' ? '' : '$hours:'}$minutes:$seconds'; | ||
setState(() {}); | ||
} | ||
|
||
@override | ||
|
@@ -307,8 +312,8 @@ class _VideoPositionSliderControlState extends State<_VideoPositionSliderControl | |
: widget.controller.value.position; | ||
|
||
return Row(children: [ | ||
Text(_formatDuration(currentPosition), | ||
style: const TextStyle(color: Colors.white)), | ||
VideoDurationLabel(currentPosition, | ||
semanticsLabel: "Current position"), | ||
Expanded( | ||
child: Slider( | ||
value: currentPosition.inMilliseconds.toDouble(), | ||
|
@@ -325,20 +330,20 @@ class _VideoPositionSliderControlState extends State<_VideoPositionSliderControl | |
_sliderValue = Duration(milliseconds: value.toInt()); | ||
}); | ||
}, | ||
onChangeEnd: (value) { | ||
onChangeEnd: (value) async { | ||
final durationValue = Duration(milliseconds: value.toInt()); | ||
setState(() { | ||
_sliderValue = durationValue; | ||
}); | ||
widget.controller.seekTo(durationValue); | ||
|
||
// The toggling back of '_isSliderDragging' is omitted here intentionally, | ||
// see '_handleVideoControllerUpdates'. | ||
await widget.controller.seekTo(durationValue); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm I see! This does feel cleaner than the previous solution. I guess this is an example that would have been caught by the lint rule In the commit message:
I don't know what you're referring to when you mention "the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It refers to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, so the ValueNotifier this is referring to is the controller? In that case I think a helpful rewording would be to replace "invoking the |
||
if (mounted) { | ||
setState(() { | ||
_sliderValue = durationValue; | ||
_isSliderDragging = false; | ||
}); | ||
} | ||
}, | ||
), | ||
), | ||
Text(_formatDuration(widget.controller.value.duration), | ||
style: const TextStyle(color: Colors.white)), | ||
VideoDurationLabel(widget.controller.value.duration, | ||
semanticsLabel: "Video duration"), | ||
]); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit in commit structure: in this first commit:
349b2be lightbox [nfc]: Factor out VideoDurationLabel for testing visibility
the VideoDurationLabel group of tests can be squashed in, and then call it a
lightbox test:
commit.That reduces the number of things that are going on in the main commit, and it also provides some motivation right within this commit to explain why it needs to be a public widget.