Rich text editor for Flutter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
4.1 KiB

Merge master into dev (#258) * Update issue templates * Updating checkbox to handle tap (#186) * updating checkbox to handle tap * updating checkbox to handle long press and using UniqueKey() to avoid weird side effects * removed useless doc Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com> * Simple viewer (#187) * 2021-04-25 * 2021-04-26 * Fix simple viewer compilation error * Upgrade version - checkbox supports tapping * 171: support for non-scrollable text editor (#188) Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com> * custom rules & optionally auto add newline for image embeds (#205) * Adding missing overrides to make package work with Flutter 2.2.0 (#226) * Improve SOC of raw editor (#227) Improve separation of concerns for RawEditor by moving the code for the text input client to a separate class, furthermore add more comments. * Upgrade version * Improve SOC of raw editor (#228) Improve separation of concerns for `RawEditor` by moving the code for the keyboard to a separate class, furthermore add more comments. The PR does not change the functionality of the code. * Improve further SOC of raw editor This improves separation of concerns for the RawEditor by moving the code for the text selection delegate to a separate class, furthermore add more comments. The PR does not change the functionality of the code. * Hide implementation files (#233) * Fixes for flutter web (#234) * Fix for Attribute object comparison * Fix for "Unexpected null value" error on web Clipboard is now supported on web, via a permission request through the browser Co-authored-by: George Johnson <george@indiespring.com> * Dispose ValueNotifier of cursor controller * Remove getter for final operator A getter for a final variable makes no sense, because the variable cannot be reassigned. It is better to remove the unnecessary getter and make the variable public. * Add comments to cursor class * Remove null exception when a disposed controller is set * Disallow lines longer than 80 characters * Don't create a lambda when a tear-off will do * Move ResponsiveWidgets to example folder This widget has nothing to do with the library and is only used in the example, so it is moved to the example. * Fix null exception * Remove exception when widget is not mounted * Fix exception when rect is not a number * Fix paste (#236) closes #235. * Fix exception * Add const types for image and divider embeds This allows to reference the type. * Fix relative path * Add new logo * Fix buttons which ignore toolbariconsize Closes #189. * Upgrade to 1.3.1 * Fix incorrect double to int cast, and guard against optional parent (#239) * use ceil instead of floor to make sure won't cause overflow * Fix example project Podfile (#241) * Show arrow indicator on toolbar (#245) * Add color parameter to Toolbar and ImageButton In addition, change these widgets to stateless widgets, since these widgets do not have a state and thus stateful is superfluous. * Fix paste bug * Remove extraneous toolbar dividers in certain configuration Closes #193. * Upgrade version to 1.3.2 * Format code * Bump file_picker to 3.0.2+2 With version 3.0.2 `name` of the file_picker library becomes non-nullable, so a warning was issued for users who had already used version 3.0.2, as we still assumed that `name` is nullable. Increasing the version and removing the exclamation mark removes the warning. * Fix a bug that Embed could be together with Text (#249) * Fix #242 (#254) * Upgrade to 1.3.3 * Format code * bugfix:The return type 'bool' isn't a 'KeyEventResult' Co-authored-by: Xin Yao <singerdmx@gmail.com> Co-authored-by: kevinDespoulains <46108869+kevinDespoulains@users.noreply.github.com> Co-authored-by: Kevin Despoulains <kevin.despoulains@scriptandgo.com> Co-authored-by: em6m6e <50019687+em6m6e@users.noreply.github.com> Co-authored-by: Gyuri Majercsik <majercsik.gyuri@gmail.com> Co-authored-by: Gyuri Majercsik <gyuri@fluttech.com> Co-authored-by: hyouuu <hyouuu@gmail.com> Co-authored-by: Till Friebe <friebetill@gmail.com> Co-authored-by: George <george.a.johnson@btopenworld.com> Co-authored-by: George Johnson <george@indiespring.com> Co-authored-by: Ben Chung <1330575+yzxben@users.noreply.github.com> Co-authored-by: lucasbstn <64323294+lucasbstn@users.noreply.github.com>
4 years ago
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import '../models/documents/nodes/leaf.dart';
import 'editor.dart';
import 'text_selection.dart';
typedef EmbedBuilder = Widget Function(BuildContext context, Embed node);
abstract class EditorTextSelectionGestureDetectorBuilderDelegate {
GlobalKey<EditorState> getEditableTextKey();
bool getForcePressEnabled();
bool getSelectionEnabled();
}
class EditorTextSelectionGestureDetectorBuilder {
EditorTextSelectionGestureDetectorBuilder(this.delegate);
final EditorTextSelectionGestureDetectorBuilderDelegate delegate;
bool shouldShowSelectionToolbar = true;
EditorState? getEditor() {
return delegate.getEditableTextKey().currentState;
}
RenderEditor? getRenderEditor() {
return getEditor()!.getRenderEditor();
}
void onTapDown(TapDownDetails details) {
getRenderEditor()!.handleTapDown(details);
final kind = details.kind;
shouldShowSelectionToolbar = kind == null ||
kind == PointerDeviceKind.touch ||
kind == PointerDeviceKind.stylus;
}
void onForcePressStart(ForcePressDetails details) {
assert(delegate.getForcePressEnabled());
shouldShowSelectionToolbar = true;
if (delegate.getSelectionEnabled()) {
getRenderEditor()!.selectWordsInRange(
details.globalPosition,
null,
SelectionChangedCause.forcePress,
);
}
}
void onForcePressEnd(ForcePressDetails details) {
assert(delegate.getForcePressEnabled());
getRenderEditor()!.selectWordsInRange(
details.globalPosition,
null,
SelectionChangedCause.forcePress,
);
if (shouldShowSelectionToolbar) {
getEditor()!.showToolbar();
}
}
void onSingleTapUp(TapUpDetails details) {
if (delegate.getSelectionEnabled()) {
getRenderEditor()!.selectWordEdge(SelectionChangedCause.tap);
}
}
void onSingleTapCancel() {}
void onSingleLongTapStart(LongPressStartDetails details) {
if (delegate.getSelectionEnabled()) {
getRenderEditor()!.selectPositionAt(
details.globalPosition,
null,
SelectionChangedCause.longPress,
);
}
}
void onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
if (delegate.getSelectionEnabled()) {
getRenderEditor()!.selectPositionAt(
details.globalPosition,
null,
SelectionChangedCause.longPress,
);
}
}
void onSingleLongTapEnd(LongPressEndDetails details) {
if (shouldShowSelectionToolbar) {
getEditor()!.showToolbar();
}
}
void onDoubleTapDown(TapDownDetails details) {
if (delegate.getSelectionEnabled()) {
getRenderEditor()!.selectWord(SelectionChangedCause.tap);
if (shouldShowSelectionToolbar) {
getEditor()!.showToolbar();
}
}
}
void onDragSelectionStart(DragStartDetails details) {
getRenderEditor()!.selectPositionAt(
details.globalPosition,
null,
SelectionChangedCause.drag,
);
}
void onDragSelectionUpdate(
DragStartDetails startDetails, DragUpdateDetails updateDetails) {
getRenderEditor()!.selectPositionAt(
startDetails.globalPosition,
updateDetails.globalPosition,
SelectionChangedCause.drag,
);
}
void onDragSelectionEnd(DragEndDetails details) {}
Widget build(HitTestBehavior behavior, Widget child) {
return EditorTextSelectionGestureDetector(
onTapDown: onTapDown,
onForcePressStart:
delegate.getForcePressEnabled() ? onForcePressStart : null,
onForcePressEnd: delegate.getForcePressEnabled() ? onForcePressEnd : null,
onSingleTapUp: onSingleTapUp,
onSingleTapCancel: onSingleTapCancel,
onSingleLongTapStart: onSingleLongTapStart,
onSingleLongTapMoveUpdate: onSingleLongTapMoveUpdate,
onSingleLongTapEnd: onSingleLongTapEnd,
onDoubleTapDown: onDoubleTapDown,
onDragSelectionStart: onDragSelectionStart,
onDragSelectionUpdate: onDragSelectionUpdate,
onDragSelectionEnd: onDragSelectionEnd,
behavior: behavior,
child: child,
);
}
}