Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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