diff --git a/lib/screens/video_player/video_player.dart b/lib/screens/video_player/video_player.dart index 59feea0..c73f958 100644 --- a/lib/screens/video_player/video_player.dart +++ b/lib/screens/video_player/video_player.dart @@ -13,6 +13,7 @@ import 'package:fladder/screens/video_player/components/video_player_next_wrappe import 'package:fladder/screens/video_player/video_player_controls.dart'; import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; import 'package:fladder/util/themes_data.dart'; +import 'package:fladder/widgets/shared/back_intent_dpad.dart'; class VideoPlayer extends ConsumerStatefulWidget { const VideoPlayer({super.key}); @@ -83,38 +84,40 @@ class _VideoPlayerState extends ConsumerState with WidgetsBindingOb }, ); - return Material( - color: Colors.black, - child: Theme( - data: ThemesData.of(context).dark, - child: Container( - color: Colors.black, - child: GestureDetector( - onScaleUpdate: (details) { - lastScale = details.scale; - }, - onScaleEnd: (details) { - if (lastScale < 1.0) { - ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(false, context: context); - } else if (lastScale > 1.0) { - ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(true, context: context); - } - lastScale = 0.0; - }, - child: VideoPlayerNextWrapper( - video: Padding( - padding: fillScreen ? EdgeInsets.zero : EdgeInsets.only(left: padding.left, right: padding.right), - child: playerController.videoWidget( - const Key("VideoPlayer"), - fillScreen - ? (MediaQuery.of(context).orientation == Orientation.portrait ? videoFit : BoxFit.cover) - : videoFit, + return BackIntentDpad( + child: Material( + color: Colors.black, + child: Theme( + data: ThemesData.of(context).dark, + child: Container( + color: Colors.black, + child: GestureDetector( + onScaleUpdate: (details) { + lastScale = details.scale; + }, + onScaleEnd: (details) { + if (lastScale < 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(false, context: context); + } else if (lastScale > 1.0) { + ref.read(videoPlayerSettingsProvider.notifier).setFillScreen(true, context: context); + } + lastScale = 0.0; + }, + child: VideoPlayerNextWrapper( + video: Padding( + padding: fillScreen ? EdgeInsets.zero : EdgeInsets.only(left: padding.left, right: padding.right), + child: playerController.videoWidget( + const Key("VideoPlayer"), + fillScreen + ? (MediaQuery.of(context).orientation == Orientation.portrait ? videoFit : BoxFit.cover) + : videoFit, + ), ), + controls: const DesktopControls(), + overlays: [ + if (errorPlaying) const _VideoErrorWidget(), + ], ), - controls: const DesktopControls(), - overlays: [ - if (errorPlaying) const _VideoErrorWidget(), - ], ), ), ), diff --git a/lib/screens/video_player/video_player_controls.dart b/lib/screens/video_player/video_player_controls.dart index b2ce0b5..74255d4 100644 --- a/lib/screens/video_player/video_player_controls.dart +++ b/lib/screens/video_player/video_player_controls.dart @@ -48,6 +48,8 @@ class DesktopControls extends ConsumerStatefulWidget { class _DesktopControlsState extends ConsumerState { final GlobalKey _bottomControlsKey = GlobalKey(); + late final initInputDevice = AdaptiveLayout.inputDeviceOf(context); + late RestartableTimer timer = RestartableTimer( const Duration(seconds: 5), () => mounted ? toggleOverlay(value: false) : null, @@ -95,12 +97,9 @@ class _DesktopControlsState extends ConsumerState { children: [ Positioned.fill( child: GestureDetector( - onTap: AdaptiveLayout.inputDeviceOf(context) == InputDevice.pointer - ? () => player.playOrPause() - : () => toggleOverlay(), - onDoubleTap: AdaptiveLayout.inputDeviceOf(context) == InputDevice.pointer - ? () => fullScreenHelper.toggleFullScreen(ref) - : null, + onTap: initInputDevice == InputDevice.pointer ? () => player.playOrPause() : () => toggleOverlay(), + onDoubleTap: + initInputDevice == InputDevice.pointer ? () => fullScreenHelper.toggleFullScreen(ref) : null, ), ), if (subtitleWidget != null) subtitleWidget, @@ -245,7 +244,7 @@ class _DesktopControlsState extends ConsumerState { ], ), ), - if (AdaptiveLayout.inputDeviceOf(context) == InputDevice.touch) + if (initInputDevice == InputDevice.touch) Align( alignment: Alignment.centerRight, child: Tooltip( @@ -362,7 +361,7 @@ class _DesktopControlsState extends ConsumerState { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - if (AdaptiveLayout.isDesktop(context)) + if (initInputDevice == InputDevice.pointer) Tooltip( message: context.localized.stop, child: IconButton( @@ -379,7 +378,7 @@ class _DesktopControlsState extends ConsumerState { ), ), }, - if (AdaptiveLayout.isDesktop(context) && + if (initInputDevice == InputDevice.pointer && AdaptiveLayout.viewSizeOf(context) > ViewSize.phone) ...[ VideoVolumeSlider( onChanged: () => resetTimer(), @@ -651,7 +650,7 @@ class _DesktopControlsState extends ConsumerState { Future clearOverlaySettings() async { toggleOverlay(value: true); - if (AdaptiveLayout.inputDeviceOf(context) != InputDevice.pointer) { + if (initInputDevice != InputDevice.pointer) { ScreenBrightness().resetApplicationScreenBrightness(); } else { disableFullScreen(); @@ -717,7 +716,7 @@ class _DesktopControlsState extends ConsumerState { return true; case VideoHotKeys.exit: disableFullScreen(); - return true; + return false; case VideoHotKeys.mute: if (volume != 0) { previousVolume = volume; diff --git a/lib/widgets/navigation_scaffold/components/navigation_body.dart b/lib/widgets/navigation_scaffold/components/navigation_body.dart index a5d1a99..9cdf9bb 100644 --- a/lib/widgets/navigation_scaffold/components/navigation_body.dart +++ b/lib/widgets/navigation_scaffold/components/navigation_body.dart @@ -10,6 +10,7 @@ import 'package:fladder/routes/auto_router.dart'; import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; import 'package:fladder/widgets/navigation_scaffold/components/destination_model.dart'; import 'package:fladder/widgets/navigation_scaffold/components/side_navigation_bar.dart'; +import 'package:fladder/widgets/shared/back_intent_dpad.dart'; class NavigationBody extends ConsumerStatefulWidget { final BuildContext parentContext; @@ -64,27 +65,29 @@ class _NavigationBodyState extends ConsumerState { child: widget.child, ); - return FocusTraversalGroup( - policy: GlobalFallbackTraversalPolicy(fallbackNode: navBarNode), - child: switch (AdaptiveLayout.layoutOf(context)) { - ViewSize.phone => paddedChild(), - ViewSize.tablet => hasOverlay - ? SideNavigationBar( - currentIndex: widget.currentIndex, - destinations: widget.destinations, - currentLocation: widget.currentLocation, - child: paddedChild(), - scaffoldKey: widget.drawerKey, - ) - : paddedChild(), - ViewSize.desktop || ViewSize.television => SideNavigationBar( - currentIndex: widget.currentIndex, - destinations: widget.destinations, - currentLocation: widget.currentLocation, - child: paddedChild(), - scaffoldKey: widget.drawerKey, - ) - }, + return BackIntentDpad( + child: FocusTraversalGroup( + policy: GlobalFallbackTraversalPolicy(fallbackNode: navBarNode), + child: switch (AdaptiveLayout.layoutOf(context)) { + ViewSize.phone => paddedChild(), + ViewSize.tablet => hasOverlay + ? SideNavigationBar( + currentIndex: widget.currentIndex, + destinations: widget.destinations, + currentLocation: widget.currentLocation, + child: paddedChild(), + scaffoldKey: widget.drawerKey, + ) + : paddedChild(), + ViewSize.desktop || ViewSize.television => SideNavigationBar( + currentIndex: widget.currentIndex, + destinations: widget.destinations, + currentLocation: widget.currentLocation, + child: paddedChild(), + scaffoldKey: widget.drawerKey, + ) + }, + ), ); } diff --git a/lib/widgets/shared/back_intent_dpad.dart b/lib/widgets/shared/back_intent_dpad.dart new file mode 100644 index 0000000..2fba1b8 --- /dev/null +++ b/lib/widgets/shared/back_intent_dpad.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:auto_route/auto_route.dart'; + +import 'package:fladder/util/adaptive_layout/adaptive_layout.dart'; + +class BackIntentDpad extends StatelessWidget { + final Widget child; + const BackIntentDpad({required this.child, super.key}); + + @override + Widget build(BuildContext context) { + if (AdaptiveLayout.inputDeviceOf(context) == InputDevice.touch) { + return child; + } + return Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.backspace): const BackIntent(), + }, + child: Actions( + actions: >{ + BackIntent: CallbackAction( + onInvoke: (intent) async { + final navigator = await context.maybePop(); + if (navigator) { + return true; + } else { + return false; + } + }, + ), + }, + child: child, + ), + ); + } +} + +class BackIntent extends Intent { + const BackIntent(); +} diff --git a/lib/wrappers/media_control_wrapper.dart b/lib/wrappers/media_control_wrapper.dart index 7c7a687..f18bd09 100644 --- a/lib/wrappers/media_control_wrapper.dart +++ b/lib/wrappers/media_control_wrapper.dart @@ -56,7 +56,7 @@ class MediaControlsWrapper extends BaseAudioHandler implements VideoPlayerContro Future init() async { if (!initializedWrapper) { initializedWrapper = true; - if (!kIsWeb || Platform.isAndroid) { + if (!kIsWeb && Platform.isAndroid) { VideoPlayerControlsCallback.setUp(this); } await AudioService.init(