mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
* fix: [FR] The text formatting toolbar should appear after the selection #1778 * chore: format code
This commit is contained in:
parent
77ff2e987a
commit
b89c69f294
@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy_editor/src/flutter/overlay.dart';
|
||||
import 'package:appflowy_editor/src/infra/log.dart';
|
||||
import 'package:appflowy_editor/src/service/context_menu/built_in_context_menu_item.dart';
|
||||
@ -121,6 +123,9 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
|
||||
EditorState get editorState => widget.editorState;
|
||||
|
||||
// Toolbar
|
||||
Timer? _toolbarTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -144,6 +149,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
clearSelection();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
currentSelection.removeListener(_onSelectionChange);
|
||||
_clearToolbar();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
@ -236,7 +242,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
// clear cursor areas
|
||||
|
||||
// hide toolbar
|
||||
editorState.service.toolbarService?.hide();
|
||||
// editorState.service.toolbarService?.hide();
|
||||
|
||||
// clear context menu
|
||||
_clearContextMenu();
|
||||
@ -482,13 +488,8 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
|
||||
Overlay.of(context)?.insertAll(_selectionAreas);
|
||||
|
||||
if (toolbarOffset != null && layerLink != null) {
|
||||
editorState.service.toolbarService?.showInOffset(
|
||||
toolbarOffset,
|
||||
alignment!,
|
||||
layerLink,
|
||||
);
|
||||
}
|
||||
// show toolbar
|
||||
_showToolbarWithDelay(toolbarOffset, layerLink, alignment!);
|
||||
}
|
||||
|
||||
void _updateCursorAreas(Position position) {
|
||||
@ -502,6 +503,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
currentSelectedNodes = [node];
|
||||
|
||||
_showCursor(node, position);
|
||||
_clearToolbar();
|
||||
}
|
||||
|
||||
void _showCursor(Node node, Position position) {
|
||||
@ -628,6 +630,40 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||
_scrollUpOrDownIfNeeded();
|
||||
}
|
||||
|
||||
void _showToolbarWithDelay(
|
||||
Offset? toolbarOffset,
|
||||
LayerLink? layerLink,
|
||||
Alignment alignment, {
|
||||
Duration delay = const Duration(milliseconds: 400),
|
||||
}) {
|
||||
if (toolbarOffset == null && layerLink == null) {
|
||||
_clearToolbar();
|
||||
return;
|
||||
}
|
||||
if (_toolbarTimer?.isActive ?? false) {
|
||||
_toolbarTimer?.cancel();
|
||||
}
|
||||
_toolbarTimer = Timer(
|
||||
delay,
|
||||
() {
|
||||
if (toolbarOffset != null && layerLink != null) {
|
||||
editorState.service.toolbarService?.showInOffset(
|
||||
toolbarOffset,
|
||||
alignment,
|
||||
layerLink,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _clearToolbar() {
|
||||
editorState.service.toolbarService?.hide();
|
||||
if (_toolbarTimer?.isActive ?? false) {
|
||||
_toolbarTimer?.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void _showDebugLayerIfNeeded({Offset? offset}) {
|
||||
// remove false to show debug overlay.
|
||||
// if (kDebugMode && false) {
|
||||
|
@ -7,7 +7,11 @@ import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
||||
|
||||
abstract class AppFlowyToolbarService {
|
||||
/// Show the toolbar widget beside the offset.
|
||||
void showInOffset(Offset offset, Alignment alignment, LayerLink layerLink);
|
||||
void showInOffset(
|
||||
Offset offset,
|
||||
Alignment alignment,
|
||||
LayerLink layerLink,
|
||||
);
|
||||
|
||||
/// Hide the toolbar widget.
|
||||
void hide();
|
||||
@ -45,7 +49,11 @@ class _FlowyToolbarState extends State<FlowyToolbar>
|
||||
}
|
||||
|
||||
@override
|
||||
void showInOffset(Offset offset, Alignment alignment, LayerLink layerLink) {
|
||||
void showInOffset(
|
||||
Offset offset,
|
||||
Alignment alignment,
|
||||
LayerLink layerLink,
|
||||
) {
|
||||
hide();
|
||||
final items = _filterItems(toolbarItems);
|
||||
if (items.isEmpty) {
|
||||
|
@ -25,6 +25,7 @@ void main() async {
|
||||
|
||||
await editor.updateSelection(h1);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
final h1Button = find.byWidgetPredicate((widget) {
|
||||
@ -52,6 +53,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(h2);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
final h2Button = find.byWidgetPredicate((widget) {
|
||||
@ -77,6 +79,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(h3);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
final h3Button = find.byWidgetPredicate((widget) {
|
||||
@ -104,6 +107,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(underline);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final underlineButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -132,6 +136,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(bold);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final boldButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -159,6 +164,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(italic);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final italicButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -187,6 +193,7 @@ void main() async {
|
||||
|
||||
await editor.updateSelection(strikeThrough);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final strikeThroughButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -214,6 +221,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(code);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final codeButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -250,6 +258,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(quote);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final quoteButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -276,6 +285,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(bulletList);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final bulletListButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -306,6 +316,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: singleLineText.length));
|
||||
|
||||
await editor.updateSelection(selection);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final highlightButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
@ -343,6 +354,7 @@ void main() async {
|
||||
);
|
||||
|
||||
await editor.updateSelection(selection);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
final colorButton = find.byWidgetPredicate((widget) {
|
||||
if (widget is ToolbarItemWidget) {
|
||||
|
@ -245,6 +245,7 @@ Future<void> _testLinkMenuInSingleTextSelection(WidgetTester tester) async {
|
||||
await editor.updateSelection(selection);
|
||||
|
||||
// show toolbar
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
// trigger the link menu
|
||||
|
@ -24,6 +24,7 @@ void main() async {
|
||||
);
|
||||
await editor.updateSelection(selection);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
// no link item
|
||||
@ -72,6 +73,7 @@ void main() async {
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0, endOffset: text.length),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
|
||||
void testHighlight(bool expectedValue) {
|
||||
@ -138,6 +140,7 @@ void main() async {
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0, endOffset: text.length),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
var itemWidget = _itemWidgetForId(tester, 'appflowy.toolbar.h1');
|
||||
expect(itemWidget.isHighlight, true);
|
||||
@ -145,6 +148,7 @@ void main() async {
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [1], startOffset: 0, endOffset: text.length),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
itemWidget = _itemWidgetForId(tester, 'appflowy.toolbar.quote');
|
||||
expect(itemWidget.isHighlight, true);
|
||||
@ -152,6 +156,7 @@ void main() async {
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [2], startOffset: 0, endOffset: text.length),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
itemWidget = _itemWidgetForId(tester, 'appflowy.toolbar.bulleted_list');
|
||||
expect(itemWidget.isHighlight, true);
|
||||
@ -183,6 +188,7 @@ void main() async {
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [2], startOffset: text.length, endOffset: 0),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
expect(
|
||||
_itemWidgetForId(tester, 'appflowy.toolbar.h1').isHighlight,
|
||||
@ -199,6 +205,7 @@ void main() async {
|
||||
end: Position(path: [1], offset: 0),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
expect(
|
||||
_itemWidgetForId(tester, 'appflowy.toolbar.bold').isHighlight,
|
||||
@ -211,6 +218,7 @@ void main() async {
|
||||
end: Position(path: [0], offset: 0),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 500));
|
||||
expect(find.byType(ToolbarWidget), findsOneWidget);
|
||||
expect(
|
||||
_itemWidgetForId(tester, 'appflowy.toolbar.bold').isHighlight,
|
||||
|
Loading…
Reference in New Issue
Block a user