diff --git a/CHANGELOG.md b/CHANGELOG.md index e75d2d440..44223a455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- Viewer: keep controls in the lower right corner even with RTL locales + ### Fixed - crash when loading SVG defined with large dimensions diff --git a/lib/widgets/viewer/overlay/bottom.dart b/lib/widgets/viewer/overlay/bottom.dart index cb9339f2a..14dd28492 100644 --- a/lib/widgets/viewer/overlay/bottom.dart +++ b/lib/widgets/viewer/overlay/bottom.dart @@ -186,41 +186,45 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> { builder: (context, child) { final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero); final selection = context.read?>(); - final viewerButtonRow = (selection?.isSelecting ?? false) - ? SelectionButton( - mainEntry: mainEntry, - scale: _buttonScale, - ) - : FocusableActionDetector( - focusNode: _buttonRowFocusScopeNode, - shortcuts: settings.useTvLayout - ? const { - SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent(), - } - : null, - actions: { - TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)), - }, - child: SafeArea( - top: false, - bottom: false, - minimum: EdgeInsets.only( - left: viewInsetsPadding.left, - right: viewInsetsPadding.right, + final viewerButtonRow = Directionality( + // always keep action buttons in the lower right corner, even with RTL locales + textDirection: TextDirection.ltr, + child: (selection?.isSelecting ?? false) + ? SelectionButton( + mainEntry: mainEntry, + scale: _buttonScale, + ) + : FocusableActionDetector( + focusNode: _buttonRowFocusScopeNode, + shortcuts: settings.useTvLayout + ? const { + SingleActivator(LogicalKeyboardKey.arrowUp): TvShowLessInfoIntent(), + } + : null, + actions: { + TvShowLessInfoIntent: CallbackAction(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)), + }, + child: SafeArea( + top: false, + bottom: false, + minimum: EdgeInsets.only( + left: viewInsetsPadding.left, + right: viewInsetsPadding.right, + ), + child: isWallpaperMode + ? WallpaperButtons( + entry: pageEntry, + scale: _buttonScale, + ) + : ViewerButtons( + mainEntry: mainEntry, + pageEntry: pageEntry, + collection: widget.collection, + scale: _buttonScale, + ), ), - child: isWallpaperMode - ? WallpaperButtons( - entry: pageEntry, - scale: _buttonScale, - ) - : ViewerButtons( - mainEntry: mainEntry, - pageEntry: pageEntry, - collection: widget.collection, - scale: _buttonScale, - ), ), - ); + ); final showMultiPageOverlay = mainEntry.isMultiPage && multiPageController != null; final collapsedPageScroller = mainEntry.isMotionPhoto; @@ -247,6 +251,8 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> { (showMultiPageOverlay && collapsedPageScroller) ? Row( crossAxisAlignment: CrossAxisAlignment.center, + // always keep action buttons in the lower right corner, even with RTL locales + textDirection: TextDirection.ltr, children: [ SafeArea( top: false, diff --git a/lib/widgets/viewer/overlay/video/video.dart b/lib/widgets/viewer/overlay/video/video.dart index 5272fa414..0ec8cdfb2 100644 --- a/lib/widgets/viewer/overlay/video/video.dart +++ b/lib/widgets/viewer/overlay/video/video.dart @@ -40,44 +40,48 @@ class _VideoControlOverlayState extends State with SingleTi @override Widget build(BuildContext context) { - return StreamBuilder( - stream: statusStream, - builder: (context, snapshot) { - // do not use stream snapshot because it is obsolete when switching between videos - final status = controller?.status ?? VideoStatus.idle; + return Directionality( + // always keep action buttons in the lower right corner, even with RTL locales + textDirection: TextDirection.ltr, + child: StreamBuilder( + stream: statusStream, + builder: (context, snapshot) { + // do not use stream snapshot because it is obsolete when switching between videos + final status = controller?.status ?? VideoStatus.idle; - if (status == VideoStatus.error) { - const action = EntryAction.openVideo; - return Align( - alignment: AlignmentDirectional.centerEnd, - child: OverlayButton( - scale: scale, - child: IconButton( - icon: action.getIcon(), - onPressed: entry.trashed ? null : () => widget.onActionSelected(action), - tooltip: action.getText(context), + if (status == VideoStatus.error) { + const action = EntryAction.openVideo; + return Align( + alignment: AlignmentDirectional.centerEnd, + child: OverlayButton( + scale: scale, + child: IconButton( + icon: action.getIcon(), + onPressed: entry.trashed ? null : () => widget.onActionSelected(action), + tooltip: action.getText(context), + ), ), - ), - ); - } + ); + } - return Row( - children: [ - Expanded( - child: VideoProgressBar( + return Row( + children: [ + Expanded( + child: VideoProgressBar( + controller: controller, + scale: scale, + ), + ), + VideoControlRow( + entry: entry, controller: controller, scale: scale, + onActionSelected: widget.onActionSelected, ), - ), - VideoControlRow( - entry: entry, - controller: controller, - scale: scale, - onActionSelected: widget.onActionSelected, - ), - ], - ); - }, + ], + ); + }, + ), ); } } diff --git a/untranslated.json b/untranslated.json index 68aae3568..5dad1ffde 100644 --- a/untranslated.json +++ b/untranslated.json @@ -6457,11 +6457,6 @@ "filePickerUseThisFolder" ], - "pt": [ - "entryActionCast", - "castDialogTitle" - ], - "ro": [ "saveCopyButtonLabel", "applyTooltip",