diff --git a/lib/widgets/delegate.dart b/lib/widgets/delegate.dart index 845fdf21..8ddc6c69 100644 --- a/lib/widgets/delegate.dart +++ b/lib/widgets/delegate.dart @@ -28,4 +28,21 @@ class EditorTextSelectionGestureDetectorBuilder { onTapDown(TapDownDetails details) { // getRenderEditor().handleTapDown(details); } + + onForcePressStart(ForcePressDetails details) { + assert(delegate.getForcePressEnabled()); + shouldShowSelectionToolbar = true; + if (delegate.getSelectionEnabled()) { + getRenderEditor().selectWordsInRange( + details.globalPosition, + null, + SelectionChangedCause.forcePress, + ); + } + } + + Widget build(HitTestBehavior behavior, Widget child) { + // TODO + return null; + } } diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 31200197..325a14f5 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -1,9 +1,11 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_quill/models/documents/document.dart'; import 'package:flutter_quill/widgets/text_selection.dart'; import 'controller.dart'; +import 'cursor.dart'; import 'delegate.dart'; abstract class RenderAbstractEditor { @@ -85,10 +87,96 @@ class _QuillEditorState extends State final GlobalKey _editorKey = GlobalKey(); EditorTextSelectionGestureDetectorBuilder _selectionGestureDetectorBuilder; + @override + void initState() { + super.initState(); + _selectionGestureDetectorBuilder = + _QuillEditorSelectionGestureDetectorBuilder(this); + } + @override Widget build(BuildContext context) { - // TODO: implement build - throw UnimplementedError(); + ThemeData theme = Theme.of(context); + TextSelectionThemeData selectionTheme = TextSelectionTheme.of(context); + + TextSelectionControls textSelectionControls; + bool paintCursorAboveText; + bool cursorOpacityAnimates; + Offset cursorOffset; + Color cursorColor; + Color selectionColor; + Radius cursorRadius; + + switch (theme.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + textSelectionControls = materialTextSelectionControls; + paintCursorAboveText = false; + cursorOpacityAnimates = false; + cursorColor ??= selectionTheme.cursorColor ?? theme.colorScheme.primary; + selectionColor = selectionTheme.selectionColor ?? + theme.colorScheme.primary.withOpacity(0.40); + break; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context); + textSelectionControls = cupertinoTextSelectionControls; + paintCursorAboveText = true; + cursorOpacityAnimates = true; + cursorColor ??= + selectionTheme.cursorColor ?? cupertinoTheme.primaryColor; + selectionColor = selectionTheme.selectionColor ?? + cupertinoTheme.primaryColor.withOpacity(0.40); + cursorRadius ??= const Radius.circular(2.0); + cursorOffset = Offset( + iOSHorizontalOffset / MediaQuery.of(context).devicePixelRatio, 0); + break; + default: + throw UnimplementedError(); + } + + return _selectionGestureDetectorBuilder.build( + HitTestBehavior.translucent, + RawEditor( + _editorKey, + widget.controller, + widget.focusNode, + widget.scrollController, + widget.scrollable, + widget.padding, + widget.readOnly, + widget.onLaunchUrl, + ToolbarOptions( + copy: true, + cut: true, + paste: true, + selectAll: true, + ), + theme.platform == TargetPlatform.iOS || + theme.platform == TargetPlatform.android, + widget.showCursor, + CursorStyle( + color: cursorColor, + backgroundColor: Colors.grey, + width: 2.0, + radius: cursorRadius, + offset: cursorOffset, + paintAboveText: paintCursorAboveText, + opacityAnimates: cursorOpacityAnimates, + ), + widget.textCapitalization, + widget.maxHeight, + widget.minHeight, + widget.expands, + widget.autoFocus, + selectionColor, + textSelectionControls, + widget.keyboardAppearance, + widget.enableInteractiveSelection, + widget.scrollPhysics), + ); } @override @@ -107,10 +195,155 @@ class _QuillEditorState extends State } } +class _QuillEditorSelectionGestureDetectorBuilder + extends EditorTextSelectionGestureDetectorBuilder { + final _QuillEditorState _state; + + _QuillEditorSelectionGestureDetectorBuilder(this._state) : super(_state); + + @override + onForcePressStart(ForcePressDetails details) { + super.onForcePressStart(details); + } +} + class RawEditor extends StatefulWidget { + final QuillController controller; + final FocusNode focusNode; + final ScrollController scrollController; + final bool scrollable; + final EdgeInsetsGeometry padding; + final bool readOnly; + final ValueChanged onLaunchUrl; + final ToolbarOptions toolbarOptions; + final bool showSelectionHandles; + final bool showCursor; + final CursorStyle cursorStyle; + final TextCapitalization textCapitalization; + final double maxHeight; + final double minHeight; + final bool expands; + final bool autoFocus; + final Color selectionColor; + final TextSelectionControls selectionCtrls; + final Brightness keyboardAppearance; + final bool enableInteractiveSelection; + final ScrollPhysics scrollPhysics; + + RawEditor( + Key key, + this.controller, + this.focusNode, + this.scrollController, + this.scrollable, + this.padding, + this.readOnly, + this.onLaunchUrl, + this.toolbarOptions, + this.showSelectionHandles, + bool showCursor, + this.cursorStyle, + this.textCapitalization, + this.maxHeight, + this.minHeight, + this.expands, + this.autoFocus, + this.selectionColor, + this.selectionCtrls, + this.keyboardAppearance, + this.enableInteractiveSelection, + this.scrollPhysics) + : assert(controller != null), + assert(focusNode != null), + assert(scrollable || scrollController != null), + assert(selectionColor != null), + assert(enableInteractiveSelection != null), + assert(showSelectionHandles != null), + assert(readOnly != null), + assert(maxHeight == null || maxHeight > 0), + assert(minHeight == null || minHeight >= 0), + assert( + maxHeight == null || minHeight == null || maxHeight >= minHeight), + assert(autoFocus != null), + assert(toolbarOptions != null), + showCursor = showCursor ?? !readOnly, + super(key: key); + @override State createState() { - // TODO: implement createState + return RawEditorState(); + } +} + +class RawEditorState extends EditorState implements TextSelectionDelegate { + final GlobalKey _editorKey = GlobalKey(); + + @override + TextEditingValue textEditingValue; + + @override + void bringIntoView(TextPosition position) { + // TODO: implement bringIntoView + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + throw UnimplementedError(); + } + + @override + // TODO: implement copyEnabled + bool get copyEnabled => throw UnimplementedError(); + + @override + // TODO: implement cutEnabled + bool get cutEnabled => throw UnimplementedError(); + + @override + RenderEditor getRenderEditor() { + // TODO: implement getRenderEditor + throw UnimplementedError(); + } + + @override + EditorTextSelectionOverlay getSelectionOverlay() { + // TODO: implement getSelectionOverlay + throw UnimplementedError(); + } + + @override + TextEditingValue getTextEditingValue() { + // TODO: implement getTextEditingValue + throw UnimplementedError(); + } + + @override + void hideToolbar() { + // TODO: implement hideToolbar + } + + @override + // TODO: implement pasteEnabled + bool get pasteEnabled => throw UnimplementedError(); + + @override + void requestKeyboard() { + // TODO: implement requestKeyboard + } + + @override + // TODO: implement selectAllEnabled + bool get selectAllEnabled => throw UnimplementedError(); + + @override + void setTextEditingValue(TextEditingValue value) { + // TODO: implement setTextEditingValue + } + + @override + bool showToolbar() { + // TODO: implement showToolbar throw UnimplementedError(); } } @@ -205,6 +438,7 @@ class RenderEditor extends RenderEditableContainerBox @override void selectWordsInRange(Offset from, Offset to, SelectionChangedCause cause) { + assert(cause != null && from != null); // TODO: implement selectWordsInRange } }