diff --git a/frontend/app_flowy/packages/flowy_editor/example/lib/main.dart b/frontend/app_flowy/packages/flowy_editor/example/lib/main.dart index 83960275e6..9cc4d8c536 100644 --- a/frontend/app_flowy/packages/flowy_editor/example/lib/main.dart +++ b/frontend/app_flowy/packages/flowy_editor/example/lib/main.dart @@ -97,6 +97,32 @@ class _MyHomePageState extends State { return FlowyEditor( editorState: _editorState, keyEventHandler: const [], + shortcuts: [ + // TODO: this won't work, just a example for now. + { + 'h1': (editorState, eventName) { + debugPrint('shortcut => $eventName'); + final selectedNodes = editorState.selectedNodes; + if (selectedNodes.isEmpty) { + return; + } + final textNode = selectedNodes.first as TextNode; + TransactionBuilder(editorState) + ..formatText(textNode, 0, textNode.toRawString().length, { + 'heading': 'h1', + }) + ..commit(); + } + }, + { + 'bold': (editorState, eventName) => + debugPrint('shortcut => $eventName') + }, + { + 'underline': (editorState, eventName) => + debugPrint('shortcut => $eventName') + }, + ], ); } }, diff --git a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart index 389bfed320..8a9c96b22e 100644 --- a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart @@ -52,7 +52,7 @@ class __ImageNodeWidgetState extends State<_ImageNodeWidget> with Selectable { } @override - TextSelection? getTextSelection() { + TextSelection? getCurrentTextSelection() { return null; } @@ -61,6 +61,16 @@ class __ImageNodeWidgetState extends State<_ImageNodeWidget> with Selectable { return Offset.zero; } + @override + Offset getBackwardOffset() { + return Offset.zero; + } + + @override + Offset getForwardOffset() { + return Offset.zero; + } + @override Widget build(BuildContext context) { return _build(context); diff --git a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/selected_text_node_widget.dart b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/selected_text_node_widget.dart index 1124ec3cbb..b234ecd967 100644 --- a/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/selected_text_node_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/selected_text_node_widget.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:example/plugin/debuggable_rich_text.dart'; import 'package:flowy_editor/flowy_editor.dart'; import 'package:flutter/foundation.dart'; @@ -98,7 +100,7 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget> } @override - TextSelection? getTextSelection() { + TextSelection? getCurrentTextSelection() { return _textSelection; } @@ -108,6 +110,30 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget> return _renderParagraph.localToGlobal(offset); } + @override + Offset getBackwardOffset() { + final textSelection = _textSelection; + if (textSelection != null) { + final leftTextSelection = TextSelection.collapsed( + offset: max(0, textSelection.baseOffset - 1), + ); + return getOffsetByTextSelection(leftTextSelection); + } + return Offset.zero; + } + + @override + Offset getForwardOffset() { + final textSelection = _textSelection; + if (textSelection != null) { + final leftTextSelection = TextSelection.collapsed( + offset: min(node.toRawString().length, textSelection.extentOffset + 1), + ); + return getOffsetByTextSelection(leftTextSelection); + } + return Offset.zero; + } + @override Widget build(BuildContext context) { Widget richText; @@ -117,6 +143,10 @@ class _SelectedTextNodeWidgetState extends State<_SelectedTextNodeWidget> richText = RichText(key: _textKey, text: node.toTextSpan()); } + if (node.children.isEmpty) { + return richText; + } + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart b/frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart index dfe734da8c..cd503843c2 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:flowy_editor/service/service.dart'; import 'package:flutter/material.dart'; import 'package:flowy_editor/document/node.dart'; @@ -21,13 +22,14 @@ class ApplyOptions { }); } -// TODO -final selectionServiceKey = GlobalKey(); - class EditorState { final StateTree document; final RenderPlugins renderPlugins; List selectedNodes = []; + + // Service reference. + final service = FlowyService(); + final UndoManager undoManager = UndoManager(); Selection? cursorSelection; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_cursor_widget.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/cursor_widget.dart similarity index 83% rename from frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_cursor_widget.dart rename to frontend/app_flowy/packages/flowy_editor/lib/render/selection/cursor_widget.dart index 9ab61e5c47..2ba42221f0 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_cursor_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/cursor_widget.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; -class FlowyCursorWidget extends StatefulWidget { - const FlowyCursorWidget({ +class CursorWidget extends StatefulWidget { + const CursorWidget({ Key? key, required this.layerLink, required this.rect, @@ -17,10 +17,10 @@ class FlowyCursorWidget extends StatefulWidget { final LayerLink layerLink; @override - State createState() => _FlowyCursorWidgetState(); + State createState() => _CursorWidgetState(); } -class _FlowyCursorWidgetState extends State { +class _CursorWidgetState extends State { bool showCursor = true; late Timer timer; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/floating_shortcut_widget.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/floating_shortcut_widget.dart new file mode 100644 index 0000000000..9fbbbbcb01 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/floating_shortcut_widget.dart @@ -0,0 +1,58 @@ +import 'package:flowy_editor/flowy_editor.dart'; +import 'package:flutter/material.dart'; + +typedef FloatingShortcutHandler = void Function( + EditorState editorState, String eventName); +typedef FloatingShortcuts = List>; + +class FloatingShortcutWidget extends StatelessWidget { + const FloatingShortcutWidget({ + Key? key, + required this.editorState, + required this.layerLink, + required this.rect, + required this.floatingShortcuts, + }) : super(key: key); + + final EditorState editorState; + final LayerLink layerLink; + final Rect rect; + final FloatingShortcuts floatingShortcuts; + + List get _shortcutNames => + floatingShortcuts.map((shortcut) => shortcut.keys.first).toList(); + List get _shortcutHandlers => + floatingShortcuts.map((shortcut) => shortcut.values.first).toList(); + + @override + Widget build(BuildContext context) { + return Positioned.fromRect( + rect: rect, + child: CompositedTransformFollower( + link: layerLink, + offset: rect.topLeft, + showWhenUnlinked: true, + child: Container( + color: Colors.white, + child: ListView.builder( + itemCount: floatingShortcuts.length, + itemBuilder: ((context, index) { + final name = _shortcutNameInIndex(index); + final handler = _shortcutHandlerInIndex(index); + return Card( + child: GestureDetector( + onTap: () => handler(editorState, name), + child: ListTile(title: Text(name)), + ), + ); + }), + ), + ), + ), + ); + } + + String _shortcutNameInIndex(int index) => _shortcutNames[index]; + FloatingShortcutHandler _shortcutHandlerInIndex(int index) => + _shortcutHandlers[index]; +} diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_selection_widget.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_selection_widget.dart index f3def681e1..96dd6a7759 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_selection_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/flowy_selection_widget.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -class FlowySelectionWidget extends StatefulWidget { - const FlowySelectionWidget({ +class SelectionWidget extends StatefulWidget { + const SelectionWidget({ Key? key, required this.layerLink, required this.rect, @@ -13,10 +13,10 @@ class FlowySelectionWidget extends StatefulWidget { final LayerLink layerLink; @override - State createState() => _FlowySelectionWidgetState(); + State createState() => _SelectionWidgetState(); } -class _FlowySelectionWidgetState extends State { +class _SelectionWidgetState extends State { @override Widget build(BuildContext context) { return Positioned.fromRect( diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/selectable.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/selectable.dart index 59849c1a6a..6fc51049a1 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/selectable.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/selectable.dart @@ -2,18 +2,40 @@ import 'package:flutter/material.dart'; /// mixin Selectable on State { - /// Returns a [Rect] list for overlay. - /// [start] and [end] are global offsets. - /// The return result must be an local offset. + /// Returns a [List] of the [Rect] selection sorrounded by start and end + /// in current widget. + /// + /// [start] and [end] are the offsets under the global coordinate system. + /// + /// The return result must be a [List] of the [Rect] + /// under the local coordinate system. List getSelectionRectsInRange(Offset start, Offset end); - /// Returns a [Rect] for cursor. - /// The return result must be an local offset. + /// Returns a [Rect] for the offset in current widget. + /// + /// [start] is the offset of the global coordination system. + /// + /// The return result must be an offset of the local coordinate system. Rect getCursorRect(Offset start); - /// For [TextNode] only. - TextSelection? getTextSelection(); + /// Returns a backward offset of the current offset based on the cause. + Offset getBackwardOffset(/* Cause */); + + /// Returns a forward offset of the current offset based on the cause. + Offset getForwardOffset(/* Cause */); /// For [TextNode] only. + /// + /// Returns a [TextSelection] or [Null]. + /// + /// Only the widget rendered by [TextNode] need to implement the detail, + /// and the rest can return null. + TextSelection? getCurrentTextSelection(); + + /// For [TextNode] only. + /// + /// Retruns a [Offset]. + /// Only the widget rendered by [TextNode] need to implement the detail, + /// and the rest can return [Offset.zero]. Offset getOffsetByTextSelection(TextSelection textSelection); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/editor_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/editor_service.dart index d0efac2a0f..7cd4eaf708 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/editor_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/editor_service.dart @@ -1,5 +1,9 @@ +import 'package:flowy_editor/render/selection/floating_shortcut_widget.dart'; +import 'package:flowy_editor/service/floating_shortcut_service.dart'; +import 'package:flowy_editor/service/flowy_key_event_handlers/arrow_keys_handler.dart'; import 'package:flowy_editor/service/flowy_key_event_handlers/delete_nodes_handler.dart'; import 'package:flowy_editor/service/flowy_key_event_handlers/delete_single_text_node_handler.dart'; +import 'package:flowy_editor/service/flowy_key_event_handlers/shortcut_handler.dart'; import 'package:flowy_editor/service/keyboard_service.dart'; import 'package:flowy_editor/service/selection_service.dart'; @@ -11,10 +15,12 @@ class FlowyEditor extends StatefulWidget { Key? key, required this.editorState, required this.keyEventHandler, + required this.shortcuts, }) : super(key: key); final EditorState editorState; final List keyEventHandler; + final FloatingShortcuts shortcuts; @override State createState() => _FlowyEditorState(); @@ -26,16 +32,25 @@ class _FlowyEditorState extends State { @override Widget build(BuildContext context) { return FlowySelection( - key: selectionServiceKey, + key: editorState.service.selectionServiceKey, editorState: editorState, child: FlowyKeyboard( + key: editorState.service.keyboardServiceKey, handlers: [ + slashShortcutHandler, flowyDeleteNodesHandler, deleteSingleTextNodeHandler, + arrowKeysHandler, ...widget.keyEventHandler, ], editorState: editorState, - child: editorState.build(context), + child: FloatingShortcut( + key: editorState.service.floatingShortcutServiceKey, + size: const Size(200, 150), // TODO: support customize size. + editorState: editorState, + floatingShortcuts: widget.shortcuts, + child: editorState.build(context), + ), ), ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/floating_shortcut_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/floating_shortcut_service.dart new file mode 100644 index 0000000000..774d906acc --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/floating_shortcut_service.dart @@ -0,0 +1,60 @@ +import 'package:flowy_editor/flowy_editor.dart'; +import 'package:flowy_editor/render/selection/floating_shortcut_widget.dart'; +import 'package:flutter/material.dart'; + +mixin FlowyFloatingShortcutService { + /// Show the floating shortcut widget beside the offset. + void showInOffset(Offset offset, LayerLink layerLink); + + /// Hide the floating shortcut widget. + void hide(); +} + +class FloatingShortcut extends StatefulWidget { + const FloatingShortcut({ + Key? key, + required this.size, + required this.editorState, + required this.floatingShortcuts, + required this.child, + }) : super(key: key); + + final Size size; + final EditorState editorState; + final Widget child; + final FloatingShortcuts floatingShortcuts; + + @override + State createState() => _FloatingShortcutState(); +} + +class _FloatingShortcutState extends State + with FlowyFloatingShortcutService { + OverlayEntry? _floatintShortcutOverlay; + + @override + void showInOffset(Offset offset, LayerLink layerLink) { + _floatintShortcutOverlay?.remove(); + _floatintShortcutOverlay = OverlayEntry( + builder: (context) => FloatingShortcutWidget( + editorState: widget.editorState, + layerLink: layerLink, + rect: offset.translate(10, 0) & widget.size, + floatingShortcuts: widget.floatingShortcuts), + ); + Overlay.of(context)?.insert(_floatintShortcutOverlay!); + } + + @override + void hide() { + _floatintShortcutOverlay?.remove(); + _floatintShortcutOverlay = null; + } + + @override + Widget build(BuildContext context) { + return Container( + child: widget.child, + ); + } +} diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/arrow_keys_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/arrow_keys_handler.dart new file mode 100644 index 0000000000..3049f54453 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/arrow_keys_handler.dart @@ -0,0 +1,37 @@ +import 'package:flowy_editor/extensions/object_extensions.dart'; +import 'package:flowy_editor/flowy_editor.dart'; +import 'package:flowy_editor/service/keyboard_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +FlowyKeyEventHandler arrowKeysHandler = (editorState, event) { + if (event.logicalKey != LogicalKeyboardKey.arrowUp && + event.logicalKey != LogicalKeyboardKey.arrowDown && + event.logicalKey != LogicalKeyboardKey.arrowLeft && + event.logicalKey != LogicalKeyboardKey.arrowRight) { + return KeyEventResult.ignored; + } + + // TODO: Up and Down + + // Left and Right + final selectedNodes = editorState.selectedNodes; + if (selectedNodes.length != 1) { + return KeyEventResult.ignored; + } + + final node = selectedNodes.first.unwrapOrNull(); + final selectable = node?.key?.currentState?.unwrapOrNull(); + Offset? offset; + if (event.logicalKey == LogicalKeyboardKey.arrowLeft) { + offset = selectable?.getBackwardOffset(); + } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) { + offset = selectable?.getForwardOffset(); + } + final selectionService = editorState.service.selectionService; + if (offset != null) { + selectionService.updateCursor(offset); + return KeyEventResult.handled; + } + return KeyEventResult.ignored; +}; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/delete_single_text_node_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/delete_single_text_node_handler.dart index 3c1c1c9e95..db12d2bbb2 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/delete_single_text_node_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/delete_single_text_node_handler.dart @@ -1,10 +1,8 @@ import 'package:flowy_editor/document/node.dart'; -import 'package:flowy_editor/editor_state.dart'; import 'package:flowy_editor/operation/transaction_builder.dart'; import 'package:flowy_editor/render/selection/selectable.dart'; import 'package:flowy_editor/service/keyboard_service.dart'; import 'package:flowy_editor/extensions/object_extensions.dart'; -import 'package:flowy_editor/service/selection_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -19,7 +17,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) { final node = selectionNodes.first.unwrapOrNull(); final selectable = node?.key?.currentState?.unwrapOrNull(); if (selectable != null) { - final textSelection = selectable.getTextSelection(); + final textSelection = selectable.getCurrentTextSelection(); if (textSelection != null) { if (textSelection.isCollapsed) { /// Three cases: @@ -33,8 +31,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) { final previous = node!.previous! as TextNode; final newTextSelection = TextSelection.collapsed( offset: previous.toRawString().length); - final selectionService = - selectionServiceKey.currentState as FlowySelectionService; + final selectionService = editorState.service.selectionService; final previousSelectable = previous.key?.currentState?.unwrapOrNull(); final newOfset = previousSelectable @@ -58,8 +55,7 @@ FlowyKeyEventHandler deleteSingleTextNodeHandler = (editorState, event) { ..commit(); final newTextSelection = TextSelection.collapsed(offset: textSelection.baseOffset - 1); - final selectionService = - selectionServiceKey.currentState as FlowySelectionService; + final selectionService = editorState.service.selectionService; final newOfset = selectable.getOffsetByTextSelection(newTextSelection); selectionService.updateCursor(newOfset); diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/shortcut_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/shortcut_handler.dart new file mode 100644 index 0000000000..4e52d1bbe9 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/flowy_key_event_handlers/shortcut_handler.dart @@ -0,0 +1,30 @@ +import 'package:flowy_editor/flowy_editor.dart'; +import 'package:flowy_editor/service/keyboard_service.dart'; +import 'package:flowy_editor/extensions/object_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// type '/' to trigger shortcut widget +FlowyKeyEventHandler slashShortcutHandler = (editorState, event) { + if (event.logicalKey != LogicalKeyboardKey.slash) { + return KeyEventResult.ignored; + } + + final selectedNodes = editorState.selectedNodes; + if (selectedNodes.length != 1) { + return KeyEventResult.ignored; + } + + final textNode = selectedNodes.first.unwrapOrNull(); + final selectable = textNode?.key?.currentState?.unwrapOrNull(); + final textSelection = selectable?.getCurrentTextSelection(); + if (textNode != null && selectable != null && textSelection != null) { + final offset = selectable.getOffsetByTextSelection(textSelection); + final rect = selectable.getCursorRect(offset); + editorState.service.floatingToolbarService + .showInOffset(rect.topLeft, textNode.layerLink); + return KeyEventResult.handled; + } + + return KeyEventResult.ignored; +}; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart index 060a9c98fb..ebd66894a7 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart @@ -46,7 +46,7 @@ class _FlowyKeyboardState extends State { } for (final handler in widget.handlers) { - debugPrint('handle keyboard event $event by $handler'); + // debugPrint('handle keyboard event $event by $handler'); KeyEventResult result = handler(widget.editorState, event); diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart index 99b0efb467..2f4bba86ec 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart @@ -1,5 +1,7 @@ -import 'package:flowy_editor/render/selection/flowy_cursor_widget.dart'; +import 'package:flowy_editor/render/selection/cursor_widget.dart'; import 'package:flowy_editor/render/selection/flowy_selection_widget.dart'; +import 'package:flowy_editor/extensions/object_extensions.dart'; +import 'package:flowy_editor/service/floating_shortcut_service.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -120,7 +122,7 @@ class _FlowySelectionState extends State final selectionRects = selectable.getSelectionRectsInRange(start, end); for (final rect in selectionRects) { final overlay = OverlayEntry( - builder: ((context) => FlowySelectionWidget( + builder: ((context) => SelectionWidget( color: Colors.yellow.withAlpha(100), layerLink: node.layerLink, rect: rect, @@ -149,7 +151,7 @@ class _FlowySelectionState extends State final selectable = selectedNode.key?.currentState as Selectable; final rect = selectable.getCursorRect(start); final cursor = OverlayEntry( - builder: ((context) => FlowyCursorWidget( + builder: ((context) => CursorWidget( key: _cursorKey, rect: rect, color: Colors.red, @@ -275,6 +277,7 @@ class _FlowySelectionState extends State void _clearAllOverlayEntries() { _clearSelection(); _clearCursor(); + _clearFloatingShorts(); } void _clearSelection() { @@ -288,4 +291,11 @@ class _FlowySelectionState extends State ..forEach((overlay) => overlay.remove()) ..clear(); } + + void _clearFloatingShorts() { + final shortcutService = editorState + .service.floatingShortcutServiceKey.currentState + ?.unwrapOrNull(); + shortcutService?.hide(); + } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/service.dart new file mode 100644 index 0000000000..7833e6d379 --- /dev/null +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/service.dart @@ -0,0 +1,27 @@ +import 'package:flowy_editor/service/floating_shortcut_service.dart'; +import 'package:flowy_editor/service/selection_service.dart'; +import 'package:flutter/material.dart'; + +class FlowyService { + // selection service + final selectionServiceKey = GlobalKey(debugLabel: 'flowy_selection_service'); + FlowySelectionService get selectionService { + assert(selectionServiceKey.currentState != null && + selectionServiceKey.currentState is FlowySelectionService); + return selectionServiceKey.currentState! as FlowySelectionService; + } + + // keyboard service + final keyboardServiceKey = GlobalKey(debugLabel: 'flowy_keyboard_service'); + + // floating shortcut service + final floatingShortcutServiceKey = + GlobalKey(debugLabel: 'flowy_floating_shortcut_service'); + FlowyFloatingShortcutService get floatingToolbarService { + assert(floatingShortcutServiceKey.currentState != null && + floatingShortcutServiceKey.currentState + is FlowyFloatingShortcutService); + return floatingShortcutServiceKey.currentState! + as FlowyFloatingShortcutService; + } +}