|
|
|
@ -1,9 +1,10 @@ |
|
|
|
|
import 'dart:math' as math; |
|
|
|
|
|
|
|
|
|
import 'package:flutter/services.dart'; |
|
|
|
|
import 'package:flutter/services.dart' show ClipboardData, Clipboard; |
|
|
|
|
import 'package:flutter/widgets.dart'; |
|
|
|
|
import 'package:html2md/html2md.dart' as html2md; |
|
|
|
|
import 'package:markdown/markdown.dart' as md; |
|
|
|
|
import 'package:meta/meta.dart'; |
|
|
|
|
|
|
|
|
|
import '../../../markdown_quill.dart'; |
|
|
|
|
import '../../../quill_delta.dart'; |
|
|
|
@ -16,6 +17,7 @@ import '../../models/structs/doc_change.dart'; |
|
|
|
|
import '../../models/structs/image_url.dart'; |
|
|
|
|
import '../../models/structs/offset_value.dart'; |
|
|
|
|
import '../../utils/delta.dart'; |
|
|
|
|
import '../toolbar/buttons/toggle_style_button.dart'; |
|
|
|
|
|
|
|
|
|
typedef ReplaceTextCallback = bool Function(int index, int len, Object? data); |
|
|
|
|
typedef DeleteCallback = void Function(int cursorPosition, bool forward); |
|
|
|
@ -24,14 +26,13 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
QuillController({ |
|
|
|
|
required Document document, |
|
|
|
|
required TextSelection selection, |
|
|
|
|
bool keepStyleOnNewLine = false, |
|
|
|
|
this.keepStyleOnNewLine = true, |
|
|
|
|
this.onReplaceText, |
|
|
|
|
this.onDelete, |
|
|
|
|
this.onSelectionCompleted, |
|
|
|
|
this.onSelectionChanged, |
|
|
|
|
}) : _document = document, |
|
|
|
|
_selection = selection, |
|
|
|
|
_keepStyleOnNewLine = keepStyleOnNewLine; |
|
|
|
|
_selection = selection; |
|
|
|
|
|
|
|
|
|
factory QuillController.basic() { |
|
|
|
|
return QuillController( |
|
|
|
@ -54,6 +55,7 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
notifyListeners(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@experimental |
|
|
|
|
void setContents( |
|
|
|
|
Delta delta, { |
|
|
|
|
ChangeSource changeSource = ChangeSource.local, |
|
|
|
@ -68,6 +70,9 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
notifyListeners(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Thoses are the values that the user selects and not the one |
|
|
|
|
// from the current line |
|
|
|
|
|
|
|
|
|
/// The current font family, null to use the default one |
|
|
|
|
String? _selectedFontFamily; |
|
|
|
|
|
|
|
|
@ -88,9 +93,20 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
_selectedFontSize = newFontSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// For the [QuillToolbarToggleStyleButton] |
|
|
|
|
final Map<Attribute, bool?> _selectedStyles = {}; |
|
|
|
|
|
|
|
|
|
/// For the [QuillToolbarToggleStyleButton] |
|
|
|
|
Map<Attribute, bool?> get selectedStyles => _selectedStyles; |
|
|
|
|
|
|
|
|
|
/// For the [QuillToolbarToggleStyleButton] |
|
|
|
|
void selectStyle(Attribute attribute, bool value) { |
|
|
|
|
_selectedStyles[attribute] = value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Tells whether to keep or reset the [toggledStyle] |
|
|
|
|
/// when user adds a new line. |
|
|
|
|
final bool _keepStyleOnNewLine; |
|
|
|
|
final bool keepStyleOnNewLine; |
|
|
|
|
|
|
|
|
|
/// Currently selected text within the [document]. |
|
|
|
|
TextSelection get selection => _selection; |
|
|
|
@ -269,6 +285,7 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
Object? data, |
|
|
|
|
TextSelection? textSelection, { |
|
|
|
|
bool ignoreFocus = false, |
|
|
|
|
bool shouldNotifyListeners = true, |
|
|
|
|
}) { |
|
|
|
|
assert(data is String || data is Embeddable); |
|
|
|
|
|
|
|
|
@ -324,7 +341,9 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
if (ignoreFocus) { |
|
|
|
|
ignoreFocusOnTextChange = true; |
|
|
|
|
} |
|
|
|
|
if (shouldNotifyListeners) { |
|
|
|
|
notifyListeners(); |
|
|
|
|
} |
|
|
|
|
ignoreFocusOnTextChange = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -342,7 +361,12 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void formatText(int index, int len, Attribute? attribute) { |
|
|
|
|
void formatText( |
|
|
|
|
int index, |
|
|
|
|
int len, |
|
|
|
|
Attribute? attribute, { |
|
|
|
|
bool shouldNotifyListeners = true, |
|
|
|
|
}) { |
|
|
|
|
if (len == 0 && |
|
|
|
|
attribute!.isInline && |
|
|
|
|
attribute.key != Attribute.link.key) { |
|
|
|
@ -361,11 +385,19 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
if (selection != adjustedSelection) { |
|
|
|
|
_updateSelection(adjustedSelection, ChangeSource.local); |
|
|
|
|
} |
|
|
|
|
if (shouldNotifyListeners) { |
|
|
|
|
notifyListeners(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void formatSelection(Attribute? attribute) { |
|
|
|
|
formatText(selection.start, selection.end - selection.start, attribute); |
|
|
|
|
void formatSelection(Attribute? attribute, |
|
|
|
|
{bool shouldNotifyListeners = true}) { |
|
|
|
|
formatText( |
|
|
|
|
selection.start, |
|
|
|
|
selection.end - selection.start, |
|
|
|
|
attribute, |
|
|
|
|
shouldNotifyListeners: shouldNotifyListeners, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void moveCursorToStart() { |
|
|
|
@ -447,7 +479,7 @@ class QuillController extends ChangeNotifier { |
|
|
|
|
_selection = selection.copyWith( |
|
|
|
|
baseOffset: math.min(selection.baseOffset, end), |
|
|
|
|
extentOffset: math.min(selection.extentOffset, end)); |
|
|
|
|
if (_keepStyleOnNewLine) { |
|
|
|
|
if (keepStyleOnNewLine) { |
|
|
|
|
final style = getSelectionStyle(); |
|
|
|
|
final ignoredStyles = style.attributes.values.where( |
|
|
|
|
(s) => !s.isInline || s.key == Attribute.link.key, |
|
|
|
|