From 7d4bfa67a8e33d9ac73386dbb0fe6e966d797468 Mon Sep 17 00:00:00 2001 From: li3317 Date: Sat, 20 Feb 2021 22:26:37 -0500 Subject: [PATCH] support placeholder for empty content --- app/lib/pages/home_page.dart | 1 + lib/models/documents/attribute.dart | 11 ++++++++++- lib/models/documents/document.dart | 2 +- lib/widgets/default_styles.dart | 12 ++++++++++++ lib/widgets/editor.dart | 6 ++++++ lib/widgets/raw_editor.dart | 10 ++++++++++ lib/widgets/text_line.dart | 5 +++++ 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 3663543f..dafa4859 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -103,6 +103,7 @@ class _HomePageState extends State { focusNode: _focusNode, autoFocus: false, readOnly: false, + placeholder: 'Add content', enableInteractiveSelection: true, expands: false, padding: EdgeInsets.zero, diff --git a/lib/models/documents/attribute.dart b/lib/models/documents/attribute.dart index d7865e7d..7b363bed 100644 --- a/lib/models/documents/attribute.dart +++ b/lib/models/documents/attribute.dart @@ -24,6 +24,7 @@ class Attribute { Attribute.link.key: Attribute.link, Attribute.color.key: Attribute.color, Attribute.background.key: Attribute.background, + Attribute.placeholder.key: Attribute.placeholder, Attribute.header.key: Attribute.header, Attribute.indent.key: Attribute.indent, Attribute.align.key: Attribute.align, @@ -53,6 +54,8 @@ class Attribute { static final BackgroundAttribute background = BackgroundAttribute(null); + static final PlaceholderAttribute placeholder = PlaceholderAttribute(); + static final HeaderAttribute header = HeaderAttribute(); static final IndentAttribute indent = IndentAttribute(); @@ -78,7 +81,8 @@ class Attribute { Attribute.strikeThrough.key, Attribute.link.key, Attribute.color.key, - Attribute.background.key + Attribute.background.key, + Attribute.placeholder.key, }; static final Set blockKeys = { @@ -222,6 +226,11 @@ class BackgroundAttribute extends Attribute { : super('background', AttributeScope.INLINE, val); } +/// This is custom attribute for hint +class PlaceholderAttribute extends Attribute { + PlaceholderAttribute() : super('placeholder', AttributeScope.INLINE, true); +} + class HeaderAttribute extends Attribute { HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level); } diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index 93585897..f41ee0bd 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -249,7 +249,7 @@ class Document { } Delta delta = node.toDelta(); - return delta.length == 1 && delta.first.data == '\n'; + return delta.length == 1 && delta.first.data == '\n' && delta.first.key == 'insert'; } } diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index cef0011b..4cad7bbb 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -54,6 +54,7 @@ class DefaultStyles { final TextStyle sizeLarge; // 'large' final TextStyle sizeHuge; // 'huge' final TextStyle link; + final DefaultTextBlockStyle placeHolder; final DefaultTextBlockStyle lists; final DefaultTextBlockStyle quote; final DefaultTextBlockStyle code; @@ -70,6 +71,7 @@ class DefaultStyles { this.underline, this.strikeThrough, this.link, + this.placeHolder, this.lists, this.quote, this.code, @@ -144,6 +146,15 @@ class DefaultStyles { color: themeData.accentColor, 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( baseStyle, baseSpacing, Tuple2(0.0, 6.0), null), quote: DefaultTextBlockStyle( @@ -188,6 +199,7 @@ class DefaultStyles { underline: other.underline ?? this.underline, strikeThrough: other.strikeThrough ?? this.strikeThrough, link: other.link ?? this.link, + placeHolder: other.placeHolder ?? this.placeHolder, lists: other.lists ?? this.lists, quote: other.quote ?? this.quote, code: other.code ?? this.code, diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 018ef0b2..29472aae 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -134,6 +134,7 @@ class QuillEditor extends StatefulWidget { final bool autoFocus; final bool showCursor; final bool readOnly; + final String placeholder; final bool enableInteractiveSelection; final double minHeight; final double maxHeight; @@ -154,6 +155,7 @@ class QuillEditor extends StatefulWidget { @required this.autoFocus, this.showCursor, @required this.readOnly, + this.placeholder, this.enableInteractiveSelection, this.minHeight, this.maxHeight, @@ -256,6 +258,7 @@ class _QuillEditorState extends State widget.scrollable, widget.padding, widget.readOnly, + widget.placeholder, widget.onLaunchUrl, ToolbarOptions( copy: true, @@ -359,6 +362,9 @@ class _QuillEditorSelectionGestureDetectorBuilder } bool _onTapping(TapUpDetails details) { + if (_state.widget.controller.document.isEmpty()) { + return false; + } TextPosition pos = getRenderEditor().getPositionForOffset(details.globalPosition); containerNode.ChildQuery result = diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 891bff86..fbbb8a83 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -32,6 +34,7 @@ class RawEditor extends StatefulWidget { final bool scrollable; final EdgeInsetsGeometry padding; final bool readOnly; + final String placeholder; final ValueChanged onLaunchUrl; final ToolbarOptions toolbarOptions; final bool showSelectionHandles; @@ -58,6 +61,7 @@ class RawEditor extends StatefulWidget { this.scrollable, this.padding, this.readOnly, + this.placeholder, this.onLaunchUrl, this.toolbarOptions, this.showSelectionHandles, @@ -504,6 +508,12 @@ class RawEditorState extends EditorState super.build(context); 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( link: _toolbarLayerLink, diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 6d7efa6b..986cf762 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -88,6 +88,11 @@ class TextLine extends StatelessWidget { 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]; Map m = { Attribute.h1: defaultStyles.h1.style,