l10n: fixes for RTL
This commit is contained in:
parent
dd6258d8ac
commit
ff16651ce1
15 changed files with 181 additions and 151 deletions
|
@ -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()) {
|
||||
|
|
|
@ -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<DurationDialog> {
|
|||
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: [
|
||||
|
|
|
@ -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<EditEntryDateDialog> {
|
|||
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: [
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
|||
|
||||
class QuickActionEditorPage<T extends Object> extends StatelessWidget {
|
||||
final String title, bannerText;
|
||||
final TextDirection? displayedButtonsDirection;
|
||||
final List<List<T>> allAvailableActions;
|
||||
final Widget Function(T action) actionIcon;
|
||||
final String Function(BuildContext context, T action) actionText;
|
||||
|
@ -29,6 +30,7 @@ class QuickActionEditorPage<T extends Object> 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<T extends Object> extends StatelessWidget {
|
|||
body: SafeArea(
|
||||
child: QuickActionEditorBody(
|
||||
bannerText: bannerText,
|
||||
displayedButtonsDirection: displayedButtonsDirection,
|
||||
allAvailableActions: allAvailableActions,
|
||||
actionIcon: actionIcon,
|
||||
actionText: actionText,
|
||||
|
@ -58,6 +61,7 @@ class QuickActionEditorPage<T extends Object> extends StatelessWidget {
|
|||
|
||||
class QuickActionEditorBody<T extends Object> extends StatefulWidget {
|
||||
final String bannerText;
|
||||
final TextDirection? displayedButtonsDirection;
|
||||
final List<List<T>> allAvailableActions;
|
||||
final Widget Function(T action) actionIcon;
|
||||
final String Function(BuildContext context, T action) actionText;
|
||||
|
@ -67,6 +71,7 @@ class QuickActionEditorBody<T extends Object> 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<T extends Object> extends State<QuickActionEdi
|
|||
removeAction: _removeQuickAction,
|
||||
onTargetLeave: _onQuickActionTargetLeave,
|
||||
);
|
||||
final originalDirection = Directionality.of(context);
|
||||
return PopScope(
|
||||
canPop: true,
|
||||
onPopInvoked: (didPop) => widget.save(_quickActions),
|
||||
|
@ -176,6 +182,8 @@ class _QuickActionEditorBodyState<T extends Object> extends State<QuickActionEdi
|
|||
highlight: highlight,
|
||||
child: child!,
|
||||
),
|
||||
child: Directionality(
|
||||
textDirection: widget.displayedButtonsDirection ?? originalDirection,
|
||||
child: SizedBox(
|
||||
height: OverlayButton.getSize(context) + quickActionVerticalPadding * 2,
|
||||
child: Stack(
|
||||
|
@ -205,7 +213,9 @@ class _QuickActionEditorBodyState<T extends Object> extends State<QuickActionEdi
|
|||
itemBuilder: (context, index, animation) {
|
||||
if (index >= _quickActions.length) return const SizedBox();
|
||||
final action = _quickActions[index];
|
||||
return QuickActionButton<T>(
|
||||
return Directionality(
|
||||
textDirection: originalDirection,
|
||||
child: QuickActionButton<T>(
|
||||
placement: QuickActionPlacement.action,
|
||||
action: action,
|
||||
panelHighlight: _quickActionHighlight,
|
||||
|
@ -221,6 +231,7 @@ class _QuickActionEditorBodyState<T extends Object> extends State<QuickActionEdi
|
|||
onPressed: () {},
|
||||
),
|
||||
child: _buildQuickActionButton(action, animation),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -240,6 +251,7 @@ class _QuickActionEditorBodyState<T extends Object> extends State<QuickActionEdi
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
|
|
|
@ -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<EntryAction>(
|
||||
title: context.l10n.settingsViewerQuickActionEditorPageTitle,
|
||||
bannerText: context.l10n.settingsViewerQuickActionEditorBanner,
|
||||
displayedButtonsDirection: ViewerBottomOverlay.actionsDirection,
|
||||
allAvailableActions: allAvailableActions,
|
||||
actionIcon: (action) => action.getIcon(),
|
||||
actionText: (context, action) => action.getText(context),
|
||||
|
|
|
@ -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,10 +188,7 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
|
|||
builder: (context, child) {
|
||||
final viewInsetsPadding = (widget.viewInsets ?? EdgeInsets.zero) + (widget.viewPadding ?? EdgeInsets.zero);
|
||||
final selection = context.read<Selection<AvesEntry>?>();
|
||||
final viewerButtonRow = Directionality(
|
||||
// always keep action buttons in the lower right corner, even with RTL locales
|
||||
textDirection: TextDirection.ltr,
|
||||
child: (selection?.isSelecting ?? false)
|
||||
final viewerButtonRow = (selection?.isSelecting ?? false)
|
||||
? SelectionButton(
|
||||
mainEntry: mainEntry,
|
||||
scale: _buttonScale,
|
||||
|
@ -222,7 +222,6 @@ class _BottomOverlayContentState extends State<_BottomOverlayContent> {
|
|||
scale: _buttonScale,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final showMultiPageOverlay = mainEntry.isMultiPage && multiPageController != null;
|
||||
|
@ -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,
|
||||
|
|
|
@ -65,7 +65,7 @@ class _ViewerLockedOverlayState extends State<ViewerLockedOverlay> {
|
|||
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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<VideoABRepeatOverlay> {
|
|||
);
|
||||
}
|
||||
return Row(
|
||||
textDirection: ViewerBottomOverlay.actionsDirection,
|
||||
children: [
|
||||
const Spacer(),
|
||||
OverlayButton(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<VideoProgressBar> {
|
|||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||
child: Directionality(
|
||||
// force directionality for `LinearProgressIndicator`
|
||||
textDirection: TextDirection.ltr,
|
||||
textDirection: videoPlaybackDirection,
|
||||
child: StreamBuilder<int>(
|
||||
stream: positionStream,
|
||||
builder: (context, snapshot) {
|
||||
|
|
|
@ -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,10 +42,7 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> 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<VideoStatus>(
|
||||
return StreamBuilder<VideoStatus>(
|
||||
stream: statusStream,
|
||||
builder: (context, snapshot) {
|
||||
// do not use stream snapshot because it is obsolete when switching between videos
|
||||
|
@ -53,7 +51,7 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
|||
if (status == VideoStatus.error) {
|
||||
const action = EntryAction.openVideo;
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
alignment: Alignment.centerRight,
|
||||
child: OverlayButton(
|
||||
scale: scale,
|
||||
child: IconButton(
|
||||
|
@ -73,6 +71,7 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
|||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
textDirection: ViewerBottomOverlay.actionsDirection,
|
||||
children: [
|
||||
Expanded(
|
||||
child: VideoProgressBar(
|
||||
|
@ -91,7 +90,6 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
|||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ViewerButtonRowContent> {
|
|||
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)),
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue