rtl fixes

This commit is contained in:
Thibault Deckers 2023-12-10 23:28:17 +01:00
parent 273ec45a28
commit 059e852ed1
10 changed files with 39 additions and 19 deletions

View file

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:ui' as ui;
import 'package:aves/app_flavor.dart'; import 'package:aves/app_flavor.dart';
import 'package:aves/flutter_version.dart'; import 'package:aves/flutter_version.dart';
@ -98,6 +99,7 @@ class _BugReportState extends State<BugReport> with FeedbackMixin {
// as of Flutter v3.0.0, `SelectableText` does not allow passing the `scrollController` // as of Flutter v3.0.0, `SelectableText` does not allow passing the `scrollController`
child: SelectableText( child: SelectableText(
info, info,
textDirection: ui.TextDirection.ltr,
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
), ),

View file

@ -58,7 +58,6 @@ class AvesApp extends StatefulWidget {
// temporary exclude locales not ready yet for prime time // temporary exclude locales not ready yet for prime time
// `ckb`: add `flutter_ckb_localization` and necessary app localization delegates when ready // `ckb`: add `flutter_ckb_localization` and necessary app localization delegates when ready
static final _unsupportedLocales = { static final _unsupportedLocales = {
'ar', // Arabic
'bn', // Bengali 'bn', // Bengali
'ckb', // Kurdish (Central) 'ckb', // Kurdish (Central)
'fa', // Persian 'fa', // Persian

View file

@ -113,17 +113,22 @@ class RenderMosaicGridRow extends RenderBox with ContainerRenderObjectMixin<Rend
final thumbnailHeight = rowLayout.height - spacing; final thumbnailHeight = rowLayout.height - spacing;
size = Size(constraints.maxWidth, rowLayout.height); size = Size(constraints.maxWidth, rowLayout.height);
final flipMainAxis = textDirection == TextDirection.rtl; final flipMainAxis = textDirection == TextDirection.rtl;
final sign = (flipMainAxis ? -1.0 : 1.0);
var i = 0; var i = 0;
var offset = Offset(flipMainAxis ? size.width - rowLayout.itemWidths[i] : 0, 0); double offsetX = flipMainAxis ? size.width : 0;
while (child != null) { while (child != null) {
final thumbnailWidth = rowLayout.itemWidths[i]; final thumbnailWidth = rowLayout.itemWidths[i];
final childConstraints = BoxConstraints.tight(Size(thumbnailWidth, thumbnailHeight)); final childConstraints = BoxConstraints.tight(Size(thumbnailWidth, thumbnailHeight));
child.layout(childConstraints, parentUsesSize: false); child.layout(childConstraints, parentUsesSize: false);
final childParentData = child.parentData! as _GridRowParentData; final childParentData = child.parentData! as _GridRowParentData;
childParentData.offset = offset; if (flipMainAxis) {
final dx = sign * (thumbnailWidth + spacing); offsetX -= thumbnailWidth;
offset += Offset(dx, 0); }
childParentData.offset = Offset(offsetX, 0);
if (flipMainAxis) {
offsetX -= spacing;
} else {
offsetX += thumbnailWidth + spacing;
}
child = childParentData.nextSibling; child = childParentData.nextSibling;
i++; i++;
} }

View file

@ -64,7 +64,7 @@ class _AvesMultiSelectionDialogState<T> extends State<AvesMultiSelectionDialog<T
setState(() {}); setState(() {});
}, },
title: Align( title: Align(
alignment: Alignment.centerLeft, alignment: AlignmentDirectional.centerStart,
child: Text(title), child: Text(title),
), ),
subtitle: subtitle != null subtitle: subtitle != null

View file

@ -15,8 +15,8 @@ class HomeWidgetPainter {
final double devicePixelRatio; final double devicePixelRatio;
static const backgroundGradient = LinearGradient( static const backgroundGradient = LinearGradient(
begin: Alignment.bottomLeft, begin: AlignmentDirectional.bottomStart,
end: Alignment.topRight, end: AlignmentDirectional.topEnd,
colors: AColors.boraBoraGradient, colors: AColors.boraBoraGradient,
); );

View file

@ -3,6 +3,7 @@
class SupportedLocales { class SupportedLocales {
static const languagesByLanguageCode = { static const languagesByLanguageCode = {
'ar': 'العربية',
'be': 'Беларуская мова', 'be': 'Беларуская мова',
'cs': 'Čeština', 'cs': 'Čeština',
'de': 'Deutsch', 'de': 'Deutsch',

View file

@ -8,6 +8,7 @@ import 'package:aves/widgets/settings/common/tiles.dart';
import 'package:aves/widgets/settings/settings_definition.dart'; import 'package:aves/widgets/settings/settings_definition.dart';
import 'package:aves/widgets/settings/thumbnails/collection_actions_editor_page.dart'; import 'package:aves/widgets/settings/thumbnails/collection_actions_editor_page.dart';
import 'package:aves/widgets/settings/thumbnails/overlay.dart'; import 'package:aves/widgets/settings/thumbnails/overlay.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -68,6 +69,6 @@ class SettingsTileBurstPatterns extends SettingsTile {
onSelection: (v) => settings.collectionBurstPatterns = v, onSelection: (v) => settings.collectionBurstPatterns = v,
tileTitle: title(context), tileTitle: title(context),
noneSubtitle: context.l10n.settingsCollectionBurstPatternsNone, noneSubtitle: context.l10n.settingsCollectionBurstPatternsNone,
optionSubtitleBuilder: BurstPatterns.getExample, optionSubtitleBuilder: (value) => '${Unicode.FSI}${BurstPatterns.getExample(value)}${Unicode.PDI}',
); );
} }

View file

@ -33,8 +33,8 @@ class SubtitleSample extends StatelessWidget {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: const LinearGradient( gradient: const LinearGradient(
begin: Alignment.bottomLeft, begin: AlignmentDirectional.bottomStart,
end: Alignment.topRight, end: AlignmentDirectional.topEnd,
colors: AColors.boraBoraGradient, colors: AColors.boraBoraGradient,
), ),
border: AvesBorder.border(context), border: AvesBorder.border(context),

View file

@ -360,7 +360,7 @@ class _BasicInfoState extends State<_BasicInfo> {
WidgetSpan( WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
child: Padding( child: Padding(
padding: const EdgeInsetsDirectional.only(end: 4), padding: const EdgeInsetsDirectional.only(start: 2, end: 4),
child: ConstrainedBox( child: ConstrainedBox(
// use constraints instead of sizing `Image`, // use constraints instead of sizing `Image`,
// so that it can collapse when handling an empty image // so that it can collapse when handling an empty image

View file

@ -116,20 +116,32 @@ class _InfoRowGroupState extends State<InfoRowGroup> {
(kv) { (kv) {
final key = kv.key; final key = kv.key;
final value = kv.value; final value = kv.value;
final spanBuilder = spanBuilders[key] ?? _buildTextValueSpans; final customSpanBuilder = spanBuilders[key];
final spanBuilder = customSpanBuilder ?? _buildTextValueSpans;
final thisSpaceSize = max(0.0, (baseValueX - keySizes[key]!)) + InfoRowGroup.keyValuePadding; final thisSpaceSize = max(0.0, (baseValueX - keySizes[key]!)) + InfoRowGroup.keyValuePadding;
final textScaleFactor = textScaler.scale(thisSpaceSize) / thisSpaceSize;
return [ InlineSpan paddingSpan;
TextSpan(text: _buildTextValue(key), style: _keyStyle), if (customSpanBuilder != null) {
WidgetSpan( // add padding using hair spaces instead of a straightforward `SizedBox` in a `WidgetSpan`,
// because ordering of multiple `WidgetSpan`s (e.g. with owner app icon) in Bidi context is tricky
final baseSpaceWidth = _getSpanWidth(TextSpan(text: '\u200A' * 100, style: _keyStyle), textScaler);
final spaceCount = (100 * thisSpaceSize / baseSpaceWidth).round();
paddingSpan = TextSpan(text: '\u200A' * spaceCount);
} else {
final textScaleFactor = textScaler.scale(thisSpaceSize) / thisSpaceSize;
paddingSpan = WidgetSpan(
child: SizedBox( child: SizedBox(
width: thisSpaceSize / textScaleFactor, width: thisSpaceSize / textScaleFactor,
// as of Flutter v3.0.0, the underline decoration from the following `TextSpan` // as of Flutter v3.0.0, the underline decoration from the following `TextSpan`
// is applied to the `WidgetSpan` too, so we add a dummy `Text` as a workaround // is applied to the `WidgetSpan` too, so we add a dummy `Text` as a workaround
child: const Text(''), child: const Text(''),
), ),
), );
}
return [
TextSpan(text: _buildTextValue(key), style: _keyStyle),
paddingSpan,
...spanBuilder(context, key, value), ...spanBuilder(context, key, value),
if (key != lastKey) const TextSpan(text: '\n'), if (key != lastKey) const TextSpan(text: '\n'),
]; ];