Skip to content

Commit

Permalink
Merge pull request #876 from Ortes/keyboard-controls
Browse files Browse the repository at this point in the history
Add keyboard controls seek forward and backward and fullscreen escape on desktop
  • Loading branch information
diegotori authored Jan 6, 2025
2 parents d8af8fe + 6cab13d commit 9c7a8a1
Showing 1 changed file with 89 additions and 32 deletions.
121 changes: 89 additions & 32 deletions lib/src/material/material_desktop_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:chewie/src/models/option_item.dart';
import 'package:chewie/src/models/subtitle_model.dart';
import 'package:chewie/src/notifiers/index.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:video_player/video_player.dart';

Expand Down Expand Up @@ -49,16 +50,36 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>

late VideoPlayerController controller;
ChewieController? _chewieController;
late final FocusNode _focusNode;

// We know that _chewieController is set in didChangeDependencies
ChewieController get chewieController => _chewieController!;

@override
void initState() {
super.initState();
_focusNode = FocusNode();
_focusNode.requestFocus();
notifier = Provider.of<PlayerNotifier>(context, listen: false);
}

void _handleKeyPress(event) {
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.space) {
_playPause();
} else if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.arrowRight) {
_seekForward();
} else if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.arrowLeft) {
_seekBackward();
} else if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.escape) {
if (chewieController.isFullScreen) {
_onExpandCollapse();
}
}
}

@override
Widget build(BuildContext context) {
if (_latestValue.hasError) {
Expand All @@ -75,39 +96,44 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
);
}

return MouseRegion(
onHover: (_) {
_cancelAndRestartTimer();
},
child: GestureDetector(
onTap: () => _cancelAndRestartTimer(),
child: AbsorbPointer(
absorbing: notifier.hideStuff,
child: Stack(
children: [
if (_displayBufferingIndicator)
_chewieController?.bufferingBuilder?.call(context) ??
const Center(
child: CircularProgressIndicator(),
)
else
_buildHitArea(),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
if (_subtitleOn)
Transform.translate(
offset: Offset(
0.0,
notifier.hideStuff ? barHeight * 0.8 : 0.0,
return KeyboardListener(
focusNode: _focusNode,
onKeyEvent: _handleKeyPress,
child: MouseRegion(
onHover: (_) {
_focusNode.requestFocus();
_cancelAndRestartTimer();
},
child: GestureDetector(
onTap: () => _cancelAndRestartTimer(),
child: AbsorbPointer(
absorbing: notifier.hideStuff,
child: Stack(
children: [
if (_displayBufferingIndicator)
_chewieController?.bufferingBuilder?.call(context) ??
const Center(
child: CircularProgressIndicator(),
)
else
_buildHitArea(),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
if (_subtitleOn)
Transform.translate(
offset: Offset(
0.0,
notifier.hideStuff ? barHeight * 0.8 : 0.0,
),
child: _buildSubtitles(
context, chewieController.subtitle!),
),
child:
_buildSubtitles(context, chewieController.subtitle!),
),
_buildBottomBar(context),
],
),
],
_buildBottomBar(context),
],
),
],
),
),
),
),
Expand All @@ -117,6 +143,7 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
@override
void dispose() {
_dispose();
_focusNode.dispose();
super.dispose();
}

Expand Down Expand Up @@ -565,6 +592,36 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
});
}

void _seekBackward() {
_seekRelative(
const Duration(
seconds: -10,
),
);
}

void _seekForward() {
_seekRelative(
const Duration(
seconds: 10,
),
);
}

void _seekRelative(Duration relativeSeek) {
_cancelAndRestartTimer();
final position = _latestValue.position + relativeSeek;
final duration = _latestValue.duration;

if (position < Duration.zero) {
controller.seekTo(Duration.zero);
} else if (position > duration) {
controller.seekTo(duration);
} else {
controller.seekTo(position);
}
}

Widget _buildProgressBar() {
return Expanded(
child: MaterialVideoProgressBar(
Expand Down

0 comments on commit 9c7a8a1

Please sign in to comment.