@@ -12,6 +12,7 @@ import 'package:chewie/src/models/option_item.dart';
1212import 'package:chewie/src/models/subtitle_model.dart' ;
1313import 'package:chewie/src/notifiers/index.dart' ;
1414import 'package:flutter/material.dart' ;
15+ import 'package:flutter/services.dart' ;
1516import 'package:provider/provider.dart' ;
1617import 'package:video_player/video_player.dart' ;
1718
@@ -49,6 +50,7 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
4950
5051 late VideoPlayerController controller;
5152 ChewieController ? _chewieController;
53+ late final FocusNode _focusNode;
5254
5355 // We know that _chewieController is set in didChangeDependencies
5456 ChewieController get chewieController => _chewieController! ;
@@ -75,39 +77,55 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
7577 );
7678 }
7779
78- return MouseRegion (
79- onHover: (_) {
80- _cancelAndRestartTimer ();
80+ return KeyboardListener (
81+ focusNode: _focusNode,
82+ onKeyEvent: (event) {
83+ if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .space) {
84+ _playPause ();
85+ } else if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .arrowRight) {
86+ _seekForward ();
87+ } else if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .arrowLeft) {
88+ _seekBackward ();
89+ } else if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey .escape) {
90+ if (chewieController.isFullScreen) {
91+ _onExpandCollapse ();
92+ }
93+ }
8194 },
82- child: GestureDetector (
83- onTap: () => _cancelAndRestartTimer (),
84- child: AbsorbPointer (
85- absorbing: notifier.hideStuff,
86- child: Stack (
87- children: [
88- if (_displayBufferingIndicator)
89- _chewieController? .bufferingBuilder? .call (context) ??
90- const Center (
91- child: CircularProgressIndicator (),
92- )
93- else
94- _buildHitArea (),
95- Column (
96- mainAxisAlignment: MainAxisAlignment .end,
97- children: < Widget > [
98- if (_subtitleOn)
99- Transform .translate (
100- offset: Offset (
101- 0.0 ,
102- notifier.hideStuff ? barHeight * 0.8 : 0.0 ,
95+ child: MouseRegion (
96+ onHover: (_) {
97+ _cancelAndRestartTimer ();
98+ },
99+ child: GestureDetector (
100+ onTap: () => _cancelAndRestartTimer (),
101+ child: AbsorbPointer (
102+ absorbing: notifier.hideStuff,
103+ child: Stack (
104+ children: [
105+ if (_displayBufferingIndicator)
106+ _chewieController? .bufferingBuilder? .call (context) ??
107+ const Center (
108+ child: CircularProgressIndicator (),
109+ )
110+ else
111+ _buildHitArea (),
112+ Column (
113+ mainAxisAlignment: MainAxisAlignment .end,
114+ children: < Widget > [
115+ if (_subtitleOn)
116+ Transform .translate (
117+ offset: Offset (
118+ 0.0 ,
119+ notifier.hideStuff ? barHeight * 0.8 : 0.0 ,
120+ ),
121+ child:
122+ _buildSubtitles (context, chewieController.subtitle! ),
103123 ),
104- child:
105- _buildSubtitles (context, chewieController.subtitle! ),
106- ),
107- _buildBottomBar (context),
108- ],
109- ),
110- ],
124+ _buildBottomBar (context),
125+ ],
126+ ),
127+ ],
128+ ),
111129 ),
112130 ),
113131 ),
@@ -565,6 +583,36 @@ class _MaterialDesktopControlsState extends State<MaterialDesktopControls>
565583 });
566584 }
567585
586+ void _seekBackward () {
587+ _seekRelative (
588+ const Duration (
589+ seconds: - 10 ,
590+ ),
591+ );
592+ }
593+
594+ void _seekForward () {
595+ _seekRelative (
596+ const Duration (
597+ seconds: 10 ,
598+ ),
599+ );
600+ }
601+
602+ void _seekRelative (Duration relativeSeek) {
603+ _cancelAndRestartTimer ();
604+ final position = _latestValue.position + relativeSeek;
605+ final duration = _latestValue.duration;
606+
607+ if (position < Duration .zero) {
608+ controller.seekTo (Duration .zero);
609+ } else if (position > duration) {
610+ controller.seekTo (duration);
611+ } else {
612+ controller.seekTo (position);
613+ }
614+ }
615+
568616 Widget _buildProgressBar () {
569617 return Expanded (
570618 child: MaterialVideoProgressBar (
0 commit comments