Merge pull request #157 from singerdmx/ignoreFocus

Pass getTextPosition instead of passing the tap text position to be more flexible; optional ignoreFocus on replaceText
pull/205/head
hyouuu 4 years ago committed by GitHub
commit 0b33c9512c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      lib/widgets/controller.dart
  2. 34
      lib/widgets/editor.dart
  3. 29
      lib/widgets/raw_editor.dart
  4. 73
      lib/widgets/toolbar.dart

@ -11,7 +11,7 @@ import '../models/quill_delta.dart';
import '../utils/diff_delta.dart';
class QuillController extends ChangeNotifier {
QuillController({required this.document, required this.selection});
QuillController({required this.document, required this.selection, this.iconSize = 18, this.toolbarHeightFactor = 2});
factory QuillController.basic() {
return QuillController(
@ -22,7 +22,11 @@ class QuillController extends ChangeNotifier {
final Document document;
TextSelection selection;
double iconSize;
double toolbarHeightFactor;
Style toggledStyle = Style();
bool ignoreFocusOnTextChange = false;
// item1: Document state before [change].
//
@ -76,7 +80,7 @@ class QuillController extends ChangeNotifier {
bool get hasRedo => document.hasRedo;
void replaceText(
int index, int len, Object? data, TextSelection? textSelection) {
int index, int len, Object? data, TextSelection? textSelection, {bool ignoreFocus = false}) {
assert(data is String || data is Embeddable);
Delta? delta;
@ -124,7 +128,12 @@ class QuillController extends ChangeNotifier {
);
}
}
if (ignoreFocus) {
ignoreFocusOnTextChange = true;
}
notifyListeners();
ignoreFocusOnTextChange = false;
}
void formatText(int index, int len, Attribute? attribute) {

@ -176,20 +176,19 @@ class QuillEditor extends StatefulWidget {
final ScrollPhysics? scrollPhysics;
final ValueChanged<String>? onLaunchUrl;
// Returns whether gesture is handled
final bool Function(TapDownDetails details, TextPosition textPosition)?
onTapDown;
final bool Function(TapDownDetails details, TextPosition Function(Offset offset))? onTapDown;
// Returns whether gesture is handled
final bool Function(TapUpDetails details, TextPosition textPosition)? onTapUp;
final bool Function(TapUpDetails details, TextPosition Function(Offset offset))? onTapUp;
// Returns whether gesture is handled
final bool Function(LongPressStartDetails details, TextPosition textPosition)?
onSingleLongTapStart;
final bool Function(LongPressStartDetails details, TextPosition Function(Offset offset))? onSingleLongTapStart;
// Returns whether gesture is handled
final bool Function(
LongPressMoveUpdateDetails details, TextPosition textPosition)?
onSingleLongTapMoveUpdate;
final bool Function(LongPressMoveUpdateDetails details, TextPosition Function(Offset offset))? onSingleLongTapMoveUpdate;
// Returns whether gesture is handled
final bool Function(LongPressEndDetails details, TextPosition textPosition)?
onSingleLongTapEnd;
final bool Function(LongPressEndDetails details, TextPosition Function(Offset offset))? onSingleLongTapEnd;
final EmbedBuilder embedBuilder;
@override
@ -340,8 +339,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.onSingleLongTapMoveUpdate != null) {
final renderEditor = getRenderEditor();
if (renderEditor != null) {
if (_state.widget.onSingleLongTapMoveUpdate!(details,
renderEditor.getPositionForOffset(details.globalPosition))) {
if (_state.widget.onSingleLongTapMoveUpdate!(details, renderEditor.getPositionForOffset)) {
return;
}
}
@ -470,8 +468,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.onTapDown != null) {
final renderEditor = getRenderEditor();
if (renderEditor != null) {
if (_state.widget.onTapDown!(details,
renderEditor.getPositionForOffset(details.globalPosition))) {
if (_state.widget.onTapDown!(details, renderEditor.getPositionForOffset)) {
return;
}
}
@ -484,8 +481,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.onTapUp != null) {
final renderEditor = getRenderEditor();
if (renderEditor != null) {
if (_state.widget.onTapUp!(details,
renderEditor.getPositionForOffset(details.globalPosition))) {
if (_state.widget.onTapUp!(details, renderEditor.getPositionForOffset)) {
return;
}
}
@ -527,8 +523,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.onSingleLongTapStart != null) {
final renderEditor = getRenderEditor();
if (renderEditor != null) {
if (_state.widget.onSingleLongTapStart!(details,
renderEditor.getPositionForOffset(details.globalPosition))) {
if (_state.widget.onSingleLongTapStart!(details, renderEditor.getPositionForOffset)) {
return;
}
}
@ -562,8 +557,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
if (_state.widget.onSingleLongTapEnd != null) {
final renderEditor = getRenderEditor();
if (renderEditor != null) {
if (_state.widget.onSingleLongTapEnd!(details,
renderEditor.getPositionForOffset(details.globalPosition))) {
if (_state.widget.onSingleLongTapEnd!(details, renderEditor.getPositionForOffset)) {
return;
}
}

@ -675,7 +675,9 @@ class RawEditorState extends EditorState
_clipboardStatus?.addListener(_onChangedClipboardStatus);
widget.controller.addListener(_didChangeTextEditingValue);
widget.controller.addListener(() {
_didChangeTextEditingValue(widget.controller.ignoreFocusOnTextChange);
});
_scrollController = widget.scrollController;
_scrollController!.addListener(_updateSelectionOverlayForScroll);
@ -883,15 +885,17 @@ class RawEditorState extends EditorState
_selectionOverlay?.markNeedsBuild();
}
void _didChangeTextEditingValue() {
void _didChangeTextEditingValue([bool ignoreFocus = false]) {
if (kIsWeb) {
_onChangeTextEditingValue();
requestKeyboard();
_onChangeTextEditingValue(ignoreFocus);
if (!ignoreFocus) {
requestKeyboard();
}
return;
}
if (_keyboardVisible) {
_onChangeTextEditingValue();
if (ignoreFocus || _keyboardVisible) {
_onChangeTextEditingValue(ignoreFocus);
} else {
requestKeyboard();
if (mounted) {
@ -903,19 +907,20 @@ class RawEditorState extends EditorState
}
}
void _onChangeTextEditingValue() {
_showCaretOnScreen();
void _onChangeTextEditingValue([bool ignoreCaret = false]) {
updateRemoteValueIfNeeded();
_cursorCont.startOrStopCursorTimerIfNeeded(
_hasFocus, widget.controller.selection);
if (ignoreCaret) {
return;
}
_showCaretOnScreen();
_cursorCont.startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
if (hasConnection) {
_cursorCont
..stopCursorTimer(resetCharTicks: false)
..startCursorTimer();
}
SchedulerBinding.instance!.addPostFrameCallback(
(_) => _updateOrDisposeSelectionOverlayIfNeeded());
SchedulerBinding.instance!.addPostFrameCallback((_) => _updateOrDisposeSelectionOverlayIfNeeded());
if (mounted) {
setState(() {
// Use widget.controller.value in build()

@ -14,9 +14,6 @@ import '../models/documents/style.dart';
import '../utils/color.dart';
import 'controller.dart';
double iconSize = 18;
double kToolbarHeight = iconSize * 2;
typedef OnImagePickCallback = Future<String> Function(File file);
typedef ImagePickImpl = Future<String?> Function(ImageSource source);
@ -37,10 +34,10 @@ class InsertEmbedButton extends StatelessWidget {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
size: controller.iconSize * 1.77,
icon: Icon(
icon,
size: iconSize,
size: controller.iconSize,
color: Theme.of(context).iconTheme.color,
),
fillColor: fillColor ?? Theme.of(context).canvasColor,
@ -101,10 +98,10 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
size: widget.controller.iconSize * 1.77,
icon: Icon(
widget.icon ?? Icons.link,
size: iconSize,
size: widget.controller.iconSize,
color: isEnabled ? theme.iconTheme.color : theme.disabledColor,
),
fillColor: Theme.of(context).canvasColor,
@ -372,8 +369,8 @@ Widget defaultToggleStyleButtonBuilder(
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
icon: Icon(icon, size: iconSize, color: iconColor),
size: 18 * 1.77,
icon: Icon(icon, size: 18, color: iconColor),
fillColor: fill,
onPressed: onPressed,
);
@ -435,12 +432,12 @@ class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> {
@override
Widget build(BuildContext context) {
return _selectHeadingStyleButtonBuilder(context, _value, _selectAttribute);
return _selectHeadingStyleButtonBuilder(context, _value, _selectAttribute, widget.controller.iconSize);
}
}
Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value,
ValueChanged<Attribute?> onSelected) {
ValueChanged<Attribute?> onSelected, double iconSize) {
final _valueToText = <Attribute, String>{
Attribute.header: 'N',
Attribute.h1: 'H1',
@ -532,12 +529,12 @@ class _ImageButtonState extends State<ImageButton> {
return QuillIconButton(
icon: Icon(
widget.icon,
size: iconSize,
size: widget.controller.iconSize,
color: theme.iconTheme.color,
),
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
size: widget.controller.iconSize * 1.77,
fillColor: theme.canvasColor,
onPressed: _handleImageButtonTap,
);
@ -708,9 +705,9 @@ class _ColorButtonState extends State<ColorButton> {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
size: widget.controller.iconSize * 1.77,
icon: Icon(widget.icon,
size: iconSize,
size: widget.controller.iconSize,
color: widget.background ? iconColorBackground : iconColor),
fillColor: widget.background ? fillColorBackground : fillColor,
onPressed: _showColorPicker,
@ -776,8 +773,8 @@ class _HistoryButtonState extends State<HistoryButton> {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
icon: Icon(widget.icon, size: iconSize, color: _iconColor),
size: widget.controller.iconSize * 1.77,
icon: Icon(widget.icon, size: widget.controller.iconSize, color: _iconColor),
fillColor: fillColor,
onPressed: _changeHistory,
);
@ -841,8 +838,8 @@ class _IndentButtonState extends State<IndentButton> {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
icon: Icon(widget.icon, size: iconSize, color: iconColor),
size: widget.controller.iconSize * 1.77,
icon: Icon(widget.icon, size: widget.controller.iconSize, color: iconColor),
fillColor: fillColor,
onPressed: () {
final indent = widget.controller
@ -895,8 +892,8 @@ class _ClearFormatButtonState extends State<ClearFormatButton> {
return QuillIconButton(
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
icon: Icon(widget.icon, size: iconSize, color: iconColor),
size: widget.controller.iconSize * 1.77,
icon: Icon(widget.icon, size: widget.controller.iconSize, color: iconColor),
fillColor: fillColor,
onPressed: () {
for (final k
@ -908,7 +905,7 @@ class _ClearFormatButtonState extends State<ClearFormatButton> {
}
class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
const QuillToolbar({required this.children, Key? key}) : super(key: key);
const QuillToolbar({required this.children, this.toolBarHeight = 36, Key? key}) : super(key: key);
factory QuillToolbar.basic({
required QuillController controller,
@ -933,8 +930,9 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
OnImagePickCallback? onImagePickCallback,
Key? key,
}) {
iconSize = toolbarIconSize;
return QuillToolbar(key: key, children: [
controller.iconSize = toolbarIconSize;
return QuillToolbar(key: key, toolBarHeight: toolbarIconSize * controller.toolbarHeightFactor, children: [
Visibility(
visible: showHistory,
child: HistoryButton(
@ -1034,12 +1032,8 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
),
),
Visibility(
visible: showHeaderStyle,
child: VerticalDivider(
indent: 12, endIndent: 12, color: Colors.grey.shade400)),
Visibility(
visible: showHeaderStyle,
child: SelectHeaderStyleButton(controller: controller)),
visible: showHeaderStyle, child: VerticalDivider(indent: 12, endIndent: 12, color: Colors.grey.shade400)),
Visibility(visible: showHeaderStyle, child: SelectHeaderStyleButton(controller: controller)),
VerticalDivider(indent: 12, endIndent: 12, color: Colors.grey.shade400),
Visibility(
visible: showListNumbers,
@ -1074,12 +1068,8 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
),
),
Visibility(
visible: !showListNumbers &&
!showListBullets &&
!showListCheck &&
!showCodeBlock,
child: VerticalDivider(
indent: 12, endIndent: 12, color: Colors.grey.shade400)),
visible: !showListNumbers && !showListBullets && !showListCheck && !showCodeBlock,
child: VerticalDivider(indent: 12, endIndent: 12, color: Colors.grey.shade400)),
Visibility(
visible: showQuote,
child: ToggleStyleButton(
@ -1104,12 +1094,8 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
isIncrease: false,
),
),
Visibility(
visible: showQuote,
child: VerticalDivider(
indent: 12, endIndent: 12, color: Colors.grey.shade400)),
Visibility(
visible: showLink, child: LinkStyleButton(controller: controller)),
Visibility(visible: showQuote, child: VerticalDivider(indent: 12, endIndent: 12, color: Colors.grey.shade400)),
Visibility(visible: showLink, child: LinkStyleButton(controller: controller)),
Visibility(
visible: showHorizontalRule,
child: InsertEmbedButton(
@ -1121,12 +1107,13 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
}
final List<Widget> children;
final double toolBarHeight;
@override
_QuillToolbarState createState() => _QuillToolbarState();
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
Size get preferredSize => Size.fromHeight(toolBarHeight);
}
class _QuillToolbarState extends State<QuillToolbar> {

Loading…
Cancel
Save