From 9d7d80b895f72150d3dd9061806f236c14fb2ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Sun, 4 Aug 2024 14:53:40 +0200 Subject: [PATCH 01/11] feat: add FleatherLocalizations delegate with translations for link dialog and headings --- packages/fleather/.gitignore | 2 + packages/fleather/l10n.yaml | 13 + packages/fleather/lib/fleather.dart | 5 +- packages/fleather/lib/l10n/app_en.arb | 39 + packages/fleather/lib/l10n/app_fr.arb | 12 + .../fleather_localizations.g.dart | 187 +++++ .../fleather_localizations_en.g.dart | 33 + .../fleather_localizations_fr.g.dart | 33 + .../lib/src/widgets/editor_toolbar.dart | 667 ++++++++---------- packages/fleather/pubspec.yaml | 2 + 10 files changed, 614 insertions(+), 379 deletions(-) create mode 100644 packages/fleather/l10n.yaml create mode 100644 packages/fleather/lib/l10n/app_en.arb create mode 100644 packages/fleather/lib/l10n/app_fr.arb create mode 100644 packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart create mode 100644 packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart create mode 100644 packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart diff --git a/packages/fleather/.gitignore b/packages/fleather/.gitignore index 11bbb513..eb5c863a 100644 --- a/packages/fleather/.gitignore +++ b/packages/fleather/.gitignore @@ -18,3 +18,5 @@ doc/api/ build/ example/feather + +lib/l10n/untranslated.txt \ No newline at end of file diff --git a/packages/fleather/l10n.yaml b/packages/fleather/l10n.yaml new file mode 100644 index 00000000..65110886 --- /dev/null +++ b/packages/fleather/l10n.yaml @@ -0,0 +1,13 @@ +format: true +use-escaping: true +nullable-getter: false +synthetic-package: false + +arb-dir: lib/l10n +template-arb-file: app_en.arb + +output-dir: lib/l10n/fleather_localizations +output-class: FleatherLocalizations +output-localization-file: fleather_localizations.g.dart + +untranslated-messages-file: lib/l10n/untranslated.txt \ No newline at end of file diff --git a/packages/fleather/lib/fleather.dart b/packages/fleather/lib/fleather.dart index 5236ad6a..9edd6fa1 100644 --- a/packages/fleather/lib/fleather.dart +++ b/packages/fleather/lib/fleather.dart @@ -5,7 +5,10 @@ library fleather; export 'package:parchment/parchment.dart'; +export 'l10n/fleather_localizations/fleather_localizations.g.dart'; export 'src/rendering/editor.dart'; +export 'src/services/clipboard_manager.dart'; +export 'src/widgets/autoformats.dart'; export 'src/widgets/controller.dart'; export 'src/widgets/cursor.dart'; export 'src/widgets/editor.dart'; @@ -14,5 +17,3 @@ export 'src/widgets/field.dart'; export 'src/widgets/link.dart' show LinkActionPickerDelegate, LinkMenuAction; export 'src/widgets/text_line.dart'; export 'src/widgets/theme.dart'; -export 'src/widgets/autoformats.dart'; -export 'src/services/clipboard_manager.dart'; diff --git a/packages/fleather/lib/l10n/app_en.arb b/packages/fleather/lib/l10n/app_en.arb new file mode 100644 index 00000000..cca0efc4 --- /dev/null +++ b/packages/fleather/lib/l10n/app_en.arb @@ -0,0 +1,39 @@ +{ + "@@locale": "en", + "linkDialogPasteLink": "Paste a link", + "@linkDialogPasteLink": { + "description": "Label for the input decoration of the link text field in the link dialog" + }, + "linkDialogApply": "Apply", + "@linkDialogApply": { + "description": "Label for the confirmation button in the link dialog" + }, + "headingNormal": "Normal", + "@headingNormal": { + "description": "A normal heading text style" + }, + "headingLevel1": "Heading 1", + "@headingLevel1": { + "description": "A level 1 heading text style" + }, + "headingLevel2": "Heading 2", + "@headingLevel2": { + "description": "A level 2 heading text style" + }, + "headingLevel3": "Heading 3", + "@headingLevel3": { + "description": "A level 3 heading text style" + }, + "headingLevel4": "Heading 4", + "@headingLevel4": { + "description": "A level 4 heading text style" + }, + "headingLevel5": "Heading 5", + "@headingLevel5": { + "description": "A level 5 heading text style" + }, + "headingLevel6": "Heading 6", + "@headingLevel6": { + "description": "A level 6 heading text style" + } +} \ No newline at end of file diff --git a/packages/fleather/lib/l10n/app_fr.arb b/packages/fleather/lib/l10n/app_fr.arb new file mode 100644 index 00000000..12b63b8a --- /dev/null +++ b/packages/fleather/lib/l10n/app_fr.arb @@ -0,0 +1,12 @@ +{ + "@@locale": "fr", + "linkDialogPasteLink": "Coller un lien", + "linkDialogApply": "Appliquer", + "headingNormal": "Normal", + "headingLevel1": "Titre 1", + "headingLevel2": "Titre 2", + "headingLevel3": "Titre 3", + "headingLevel4": "Titre 4", + "headingLevel5": "Titre 5", + "headingLevel6": "Titre 6" +} \ No newline at end of file diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart new file mode 100644 index 00000000..b7ee3362 --- /dev/null +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart @@ -0,0 +1,187 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'fleather_localizations_en.g.dart'; +import 'fleather_localizations_fr.g.dart'; + +/// Callers can lookup localized strings with an instance of FleatherLocalizations +/// returned by `FleatherLocalizations.of(context)`. +/// +/// Applications need to include `FleatherLocalizations.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'fleather_localizations/fleather_localizations.g.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: FleatherLocalizations.localizationsDelegates, +/// supportedLocales: FleatherLocalizations.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the FleatherLocalizations.supportedLocales +/// property. +abstract class FleatherLocalizations { + FleatherLocalizations(String locale) + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static FleatherLocalizations of(BuildContext context) { + return Localizations.of( + context, FleatherLocalizations)!; + } + + static const LocalizationsDelegate delegate = + _FleatherLocalizationsDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// Additional delegates can be added by appending to this list in + /// MaterialApp. This list does not have to be used at all if a custom list + /// of delegates is preferred or required. + static const List> localizationsDelegates = + >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('fr') + ]; + + /// Label for the input decoration of the link text field in the link dialog + /// + /// In en, this message translates to: + /// **'Paste a link'** + String get linkDialogPasteLink; + + /// Label for the confirmation button in the link dialog + /// + /// In en, this message translates to: + /// **'Apply'** + String get linkDialogApply; + + /// A normal heading text style + /// + /// In en, this message translates to: + /// **'Normal'** + String get headingNormal; + + /// A level 1 heading text style + /// + /// In en, this message translates to: + /// **'Heading 1'** + String get headingLevel1; + + /// A level 2 heading text style + /// + /// In en, this message translates to: + /// **'Heading 2'** + String get headingLevel2; + + /// A level 3 heading text style + /// + /// In en, this message translates to: + /// **'Heading 3'** + String get headingLevel3; + + /// A level 4 heading text style + /// + /// In en, this message translates to: + /// **'Heading 4'** + String get headingLevel4; + + /// A level 5 heading text style + /// + /// In en, this message translates to: + /// **'Heading 5'** + String get headingLevel5; + + /// A level 6 heading text style + /// + /// In en, this message translates to: + /// **'Heading 6'** + String get headingLevel6; +} + +class _FleatherLocalizationsDelegate + extends LocalizationsDelegate { + const _FleatherLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture( + lookupFleatherLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) => + ['en', 'fr'].contains(locale.languageCode); + + @override + bool shouldReload(_FleatherLocalizationsDelegate old) => false; +} + +FleatherLocalizations lookupFleatherLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': + return FleatherLocalizationsEn(); + case 'fr': + return FleatherLocalizationsFr(); + } + + throw FlutterError( + 'FleatherLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); +} diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart new file mode 100644 index 00000000..806e1905 --- /dev/null +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart @@ -0,0 +1,33 @@ +import 'fleather_localizations.g.dart'; + +/// The translations for English (`en`). +class FleatherLocalizationsEn extends FleatherLocalizations { + FleatherLocalizationsEn([String locale = 'en']) : super(locale); + + @override + String get linkDialogPasteLink => 'Paste a link'; + + @override + String get linkDialogApply => 'Apply'; + + @override + String get headingNormal => 'Normal'; + + @override + String get headingLevel1 => 'Heading 1'; + + @override + String get headingLevel2 => 'Heading 2'; + + @override + String get headingLevel3 => 'Heading 3'; + + @override + String get headingLevel4 => 'Heading 4'; + + @override + String get headingLevel5 => 'Heading 5'; + + @override + String get headingLevel6 => 'Heading 6'; +} diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart new file mode 100644 index 00000000..51cf56a8 --- /dev/null +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart @@ -0,0 +1,33 @@ +import 'fleather_localizations.g.dart'; + +/// The translations for French (`fr`). +class FleatherLocalizationsFr extends FleatherLocalizations { + FleatherLocalizationsFr([String locale = 'fr']) : super(locale); + + @override + String get linkDialogPasteLink => 'Coller un lien'; + + @override + String get linkDialogApply => 'Appliquer'; + + @override + String get headingNormal => 'Normal'; + + @override + String get headingLevel1 => 'Titre 1'; + + @override + String get headingLevel2 => 'Titre 2'; + + @override + String get headingLevel3 => 'Titre 3'; + + @override + String get headingLevel4 => 'Titre 4'; + + @override + String get headingLevel5 => 'Titre 5'; + + @override + String get headingLevel6 => 'Titre 6'; +} diff --git a/packages/fleather/lib/src/widgets/editor_toolbar.dart b/packages/fleather/lib/src/widgets/editor_toolbar.dart index 27eb3a1d..34f8f30c 100644 --- a/packages/fleather/lib/src/widgets/editor_toolbar.dart +++ b/packages/fleather/lib/src/widgets/editor_toolbar.dart @@ -1,12 +1,8 @@ import 'dart:async'; -import 'package:fleather/src/widgets/editor.dart'; +import 'package:fleather/fleather.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:parchment/parchment.dart'; - -import 'controller.dart'; -import 'theme.dart'; const double kToolbarHeight = 56.0; @@ -41,8 +37,7 @@ class InsertEmbedButton extends StatelessWidget { baseOffset: index + 2, extentOffset: index + 2, ); - controller.replaceText(index, length, BlockEmbed.horizontalRule, - selection: newSelection); + controller.replaceText(index, length, BlockEmbed.horizontalRule, selection: newSelection); FleatherToolbar._of(context).requestKeyboard(); }, ); @@ -86,8 +81,7 @@ class UndoRedoButton extends StatelessWidget { return AnimatedBuilder( animation: controller, builder: (context, child) { - final icon = - _variant == _UndoRedoButtonVariant.undo ? Icons.undo : Icons.redo; + final icon = _variant == _UndoRedoButtonVariant.undo ? Icons.undo : Icons.redo; final isEnabled = _isEnabled(); final theme = Theme.of(context); @@ -183,8 +177,7 @@ class _LinkStyleButtonState extends State { void _linkSubmitted(String? value) { if (value == null || value.isEmpty) return; - widget.controller - .formatSelection(ParchmentAttribute.link.fromString(value)); + widget.controller.formatSelection(ParchmentAttribute.link.fromString(value)); FleatherToolbar._of(context).requestKeyboard(); } } @@ -201,16 +194,18 @@ class _LinkDialogState extends State<_LinkDialog> { @override Widget build(BuildContext context) { + final localizations = FleatherLocalizations.of(context); + return AlertDialog( content: TextField( - decoration: const InputDecoration(labelText: 'Paste a link'), + decoration: InputDecoration(labelText: localizations.linkDialogPasteLink), autofocus: true, onChanged: _linkChanged, ), actions: [ TextButton( onPressed: _link.isNotEmpty ? _applyLink : null, - child: const Text('Apply'), + child: Text(localizations.linkDialogApply), ), ], ); @@ -302,12 +297,9 @@ class _ToggleStyleButtonState extends State { // toggle style buttons (except the code block button itself) since there // is no point in applying styles to a unformatted block of text. // TODO: Add code block checks to heading and embed buttons as well. - final isInCodeBlock = - _selectionStyle.containsSame(ParchmentAttribute.block.code); - final isEnabled = - !isInCodeBlock || widget.attribute == ParchmentAttribute.block.code; - return widget.childBuilder(context, widget.attribute, widget.icon, - _isToggled, isEnabled ? _toggleAttribute : null); + final isInCodeBlock = _selectionStyle.containsSame(ParchmentAttribute.block.code); + final isEnabled = !isInCodeBlock || widget.attribute == ParchmentAttribute.block.code; + return widget.childBuilder(context, widget.attribute, widget.icon, _isToggled, isEnabled ? _toggleAttribute : null); } void _toggleAttribute() { @@ -397,13 +389,11 @@ class _ColorButtonState extends State { void _didChangeEditingValue() { setState(() { final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = - selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; }); } - Future _defaultPickColor( - BuildContext context, String nullColorLabel) async { + Future _defaultPickColor(BuildContext context, String nullColorLabel) async { final isMobile = switch (defaultTargetPlatform) { TargetPlatform.android || TargetPlatform.iOS => true, _ => false, @@ -419,8 +409,7 @@ class _ColorButtonState extends State { child: Container( constraints: BoxConstraints(maxWidth: maxWidth), padding: const EdgeInsets.all(8.0), - child: _ColorPalette(nullColorLabel, - onSelectedColor: completer.complete)), + child: _ColorPalette(nullColorLabel, onSelectedColor: completer.complete)), ); return SelectorScope.showSelector(context, selector, completer); @@ -430,8 +419,7 @@ class _ColorButtonState extends State { void initState() { super.initState(); final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = - selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; widget.controller.addListener(_didChangeEditingValue); } @@ -442,8 +430,7 @@ class _ColorButtonState extends State { oldWidget.controller.removeListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue); final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = - selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; } } @@ -456,8 +443,7 @@ class _ColorButtonState extends State { @override Widget build(BuildContext context) { return ConstrainedBox( - constraints: - BoxConstraints.tightFor(width: buttonSize, height: buttonSize), + constraints: BoxConstraints.tightFor(width: buttonSize, height: buttonSize), child: RawMaterialButton( visualDensity: VisualDensity.compact, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2)), @@ -468,11 +454,9 @@ class _ColorButtonState extends State { hoverElevation: 0, onPressed: () async { final toolbar = FleatherToolbar._of(context); - final selectedColor = await (widget.pickColor ?? _defaultPickColor)( - context, widget.nullColorLabel); - final attribute = selectedColor != null - ? widget.attributeKey.withColor(selectedColor.value) - : widget.attributeKey.unset; + final selectedColor = await (widget.pickColor ?? _defaultPickColor)(context, widget.nullColorLabel); + final attribute = + selectedColor != null ? widget.attributeKey.withColor(selectedColor.value) : widget.attributeKey.unset; widget.controller.formatSelection(attribute); toolbar.requestKeyboard(); }, @@ -515,16 +499,13 @@ class _ColorPalette extends StatelessWidget { alignment: WrapAlignment.start, runSpacing: 4, spacing: 4, - children: [...colors] - .map((e) => _ColorPaletteElement(e, nullColorLabel, onSelectedColor)) - .toList(), + children: [...colors].map((e) => _ColorPaletteElement(e, nullColorLabel, onSelectedColor)).toList(), ); } } class _ColorPaletteElement extends StatelessWidget { - const _ColorPaletteElement( - this.color, this.nullColorLabel, this.onSelectedColor); + const _ColorPaletteElement(this.color, this.nullColorLabel, this.onSelectedColor); final Color? color; final String nullColorLabel; @@ -568,15 +549,19 @@ class SelectHeadingButton extends StatefulWidget { State createState() => _SelectHeadingButtonState(); } -final _headingToText = { - ParchmentAttribute.heading.unset: 'Normal', - ParchmentAttribute.heading.level1: 'Heading 1', - ParchmentAttribute.heading.level2: 'Heading 2', - ParchmentAttribute.heading.level3: 'Heading 3', - ParchmentAttribute.heading.level4: 'Heading 4', - ParchmentAttribute.heading.level5: 'Heading 5', - ParchmentAttribute.heading.level6: 'Heading 6', -}; +Map, String> _headingToText(BuildContext context) { + final localizations = FleatherLocalizations.of(context); + + return { + ParchmentAttribute.heading.unset: localizations.headingNormal, + ParchmentAttribute.heading.level1: localizations.headingLevel1, + ParchmentAttribute.heading.level2: localizations.headingLevel2, + ParchmentAttribute.heading.level3: localizations.headingLevel3, + ParchmentAttribute.heading.level4: localizations.headingLevel4, + ParchmentAttribute.heading.level5: localizations.headingLevel5, + ParchmentAttribute.heading.level6: localizations.headingLevel6, + }; +} class _SelectHeadingButtonState extends State { static double buttonHeight = 32; @@ -587,16 +572,14 @@ class _SelectHeadingButtonState extends State { void _didChangeEditingValue() { setState(() { - current = selectionStyle.get(ParchmentAttribute.heading) ?? - ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; }); } @override void initState() { super.initState(); - current = selectionStyle.get(ParchmentAttribute.heading) ?? - ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; widget.controller.addListener(_didChangeEditingValue); } @@ -606,8 +589,7 @@ class _SelectHeadingButtonState extends State { if (oldWidget.controller != widget.controller) { oldWidget.controller.removeListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue); - current = selectionStyle.get(ParchmentAttribute.heading) ?? - ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; } } @@ -636,7 +618,7 @@ class _SelectHeadingButtonState extends State { toolbar.requestKeyboard(); } }, - child: Text(_headingToText[current] ?? ''), + child: Text(_headingToText(context)[current] ?? ''), ), ); } @@ -672,16 +654,13 @@ class _HeadingList extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _headingToText.entries - .map((entry) => _listItem(theme, entry.key, entry.value)) - .toList(), + children: _headingToText(context).entries.map((entry) => _listItem(theme, entry.key, entry.value)).toList(), ), ), ); } - Widget _listItem( - FleatherThemeData? theme, ParchmentAttribute value, String text) { + Widget _listItem(FleatherThemeData? theme, ParchmentAttribute value, String text) { final valueToStyle = { ParchmentAttribute.heading.unset: theme?.paragraph.style, ParchmentAttribute.heading.level1: theme?.heading1.style, @@ -691,20 +670,12 @@ class _HeadingList extends StatelessWidget { ParchmentAttribute.heading.level5: theme?.heading5.style, ParchmentAttribute.heading.level6: theme?.heading6.style, }; - return _HeadingListEntry( - value: value, - text: text, - style: valueToStyle[value], - onSelected: onSelected); + return _HeadingListEntry(value: value, text: text, style: valueToStyle[value], onSelected: onSelected); } } class _HeadingListEntry extends StatelessWidget { - const _HeadingListEntry( - {required this.value, - required this.text, - required this.style, - required this.onSelected}); + const _HeadingListEntry({required this.value, required this.text, required this.style, required this.onSelected}); final ParchmentAttribute value; final String text; @@ -735,8 +706,7 @@ class IndentationButton extends StatefulWidget { final bool increase; final FleatherController controller; - const IndentationButton( - {super.key, this.increase = true, required this.controller}); + const IndentationButton({super.key, this.increase = true, required this.controller}); @override State createState() => _IndentationButtonState(); @@ -772,34 +742,27 @@ class _IndentationButtonState extends State { @override Widget build(BuildContext context) { - final isEnabled = - !_selectionStyle.containsSame(ParchmentAttribute.block.code); + final isEnabled = !_selectionStyle.containsSame(ParchmentAttribute.block.code); final theme = Theme.of(context); final iconColor = isEnabled ? theme.iconTheme.color : theme.disabledColor; return FLIconButton( highlightElevation: 0, hoverElevation: 0, size: 32, - icon: Icon( - widget.increase - ? Icons.format_indent_increase - : Icons.format_indent_decrease, - size: 18, - color: iconColor), + icon: Icon(widget.increase ? Icons.format_indent_increase : Icons.format_indent_decrease, + size: 18, color: iconColor), fillColor: theme.canvasColor, onPressed: isEnabled ? () { - final indentLevel = - _selectionStyle.get(ParchmentAttribute.indent)?.value ?? 0; + final indentLevel = _selectionStyle.get(ParchmentAttribute.indent)?.value ?? 0; if (indentLevel == 0 && !widget.increase) { return; } if (indentLevel == 1 && !widget.increase) { - widget.controller - .formatSelection(ParchmentAttribute.indent.unset); + widget.controller.formatSelection(ParchmentAttribute.indent.unset); } else { - widget.controller.formatSelection(ParchmentAttribute.indent - .withLevel(indentLevel + (widget.increase ? 1 : -1))); + widget.controller + .formatSelection(ParchmentAttribute.indent.withLevel(indentLevel + (widget.increase ? 1 : -1))); } FleatherToolbar._of(context).requestKeyboard(); } @@ -815,8 +778,7 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { /// If provided, toolbar requests focus and keyboard on toolbar buttons press. final GlobalKey? editorKey; - const FleatherToolbar( - {super.key, this.editorKey, this.padding, required this.children}); + const FleatherToolbar({super.key, this.editorKey, this.padding, required this.children}); factory FleatherToolbar.basic({ Key? key, @@ -862,8 +824,7 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { ], ); Widget textColorBuilder(context, value) { - Color effectiveColor = - value ?? DefaultTextStyle.of(context).style.color ?? Colors.black; + Color effectiveColor = value ?? DefaultTextStyle.of(context).style.color ?? Colors.black; return Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, @@ -881,265 +842,236 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { ); } - return FleatherToolbar( - key: key, - editorKey: editorKey, - padding: padding, - children: [ - ...leading, - Visibility( - visible: !hideBoldButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.bold, - icon: Icons.format_bold, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideItalicButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.italic, - icon: Icons.format_italic, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideUnderLineButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.underline, - icon: Icons.format_underline, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideStrikeThrough, - child: ToggleStyleButton( - attribute: ParchmentAttribute.strikethrough, - icon: Icons.format_strikethrough, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideForegroundColor, - child: ColorButton( - controller: controller, - attributeKey: ParchmentAttribute.foregroundColor, - nullColorLabel: 'Automatic', - builder: textColorBuilder, - ), - ), - Visibility( - visible: !hideBackgroundColor, - child: ColorButton( - controller: controller, - attributeKey: ParchmentAttribute.backgroundColor, - nullColorLabel: 'No color', - builder: backgroundColorBuilder, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideInlineCode, - child: ToggleStyleButton( - attribute: ParchmentAttribute.inlineCode, - icon: Icons.code, - controller: controller, - ), - ), - Visibility( - visible: !hideBoldButton && - !hideItalicButton && - !hideUnderLineButton && - !hideStrikeThrough && - !hideInlineCode, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideDirection, - child: ToggleStyleButton( - attribute: ParchmentAttribute.rtl, - icon: Icons.format_textdirection_r_to_l, - controller: controller, - )), - Visibility( - visible: !hideDirection, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.left, - icon: Icons.format_align_left, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.center, - icon: Icons.format_align_center, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.right, - icon: Icons.format_align_right, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.justify, - icon: Icons.format_align_justify, - controller: controller, - ), - ), - Visibility( - visible: !hideAlignment, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideIndentation, - child: IndentationButton( - increase: false, - controller: controller, - ), - ), - Visibility( - visible: !hideIndentation, - child: IndentationButton( - controller: controller, - ), - ), - Visibility( - visible: !hideIndentation, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideHeadingStyle, - child: SelectHeadingButton(controller: controller)), - Visibility( - visible: !hideHeadingStyle, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - Visibility( - visible: !hideListNumbers, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.numberList, - controller: controller, - icon: Icons.format_list_numbered, - ), - ), + return FleatherToolbar(key: key, editorKey: editorKey, padding: padding, children: [ + ...leading, + Visibility( + visible: !hideBoldButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.bold, + icon: Icons.format_bold, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideItalicButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.italic, + icon: Icons.format_italic, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideUnderLineButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.underline, + icon: Icons.format_underline, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideStrikeThrough, + child: ToggleStyleButton( + attribute: ParchmentAttribute.strikethrough, + icon: Icons.format_strikethrough, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideForegroundColor, + child: ColorButton( + controller: controller, + attributeKey: ParchmentAttribute.foregroundColor, + nullColorLabel: 'Automatic', + builder: textColorBuilder, + ), + ), + Visibility( + visible: !hideBackgroundColor, + child: ColorButton( + controller: controller, + attributeKey: ParchmentAttribute.backgroundColor, + nullColorLabel: 'No color', + builder: backgroundColorBuilder, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideInlineCode, + child: ToggleStyleButton( + attribute: ParchmentAttribute.inlineCode, + icon: Icons.code, + controller: controller, + ), + ), + Visibility( + visible: + !hideBoldButton && !hideItalicButton && !hideUnderLineButton && !hideStrikeThrough && !hideInlineCode, + child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideDirection, + child: ToggleStyleButton( + attribute: ParchmentAttribute.rtl, + icon: Icons.format_textdirection_r_to_l, + controller: controller, + )), + Visibility( + visible: !hideDirection, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.left, + icon: Icons.format_align_left, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.center, + icon: Icons.format_align_center, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.right, + icon: Icons.format_align_right, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.justify, + icon: Icons.format_align_justify, + controller: controller, + ), + ), + Visibility( + visible: !hideAlignment, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - Visibility( - visible: !hideListBullets, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.bulletList, - controller: controller, - icon: Icons.format_list_bulleted, - ), - ), - Visibility( - visible: !hideListChecks, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.checkList, - controller: controller, - icon: Icons.checklist, - ), - ), - Visibility( - visible: !hideCodeBlock, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.code, - controller: controller, - icon: Icons.code, - ), - ), - Visibility( - visible: !hideListNumbers && - !hideListBullets && - !hideListChecks && - !hideCodeBlock, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideQuote, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.quote, - controller: controller, - icon: Icons.format_quote, - ), - ), - Visibility( - visible: !hideQuote, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideLink, - child: LinkStyleButton(controller: controller)), - Visibility( - visible: !hideHorizontalRule, - child: InsertEmbedButton( - controller: controller, - icon: Icons.horizontal_rule, - ), - ), - Visibility( - visible: !hideHorizontalRule || !hideLink, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), + /// ################################################################ - /// ################################################################ + Visibility( + visible: !hideIndentation, + child: IndentationButton( + increase: false, + controller: controller, + ), + ), + Visibility( + visible: !hideIndentation, + child: IndentationButton( + controller: controller, + ), + ), + Visibility( + visible: !hideIndentation, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility(visible: !hideHeadingStyle, child: SelectHeadingButton(controller: controller)), + Visibility( + visible: !hideHeadingStyle, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + Visibility( + visible: !hideListNumbers, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.numberList, + controller: controller, + icon: Icons.format_list_numbered, + ), + ), - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.undo( - controller: controller, - ), - ), - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.redo( - controller: controller, - ), - ), + Visibility( + visible: !hideListBullets, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.bulletList, + controller: controller, + icon: Icons.format_list_bulleted, + ), + ), + Visibility( + visible: !hideListChecks, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.checkList, + controller: controller, + icon: Icons.checklist, + ), + ), + Visibility( + visible: !hideCodeBlock, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.code, + controller: controller, + icon: Icons.code, + ), + ), + Visibility( + visible: !hideListNumbers && !hideListBullets && !hideListChecks && !hideCodeBlock, + child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideQuote, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.quote, + controller: controller, + icon: Icons.format_quote, + ), + ), + Visibility(visible: !hideQuote, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility(visible: !hideLink, child: LinkStyleButton(controller: controller)), + Visibility( + visible: !hideHorizontalRule, + child: InsertEmbedButton( + controller: controller, + icon: Icons.horizontal_rule, + ), + ), + Visibility( + visible: !hideHorizontalRule || !hideLink, + child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.undo( + controller: controller, + ), + ), + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.redo( + controller: controller, + ), + ), - ...trailing, - ]); + ...trailing, + ]); } - static _FleatherToolbarState _of(BuildContext context) => - context.findAncestorStateOfType<_FleatherToolbarState>()!; + static _FleatherToolbarState _of(BuildContext context) => context.findAncestorStateOfType<_FleatherToolbarState>()!; @override State createState() => _FleatherToolbarState(); @@ -1156,9 +1088,7 @@ class _FleatherToolbarState extends State { super.didChangeDependencies(); final parentTheme = FleatherTheme.of(context, nullOk: true); final fallbackTheme = FleatherThemeData.fallback(context); - theme = (parentTheme != null) - ? fallbackTheme.merge(parentTheme) - : fallbackTheme; + theme = (parentTheme != null) ? fallbackTheme.merge(parentTheme) : fallbackTheme; } void requestKeyboard() => widget.editorKey?.currentState?.requestKeyboard(); @@ -1170,8 +1100,7 @@ class _FleatherToolbarState extends State { child: SelectorScope( child: Container( padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: 8), - constraints: - BoxConstraints.tightFor(height: widget.preferredSize.height), + constraints: BoxConstraints.tightFor(height: widget.preferredSize.height), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -1229,15 +1158,12 @@ class SelectorScope extends StatefulWidget { const SelectorScope({super.key, required this.child}); - static SelectorScopeState of(BuildContext context) => - context.findAncestorStateOfType()!; + static SelectorScopeState of(BuildContext context) => context.findAncestorStateOfType()!; /// The [context] should belong to the presenter widget. - static Future showSelector( - BuildContext context, Widget selector, Completer completer, + static Future showSelector(BuildContext context, Widget selector, Completer completer, {bool rootOverlay = false}) => - SelectorScope.of(context) - .showSelector(context, selector, completer, rootOverlay: rootOverlay); + SelectorScope.of(context).showSelector(context, selector, completer, rootOverlay: rootOverlay); @override State createState() => SelectorScopeState(); @@ -1247,16 +1173,14 @@ class SelectorScopeState extends State { OverlayEntry? _overlayEntry; /// The [context] should belong to the presenter widget. - Future showSelector( - BuildContext context, Widget selector, Completer completer, + Future showSelector(BuildContext context, Widget selector, Completer completer, {bool rootOverlay = false}) { _overlayEntry?.remove(); final overlay = Overlay.of(context, rootOverlay: rootOverlay); final RenderBox presenter = context.findRenderObject() as RenderBox; - final RenderBox overlayBox = - overlay.context.findRenderObject() as RenderBox; + final RenderBox overlayBox = overlay.context.findRenderObject() as RenderBox; final offset = Offset(0.0, presenter.size.height); final position = RelativeRect.fromSize( Rect.fromPoints( @@ -1380,9 +1304,7 @@ class _SelectorLayout extends SingleChildLayoutDelegate { final Offset wantedPosition = Offset(x, y); final Offset originCenter = position.toRect(Offset.zero & size).center; - final Iterable subScreens = - DisplayFeatureSubScreen.subScreensInBounds( - Offset.zero & size, avoidBounds); + final Iterable subScreens = DisplayFeatureSubScreen.subScreensInBounds(Offset.zero & size, avoidBounds); final Rect subScreen = _closestScreen(subScreens, originCenter); return _fitInsideScreen(subScreen, childSize, wantedPosition); } @@ -1390,8 +1312,7 @@ class _SelectorLayout extends SingleChildLayoutDelegate { Rect _closestScreen(Iterable screens, Offset point) { Rect closest = screens.first; for (final Rect screen in screens) { - if ((screen.center - point).distance < - (closest.center - point).distance) { + if ((screen.center - point).distance < (closest.center - point).distance) { closest = screen; } } @@ -1405,21 +1326,13 @@ class _SelectorLayout extends SingleChildLayoutDelegate { // edge of the screen in every direction. if (x < screen.left + _selectorScreenPadding + padding.left) { x = screen.left + _selectorScreenPadding + padding.left; - } else if (x + childSize.width > - screen.right - _selectorScreenPadding - padding.right) { - x = screen.right - - childSize.width - - _selectorScreenPadding - - padding.right; + } else if (x + childSize.width > screen.right - _selectorScreenPadding - padding.right) { + x = screen.right - childSize.width - _selectorScreenPadding - padding.right; } if (y < screen.top + _selectorScreenPadding + padding.top) { y = _selectorScreenPadding + padding.top; - } else if (y + childSize.height > - screen.bottom - _selectorScreenPadding - padding.bottom) { - y = screen.bottom - - childSize.height - - _selectorScreenPadding - - padding.bottom; + } else if (y + childSize.height > screen.bottom - _selectorScreenPadding - padding.bottom) { + y = screen.bottom - childSize.height - _selectorScreenPadding - padding.bottom; } return Offset(x, y); diff --git a/packages/fleather/pubspec.yaml b/packages/fleather/pubspec.yaml index 4a2c907f..26f2b162 100644 --- a/packages/fleather/pubspec.yaml +++ b/packages/fleather/pubspec.yaml @@ -26,6 +26,8 @@ dependencies: parchment_delta: ^1.0.0 parchment: ^1.15.0 intl: ^0.19.0 + flutter_localizations: + sdk: flutter dependency_overrides: parchment: From 3ee93c2db53b93b49c4bfe4b4df09a71880cc21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:00:30 +0200 Subject: [PATCH 02/11] fix: format --- .../lib/src/widgets/editor_toolbar.dart | 635 ++++++++++-------- 1 file changed, 363 insertions(+), 272 deletions(-) diff --git a/packages/fleather/lib/src/widgets/editor_toolbar.dart b/packages/fleather/lib/src/widgets/editor_toolbar.dart index 34f8f30c..2d8e9097 100644 --- a/packages/fleather/lib/src/widgets/editor_toolbar.dart +++ b/packages/fleather/lib/src/widgets/editor_toolbar.dart @@ -37,7 +37,8 @@ class InsertEmbedButton extends StatelessWidget { baseOffset: index + 2, extentOffset: index + 2, ); - controller.replaceText(index, length, BlockEmbed.horizontalRule, selection: newSelection); + controller.replaceText(index, length, BlockEmbed.horizontalRule, + selection: newSelection); FleatherToolbar._of(context).requestKeyboard(); }, ); @@ -81,7 +82,8 @@ class UndoRedoButton extends StatelessWidget { return AnimatedBuilder( animation: controller, builder: (context, child) { - final icon = _variant == _UndoRedoButtonVariant.undo ? Icons.undo : Icons.redo; + final icon = + _variant == _UndoRedoButtonVariant.undo ? Icons.undo : Icons.redo; final isEnabled = _isEnabled(); final theme = Theme.of(context); @@ -177,7 +179,8 @@ class _LinkStyleButtonState extends State { void _linkSubmitted(String? value) { if (value == null || value.isEmpty) return; - widget.controller.formatSelection(ParchmentAttribute.link.fromString(value)); + widget.controller + .formatSelection(ParchmentAttribute.link.fromString(value)); FleatherToolbar._of(context).requestKeyboard(); } } @@ -198,7 +201,8 @@ class _LinkDialogState extends State<_LinkDialog> { return AlertDialog( content: TextField( - decoration: InputDecoration(labelText: localizations.linkDialogPasteLink), + decoration: + InputDecoration(labelText: localizations.linkDialogPasteLink), autofocus: true, onChanged: _linkChanged, ), @@ -297,9 +301,12 @@ class _ToggleStyleButtonState extends State { // toggle style buttons (except the code block button itself) since there // is no point in applying styles to a unformatted block of text. // TODO: Add code block checks to heading and embed buttons as well. - final isInCodeBlock = _selectionStyle.containsSame(ParchmentAttribute.block.code); - final isEnabled = !isInCodeBlock || widget.attribute == ParchmentAttribute.block.code; - return widget.childBuilder(context, widget.attribute, widget.icon, _isToggled, isEnabled ? _toggleAttribute : null); + final isInCodeBlock = + _selectionStyle.containsSame(ParchmentAttribute.block.code); + final isEnabled = + !isInCodeBlock || widget.attribute == ParchmentAttribute.block.code; + return widget.childBuilder(context, widget.attribute, widget.icon, + _isToggled, isEnabled ? _toggleAttribute : null); } void _toggleAttribute() { @@ -389,11 +396,13 @@ class _ColorButtonState extends State { void _didChangeEditingValue() { setState(() { final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = + selectionColor?.value != null ? Color(selectionColor!.value!) : null; }); } - Future _defaultPickColor(BuildContext context, String nullColorLabel) async { + Future _defaultPickColor( + BuildContext context, String nullColorLabel) async { final isMobile = switch (defaultTargetPlatform) { TargetPlatform.android || TargetPlatform.iOS => true, _ => false, @@ -409,7 +418,8 @@ class _ColorButtonState extends State { child: Container( constraints: BoxConstraints(maxWidth: maxWidth), padding: const EdgeInsets.all(8.0), - child: _ColorPalette(nullColorLabel, onSelectedColor: completer.complete)), + child: _ColorPalette(nullColorLabel, + onSelectedColor: completer.complete)), ); return SelectorScope.showSelector(context, selector, completer); @@ -419,7 +429,8 @@ class _ColorButtonState extends State { void initState() { super.initState(); final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = + selectionColor?.value != null ? Color(selectionColor!.value!) : null; widget.controller.addListener(_didChangeEditingValue); } @@ -430,7 +441,8 @@ class _ColorButtonState extends State { oldWidget.controller.removeListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue); final selectionColor = _selectionStyle.get(widget.attributeKey); - _value = selectionColor?.value != null ? Color(selectionColor!.value!) : null; + _value = + selectionColor?.value != null ? Color(selectionColor!.value!) : null; } } @@ -443,7 +455,8 @@ class _ColorButtonState extends State { @override Widget build(BuildContext context) { return ConstrainedBox( - constraints: BoxConstraints.tightFor(width: buttonSize, height: buttonSize), + constraints: + BoxConstraints.tightFor(width: buttonSize, height: buttonSize), child: RawMaterialButton( visualDensity: VisualDensity.compact, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2)), @@ -454,9 +467,11 @@ class _ColorButtonState extends State { hoverElevation: 0, onPressed: () async { final toolbar = FleatherToolbar._of(context); - final selectedColor = await (widget.pickColor ?? _defaultPickColor)(context, widget.nullColorLabel); - final attribute = - selectedColor != null ? widget.attributeKey.withColor(selectedColor.value) : widget.attributeKey.unset; + final selectedColor = await (widget.pickColor ?? _defaultPickColor)( + context, widget.nullColorLabel); + final attribute = selectedColor != null + ? widget.attributeKey.withColor(selectedColor.value) + : widget.attributeKey.unset; widget.controller.formatSelection(attribute); toolbar.requestKeyboard(); }, @@ -499,13 +514,16 @@ class _ColorPalette extends StatelessWidget { alignment: WrapAlignment.start, runSpacing: 4, spacing: 4, - children: [...colors].map((e) => _ColorPaletteElement(e, nullColorLabel, onSelectedColor)).toList(), + children: [...colors] + .map((e) => _ColorPaletteElement(e, nullColorLabel, onSelectedColor)) + .toList(), ); } } class _ColorPaletteElement extends StatelessWidget { - const _ColorPaletteElement(this.color, this.nullColorLabel, this.onSelectedColor); + const _ColorPaletteElement( + this.color, this.nullColorLabel, this.onSelectedColor); final Color? color; final String nullColorLabel; @@ -572,14 +590,16 @@ class _SelectHeadingButtonState extends State { void _didChangeEditingValue() { setState(() { - current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? + ParchmentAttribute.heading.unset; }); } @override void initState() { super.initState(); - current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? + ParchmentAttribute.heading.unset; widget.controller.addListener(_didChangeEditingValue); } @@ -589,7 +609,8 @@ class _SelectHeadingButtonState extends State { if (oldWidget.controller != widget.controller) { oldWidget.controller.removeListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue); - current = selectionStyle.get(ParchmentAttribute.heading) ?? ParchmentAttribute.heading.unset; + current = selectionStyle.get(ParchmentAttribute.heading) ?? + ParchmentAttribute.heading.unset; } } @@ -654,13 +675,17 @@ class _HeadingList extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _headingToText(context).entries.map((entry) => _listItem(theme, entry.key, entry.value)).toList(), + children: _headingToText(context) + .entries + .map((entry) => _listItem(theme, entry.key, entry.value)) + .toList(), ), ), ); } - Widget _listItem(FleatherThemeData? theme, ParchmentAttribute value, String text) { + Widget _listItem( + FleatherThemeData? theme, ParchmentAttribute value, String text) { final valueToStyle = { ParchmentAttribute.heading.unset: theme?.paragraph.style, ParchmentAttribute.heading.level1: theme?.heading1.style, @@ -670,12 +695,20 @@ class _HeadingList extends StatelessWidget { ParchmentAttribute.heading.level5: theme?.heading5.style, ParchmentAttribute.heading.level6: theme?.heading6.style, }; - return _HeadingListEntry(value: value, text: text, style: valueToStyle[value], onSelected: onSelected); + return _HeadingListEntry( + value: value, + text: text, + style: valueToStyle[value], + onSelected: onSelected); } } class _HeadingListEntry extends StatelessWidget { - const _HeadingListEntry({required this.value, required this.text, required this.style, required this.onSelected}); + const _HeadingListEntry( + {required this.value, + required this.text, + required this.style, + required this.onSelected}); final ParchmentAttribute value; final String text; @@ -706,7 +739,8 @@ class IndentationButton extends StatefulWidget { final bool increase; final FleatherController controller; - const IndentationButton({super.key, this.increase = true, required this.controller}); + const IndentationButton( + {super.key, this.increase = true, required this.controller}); @override State createState() => _IndentationButtonState(); @@ -742,27 +776,34 @@ class _IndentationButtonState extends State { @override Widget build(BuildContext context) { - final isEnabled = !_selectionStyle.containsSame(ParchmentAttribute.block.code); + final isEnabled = + !_selectionStyle.containsSame(ParchmentAttribute.block.code); final theme = Theme.of(context); final iconColor = isEnabled ? theme.iconTheme.color : theme.disabledColor; return FLIconButton( highlightElevation: 0, hoverElevation: 0, size: 32, - icon: Icon(widget.increase ? Icons.format_indent_increase : Icons.format_indent_decrease, - size: 18, color: iconColor), + icon: Icon( + widget.increase + ? Icons.format_indent_increase + : Icons.format_indent_decrease, + size: 18, + color: iconColor), fillColor: theme.canvasColor, onPressed: isEnabled ? () { - final indentLevel = _selectionStyle.get(ParchmentAttribute.indent)?.value ?? 0; + final indentLevel = + _selectionStyle.get(ParchmentAttribute.indent)?.value ?? 0; if (indentLevel == 0 && !widget.increase) { return; } if (indentLevel == 1 && !widget.increase) { - widget.controller.formatSelection(ParchmentAttribute.indent.unset); - } else { widget.controller - .formatSelection(ParchmentAttribute.indent.withLevel(indentLevel + (widget.increase ? 1 : -1))); + .formatSelection(ParchmentAttribute.indent.unset); + } else { + widget.controller.formatSelection(ParchmentAttribute.indent + .withLevel(indentLevel + (widget.increase ? 1 : -1))); } FleatherToolbar._of(context).requestKeyboard(); } @@ -778,7 +819,8 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { /// If provided, toolbar requests focus and keyboard on toolbar buttons press. final GlobalKey? editorKey; - const FleatherToolbar({super.key, this.editorKey, this.padding, required this.children}); + const FleatherToolbar( + {super.key, this.editorKey, this.padding, required this.children}); factory FleatherToolbar.basic({ Key? key, @@ -824,7 +866,8 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { ], ); Widget textColorBuilder(context, value) { - Color effectiveColor = value ?? DefaultTextStyle.of(context).style.color ?? Colors.black; + Color effectiveColor = + value ?? DefaultTextStyle.of(context).style.color ?? Colors.black; return Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, @@ -842,236 +885,265 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { ); } - return FleatherToolbar(key: key, editorKey: editorKey, padding: padding, children: [ - ...leading, - Visibility( - visible: !hideBoldButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.bold, - icon: Icons.format_bold, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideItalicButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.italic, - icon: Icons.format_italic, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideUnderLineButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.underline, - icon: Icons.format_underline, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideStrikeThrough, - child: ToggleStyleButton( - attribute: ParchmentAttribute.strikethrough, - icon: Icons.format_strikethrough, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideForegroundColor, - child: ColorButton( - controller: controller, - attributeKey: ParchmentAttribute.foregroundColor, - nullColorLabel: 'Automatic', - builder: textColorBuilder, - ), - ), - Visibility( - visible: !hideBackgroundColor, - child: ColorButton( - controller: controller, - attributeKey: ParchmentAttribute.backgroundColor, - nullColorLabel: 'No color', - builder: backgroundColorBuilder, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideInlineCode, - child: ToggleStyleButton( - attribute: ParchmentAttribute.inlineCode, - icon: Icons.code, - controller: controller, - ), - ), - Visibility( - visible: - !hideBoldButton && !hideItalicButton && !hideUnderLineButton && !hideStrikeThrough && !hideInlineCode, - child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideDirection, - child: ToggleStyleButton( - attribute: ParchmentAttribute.rtl, - icon: Icons.format_textdirection_r_to_l, - controller: controller, - )), - Visibility( - visible: !hideDirection, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.left, - icon: Icons.format_align_left, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.center, - icon: Icons.format_align_center, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.right, - icon: Icons.format_align_right, - controller: controller, - ), - ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.justify, - icon: Icons.format_align_justify, - controller: controller, - ), - ), - Visibility( - visible: !hideAlignment, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideIndentation, - child: IndentationButton( - increase: false, - controller: controller, - ), - ), - Visibility( - visible: !hideIndentation, - child: IndentationButton( - controller: controller, - ), - ), - Visibility( - visible: !hideIndentation, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility(visible: !hideHeadingStyle, child: SelectHeadingButton(controller: controller)), - Visibility( - visible: !hideHeadingStyle, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - Visibility( - visible: !hideListNumbers, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.numberList, - controller: controller, - icon: Icons.format_list_numbered, - ), - ), - - Visibility( - visible: !hideListBullets, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.bulletList, - controller: controller, - icon: Icons.format_list_bulleted, - ), - ), - Visibility( - visible: !hideListChecks, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.checkList, - controller: controller, - icon: Icons.checklist, - ), - ), - Visibility( - visible: !hideCodeBlock, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.code, - controller: controller, - icon: Icons.code, - ), - ), - Visibility( - visible: !hideListNumbers && !hideListBullets && !hideListChecks && !hideCodeBlock, - child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideQuote, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.quote, - controller: controller, - icon: Icons.format_quote, - ), - ), - Visibility(visible: !hideQuote, child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ + return FleatherToolbar( + key: key, + editorKey: editorKey, + padding: padding, + children: [ + ...leading, + Visibility( + visible: !hideBoldButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.bold, + icon: Icons.format_bold, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideItalicButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.italic, + icon: Icons.format_italic, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideUnderLineButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.underline, + icon: Icons.format_underline, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideStrikeThrough, + child: ToggleStyleButton( + attribute: ParchmentAttribute.strikethrough, + icon: Icons.format_strikethrough, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideForegroundColor, + child: ColorButton( + controller: controller, + attributeKey: ParchmentAttribute.foregroundColor, + nullColorLabel: 'Automatic', + builder: textColorBuilder, + ), + ), + Visibility( + visible: !hideBackgroundColor, + child: ColorButton( + controller: controller, + attributeKey: ParchmentAttribute.backgroundColor, + nullColorLabel: 'No color', + builder: backgroundColorBuilder, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideInlineCode, + child: ToggleStyleButton( + attribute: ParchmentAttribute.inlineCode, + icon: Icons.code, + controller: controller, + ), + ), + Visibility( + visible: !hideBoldButton && + !hideItalicButton && + !hideUnderLineButton && + !hideStrikeThrough && + !hideInlineCode, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideDirection, + child: ToggleStyleButton( + attribute: ParchmentAttribute.rtl, + icon: Icons.format_textdirection_r_to_l, + controller: controller, + )), + Visibility( + visible: !hideDirection, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.left, + icon: Icons.format_align_left, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.center, + icon: Icons.format_align_center, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.right, + icon: Icons.format_align_right, + controller: controller, + ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.justify, + icon: Icons.format_align_justify, + controller: controller, + ), + ), + Visibility( + visible: !hideAlignment, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideIndentation, + child: IndentationButton( + increase: false, + controller: controller, + ), + ), + Visibility( + visible: !hideIndentation, + child: IndentationButton( + controller: controller, + ), + ), + Visibility( + visible: !hideIndentation, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideHeadingStyle, + child: SelectHeadingButton(controller: controller)), + Visibility( + visible: !hideHeadingStyle, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + Visibility( + visible: !hideListNumbers, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.numberList, + controller: controller, + icon: Icons.format_list_numbered, + ), + ), - Visibility(visible: !hideLink, child: LinkStyleButton(controller: controller)), - Visibility( - visible: !hideHorizontalRule, - child: InsertEmbedButton( - controller: controller, - icon: Icons.horizontal_rule, - ), - ), - Visibility( - visible: !hideHorizontalRule || !hideLink, - child: VerticalDivider(indent: 16, endIndent: 16, color: Colors.grey.shade400)), + Visibility( + visible: !hideListBullets, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.bulletList, + controller: controller, + icon: Icons.format_list_bulleted, + ), + ), + Visibility( + visible: !hideListChecks, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.checkList, + controller: controller, + icon: Icons.checklist, + ), + ), + Visibility( + visible: !hideCodeBlock, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.code, + controller: controller, + icon: Icons.code, + ), + ), + Visibility( + visible: !hideListNumbers && + !hideListBullets && + !hideListChecks && + !hideCodeBlock, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideQuote, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.quote, + controller: controller, + icon: Icons.format_quote, + ), + ), + Visibility( + visible: !hideQuote, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideLink, + child: LinkStyleButton(controller: controller)), + Visibility( + visible: !hideHorizontalRule, + child: InsertEmbedButton( + controller: controller, + icon: Icons.horizontal_rule, + ), + ), + Visibility( + visible: !hideHorizontalRule || !hideLink, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), - /// ################################################################ + /// ################################################################ - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.undo( - controller: controller, - ), - ), - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.redo( - controller: controller, - ), - ), + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.undo( + controller: controller, + ), + ), + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.redo( + controller: controller, + ), + ), - ...trailing, - ]); + ...trailing, + ]); } - static _FleatherToolbarState _of(BuildContext context) => context.findAncestorStateOfType<_FleatherToolbarState>()!; + static _FleatherToolbarState _of(BuildContext context) => + context.findAncestorStateOfType<_FleatherToolbarState>()!; @override State createState() => _FleatherToolbarState(); @@ -1088,7 +1160,9 @@ class _FleatherToolbarState extends State { super.didChangeDependencies(); final parentTheme = FleatherTheme.of(context, nullOk: true); final fallbackTheme = FleatherThemeData.fallback(context); - theme = (parentTheme != null) ? fallbackTheme.merge(parentTheme) : fallbackTheme; + theme = (parentTheme != null) + ? fallbackTheme.merge(parentTheme) + : fallbackTheme; } void requestKeyboard() => widget.editorKey?.currentState?.requestKeyboard(); @@ -1100,7 +1174,8 @@ class _FleatherToolbarState extends State { child: SelectorScope( child: Container( padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: 8), - constraints: BoxConstraints.tightFor(height: widget.preferredSize.height), + constraints: + BoxConstraints.tightFor(height: widget.preferredSize.height), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -1158,12 +1233,15 @@ class SelectorScope extends StatefulWidget { const SelectorScope({super.key, required this.child}); - static SelectorScopeState of(BuildContext context) => context.findAncestorStateOfType()!; + static SelectorScopeState of(BuildContext context) => + context.findAncestorStateOfType()!; /// The [context] should belong to the presenter widget. - static Future showSelector(BuildContext context, Widget selector, Completer completer, + static Future showSelector( + BuildContext context, Widget selector, Completer completer, {bool rootOverlay = false}) => - SelectorScope.of(context).showSelector(context, selector, completer, rootOverlay: rootOverlay); + SelectorScope.of(context) + .showSelector(context, selector, completer, rootOverlay: rootOverlay); @override State createState() => SelectorScopeState(); @@ -1173,14 +1251,16 @@ class SelectorScopeState extends State { OverlayEntry? _overlayEntry; /// The [context] should belong to the presenter widget. - Future showSelector(BuildContext context, Widget selector, Completer completer, + Future showSelector( + BuildContext context, Widget selector, Completer completer, {bool rootOverlay = false}) { _overlayEntry?.remove(); final overlay = Overlay.of(context, rootOverlay: rootOverlay); final RenderBox presenter = context.findRenderObject() as RenderBox; - final RenderBox overlayBox = overlay.context.findRenderObject() as RenderBox; + final RenderBox overlayBox = + overlay.context.findRenderObject() as RenderBox; final offset = Offset(0.0, presenter.size.height); final position = RelativeRect.fromSize( Rect.fromPoints( @@ -1304,7 +1384,9 @@ class _SelectorLayout extends SingleChildLayoutDelegate { final Offset wantedPosition = Offset(x, y); final Offset originCenter = position.toRect(Offset.zero & size).center; - final Iterable subScreens = DisplayFeatureSubScreen.subScreensInBounds(Offset.zero & size, avoidBounds); + final Iterable subScreens = + DisplayFeatureSubScreen.subScreensInBounds( + Offset.zero & size, avoidBounds); final Rect subScreen = _closestScreen(subScreens, originCenter); return _fitInsideScreen(subScreen, childSize, wantedPosition); } @@ -1312,7 +1394,8 @@ class _SelectorLayout extends SingleChildLayoutDelegate { Rect _closestScreen(Iterable screens, Offset point) { Rect closest = screens.first; for (final Rect screen in screens) { - if ((screen.center - point).distance < (closest.center - point).distance) { + if ((screen.center - point).distance < + (closest.center - point).distance) { closest = screen; } } @@ -1326,13 +1409,21 @@ class _SelectorLayout extends SingleChildLayoutDelegate { // edge of the screen in every direction. if (x < screen.left + _selectorScreenPadding + padding.left) { x = screen.left + _selectorScreenPadding + padding.left; - } else if (x + childSize.width > screen.right - _selectorScreenPadding - padding.right) { - x = screen.right - childSize.width - _selectorScreenPadding - padding.right; + } else if (x + childSize.width > + screen.right - _selectorScreenPadding - padding.right) { + x = screen.right - + childSize.width - + _selectorScreenPadding - + padding.right; } if (y < screen.top + _selectorScreenPadding + padding.top) { y = _selectorScreenPadding + padding.top; - } else if (y + childSize.height > screen.bottom - _selectorScreenPadding - padding.bottom) { - y = screen.bottom - childSize.height - _selectorScreenPadding - padding.bottom; + } else if (y + childSize.height > + screen.bottom - _selectorScreenPadding - padding.bottom) { + y = screen.bottom - + childSize.height - + _selectorScreenPadding - + padding.bottom; } return Offset(x, y); From 9a60c1a7c6ff47d546d67c1d97f1ef813400ec7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Sun, 4 Aug 2024 15:15:05 +0200 Subject: [PATCH 03/11] fix: ignore generated files in analysis --- packages/fleather/analysis_options.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/fleather/analysis_options.yaml b/packages/fleather/analysis_options.yaml index 4c5af234..1e6f852f 100644 --- a/packages/fleather/analysis_options.yaml +++ b/packages/fleather/analysis_options.yaml @@ -1,5 +1,9 @@ include: package:flutter_lints/flutter.yaml +analyzer: + exclude: + - '**.g.dart' + linter: rules: always_declare_return_types: true From 7bdc26b73b31da08bf8a664baf4f2a8ac89544ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:49:02 +0200 Subject: [PATCH 04/11] feat: add localizations for all other strings --- packages/fleather/lib/l10n/app_en.arb | 32 +- packages/fleather/lib/l10n/app_fr.arb | 11 +- .../fleather_localizations.g.dart | 42 +- .../fleather_localizations_en.g.dart | 19 +- .../fleather_localizations_fr.g.dart | 19 +- .../lib/src/widgets/editor_toolbar.dart | 454 +++++++++--------- packages/fleather/lib/src/widgets/link.dart | 24 +- 7 files changed, 351 insertions(+), 250 deletions(-) diff --git a/packages/fleather/lib/l10n/app_en.arb b/packages/fleather/lib/l10n/app_en.arb index cca0efc4..5f9af47d 100644 --- a/packages/fleather/lib/l10n/app_en.arb +++ b/packages/fleather/lib/l10n/app_en.arb @@ -1,12 +1,12 @@ { "@@locale": "en", - "linkDialogPasteLink": "Paste a link", - "@linkDialogPasteLink": { - "description": "Label for the input decoration of the link text field in the link dialog" + "foregroundColorAutomatic": "Automatic", + "@foregroundColorAutomatic": { + "description": "Automatically assign a foreground color to the text" }, - "linkDialogApply": "Apply", - "@linkDialogApply": { - "description": "Label for the confirmation button in the link dialog" + "backgroundColorNoColor": "No color", + "@backgroundColorNoColor": { + "description": "Assign no background color to the text" }, "headingNormal": "Normal", "@headingNormal": { @@ -35,5 +35,25 @@ "headingLevel6": "Heading 6", "@headingLevel6": { "description": "A level 6 heading text style" + }, + "addLinkDialogPasteLink": "Paste a link", + "@addLinkDialogPasteLink": { + "description": "Label for the input decoration of the link text field in the add link dialog" + }, + "addLinkDialogApply": "Apply", + "@addLinkDialogApply": { + "description": "Label for the confirmation button in the link dialog" + }, + "linkDialogOpen": "Open", + "@linkDialogOpen": { + "description": "Open the link" + }, + "linkDialogCopy": "Copy", + "@linkDialogCopy": { + "description": "Copy the link" + }, + "linkDialogRemove": "Remove", + "@linkDialogRemove": { + "description": "Remove the link" } } \ No newline at end of file diff --git a/packages/fleather/lib/l10n/app_fr.arb b/packages/fleather/lib/l10n/app_fr.arb index 12b63b8a..c2a8222b 100644 --- a/packages/fleather/lib/l10n/app_fr.arb +++ b/packages/fleather/lib/l10n/app_fr.arb @@ -1,12 +1,17 @@ { "@@locale": "fr", - "linkDialogPasteLink": "Coller un lien", - "linkDialogApply": "Appliquer", + "foregroundColorAutomatic": "Automatique", + "backgroundColorNoColor": "Aucune couleur", "headingNormal": "Normal", "headingLevel1": "Titre 1", "headingLevel2": "Titre 2", "headingLevel3": "Titre 3", "headingLevel4": "Titre 4", "headingLevel5": "Titre 5", - "headingLevel6": "Titre 6" + "headingLevel6": "Titre 6", + "addLinkDialogPasteLink": "Coller un lien", + "addLinkDialogApply": "Appliquer", + "linkDialogOpen": "Ouvrir", + "linkDialogCopy": "Copier", + "linkDialogRemove": "Retirer" } \ No newline at end of file diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart index b7ee3362..4d676f18 100644 --- a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart @@ -97,17 +97,17 @@ abstract class FleatherLocalizations { Locale('fr') ]; - /// Label for the input decoration of the link text field in the link dialog + /// Automatically assign a foreground color to the text /// /// In en, this message translates to: - /// **'Paste a link'** - String get linkDialogPasteLink; + /// **'Automatic'** + String get foregroundColorAutomatic; - /// Label for the confirmation button in the link dialog + /// Assign no background color to the text /// /// In en, this message translates to: - /// **'Apply'** - String get linkDialogApply; + /// **'No color'** + String get backgroundColorNoColor; /// A normal heading text style /// @@ -150,6 +150,36 @@ abstract class FleatherLocalizations { /// In en, this message translates to: /// **'Heading 6'** String get headingLevel6; + + /// Label for the input decoration of the link text field in the add link dialog + /// + /// In en, this message translates to: + /// **'Paste a link'** + String get addLinkDialogPasteLink; + + /// Label for the confirmation button in the link dialog + /// + /// In en, this message translates to: + /// **'Apply'** + String get addLinkDialogApply; + + /// Open the link + /// + /// In en, this message translates to: + /// **'Open'** + String get linkDialogOpen; + + /// Copy the link + /// + /// In en, this message translates to: + /// **'Copy'** + String get linkDialogCopy; + + /// Remove the link + /// + /// In en, this message translates to: + /// **'Remove'** + String get linkDialogRemove; } class _FleatherLocalizationsDelegate diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart index 806e1905..28938095 100644 --- a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart @@ -5,10 +5,10 @@ class FleatherLocalizationsEn extends FleatherLocalizations { FleatherLocalizationsEn([String locale = 'en']) : super(locale); @override - String get linkDialogPasteLink => 'Paste a link'; + String get foregroundColorAutomatic => 'Automatic'; @override - String get linkDialogApply => 'Apply'; + String get backgroundColorNoColor => 'No color'; @override String get headingNormal => 'Normal'; @@ -30,4 +30,19 @@ class FleatherLocalizationsEn extends FleatherLocalizations { @override String get headingLevel6 => 'Heading 6'; + + @override + String get addLinkDialogPasteLink => 'Paste a link'; + + @override + String get addLinkDialogApply => 'Apply'; + + @override + String get linkDialogOpen => 'Open'; + + @override + String get linkDialogCopy => 'Copy'; + + @override + String get linkDialogRemove => 'Remove'; } diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart index 51cf56a8..6d21f012 100644 --- a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart +++ b/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart @@ -5,10 +5,10 @@ class FleatherLocalizationsFr extends FleatherLocalizations { FleatherLocalizationsFr([String locale = 'fr']) : super(locale); @override - String get linkDialogPasteLink => 'Coller un lien'; + String get foregroundColorAutomatic => 'Automatique'; @override - String get linkDialogApply => 'Appliquer'; + String get backgroundColorNoColor => 'Aucune couleur'; @override String get headingNormal => 'Normal'; @@ -30,4 +30,19 @@ class FleatherLocalizationsFr extends FleatherLocalizations { @override String get headingLevel6 => 'Titre 6'; + + @override + String get addLinkDialogPasteLink => 'Coller un lien'; + + @override + String get addLinkDialogApply => 'Appliquer'; + + @override + String get linkDialogOpen => 'Ouvrir'; + + @override + String get linkDialogCopy => 'Copier'; + + @override + String get linkDialogRemove => 'Retirer'; } diff --git a/packages/fleather/lib/src/widgets/editor_toolbar.dart b/packages/fleather/lib/src/widgets/editor_toolbar.dart index 2d8e9097..3361ce07 100644 --- a/packages/fleather/lib/src/widgets/editor_toolbar.dart +++ b/packages/fleather/lib/src/widgets/editor_toolbar.dart @@ -197,19 +197,20 @@ class _LinkDialogState extends State<_LinkDialog> { @override Widget build(BuildContext context) { - final localizations = FleatherLocalizations.of(context); - return AlertDialog( content: TextField( - decoration: - InputDecoration(labelText: localizations.linkDialogPasteLink), + decoration: InputDecoration( + labelText: FleatherLocalizations.of(context).addLinkDialogPasteLink, + ), autofocus: true, onChanged: _linkChanged, ), actions: [ TextButton( onPressed: _link.isNotEmpty ? _applyLink : null, - child: Text(localizations.linkDialogApply), + child: Text( + FleatherLocalizations.of(context).addLinkDialogApply, + ), ), ], ); @@ -819,8 +820,12 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { /// If provided, toolbar requests focus and keyboard on toolbar buttons press. final GlobalKey? editorKey; - const FleatherToolbar( - {super.key, this.editorKey, this.padding, required this.children}); + const FleatherToolbar({ + super.key, + this.editorKey, + this.padding, + required this.children, + }); factory FleatherToolbar.basic({ Key? key, @@ -886,260 +891,267 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { } return FleatherToolbar( - key: key, - editorKey: editorKey, - padding: padding, - children: [ - ...leading, - Visibility( - visible: !hideBoldButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.bold, - icon: Icons.format_bold, - controller: controller, - ), + key: key, + editorKey: editorKey, + padding: padding, + children: [ + ...leading, + + Visibility( + visible: !hideBoldButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.bold, + icon: Icons.format_bold, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideItalicButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.italic, - icon: Icons.format_italic, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideItalicButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.italic, + icon: Icons.format_italic, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideUnderLineButton, - child: ToggleStyleButton( - attribute: ParchmentAttribute.underline, - icon: Icons.format_underline, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideUnderLineButton, + child: ToggleStyleButton( + attribute: ParchmentAttribute.underline, + icon: Icons.format_underline, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideStrikeThrough, - child: ToggleStyleButton( - attribute: ParchmentAttribute.strikethrough, - icon: Icons.format_strikethrough, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideStrikeThrough, + child: ToggleStyleButton( + attribute: ParchmentAttribute.strikethrough, + icon: Icons.format_strikethrough, + controller: controller, ), - const SizedBox(width: 1), - Visibility( + ), + const SizedBox(width: 1), + Builder(builder: (context) { + return Visibility( visible: !hideForegroundColor, child: ColorButton( controller: controller, attributeKey: ParchmentAttribute.foregroundColor, - nullColorLabel: 'Automatic', + nullColorLabel: + FleatherLocalizations.of(context).foregroundColorAutomatic, builder: textColorBuilder, ), - ), - Visibility( + ); + }), + Builder(builder: (context) { + return Visibility( visible: !hideBackgroundColor, child: ColorButton( controller: controller, attributeKey: ParchmentAttribute.backgroundColor, - nullColorLabel: 'No color', + nullColorLabel: + FleatherLocalizations.of(context).backgroundColorNoColor, builder: backgroundColorBuilder, ), + ); + }), + const SizedBox(width: 1), + Visibility( + visible: !hideInlineCode, + child: ToggleStyleButton( + attribute: ParchmentAttribute.inlineCode, + icon: Icons.code, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideInlineCode, + ), + Visibility( + visible: !hideBoldButton && + !hideItalicButton && + !hideUnderLineButton && + !hideStrikeThrough && + !hideInlineCode, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideDirection, child: ToggleStyleButton( - attribute: ParchmentAttribute.inlineCode, - icon: Icons.code, + attribute: ParchmentAttribute.rtl, + icon: Icons.format_textdirection_r_to_l, controller: controller, - ), + )), + Visibility( + visible: !hideDirection, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.left, + icon: Icons.format_align_left, + controller: controller, ), - Visibility( - visible: !hideBoldButton && - !hideItalicButton && - !hideUnderLineButton && - !hideStrikeThrough && - !hideInlineCode, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideDirection, - child: ToggleStyleButton( - attribute: ParchmentAttribute.rtl, - icon: Icons.format_textdirection_r_to_l, - controller: controller, - )), - Visibility( - visible: !hideDirection, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.left, - icon: Icons.format_align_left, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.center, + icon: Icons.format_align_center, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.center, - icon: Icons.format_align_center, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.right, + icon: Icons.format_align_right, + controller: controller, ), - const SizedBox(width: 1), - Visibility( - visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.right, - icon: Icons.format_align_right, - controller: controller, - ), + ), + const SizedBox(width: 1), + Visibility( + visible: !hideAlignment, + child: ToggleStyleButton( + attribute: ParchmentAttribute.justify, + icon: Icons.format_align_justify, + controller: controller, ), - const SizedBox(width: 1), - Visibility( + ), + Visibility( visible: !hideAlignment, - child: ToggleStyleButton( - attribute: ParchmentAttribute.justify, - icon: Icons.format_align_justify, - controller: controller, - ), - ), - Visibility( - visible: !hideAlignment, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), - /// ################################################################ + /// ################################################################ - Visibility( - visible: !hideIndentation, - child: IndentationButton( - increase: false, - controller: controller, - ), + Visibility( + visible: !hideIndentation, + child: IndentationButton( + increase: false, + controller: controller, ), - Visibility( - visible: !hideIndentation, - child: IndentationButton( - controller: controller, - ), + ), + Visibility( + visible: !hideIndentation, + child: IndentationButton( + controller: controller, ), - Visibility( - visible: !hideIndentation, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideHeadingStyle, - child: SelectHeadingButton(controller: controller)), - Visibility( - visible: !hideHeadingStyle, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - Visibility( - visible: !hideListNumbers, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.numberList, - controller: controller, - icon: Icons.format_list_numbered, - ), + ), + Visibility( + visible: !hideIndentation, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideHeadingStyle, + child: SelectHeadingButton(controller: controller)), + Visibility( + visible: !hideHeadingStyle, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + Visibility( + visible: !hideListNumbers, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.numberList, + controller: controller, + icon: Icons.format_list_numbered, ), + ), - Visibility( - visible: !hideListBullets, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.bulletList, - controller: controller, - icon: Icons.format_list_bulleted, - ), + Visibility( + visible: !hideListBullets, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.bulletList, + controller: controller, + icon: Icons.format_list_bulleted, ), - Visibility( - visible: !hideListChecks, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.checkList, - controller: controller, - icon: Icons.checklist, - ), + ), + Visibility( + visible: !hideListChecks, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.checkList, + controller: controller, + icon: Icons.checklist, ), - Visibility( - visible: !hideCodeBlock, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.code, - controller: controller, - icon: Icons.code, - ), + ), + Visibility( + visible: !hideCodeBlock, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.code, + controller: controller, + icon: Icons.code, ), - Visibility( - visible: !hideListNumbers && - !hideListBullets && - !hideListChecks && - !hideCodeBlock, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideQuote, - child: ToggleStyleButton( - attribute: ParchmentAttribute.block.quote, - controller: controller, - icon: Icons.format_quote, - ), + ), + Visibility( + visible: !hideListNumbers && + !hideListBullets && + !hideListChecks && + !hideCodeBlock, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideQuote, + child: ToggleStyleButton( + attribute: ParchmentAttribute.block.quote, + controller: controller, + icon: Icons.format_quote, ), - Visibility( - visible: !hideQuote, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), - - /// ################################################################ - - Visibility( - visible: !hideLink, - child: LinkStyleButton(controller: controller)), - Visibility( - visible: !hideHorizontalRule, - child: InsertEmbedButton( - controller: controller, - icon: Icons.horizontal_rule, - ), + ), + Visibility( + visible: !hideQuote, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), + + /// ################################################################ + + Visibility( + visible: !hideLink, child: LinkStyleButton(controller: controller)), + Visibility( + visible: !hideHorizontalRule, + child: InsertEmbedButton( + controller: controller, + icon: Icons.horizontal_rule, ), - Visibility( - visible: !hideHorizontalRule || !hideLink, - child: VerticalDivider( - indent: 16, endIndent: 16, color: Colors.grey.shade400)), + ), + Visibility( + visible: !hideHorizontalRule || !hideLink, + child: VerticalDivider( + indent: 16, endIndent: 16, color: Colors.grey.shade400)), - /// ################################################################ + /// ################################################################ - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.undo( - controller: controller, - ), + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.undo( + controller: controller, ), - Visibility( - visible: !hideUndoRedo, - child: UndoRedoButton.redo( - controller: controller, - ), + ), + Visibility( + visible: !hideUndoRedo, + child: UndoRedoButton.redo( + controller: controller, ), + ), - ...trailing, - ]); + ...trailing, + ], + ); } static _FleatherToolbarState _of(BuildContext context) => diff --git a/packages/fleather/lib/src/widgets/link.dart b/packages/fleather/lib/src/widgets/link.dart index 113dd1f4..2c8c2d96 100644 --- a/packages/fleather/lib/src/widgets/link.dart +++ b/packages/fleather/lib/src/widgets/link.dart @@ -1,7 +1,7 @@ +import 'package:fleather/fleather.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:parchment/parchment.dart'; /// List of possible actions returned from [LinkActionPickerDelegate]. enum LinkMenuAction { @@ -39,25 +39,27 @@ Future defaultLinkActionPickerDelegate( } Future _showCupertinoLinkMenu( - BuildContext context, String link) async { + BuildContext context, + String link, +) async { final result = await showCupertinoModalPopup( context: context, - builder: (ctx) { + builder: (context) { return CupertinoActionSheet( title: Text(link), actions: [ _CupertinoAction( - title: 'Open', + title: FleatherLocalizations.of(context).linkDialogOpen, icon: Icons.language_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch), ), _CupertinoAction( - title: 'Copy', + title: FleatherLocalizations.of(context).linkDialogCopy, icon: Icons.copy_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy), ), _CupertinoAction( - title: 'Remove', + title: FleatherLocalizations.of(context).linkDialogRemove, icon: Icons.link_off_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove), ), @@ -108,7 +110,9 @@ class _CupertinoAction extends StatelessWidget { } Future _showMaterialMenu( - BuildContext context, String link) async { + BuildContext context, + String link, +) async { final result = await showModalBottomSheet( clipBehavior: Clip.hardEdge, context: context, @@ -118,17 +122,17 @@ Future _showMaterialMenu( mainAxisSize: MainAxisSize.min, children: [ _MaterialAction( - title: 'Open', + title: FleatherLocalizations.of(context).linkDialogOpen, icon: Icons.language_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch), ), _MaterialAction( - title: 'Copy', + title: FleatherLocalizations.of(context).linkDialogCopy, icon: Icons.copy_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy), ), _MaterialAction( - title: 'Remove', + title: FleatherLocalizations.of(context).linkDialogRemove, icon: Icons.link_off_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove), ), From 58d8295fbba90b273b5ed9bc26fa0170dd7239fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Chiotti?= <44336112+maelchiotti@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:59:26 +0200 Subject: [PATCH 05/11] tests: fix tests by adding localizations to the MaterialApp widgets --- .../test/widgets/editor_toolbar_test.dart | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/fleather/test/widgets/editor_toolbar_test.dart b/packages/fleather/test/widgets/editor_toolbar_test.dart index 91e2b590..544cfc19 100644 --- a/packages/fleather/test/widgets/editor_toolbar_test.dart +++ b/packages/fleather/test/widgets/editor_toolbar_test.dart @@ -1,5 +1,6 @@ import 'package:fleather/fleather.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:parchment_delta/parchment_delta.dart'; @@ -52,6 +53,16 @@ Widget widget(FleatherController controller, {bool withBasic = false}) { ); final editorKey = GlobalKey(); return MaterialApp( + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + FleatherLocalizations.delegate, + ], + supportedLocales: const [ + ...FleatherLocalizations.supportedLocales, + ], + locale: const Locale('en'), home: Material( child: Column(children: [ if (withBasic) @@ -425,6 +436,16 @@ void main() { ); final controller = FleatherController(); final widget = MaterialApp( + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + FleatherLocalizations.delegate, + ], + supportedLocales: const [ + ...FleatherLocalizations.supportedLocales, + ], + locale: const Locale('en'), home: TestUpdateWidget( focusNodeAfterChange: FocusNode(), controller: controller, @@ -457,6 +478,16 @@ void main() { const padding = EdgeInsets.all(32); final controller = FleatherController(); await tester.pumpWidget(MaterialApp( + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + FleatherLocalizations.delegate, + ], + supportedLocales: const [ + ...FleatherLocalizations.supportedLocales, + ], + locale: const Locale('en'), home: Scaffold( appBar: AppBar(), body: Column( @@ -479,6 +510,16 @@ void main() { equals(validRect), ); await tester.pumpWidget(MaterialApp( + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + FleatherLocalizations.delegate, + ], + supportedLocales: const [ + ...FleatherLocalizations.supportedLocales, + ], + locale: const Locale('en'), home: Scaffold( appBar: AppBar(), body: Column( From 5536b0b7f45cae127bedfe6643e561787aa6408c Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Fri, 9 Aug 2024 21:28:12 +0330 Subject: [PATCH 06/11] Reorganize localization files --- packages/fleather/.gitignore | 2 +- packages/fleather/example/macos/Podfile.lock | 4 ++-- packages/fleather/l10n.yaml | 7 +++---- packages/fleather/{lib => }/l10n/app_en.arb | 0 packages/fleather/{lib => }/l10n/app_fr.arb | 0 packages/fleather/lib/fleather.dart | 2 +- .../fleather_localizations.g.dart | 6 +++--- .../fleather_localizations_en.g.dart | 0 .../fleather_localizations_fr.g.dart | 0 packages/fleather/lib/l10n/l10n.dart | 4 ++++ packages/fleather/lib/l10n/utils.dart | 9 +++++++++ .../fleather/lib/src/widgets/editor_toolbar.dart | 15 ++++++--------- packages/fleather/lib/src/widgets/link.dart | 13 +++++++------ packages/fleather/pubspec.yaml | 4 ++-- 14 files changed, 38 insertions(+), 28 deletions(-) rename packages/fleather/{lib => }/l10n/app_en.arb (100%) rename packages/fleather/{lib => }/l10n/app_fr.arb (100%) rename packages/fleather/lib/l10n/{fleather_localizations => }/fleather_localizations.g.dart (97%) rename packages/fleather/lib/l10n/{fleather_localizations => }/fleather_localizations_en.g.dart (100%) rename packages/fleather/lib/l10n/{fleather_localizations => }/fleather_localizations_fr.g.dart (100%) create mode 100644 packages/fleather/lib/l10n/l10n.dart create mode 100644 packages/fleather/lib/l10n/utils.dart diff --git a/packages/fleather/.gitignore b/packages/fleather/.gitignore index eb5c863a..b00ae1f3 100644 --- a/packages/fleather/.gitignore +++ b/packages/fleather/.gitignore @@ -19,4 +19,4 @@ build/ example/feather -lib/l10n/untranslated.txt \ No newline at end of file +untranslated.txt \ No newline at end of file diff --git a/packages/fleather/example/macos/Podfile.lock b/packages/fleather/example/macos/Podfile.lock index 96677979..99f1ba3b 100644 --- a/packages/fleather/example/macos/Podfile.lock +++ b/packages/fleather/example/macos/Podfile.lock @@ -19,9 +19,9 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: - file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 + file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/packages/fleather/l10n.yaml b/packages/fleather/l10n.yaml index 65110886..0ca88515 100644 --- a/packages/fleather/l10n.yaml +++ b/packages/fleather/l10n.yaml @@ -1,13 +1,12 @@ format: true use-escaping: true -nullable-getter: false synthetic-package: false -arb-dir: lib/l10n +arb-dir: l10n template-arb-file: app_en.arb -output-dir: lib/l10n/fleather_localizations +output-dir: lib/l10n output-class: FleatherLocalizations output-localization-file: fleather_localizations.g.dart -untranslated-messages-file: lib/l10n/untranslated.txt \ No newline at end of file +untranslated-messages-file: untranslated.txt \ No newline at end of file diff --git a/packages/fleather/lib/l10n/app_en.arb b/packages/fleather/l10n/app_en.arb similarity index 100% rename from packages/fleather/lib/l10n/app_en.arb rename to packages/fleather/l10n/app_en.arb diff --git a/packages/fleather/lib/l10n/app_fr.arb b/packages/fleather/l10n/app_fr.arb similarity index 100% rename from packages/fleather/lib/l10n/app_fr.arb rename to packages/fleather/l10n/app_fr.arb diff --git a/packages/fleather/lib/fleather.dart b/packages/fleather/lib/fleather.dart index 9edd6fa1..6477aa41 100644 --- a/packages/fleather/lib/fleather.dart +++ b/packages/fleather/lib/fleather.dart @@ -5,7 +5,7 @@ library fleather; export 'package:parchment/parchment.dart'; -export 'l10n/fleather_localizations/fleather_localizations.g.dart'; +export 'l10n/l10n.dart' hide BuildContextLocalizationsExtension; export 'src/rendering/editor.dart'; export 'src/services/clipboard_manager.dart'; export 'src/widgets/autoformats.dart'; diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart b/packages/fleather/lib/l10n/fleather_localizations.g.dart similarity index 97% rename from packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart rename to packages/fleather/lib/l10n/fleather_localizations.g.dart index 4d676f18..3cfbd9fb 100644 --- a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations.g.dart +++ b/packages/fleather/lib/l10n/fleather_localizations.g.dart @@ -16,7 +16,7 @@ import 'fleather_localizations_fr.g.dart'; /// `supportedLocales` list. For example: /// /// ```dart -/// import 'fleather_localizations/fleather_localizations.g.dart'; +/// import 'l10n/fleather_localizations.g.dart'; /// /// return MaterialApp( /// localizationsDelegates: FleatherLocalizations.localizationsDelegates, @@ -65,9 +65,9 @@ abstract class FleatherLocalizations { final String localeName; - static FleatherLocalizations of(BuildContext context) { + static FleatherLocalizations? of(BuildContext context) { return Localizations.of( - context, FleatherLocalizations)!; + context, FleatherLocalizations); } static const LocalizationsDelegate delegate = diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart b/packages/fleather/lib/l10n/fleather_localizations_en.g.dart similarity index 100% rename from packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_en.g.dart rename to packages/fleather/lib/l10n/fleather_localizations_en.g.dart diff --git a/packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart b/packages/fleather/lib/l10n/fleather_localizations_fr.g.dart similarity index 100% rename from packages/fleather/lib/l10n/fleather_localizations/fleather_localizations_fr.g.dart rename to packages/fleather/lib/l10n/fleather_localizations_fr.g.dart diff --git a/packages/fleather/lib/l10n/l10n.dart b/packages/fleather/lib/l10n/l10n.dart new file mode 100644 index 00000000..edbf6b26 --- /dev/null +++ b/packages/fleather/lib/l10n/l10n.dart @@ -0,0 +1,4 @@ +library l10n; + +export 'fleather_localizations.g.dart'; +export 'utils.dart'; diff --git a/packages/fleather/lib/l10n/utils.dart b/packages/fleather/lib/l10n/utils.dart new file mode 100644 index 00000000..8b23e126 --- /dev/null +++ b/packages/fleather/lib/l10n/utils.dart @@ -0,0 +1,9 @@ +import 'package:fleather/l10n/fleather_localizations_en.g.dart'; +import 'package:flutter/widgets.dart'; + +import 'fleather_localizations.g.dart'; + +extension BuildContextLocalizationsExtension on BuildContext { + FleatherLocalizations get l => + FleatherLocalizations.of(this) ?? FleatherLocalizationsEn(); +} diff --git a/packages/fleather/lib/src/widgets/editor_toolbar.dart b/packages/fleather/lib/src/widgets/editor_toolbar.dart index 3361ce07..176e94d4 100644 --- a/packages/fleather/lib/src/widgets/editor_toolbar.dart +++ b/packages/fleather/lib/src/widgets/editor_toolbar.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:fleather/fleather.dart'; +import 'package:fleather/l10n/l10n.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -200,7 +201,7 @@ class _LinkDialogState extends State<_LinkDialog> { return AlertDialog( content: TextField( decoration: InputDecoration( - labelText: FleatherLocalizations.of(context).addLinkDialogPasteLink, + labelText: context.l.addLinkDialogPasteLink, ), autofocus: true, onChanged: _linkChanged, @@ -208,9 +209,7 @@ class _LinkDialogState extends State<_LinkDialog> { actions: [ TextButton( onPressed: _link.isNotEmpty ? _applyLink : null, - child: Text( - FleatherLocalizations.of(context).addLinkDialogApply, - ), + child: Text(context.l.addLinkDialogApply), ), ], ); @@ -569,7 +568,7 @@ class SelectHeadingButton extends StatefulWidget { } Map, String> _headingToText(BuildContext context) { - final localizations = FleatherLocalizations.of(context); + final localizations = context.l; return { ParchmentAttribute.heading.unset: localizations.headingNormal, @@ -939,8 +938,7 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { child: ColorButton( controller: controller, attributeKey: ParchmentAttribute.foregroundColor, - nullColorLabel: - FleatherLocalizations.of(context).foregroundColorAutomatic, + nullColorLabel: context.l.foregroundColorAutomatic, builder: textColorBuilder, ), ); @@ -951,8 +949,7 @@ class FleatherToolbar extends StatefulWidget implements PreferredSizeWidget { child: ColorButton( controller: controller, attributeKey: ParchmentAttribute.backgroundColor, - nullColorLabel: - FleatherLocalizations.of(context).backgroundColorNoColor, + nullColorLabel: context.l.backgroundColorNoColor, builder: backgroundColorBuilder, ), ); diff --git a/packages/fleather/lib/src/widgets/link.dart b/packages/fleather/lib/src/widgets/link.dart index 2c8c2d96..40669263 100644 --- a/packages/fleather/lib/src/widgets/link.dart +++ b/packages/fleather/lib/src/widgets/link.dart @@ -1,4 +1,5 @@ import 'package:fleather/fleather.dart'; +import 'package:fleather/l10n/l10n.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -49,17 +50,17 @@ Future _showCupertinoLinkMenu( title: Text(link), actions: [ _CupertinoAction( - title: FleatherLocalizations.of(context).linkDialogOpen, + title: context.l.linkDialogOpen, icon: Icons.language_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch), ), _CupertinoAction( - title: FleatherLocalizations.of(context).linkDialogCopy, + title: context.l.linkDialogCopy, icon: Icons.copy_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy), ), _CupertinoAction( - title: FleatherLocalizations.of(context).linkDialogRemove, + title: context.l.linkDialogRemove, icon: Icons.link_off_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove), ), @@ -122,17 +123,17 @@ Future _showMaterialMenu( mainAxisSize: MainAxisSize.min, children: [ _MaterialAction( - title: FleatherLocalizations.of(context).linkDialogOpen, + title: context.l.linkDialogOpen, icon: Icons.language_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.launch), ), _MaterialAction( - title: FleatherLocalizations.of(context).linkDialogCopy, + title: context.l.linkDialogCopy, icon: Icons.copy_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.copy), ), _MaterialAction( - title: FleatherLocalizations.of(context).linkDialogRemove, + title: context.l.linkDialogRemove, icon: Icons.link_off_sharp, onPressed: () => Navigator.of(context).pop(LinkMenuAction.remove), ), diff --git a/packages/fleather/pubspec.yaml b/packages/fleather/pubspec.yaml index 26f2b162..65d8e3d8 100644 --- a/packages/fleather/pubspec.yaml +++ b/packages/fleather/pubspec.yaml @@ -22,12 +22,12 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter collection: ^1.18.0 parchment_delta: ^1.0.0 parchment: ^1.15.0 intl: ^0.19.0 - flutter_localizations: - sdk: flutter dependency_overrides: parchment: From 5e96eff9ac2a5064eafe8ca37b099e66c482a245 Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Fri, 9 Aug 2024 21:28:36 +0330 Subject: [PATCH 07/11] Ignore generated files in codecov --- .gitattributes | 1 + codecov.yml | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 .gitattributes create mode 100644 codecov.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dd8459ee --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.g.dart linguist-generated \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..079ba826 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - '*.g.dart' \ No newline at end of file From 64da4f4270e749706111773ed0587715e970ce55 Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Fri, 9 Aug 2024 21:42:51 +0330 Subject: [PATCH 08/11] Revert "tests: fix tests by adding localizations to the MaterialApp widgets" This reverts commit 58d8295fbba90b273b5ed9bc26fa0170dd7239fd. --- .../test/widgets/editor_toolbar_test.dart | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/packages/fleather/test/widgets/editor_toolbar_test.dart b/packages/fleather/test/widgets/editor_toolbar_test.dart index 544cfc19..91e2b590 100644 --- a/packages/fleather/test/widgets/editor_toolbar_test.dart +++ b/packages/fleather/test/widgets/editor_toolbar_test.dart @@ -1,6 +1,5 @@ import 'package:fleather/fleather.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:parchment_delta/parchment_delta.dart'; @@ -53,16 +52,6 @@ Widget widget(FleatherController controller, {bool withBasic = false}) { ); final editorKey = GlobalKey(); return MaterialApp( - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - FleatherLocalizations.delegate, - ], - supportedLocales: const [ - ...FleatherLocalizations.supportedLocales, - ], - locale: const Locale('en'), home: Material( child: Column(children: [ if (withBasic) @@ -436,16 +425,6 @@ void main() { ); final controller = FleatherController(); final widget = MaterialApp( - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - FleatherLocalizations.delegate, - ], - supportedLocales: const [ - ...FleatherLocalizations.supportedLocales, - ], - locale: const Locale('en'), home: TestUpdateWidget( focusNodeAfterChange: FocusNode(), controller: controller, @@ -478,16 +457,6 @@ void main() { const padding = EdgeInsets.all(32); final controller = FleatherController(); await tester.pumpWidget(MaterialApp( - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - FleatherLocalizations.delegate, - ], - supportedLocales: const [ - ...FleatherLocalizations.supportedLocales, - ], - locale: const Locale('en'), home: Scaffold( appBar: AppBar(), body: Column( @@ -510,16 +479,6 @@ void main() { equals(validRect), ); await tester.pumpWidget(MaterialApp( - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - FleatherLocalizations.delegate, - ], - supportedLocales: const [ - ...FleatherLocalizations.supportedLocales, - ], - locale: const Locale('en'), home: Scaffold( appBar: AppBar(), body: Column( From 5eb27cd1bd940a2a0bc2ab1ca4ba4751d9f602ea Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Sat, 10 Aug 2024 08:16:52 +0330 Subject: [PATCH 09/11] Update codecov.yml --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index 079ba826..f69101ad 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,2 +1,2 @@ ignore: - - '*.g.dart' \ No newline at end of file + - '**.g.dart' \ No newline at end of file From 10dd50c296fec630cdcf4e4919b6e88ed7691191 Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Sat, 10 Aug 2024 21:58:26 +0330 Subject: [PATCH 10/11] Reorganize translation files according to Flutter documentation --- packages/fleather/l10n.yaml | 4 ++-- .../{l10n/app_en.arb => lib/l10n/translations/en.arb} | 0 .../{l10n/app_fr.arb => lib/l10n/translations/fr.arb} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/fleather/{l10n/app_en.arb => lib/l10n/translations/en.arb} (100%) rename packages/fleather/{l10n/app_fr.arb => lib/l10n/translations/fr.arb} (100%) diff --git a/packages/fleather/l10n.yaml b/packages/fleather/l10n.yaml index 0ca88515..65ca2532 100644 --- a/packages/fleather/l10n.yaml +++ b/packages/fleather/l10n.yaml @@ -2,8 +2,8 @@ format: true use-escaping: true synthetic-package: false -arb-dir: l10n -template-arb-file: app_en.arb +arb-dir: lib/l10n/translations +template-arb-file: en.arb output-dir: lib/l10n output-class: FleatherLocalizations diff --git a/packages/fleather/l10n/app_en.arb b/packages/fleather/lib/l10n/translations/en.arb similarity index 100% rename from packages/fleather/l10n/app_en.arb rename to packages/fleather/lib/l10n/translations/en.arb diff --git a/packages/fleather/l10n/app_fr.arb b/packages/fleather/lib/l10n/translations/fr.arb similarity index 100% rename from packages/fleather/l10n/app_fr.arb rename to packages/fleather/lib/l10n/translations/fr.arb From 0f9b6fb8e3fac719e3860596b11b7a32dfe44683 Mon Sep 17 00:00:00 2001 From: Amir Panahandeh Date: Sat, 10 Aug 2024 22:05:03 +0330 Subject: [PATCH 11/11] Use relative import --- packages/fleather/lib/src/widgets/editor_toolbar.dart | 9 ++++++--- packages/fleather/lib/src/widgets/link.dart | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/fleather/lib/src/widgets/editor_toolbar.dart b/packages/fleather/lib/src/widgets/editor_toolbar.dart index 176e94d4..e9852a5b 100644 --- a/packages/fleather/lib/src/widgets/editor_toolbar.dart +++ b/packages/fleather/lib/src/widgets/editor_toolbar.dart @@ -1,9 +1,12 @@ import 'dart:async'; - -import 'package:fleather/fleather.dart'; -import 'package:fleather/l10n/l10n.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:parchment/parchment.dart'; + +import 'controller.dart'; +import 'editor.dart'; +import 'theme.dart'; +import '../../l10n/l10n.dart'; const double kToolbarHeight = 56.0; diff --git a/packages/fleather/lib/src/widgets/link.dart b/packages/fleather/lib/src/widgets/link.dart index 40669263..2fefca26 100644 --- a/packages/fleather/lib/src/widgets/link.dart +++ b/packages/fleather/lib/src/widgets/link.dart @@ -1,8 +1,9 @@ -import 'package:fleather/fleather.dart'; -import 'package:fleather/l10n/l10n.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:parchment/parchment.dart'; + +import '../../l10n/l10n.dart'; /// List of possible actions returned from [LinkActionPickerDelegate]. enum LinkMenuAction {