support placeholder for empty content

pull/37/head^2
li3317 4 years ago
parent f4f81d5b1d
commit 7d4bfa67a8
  1. 1
      app/lib/pages/home_page.dart
  2. 11
      lib/models/documents/attribute.dart
  3. 2
      lib/models/documents/document.dart
  4. 12
      lib/widgets/default_styles.dart
  5. 6
      lib/widgets/editor.dart
  6. 10
      lib/widgets/raw_editor.dart
  7. 5
      lib/widgets/text_line.dart

@ -103,6 +103,7 @@ class _HomePageState extends State<HomePage> {
focusNode: _focusNode, focusNode: _focusNode,
autoFocus: false, autoFocus: false,
readOnly: false, readOnly: false,
placeholder: 'Add content',
enableInteractiveSelection: true, enableInteractiveSelection: true,
expands: false, expands: false,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,

@ -24,6 +24,7 @@ class Attribute<T> {
Attribute.link.key: Attribute.link, Attribute.link.key: Attribute.link,
Attribute.color.key: Attribute.color, Attribute.color.key: Attribute.color,
Attribute.background.key: Attribute.background, Attribute.background.key: Attribute.background,
Attribute.placeholder.key: Attribute.placeholder,
Attribute.header.key: Attribute.header, Attribute.header.key: Attribute.header,
Attribute.indent.key: Attribute.indent, Attribute.indent.key: Attribute.indent,
Attribute.align.key: Attribute.align, Attribute.align.key: Attribute.align,
@ -53,6 +54,8 @@ class Attribute<T> {
static final BackgroundAttribute background = BackgroundAttribute(null); static final BackgroundAttribute background = BackgroundAttribute(null);
static final PlaceholderAttribute placeholder = PlaceholderAttribute();
static final HeaderAttribute header = HeaderAttribute(); static final HeaderAttribute header = HeaderAttribute();
static final IndentAttribute indent = IndentAttribute(); static final IndentAttribute indent = IndentAttribute();
@ -78,7 +81,8 @@ class Attribute<T> {
Attribute.strikeThrough.key, Attribute.strikeThrough.key,
Attribute.link.key, Attribute.link.key,
Attribute.color.key, Attribute.color.key,
Attribute.background.key Attribute.background.key,
Attribute.placeholder.key,
}; };
static final Set<String> blockKeys = { static final Set<String> blockKeys = {
@ -222,6 +226,11 @@ class BackgroundAttribute extends Attribute<String> {
: super('background', AttributeScope.INLINE, val); : super('background', AttributeScope.INLINE, val);
} }
/// This is custom attribute for hint
class PlaceholderAttribute extends Attribute<bool> {
PlaceholderAttribute() : super('placeholder', AttributeScope.INLINE, true);
}
class HeaderAttribute extends Attribute<int> { class HeaderAttribute extends Attribute<int> {
HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level); HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level);
} }

@ -249,7 +249,7 @@ class Document {
} }
Delta delta = node.toDelta(); Delta delta = node.toDelta();
return delta.length == 1 && delta.first.data == '\n'; return delta.length == 1 && delta.first.data == '\n' && delta.first.key == 'insert';
} }
} }

@ -54,6 +54,7 @@ class DefaultStyles {
final TextStyle sizeLarge; // 'large' final TextStyle sizeLarge; // 'large'
final TextStyle sizeHuge; // 'huge' final TextStyle sizeHuge; // 'huge'
final TextStyle link; final TextStyle link;
final DefaultTextBlockStyle placeHolder;
final DefaultTextBlockStyle lists; final DefaultTextBlockStyle lists;
final DefaultTextBlockStyle quote; final DefaultTextBlockStyle quote;
final DefaultTextBlockStyle code; final DefaultTextBlockStyle code;
@ -70,6 +71,7 @@ class DefaultStyles {
this.underline, this.underline,
this.strikeThrough, this.strikeThrough,
this.link, this.link,
this.placeHolder,
this.lists, this.lists,
this.quote, this.quote,
this.code, this.code,
@ -144,6 +146,15 @@ class DefaultStyles {
color: themeData.accentColor, color: themeData.accentColor,
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
), ),
placeHolder: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith(
fontSize: 20.0,
height: 1.5,
color: Colors.grey.withOpacity(0.6),
),
Tuple2(0.0, 0.0),
Tuple2(0.0, 0.0),
null),
lists: DefaultTextBlockStyle( lists: DefaultTextBlockStyle(
baseStyle, baseSpacing, Tuple2(0.0, 6.0), null), baseStyle, baseSpacing, Tuple2(0.0, 6.0), null),
quote: DefaultTextBlockStyle( quote: DefaultTextBlockStyle(
@ -188,6 +199,7 @@ class DefaultStyles {
underline: other.underline ?? this.underline, underline: other.underline ?? this.underline,
strikeThrough: other.strikeThrough ?? this.strikeThrough, strikeThrough: other.strikeThrough ?? this.strikeThrough,
link: other.link ?? this.link, link: other.link ?? this.link,
placeHolder: other.placeHolder ?? this.placeHolder,
lists: other.lists ?? this.lists, lists: other.lists ?? this.lists,
quote: other.quote ?? this.quote, quote: other.quote ?? this.quote,
code: other.code ?? this.code, code: other.code ?? this.code,

@ -134,6 +134,7 @@ class QuillEditor extends StatefulWidget {
final bool autoFocus; final bool autoFocus;
final bool showCursor; final bool showCursor;
final bool readOnly; final bool readOnly;
final String placeholder;
final bool enableInteractiveSelection; final bool enableInteractiveSelection;
final double minHeight; final double minHeight;
final double maxHeight; final double maxHeight;
@ -154,6 +155,7 @@ class QuillEditor extends StatefulWidget {
@required this.autoFocus, @required this.autoFocus,
this.showCursor, this.showCursor,
@required this.readOnly, @required this.readOnly,
this.placeholder,
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.minHeight, this.minHeight,
this.maxHeight, this.maxHeight,
@ -256,6 +258,7 @@ class _QuillEditorState extends State<QuillEditor>
widget.scrollable, widget.scrollable,
widget.padding, widget.padding,
widget.readOnly, widget.readOnly,
widget.placeholder,
widget.onLaunchUrl, widget.onLaunchUrl,
ToolbarOptions( ToolbarOptions(
copy: true, copy: true,
@ -359,6 +362,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
} }
bool _onTapping(TapUpDetails details) { bool _onTapping(TapUpDetails details) {
if (_state.widget.controller.document.isEmpty()) {
return false;
}
TextPosition pos = TextPosition pos =
getRenderEditor().getPositionForOffset(details.globalPosition); getRenderEditor().getPositionForOffset(details.globalPosition);
containerNode.ChildQuery result = containerNode.ChildQuery result =

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -32,6 +34,7 @@ class RawEditor extends StatefulWidget {
final bool scrollable; final bool scrollable;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final bool readOnly; final bool readOnly;
final String placeholder;
final ValueChanged<String> onLaunchUrl; final ValueChanged<String> onLaunchUrl;
final ToolbarOptions toolbarOptions; final ToolbarOptions toolbarOptions;
final bool showSelectionHandles; final bool showSelectionHandles;
@ -58,6 +61,7 @@ class RawEditor extends StatefulWidget {
this.scrollable, this.scrollable,
this.padding, this.padding,
this.readOnly, this.readOnly,
this.placeholder,
this.onLaunchUrl, this.onLaunchUrl,
this.toolbarOptions, this.toolbarOptions,
this.showSelectionHandles, this.showSelectionHandles,
@ -504,6 +508,12 @@ class RawEditorState extends EditorState
super.build(context); super.build(context);
Document _doc = widget.controller.document; Document _doc = widget.controller.document;
if (_doc.isEmpty() &&
!widget.focusNode.hasFocus &&
widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode(
'[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
}
Widget child = CompositedTransformTarget( Widget child = CompositedTransformTarget(
link: _toolbarLayerLink, link: _toolbarLayerLink,

@ -88,6 +88,11 @@ class TextLine extends StatelessWidget {
TextStyle textStyle = TextStyle(); TextStyle textStyle = TextStyle();
if (line.style.containsKey(Attribute.placeholder.key)) {
textStyle = defaultStyles.placeHolder.style;
return TextSpan(children: children, style: textStyle);
}
Attribute header = line.style.attributes[Attribute.header.key]; Attribute header = line.style.attributes[Attribute.header.key];
Map<Attribute, TextStyle> m = { Map<Attribute, TextStyle> m = {
Attribute.h1: defaultStyles.h1.style, Attribute.h1: defaultStyles.h1.style,

Loading…
Cancel
Save