From ff16651ce188f693c8f6547d6bbe2397dd9e0033 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 20 May 2024 01:41:00 +0200 Subject: [PATCH] l10n: fixes for RTL --- lib/ref/locales.dart | 6 + lib/widgets/dialogs/duration_dialog.dart | 4 +- .../entry_editors/edit_date_dialog.dart | 4 +- .../common/quick_actions/editor_page.dart | 128 ++++++++++-------- .../viewer/viewer_actions_editor.dart | 2 + lib/widgets/viewer/overlay/bottom.dart | 76 +++++------ lib/widgets/viewer/overlay/locked.dart | 2 +- lib/widgets/viewer/overlay/panorama.dart | 2 + .../viewer/overlay/selection_button.dart | 3 + .../viewer/overlay/video/ab_repeat.dart | 2 + .../viewer/overlay/video/controls.dart | 6 +- .../viewer/overlay/video/progress_bar.dart | 4 +- lib/widgets/viewer/overlay/video/video.dart | 88 ++++++------ .../viewer/overlay/viewer_buttons.dart | 3 + .../viewer/overlay/wallpaper_buttons.dart | 2 + 15 files changed, 181 insertions(+), 151 deletions(-) diff --git a/lib/ref/locales.dart b/lib/ref/locales.dart index fc58e5c11..8ceb04a2e 100644 --- a/lib/ref/locales.dart +++ b/lib/ref/locales.dart @@ -2,6 +2,12 @@ import 'dart:ui'; const String asciiLocale = 'en_US'; +// time components hours/minutes/seconds are always displayed in that order +const TextDirection timeComponentsDirection = TextDirection.ltr; + +// represents direction of tape being played, not direction of time +const TextDirection videoPlaybackDirection = TextDirection.ltr; + // cf https://en.wikipedia.org/wiki/Eastern_Arabic_numerals bool shouldUseNativeDigits(Locale? countrifiedLocale) { switch (countrifiedLocale?.toString()) { diff --git a/lib/widgets/dialogs/duration_dialog.dart b/lib/widgets/dialogs/duration_dialog.dart index 22190f831..bd547686f 100644 --- a/lib/widgets/dialogs/duration_dialog.dart +++ b/lib/widgets/dialogs/duration_dialog.dart @@ -1,3 +1,4 @@ +import 'package:aves/ref/locales.dart'; import 'package:aves/utils/time_utils.dart'; import 'package:aves/widgets/common/basic/wheel.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; @@ -48,8 +49,7 @@ class _DurationDialogState extends State { padding: const EdgeInsets.only(top: 16), child: Center( child: Table( - // even when ambient direction is RTL, time is displayed in LTR - textDirection: TextDirection.ltr, + textDirection: timeComponentsDirection, children: [ TableRow( children: [ diff --git a/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart b/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart index 8a0bb0384..28cd80e5c 100644 --- a/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart +++ b/lib/widgets/dialogs/entry_editors/edit_date_dialog.dart @@ -1,6 +1,7 @@ import 'package:aves/model/entry/entry.dart'; import 'package:aves/model/metadata/date_modifier.dart'; import 'package:aves/model/source/collection_lens.dart'; +import 'package:aves/ref/locales.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/theme/format.dart'; import 'package:aves/theme/icons.dart'; @@ -204,8 +205,7 @@ class _EditEntryDateDialogState extends State { const textStyle = TextStyle(fontSize: 34); return Center( child: Table( - // even when ambient direction is RTL, time is displayed in LTR - textDirection: TextDirection.ltr, + textDirection: timeComponentsDirection, children: [ TableRow( children: [ diff --git a/lib/widgets/settings/common/quick_actions/editor_page.dart b/lib/widgets/settings/common/quick_actions/editor_page.dart index 1b13567f6..e31b2d7e1 100644 --- a/lib/widgets/settings/common/quick_actions/editor_page.dart +++ b/lib/widgets/settings/common/quick_actions/editor_page.dart @@ -19,6 +19,7 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart'; class QuickActionEditorPage extends StatelessWidget { final String title, bannerText; + final TextDirection? displayedButtonsDirection; final List> allAvailableActions; final Widget Function(T action) actionIcon; final String Function(BuildContext context, T action) actionText; @@ -29,6 +30,7 @@ class QuickActionEditorPage extends StatelessWidget { super.key, required this.title, required this.bannerText, + this.displayedButtonsDirection, required this.allAvailableActions, required this.actionIcon, required this.actionText, @@ -45,6 +47,7 @@ class QuickActionEditorPage extends StatelessWidget { body: SafeArea( child: QuickActionEditorBody( bannerText: bannerText, + displayedButtonsDirection: displayedButtonsDirection, allAvailableActions: allAvailableActions, actionIcon: actionIcon, actionText: actionText, @@ -58,6 +61,7 @@ class QuickActionEditorPage extends StatelessWidget { class QuickActionEditorBody extends StatefulWidget { final String bannerText; + final TextDirection? displayedButtonsDirection; final List> allAvailableActions; final Widget Function(T action) actionIcon; final String Function(BuildContext context, T action) actionText; @@ -67,6 +71,7 @@ class QuickActionEditorBody extends StatefulWidget { const QuickActionEditorBody({ super.key, required this.bannerText, + this.displayedButtonsDirection, required this.allAvailableActions, required this.actionIcon, required this.actionText, @@ -147,6 +152,7 @@ class _QuickActionEditorBodyState extends State widget.save(_quickActions), @@ -176,67 +182,73 @@ class _QuickActionEditorBodyState extends State= _quickActions.length) return const SizedBox(); - final action = _quickActions[index]; - return QuickActionButton( - placement: QuickActionPlacement.action, - action: action, - panelHighlight: _quickActionHighlight, - draggedQuickAction: _draggedQuickAction, - draggedAvailableAction: _draggedAvailableAction, - insertAction: _insertQuickAction, - removeAction: _removeQuickAction, - onTargetLeave: _onQuickActionTargetLeave, - draggableFeedbackBuilder: (action) => CaptionedButton( - icon: widget.actionIcon(action), - caption: widget.actionText(context, action), - showCaption: false, - onPressed: () {}, - ), - child: _buildQuickActionButton(action, animation), - ); - }, - ), - ), - AnimatedBuilder( - animation: _quickActionsChangeNotifier, - builder: (context, child) => _quickActions.isEmpty - ? Center( - child: Text( - context.l10n.settingsViewerQuickActionEmpty, - style: theme.textTheme.bodySmall, + Container( + alignment: Alignment.center, + child: AnimatedList( + key: _animatedListKey, + initialItemCount: _quickActions.length, + scrollDirection: Axis.horizontal, + shrinkWrap: true, + padding: EdgeInsets.zero, + itemBuilder: (context, index, animation) { + if (index >= _quickActions.length) return const SizedBox(); + final action = _quickActions[index]; + return Directionality( + textDirection: originalDirection, + child: QuickActionButton( + placement: QuickActionPlacement.action, + action: action, + panelHighlight: _quickActionHighlight, + draggedQuickAction: _draggedQuickAction, + draggedAvailableAction: _draggedAvailableAction, + insertAction: _insertQuickAction, + removeAction: _removeQuickAction, + onTargetLeave: _onQuickActionTargetLeave, + draggableFeedbackBuilder: (action) => CaptionedButton( + icon: widget.actionIcon(action), + caption: widget.actionText(context, action), + showCaption: false, + onPressed: () {}, + ), + child: _buildQuickActionButton(action, animation), ), - ) - : const SizedBox(), - ), - ], + ); + }, + ), + ), + AnimatedBuilder( + animation: _quickActionsChangeNotifier, + builder: (context, child) => _quickActions.isEmpty + ? Center( + child: Text( + context.l10n.settingsViewerQuickActionEmpty, + style: theme.textTheme.bodySmall, + ), + ) + : const SizedBox(), + ), + ], + ), ), ), ), diff --git a/lib/widgets/settings/viewer/viewer_actions_editor.dart b/lib/widgets/settings/viewer/viewer_actions_editor.dart index ccbd6fdd6..c3d89e294 100644 --- a/lib/widgets/settings/viewer/viewer_actions_editor.dart +++ b/lib/widgets/settings/viewer/viewer_actions_editor.dart @@ -2,6 +2,7 @@ import 'package:aves/model/settings/settings.dart'; import 'package:aves/view/view.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/settings/common/quick_actions/editor_page.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves_model/aves_model.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -40,6 +41,7 @@ class ViewerActionEditorPage extends StatelessWidget { return QuickActionEditorPage( title: context.l10n.settingsViewerQuickActionEditorPageTitle, bannerText: context.l10n.settingsViewerQuickActionEditorBanner, + displayedButtonsDirection: ViewerBottomOverlay.actionsDirection, allAvailableActions: allAvailableActions, actionIcon: (action) => action.getIcon(), actionText: (context, action) => action.getText(context), diff --git a/lib/widgets/viewer/overlay/bottom.dart b/lib/widgets/viewer/overlay/bottom.dart index e75f84c8b..728c530d5 100644 --- a/lib/widgets/viewer/overlay/bottom.dart +++ b/lib/widgets/viewer/overlay/bottom.dart @@ -30,6 +30,9 @@ class ViewerBottomOverlay extends StatefulWidget { final EdgeInsets? viewInsets, viewPadding; final MultiPageController? multiPageController; + // always keep action buttons in the lower right corner, even with RTL locales + static const actionsDirection = TextDirection.ltr; + const ViewerBottomOverlay({ super.key, required this.entries, @@ -185,45 +188,41 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> { builder: (context, child) { final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero); final selection = context.read?>(); - 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, - ), + 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, ), + 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; @@ -250,8 +249,7 @@ 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, + textDirection: ViewerBottomOverlay.actionsDirection, children: [ SafeArea( top: false, diff --git a/lib/widgets/viewer/overlay/locked.dart b/lib/widgets/viewer/overlay/locked.dart index 57ec2484e..7c730708a 100644 --- a/lib/widgets/viewer/overlay/locked.dart +++ b/lib/widgets/viewer/overlay/locked.dart @@ -65,7 +65,7 @@ class _ViewerLockedOverlayState extends State { builder: (context, mqPaddingBottom, child) { final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero); return Container( - alignment: AlignmentDirectional.bottomEnd, + alignment: Alignment.bottomRight, padding: EdgeInsets.only(bottom: mqPaddingBottom) + const EdgeInsets.all(ViewerButtonRowContent.padding), child: SafeArea( top: false, diff --git a/lib/widgets/viewer/overlay/panorama.dart b/lib/widgets/viewer/overlay/panorama.dart index 2f58aae82..383091717 100644 --- a/lib/widgets/viewer/overlay/panorama.dart +++ b/lib/widgets/viewer/overlay/panorama.dart @@ -4,6 +4,7 @@ import 'package:aves/model/entry/entry.dart'; import 'package:aves/services/common/services.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/panorama_page.dart'; import 'package:flutter/material.dart'; @@ -20,6 +21,7 @@ class PanoramaOverlay extends StatelessWidget { @override Widget build(BuildContext context) { return Row( + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const Spacer(), ScalingOverlayTextButton( diff --git a/lib/widgets/viewer/overlay/selection_button.dart b/lib/widgets/viewer/overlay/selection_button.dart index 643e3da42..9549dbf82 100644 --- a/lib/widgets/viewer/overlay/selection_button.dart +++ b/lib/widgets/viewer/overlay/selection_button.dart @@ -6,6 +6,7 @@ import 'package:aves/theme/text.dart'; import 'package:aves/widgets/common/basic/text/animated_diff.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -33,6 +34,7 @@ class SelectionButton extends StatelessWidget { padding: const EdgeInsets.only(left: padding, right: padding, bottom: padding), child: Row( mainAxisSize: MainAxisSize.min, + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const Spacer(), ScalingOverlayTextButton( @@ -43,6 +45,7 @@ class SelectionButton extends StatelessWidget { builder: (context, count, child) { return Row( mainAxisSize: MainAxisSize.min, + textDirection: ViewerBottomOverlay.actionsDirection, children: [ AnimatedDiffText( count == 0 ? l10n.collectionSelectPageTitle : l10n.itemCount(count), diff --git a/lib/widgets/viewer/overlay/video/ab_repeat.dart b/lib/widgets/viewer/overlay/video/ab_repeat.dart index c86707161..4aaf184d4 100644 --- a/lib/widgets/viewer/overlay/video/ab_repeat.dart +++ b/lib/widgets/viewer/overlay/video/ab_repeat.dart @@ -1,6 +1,7 @@ import 'package:aves/theme/icons.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves_video/aves_video.dart'; import 'package:flutter/material.dart'; @@ -55,6 +56,7 @@ class _VideoABRepeatOverlayState extends State { ); } return Row( + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const Spacer(), OverlayButton( diff --git a/lib/widgets/viewer/overlay/video/controls.dart b/lib/widgets/viewer/overlay/video/controls.dart index e3f41e9ce..3921ff045 100644 --- a/lib/widgets/viewer/overlay/video/controls.dart +++ b/lib/widgets/viewer/overlay/video/controls.dart @@ -3,6 +3,7 @@ import 'package:aves/model/settings/settings.dart'; import 'package:aves/view/view.dart'; import 'package:aves/widgets/common/action_controls/togglers/play.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves_model/aves_model.dart'; import 'package:aves_video/aves_video.dart'; import 'package:flutter/material.dart'; @@ -33,7 +34,7 @@ class VideoControlRow extends StatelessWidget { switch (videoControls) { case VideoControls.play: return Padding( - padding: const EdgeInsetsDirectional.only(start: padding), + padding: const EdgeInsets.only(left: padding), child: _buildOverlayButton( child: PlayToggler( controller: controller, @@ -44,6 +45,7 @@ class VideoControlRow extends StatelessWidget { case VideoControls.playSeek: return Row( mainAxisSize: MainAxisSize.min, + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const SizedBox(width: padding), _buildIconButton( @@ -67,7 +69,7 @@ class VideoControlRow extends StatelessWidget { ); case VideoControls.playOutside: return Padding( - padding: const EdgeInsetsDirectional.only(start: padding), + padding: const EdgeInsets.only(left: padding), child: _buildIconButton(context, EntryAction.openVideo, enabled: !entry.trashed), ); case VideoControls.none: diff --git a/lib/widgets/viewer/overlay/video/progress_bar.dart b/lib/widgets/viewer/overlay/video/progress_bar.dart index 71d593a92..0a9144c9c 100644 --- a/lib/widgets/viewer/overlay/video/progress_bar.dart +++ b/lib/widgets/viewer/overlay/video/progress_bar.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:aves/model/settings/settings.dart'; +import 'package:aves/ref/locales.dart'; import 'package:aves/theme/format.dart'; import 'package:aves/theme/icons.dart'; import 'package:aves/theme/styles.dart'; @@ -122,8 +123,7 @@ class _VideoProgressBarState extends State { ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(4)), child: Directionality( - // force directionality for `LinearProgressIndicator` - textDirection: TextDirection.ltr, + textDirection: videoPlaybackDirection, child: StreamBuilder( stream: positionStream, builder: (context, snapshot) { diff --git a/lib/widgets/viewer/overlay/video/video.dart b/lib/widgets/viewer/overlay/video/video.dart index 7abcff3e2..2d9b97d6b 100644 --- a/lib/widgets/viewer/overlay/video/video.dart +++ b/lib/widgets/viewer/overlay/video/video.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:aves/model/entry/entry.dart'; import 'package:aves/view/view.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/video/ab_repeat.dart'; import 'package:aves/widgets/viewer/overlay/video/controls.dart'; import 'package:aves/widgets/viewer/overlay/video/progress_bar.dart'; @@ -41,57 +42,54 @@ class _VideoControlOverlayState extends State with SingleTi @override Widget build(BuildContext context) { - 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; + 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; - 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: Alignment.centerRight, + child: OverlayButton( + scale: scale, + child: IconButton( + icon: action.getIcon(), + onPressed: entry.trashed ? null : () => widget.onActionSelected(action), + tooltip: action.getText(context), ), - ); - } + ), + ); + } - return Column( - children: [ - VideoABRepeatOverlay( - controller: controller, - scale: scale, - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: VideoProgressBar( - controller: controller, - scale: scale, - ), - ), - VideoControlRow( - entry: entry, + return Column( + children: [ + VideoABRepeatOverlay( + controller: controller, + scale: scale, + ), + const SizedBox(height: 8), + Row( + textDirection: ViewerBottomOverlay.actionsDirection, + children: [ + Expanded( + child: VideoProgressBar( controller: controller, scale: scale, - onActionSelected: widget.onActionSelected, ), - ], - ), - ], - ); - }, - ), + ), + VideoControlRow( + entry: entry, + controller: controller, + scale: scale, + onActionSelected: widget.onActionSelected, + ), + ], + ), + ], + ); + }, ); } } diff --git a/lib/widgets/viewer/overlay/viewer_buttons.dart b/lib/widgets/viewer/overlay/viewer_buttons.dart index 88a8508e5..6b2e3a237 100644 --- a/lib/widgets/viewer/overlay/viewer_buttons.dart +++ b/lib/widgets/viewer/overlay/viewer_buttons.dart @@ -26,6 +26,7 @@ import 'package:aves/widgets/common/identity/buttons/captioned_button.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves/widgets/viewer/action/entry_action_delegate.dart'; import 'package:aves/widgets/viewer/controls/notifications.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves_model/aves_model.dart'; import 'package:aves_utils/aves_utils.dart'; @@ -130,6 +131,7 @@ class _TvButtonRowContent extends StatelessWidget { return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, + textDirection: ViewerBottomOverlay.actionsDirection, children: [ ...EntryActions.topLevel, ...EntryActions.export, @@ -257,6 +259,7 @@ class _ViewerButtonRowContentState extends State { return Padding( padding: const EdgeInsets.only(left: padding / 2, right: padding / 2, bottom: padding), child: Row( + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const Spacer(), ...widget.quickActions.map((action) => _buildOverlayButton(context, action, videoController)), diff --git a/lib/widgets/viewer/overlay/wallpaper_buttons.dart b/lib/widgets/viewer/overlay/wallpaper_buttons.dart index 1d4b2d519..3c058a441 100644 --- a/lib/widgets/viewer/overlay/wallpaper_buttons.dart +++ b/lib/widgets/viewer/overlay/wallpaper_buttons.dart @@ -10,6 +10,7 @@ import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/identity/buttons/overlay_button.dart'; import 'package:aves/widgets/dialogs/wallpaper_settings_dialog.dart'; +import 'package:aves/widgets/viewer/overlay/bottom.dart'; import 'package:aves/widgets/viewer/overlay/viewer_buttons.dart'; import 'package:aves/widgets/viewer/video/conductor.dart'; import 'package:aves/widgets/viewer/view/conductor.dart'; @@ -38,6 +39,7 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin { child: Padding( padding: const EdgeInsets.only(left: padding / 2, right: padding / 2, bottom: padding), child: Row( + textDirection: ViewerBottomOverlay.actionsDirection, children: [ const Spacer(), Padding(