Skip to content

Commit

Permalink
feat: support RTL in toolbar (AppFlowy-IO#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
1akhanBaheti authored Sep 27, 2023
1 parent d1b9084 commit 2b58d4f
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 22 deletions.
1 change: 1 addition & 0 deletions example/lib/pages/desktop_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class _DesktopEditorState extends State<DesktopEditor> {
...alignmentItems,
],
editorState: editorState,
textDirection: widget.textDirection,
editorScrollController: editorScrollController,
child: Directionality(
textDirection: widget.textDirection,
Expand Down
3 changes: 3 additions & 0 deletions lib/src/editor/toolbar/desktop/floating_toolbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ class FloatingToolbar extends StatefulWidget {
required this.items,
required this.editorState,
required this.editorScrollController,
required this.textDirection,
required this.child,
this.style = const FloatingToolbarStyle(),
});

final List<ToolbarItem> items;
final EditorState editorState;
final EditorScrollController editorScrollController;
final TextDirection? textDirection;
final Widget child;
final FloatingToolbarStyle style;

Expand Down Expand Up @@ -172,6 +174,7 @@ class _FloatingToolbarState extends State<FloatingToolbar>
editorState: editorState,
backgroundColor: widget.style.backgroundColor,
toolbarActiveColor: widget.style.toolbarActiveColor,
textDirection: widget.textDirection ?? Directionality.of(context),
);
return _toolbarWidget!;
}
Expand Down
36 changes: 26 additions & 10 deletions lib/src/editor/toolbar/desktop/floating_toolbar_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@ import 'package:flutter/material.dart';

const floatingToolbarHeight = 32.0;

@visibleForTesting
const floatingToolbarContainerKey =
Key('appflowy_editor_floating_toolbar_container');
@visibleForTesting
const floatingToolbarItemPrefixKey = 'appflowy_editor_floating_toolbar_item';

class FloatingToolbarWidget extends StatefulWidget {
const FloatingToolbarWidget({
super.key,
this.backgroundColor = Colors.black,
required this.toolbarActiveColor,
required this.items,
required this.editorState,
required this.textDirection,
});

final List<ToolbarItem> items;
final Color backgroundColor;
final Color toolbarActiveColor;
final EditorState editorState;
final TextDirection textDirection;

@override
State<FloatingToolbarWidget> createState() => _FloatingToolbarWidgetState();
Expand All @@ -37,18 +45,24 @@ class _FloatingToolbarWidgetState extends State<FloatingToolbarWidget> {
child: SizedBox(
height: floatingToolbarHeight,
child: Row(
key: floatingToolbarContainerKey,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: activeItems.map((item) {
final builder = item.builder;
return Center(
child: builder!(
context,
widget.editorState,
widget.toolbarActiveColor,
),
);
}).toList(growable: false),
textDirection: widget.textDirection,
children: activeItems
.mapIndexed(
(index, item) => Center(
key: Key(
'${floatingToolbarItemPrefixKey}_${item.id}_$index',
),
child: item.builder!(
context,
widget.editorState,
widget.toolbarActiveColor,
),
),
)
.toList(growable: false),
),
),
),
Expand All @@ -62,8 +76,10 @@ class _FloatingToolbarWidgetState extends State<FloatingToolbarWidget> {
if (activeItems.isEmpty) {
return [];
}

// sort by group.
activeItems.sort((a, b) => a.group.compareTo(b.group));

// insert the divider.
return activeItems
.splitBetween((first, second) => first.group != second.group)
Expand Down
1 change: 1 addition & 0 deletions test/customer/custom_toolbar_item_color_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class CustomToolbarItemColor extends StatelessWidget {
border: Border.all(color: Colors.blue),
),
child: FloatingToolbar(
textDirection: TextDirection.ltr,
items: [bulletedListItem],
style: const FloatingToolbarStyle(
backgroundColor: Colors.red,
Expand Down
32 changes: 21 additions & 11 deletions test/new/infra/testable_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ import 'package:flutter_test/flutter_test.dart';
import '../find_replace_menu/find_replace_menu_utils.dart';
import '../util/util.dart';

final floatingToolbarItems = [
paragraphItem,
...headingItems,
...markdownFormatItems,
quoteItem,
bulletedListItem,
numberedListItem,
linkItem,
buildTextColorItem(),
buildHighlightColorItem(),
];

class TestableEditor {
TestableEditor({
required this.tester,
Expand Down Expand Up @@ -42,6 +54,7 @@ class TestableEditor {
Widget Function(Widget child)? wrapper,
TargetPlatform? platform,
String? defaultTextDirection,
TextDirection textDirection = TextDirection.ltr,
}) async {
await AppFlowyEditorLocalizations.load(locale);

Expand Down Expand Up @@ -106,23 +119,20 @@ class TestableEditor {
);
} else {
editor = FloatingToolbar(
items: [
paragraphItem,
...headingItems,
...markdownFormatItems,
quoteItem,
bulletedListItem,
numberedListItem,
linkItem,
buildTextColorItem(),
buildHighlightColorItem(),
],
items: floatingToolbarItems,
editorState: editorState,
textDirection: textDirection,
editorScrollController: editorScrollController,
child: editor,
);
}
}

editor = Directionality(
textDirection: textDirection,
child: editor,
);

await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: platform),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Future<void> _testLinkMenuInSingleTextSelection(WidgetTester tester) async {
buildHighlightColorItem(),
],
editorState: editor.editorState,
textDirection: TextDirection.ltr,
editorScrollController: EditorScrollController(
editorState: editor.editorState,
scrollController: scrollController,
Expand Down
51 changes: 50 additions & 1 deletion test/new/toolbar/desktop/floating_toolbar_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../infra/testable_editor.dart';
Expand All @@ -21,11 +22,59 @@ void main() async {
endOffset: text.length,
);
await editor.updateSelection(selection);
await tester.pumpAndSettle();

final floatingToolbar = find.byType(FloatingToolbarWidget);
expect(floatingToolbar, findsOneWidget);
expect(tester.getTopLeft(floatingToolbar).dy >= 0, true);

await editor.dispose();
});

testWidgets(
'select the first line of the document, the toolbar layout should be right to left in RTL mode',
(tester) async {
final editor = tester.editor..addParagraphs(3, initialText: text);
await editor.startTesting(
withFloatingToolbar: true,
textDirection: TextDirection.rtl,
);

final selection = Selection.single(
path: [0],
startOffset: 0,
endOffset: text.length,
);
await editor.updateSelection(selection);

final floatingToolbar = find.byType(FloatingToolbarWidget);
expect(floatingToolbar, findsOneWidget);
final floatingToolbarContainer = tester.widget<Row>(
find.byKey(floatingToolbarContainerKey),
);
expect(floatingToolbarContainer.textDirection, TextDirection.rtl);
final List<Widget> toolbarItemWidgets = floatingToolbarContainer.children;
expect(
toolbarItemWidgets.length,
// the floating toolbar items will add the divider between the groups,
// so the length of the toolbar items will be the sum of the (floatingToolbarItems.length +
// the number of the groups) - 1.
floatingToolbarItems.length +
floatingToolbarItems.map((e) => e.group).toSet().length -
1,
);

final expectedIds = floatingToolbarItems.map((e) => e.id).toList();
var j = 0;
for (int i = 0; i < toolbarItemWidgets.length; i++) {
final id = '${floatingToolbarItemPrefixKey}_${expectedIds[j]}_$i';
final key = toolbarItemWidgets[i].key as ValueKey;
if (key.value.contains(placeholderItem.id)) {
continue;
}
expect(key, Key(id));
j++;
}

await editor.dispose();
});
});
Expand Down

0 comments on commit 2b58d4f

Please sign in to comment.