mirror of
https://github.com/AppFlowy-IO/AppFlowy
synced 2026-05-24 09:38:25 +00:00
feat: refactor current selection and current selectedNodes in selection_service
This commit is contained in:
parent
4b4ce1020d
commit
7e6c7a2b4e
8 changed files with 51 additions and 48 deletions
|
|
@ -67,13 +67,13 @@ class _ToolbarWidgetState extends State<ToolbarWidget> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
widget.editorState.service.selectionService.currentSelectedNodes
|
widget.editorState.service.selectionService.currentSelection
|
||||||
.addListener(_onSelectionChange);
|
.addListener(_onSelectionChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
widget.editorState.service.selectionService.currentSelectedNodes
|
widget.editorState.service.selectionService.currentSelection
|
||||||
.removeListener(_onSelectionChange);
|
.removeListener(_onSelectionChange);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ void formatBulletedList(EditorState editorState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool formatTextNodes(EditorState editorState, Attributes attributes) {
|
bool formatTextNodes(EditorState editorState, Attributes attributes) {
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
final textNodes = nodes.whereType<TextNode>().toList();
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
|
|
||||||
if (textNodes.isEmpty) {
|
if (textNodes.isEmpty) {
|
||||||
|
|
@ -85,8 +85,8 @@ bool formatStrikethrough(EditorState editorState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool formatRichTextPartialStyle(EditorState editorState, String styleKey) {
|
bool formatRichTextPartialStyle(EditorState editorState, String styleKey) {
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
final textNodes = nodes.whereType<TextNode>().toList(growable: false);
|
final textNodes = nodes.whereType<TextNode>().toList(growable: false);
|
||||||
|
|
||||||
if (selection == null || textNodes.isEmpty) {
|
if (selection == null || textNodes.isEmpty) {
|
||||||
|
|
@ -107,8 +107,8 @@ bool formatRichTextPartialStyle(EditorState editorState, String styleKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
|
bool formatRichTextStyle(EditorState editorState, Attributes attributes) {
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
final textNodes = nodes.whereType<TextNode>().toList();
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
|
|
||||||
if (selection == null || textNodes.isEmpty) {
|
if (selection == null || textNodes.isEmpty) {
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,15 @@ class _FlowyInputState extends State<FlowyInput>
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_editorState.service.selectionService.currentSelectedNodes
|
_editorState.service.selectionService.currentSelection
|
||||||
.addListener(_onSelectedNodesChange);
|
.addListener(_onSelectionChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
close();
|
close();
|
||||||
_editorState.service.selectionService.currentSelectedNodes
|
_editorState.service.selectionService.currentSelection
|
||||||
.removeListener(_onSelectedNodesChange);
|
.removeListener(_onSelectionChange);
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
@ -105,13 +105,12 @@ class _FlowyInputState extends State<FlowyInput>
|
||||||
|
|
||||||
void _applyInsert(TextEditingDeltaInsertion delta) {
|
void _applyInsert(TextEditingDeltaInsertion delta) {
|
||||||
final selectionService = _editorState.service.selectionService;
|
final selectionService = _editorState.service.selectionService;
|
||||||
final currentSelection = selectionService.currentSelection;
|
final currentSelection = selectionService.currentSelection.value;
|
||||||
if (currentSelection == null) {
|
if (currentSelection == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentSelection.isSingle) {
|
if (currentSelection.isSingle) {
|
||||||
final textNode =
|
final textNode = selectionService.currentSelectedNodes.first as TextNode;
|
||||||
selectionService.currentSelectedNodes.value.first as TextNode;
|
|
||||||
TransactionBuilder(_editorState)
|
TransactionBuilder(_editorState)
|
||||||
..insertText(
|
..insertText(
|
||||||
textNode,
|
textNode,
|
||||||
|
|
@ -126,13 +125,12 @@ class _FlowyInputState extends State<FlowyInput>
|
||||||
|
|
||||||
void _applyReplacement(TextEditingDeltaReplacement delta) {
|
void _applyReplacement(TextEditingDeltaReplacement delta) {
|
||||||
final selectionService = _editorState.service.selectionService;
|
final selectionService = _editorState.service.selectionService;
|
||||||
final currentSelection = selectionService.currentSelection;
|
final currentSelection = selectionService.currentSelection.value;
|
||||||
if (currentSelection == null) {
|
if (currentSelection == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentSelection.isSingle) {
|
if (currentSelection.isSingle) {
|
||||||
final textNode =
|
final textNode = selectionService.currentSelectedNodes.first as TextNode;
|
||||||
selectionService.currentSelectedNodes.value.first as TextNode;
|
|
||||||
final length = delta.replacedRange.end - delta.replacedRange.start;
|
final length = delta.replacedRange.end - delta.replacedRange.start;
|
||||||
TransactionBuilder(_editorState)
|
TransactionBuilder(_editorState)
|
||||||
..replaceText(
|
..replaceText(
|
||||||
|
|
@ -209,11 +207,11 @@ class _FlowyInputState extends State<FlowyInput>
|
||||||
// TODO: implement updateFloatingCursor
|
// TODO: implement updateFloatingCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectedNodesChange() {
|
void _onSelectionChange() {
|
||||||
final textNodes = _editorState
|
final textNodes = _editorState.service.selectionService.currentSelectedNodes
|
||||||
.service.selectionService.currentSelectedNodes.value
|
|
||||||
.whereType<TextNode>();
|
.whereType<TextNode>();
|
||||||
final selection = _editorState.service.selectionService.currentSelection;
|
final selection =
|
||||||
|
_editorState.service.selectionService.currentSelection.value;
|
||||||
// FIXME: upward and selection update.
|
// FIXME: upward and selection update.
|
||||||
if (textNodes.isNotEmpty && selection != null) {
|
if (textNodes.isNotEmpty && selection != null) {
|
||||||
final text = textNodes.fold<String>(
|
final text = textNodes.fold<String>(
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ FlowyKeyEventHandler deleteTextHandler = (editorState, event) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
// make sure all nodes is [TextNode].
|
// make sure all nodes is [TextNode].
|
||||||
final textNodes = nodes.whereType<TextNode>().toList();
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
if (textNodes.length != nodes.length) {
|
if (textNodes.length != nodes.length) {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ FlowyKeyEventHandler enterInEdgeOfTextNodeHandler = (editorState, event) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
if (selection == null ||
|
if (selection == null ||
|
||||||
nodes.length != 1 ||
|
nodes.length != 1 ||
|
||||||
nodes.first is! TextNode ||
|
nodes.first is! TextNode ||
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,13 @@ FlowyKeyEventHandler slashShortcutHandler = (editorState, event) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final textNodes = editorState
|
final textNodes = editorState.service.selectionService.currentSelectedNodes
|
||||||
.service.selectionService.currentSelectedNodes.value
|
|
||||||
.whereType<TextNode>();
|
.whereType<TextNode>();
|
||||||
if (textNodes.length != 1) {
|
if (textNodes.length != 1) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
final textNode = textNodes.first;
|
final textNode = textNodes.first;
|
||||||
final context = textNode.context;
|
final context = textNode.context;
|
||||||
final selectable = textNode.selectable;
|
final selectable = textNode.selectable;
|
||||||
|
|
@ -97,9 +96,9 @@ FlowyKeyEventHandler slashShortcutHandler = (editorState, event) {
|
||||||
|
|
||||||
Overlay.of(context)?.insert(_popupListOverlay!);
|
Overlay.of(context)?.insert(_popupListOverlay!);
|
||||||
|
|
||||||
editorState.service.selectionService.currentSelectedNodes
|
editorState.service.selectionService.currentSelection
|
||||||
.removeListener(clearPopupListOverlay);
|
.removeListener(clearPopupListOverlay);
|
||||||
editorState.service.selectionService.currentSelectedNodes
|
editorState.service.selectionService.currentSelection
|
||||||
.addListener(clearPopupListOverlay);
|
.addListener(clearPopupListOverlay);
|
||||||
// editorState.service.keyboardService?.disable();
|
// editorState.service.keyboardService?.disable();
|
||||||
_editorState = editorState;
|
_editorState = editorState;
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ FlowyKeyEventHandler updateTextStyleByCommandXHandler = (editorState, event) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
final selection = editorState.service.selectionService.currentSelection;
|
final selection = editorState.service.selectionService.currentSelection.value;
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes.value;
|
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
final textNodes = nodes.whereType<TextNode>().toList(growable: false);
|
final textNodes = nodes.whereType<TextNode>().toList(growable: false);
|
||||||
|
|
||||||
if (selection == null || textNodes.isEmpty) {
|
if (selection == null || textNodes.isEmpty) {
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,26 @@ import 'package:flowy_editor/render/selection/selection_widget.dart';
|
||||||
|
|
||||||
/// Process selection and cursor
|
/// Process selection and cursor
|
||||||
mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
|
mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
|
||||||
/// Returns the currently selected [Node]s.
|
/// Returns the current [Selection]
|
||||||
|
ValueNotifier<Selection?> get currentSelection;
|
||||||
|
|
||||||
|
/// Returns the current selected [Node]s.
|
||||||
///
|
///
|
||||||
/// The order of the return is determined according to the selected order.
|
/// The order of the return is determined according to the selected order.
|
||||||
ValueNotifier<List<Node>> get currentSelectedNodes;
|
List<Node> get currentSelectedNodes;
|
||||||
Selection? get currentSelection;
|
|
||||||
|
|
||||||
/// ------------------ Selection ------------------------
|
|
||||||
|
|
||||||
|
/// Update the selection or cursor.
|
||||||
///
|
///
|
||||||
|
/// If selection is collapsed, this method will
|
||||||
|
/// update the position of the cursor.
|
||||||
|
/// Otherwise, will update the selection.
|
||||||
void updateSelection(Selection selection);
|
void updateSelection(Selection selection);
|
||||||
|
|
||||||
///
|
/// Clear the selection or cursor.
|
||||||
void clearSelection();
|
void clearSelection();
|
||||||
|
|
||||||
|
/// ------------------ Selection ------------------------
|
||||||
|
|
||||||
List<Rect> rects();
|
List<Rect> rects();
|
||||||
|
|
||||||
Position? hitTest(Offset? offset);
|
Position? hitTest(Offset? offset);
|
||||||
|
|
@ -124,10 +130,10 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||||
EditorState get editorState => widget.editorState;
|
EditorState get editorState => widget.editorState;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Selection? currentSelection;
|
ValueNotifier<Selection?> currentSelection = ValueNotifier(null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValueNotifier<List<Node>> currentSelectedNodes = ValueNotifier([]);
|
List<Node> currentSelectedNodes = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Node> getNodesInSelection(Selection selection) =>
|
List<Node> getNodesInSelection(Selection selection) =>
|
||||||
|
|
@ -145,8 +151,8 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||||
super.didChangeMetrics();
|
super.didChangeMetrics();
|
||||||
|
|
||||||
// Need to refresh the selection when the metrics changed.
|
// Need to refresh the selection when the metrics changed.
|
||||||
if (currentSelection != null) {
|
if (currentSelection.value != null) {
|
||||||
updateSelection(currentSelection!);
|
updateSelection(currentSelection.value!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,8 +198,8 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void clearSelection() {
|
void clearSelection() {
|
||||||
currentSelection = null;
|
currentSelectedNodes = [];
|
||||||
currentSelectedNodes.value = [];
|
currentSelection.value = null;
|
||||||
|
|
||||||
// clear selection
|
// clear selection
|
||||||
_selectionOverlays
|
_selectionOverlays
|
||||||
|
|
@ -399,8 +405,8 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||||
void _updateSelection(Selection selection) {
|
void _updateSelection(Selection selection) {
|
||||||
final nodes = _selectedNodesInSelection(editorState.document, selection);
|
final nodes = _selectedNodesInSelection(editorState.document, selection);
|
||||||
|
|
||||||
currentSelection = selection;
|
currentSelectedNodes = nodes;
|
||||||
currentSelectedNodes.value = nodes;
|
currentSelection.value = selection;
|
||||||
|
|
||||||
Rect? topmostRect;
|
Rect? topmostRect;
|
||||||
LayerLink? layerLink;
|
LayerLink? layerLink;
|
||||||
|
|
@ -480,8 +486,8 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSelection = Selection.collapsed(position);
|
currentSelectedNodes = [node];
|
||||||
currentSelectedNodes.value = [node];
|
currentSelection.value = Selection.collapsed(position);
|
||||||
|
|
||||||
final selectable = node.selectable;
|
final selectable = node.selectable;
|
||||||
final rect = selectable?.getCursorRectInPosition(position);
|
final rect = selectable?.getCursorRectInPosition(position);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue