copy/cut select image and text together.

pull/1307/head
hehong 2 years ago
parent ffbb17c776
commit 954d5b9444
  1. 6
      lib/src/models/documents/document.dart
  2. 38
      lib/src/models/documents/nodes/line.dart
  3. 6
      lib/src/widgets/controller.dart
  4. 2
      lib/src/widgets/editor.dart
  5. 8
      lib/src/widgets/raw_editor.dart
  6. 32
      lib/src/widgets/raw_editor/raw_editor_state_selection_delegate_mixin.dart

@ -165,6 +165,12 @@ class Document {
return (res.node as Line).collectAllIndividualStyles(res.offset, len); return (res.node as Line).collectAllIndividualStyles(res.offset, len);
} }
List<OffsetValue> collectAllIndividualStyleAndEmbed(int index, int len) {
final res = queryChild(index);
return (res.node as Line)
.collectAllIndividualStylesAndEmbed(res.offset, len);
}
/// Returns all styles for any character within the specified text range. /// Returns all styles for any character within the specified text range.
List<Style> collectAllStyles(int index, int len) { List<Style> collectAllStyles(int index, int len) {
final res = queryChild(index); final res = queryChild(index);

@ -430,6 +430,44 @@ class Line extends Container<Leaf?> {
return result; return result;
} }
List<OffsetValue> collectAllIndividualStylesAndEmbed(int offset, int len,
{int beg = 0}) {
final local = math.min(length - offset, len);
final result = <OffsetValue>[];
final data = queryChild(offset, true);
var node = data.node as Leaf?;
if (node != null) {
var pos = 0;
if (node is Text) {
pos = node.length - data.offset;
result.add(OffsetValue(beg, node.style));
} else if (node.value is Embeddable) {
pos = node.length - data.offset;
result.add(OffsetValue(beg, node.value as Embeddable));
}
while (!node!.isLast && pos < local) {
node = node.next as Leaf;
if (node is Text) {
result.add(OffsetValue(pos + beg, node.style));
pos += node.length;
} else if (node.value is Embeddable) {
result.add(OffsetValue(pos + beg, node.value as Embeddable));
pos += node.length;
}
}
}
final remaining = len - local;
if (remaining > 0 && nextLine != null) {
final rest =
nextLine!.collectAllIndividualStylesAndEmbed(0, remaining, beg: local);
result.addAll(rest);
}
return result;
}
/// Returns all styles for any character within the specified text range. /// Returns all styles for any character within the specified text range.
/// In essence, it is UNION of each individual segment's styles /// In essence, it is UNION of each individual segment's styles
List<Style> collectAllStyles(int offset, int len) { List<Style> collectAllStyles(int offset, int len) {

@ -166,6 +166,12 @@ class QuillController extends ChangeNotifier {
return styles; return styles;
} }
List<OffsetValue> getAllIndividualSelectionStylesAndEmbed() {
final stylesAndEmbed = document.collectAllIndividualStyleAndEmbed(
selection.start, selection.end - selection.start);
return stylesAndEmbed;
}
/// Returns plain text for each node within selection /// Returns plain text for each node within selection
String getPlainText() { String getPlainText() {
final text = final text =

@ -38,7 +38,7 @@ abstract class EditorState extends State<RawEditor>
EditorTextSelectionOverlay? get selectionOverlay; EditorTextSelectionOverlay? get selectionOverlay;
List<OffsetValue<Style>> get pasteStyle; List<OffsetValue> get pasteStyleAndEmbed;
String get pastePlainText; String get pastePlainText;

@ -318,8 +318,8 @@ class RawEditorState extends EditorState
// for pasting style // for pasting style
@override @override
List<OffsetValue<Style>> get pasteStyle => _pasteStyle; List<OffsetValue> get pasteStyleAndEmbed => _pasteStyleAndEmbed;
List<OffsetValue<Style>> _pasteStyle = <OffsetValue<Style>>[]; List<OffsetValue> _pasteStyleAndEmbed = <OffsetValue>[];
@override @override
String get pastePlainText => _pastePlainText; String get pastePlainText => _pastePlainText;
@ -1435,7 +1435,7 @@ class RawEditorState extends EditorState
void copySelection(SelectionChangedCause cause) { void copySelection(SelectionChangedCause cause) {
controller.copiedImageUrl = null; controller.copiedImageUrl = null;
_pastePlainText = controller.getPlainText(); _pastePlainText = controller.getPlainText();
_pasteStyle = controller.getAllIndividualSelectionStyles(); _pasteStyleAndEmbed = controller.getAllIndividualSelectionStylesAndEmbed();
final selection = textEditingValue.selection; final selection = textEditingValue.selection;
final text = textEditingValue.text; final text = textEditingValue.text;
@ -1464,7 +1464,7 @@ class RawEditorState extends EditorState
void cutSelection(SelectionChangedCause cause) { void cutSelection(SelectionChangedCause cause) {
controller.copiedImageUrl = null; controller.copiedImageUrl = null;
_pastePlainText = controller.getPlainText(); _pastePlainText = controller.getPlainText();
_pasteStyle = controller.getAllIndividualSelectionStyles(); _pasteStyleAndEmbed = controller.getAllIndividualSelectionStylesAndEmbed();
if (widget.readOnly) { if (widget.readOnly) {
return; return;

@ -3,6 +3,7 @@ import 'dart:math' as math;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import '../../../flutter_quill.dart';
import '../../models/documents/document.dart'; import '../../models/documents/document.dart';
import '../../models/documents/nodes/leaf.dart'; import '../../models/documents/nodes/leaf.dart';
import '../../utils/delta.dart'; import '../../utils/delta.dart';
@ -10,6 +11,9 @@ import '../editor.dart';
mixin RawEditorStateSelectionDelegateMixin on EditorState mixin RawEditorStateSelectionDelegateMixin on EditorState
implements TextSelectionDelegate { implements TextSelectionDelegate {
bool isContainEmbed = false;
@override @override
TextEditingValue get textEditingValue { TextEditingValue get textEditingValue {
return widget.controller.plainTextEditingValue; return widget.controller.plainTextEditingValue;
@ -26,6 +30,7 @@ mixin RawEditorStateSelectionDelegateMixin on EditorState
return; return;
} }
isContainEmbed = false;
final insertedText = _adjustInsertedText(diff.inserted); final insertedText = _adjustInsertedText(diff.inserted);
widget.controller.replaceText( widget.controller.replaceText(
@ -37,15 +42,29 @@ mixin RawEditorStateSelectionDelegateMixin on EditorState
void _applyPasteStyle(String insertedText, int start) { void _applyPasteStyle(String insertedText, int start) {
if (insertedText == pastePlainText && pastePlainText != '') { if (insertedText == pastePlainText && pastePlainText != '') {
final pos = start; final pos = start;
for (var i = 0; i < pasteStyle.length; i++) { for (var i = 0; i < pasteStyleAndEmbed.length; i++) {
final offset = pasteStyle[i].offset; final offset = pasteStyleAndEmbed[i].offset;
final style = pasteStyle[i].value; final styleAndEmbed = pasteStyleAndEmbed[i].value;
if (styleAndEmbed is Embeddable) {
widget.controller.replaceText(pos + offset, 0, styleAndEmbed, null);
} else {
widget.controller.formatTextStyle( widget.controller.formatTextStyle(
pos + offset, pos + offset,
i == pasteStyle.length - 1 i == pasteStyleAndEmbed.length - 1
? pastePlainText.length - offset ? pastePlainText.length - offset
: pasteStyle[i + 1].offset, : pasteStyleAndEmbed[i + 1].offset,
style); styleAndEmbed);
}
}
}else if(isContainEmbed){
final pos = start;
for (var i = 0; i < pasteStyleAndEmbed.length; i++) {
final offset = pasteStyleAndEmbed[i].offset;
final style = pasteStyleAndEmbed[i].value;
if (style is Embeddable) {
widget.controller.replaceText(pos + offset, 0, style, null);
}
} }
} }
} }
@ -61,6 +80,7 @@ mixin RawEditorStateSelectionDelegateMixin on EditorState
final sb = StringBuffer(); final sb = StringBuffer();
for (var i = 0; i < text.length; i++) { for (var i = 0; i < text.length; i++) {
if (text.codeUnitAt(i) == Embed.kObjectReplacementInt) { if (text.codeUnitAt(i) == Embed.kObjectReplacementInt) {
isContainEmbed = true;
continue; continue;
} }
sb.write(text[i]); sb.write(text[i]);

Loading…
Cancel
Save