Add Custom Style Attribute builder

pull/350/head
ritheshSalyan 4 years ago
parent d59fbf1d90
commit 7374eee0a2
  1. 2
      .vscode/launch.json
  2. 15
      app/lib/generated_plugin_registrant.dart
  3. 1
      app/windows/flutter/ephemeral/.plugin_symlinks/url_launcher_windows
  4. 5
      lib/src/models/documents/attribute.dart
  5. 3
      lib/src/models/documents/style.dart
  6. 3
      lib/src/widgets/delegate.dart
  7. 63
      lib/src/widgets/editor.dart
  8. 5
      lib/src/widgets/raw_editor.dart
  9. 5
      lib/src/widgets/simple_viewer.dart
  10. 3
      lib/src/widgets/text_block.dart
  11. 17
      lib/src/widgets/text_line.dart

@ -8,7 +8,7 @@
"name": "flutter-quill", "name": "flutter-quill",
"request": "launch", "request": "launch",
"type": "dart", "type": "dart",
"program": "app/lib/main.dart" "program": "example/lib/main.dart"
}, },
] ]

@ -0,0 +1,15 @@
//
// Generated file. Do not edit.
//
// ignore_for_file: lines_longer_than_80_chars
import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
UrlLauncherPlugin.registerWith(registrar);
registrar.registerMessageHandler();
}

@ -0,0 +1 @@
C:/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.0.1+3/

@ -165,9 +165,10 @@ class Attribute<T> {
Map<String, dynamic> toJson() => <String, dynamic>{key: value}; Map<String, dynamic> toJson() => <String, dynamic>{key: value};
static Attribute fromKeyValue(String key, dynamic value) { static Attribute? fromKeyValue(String key, dynamic value) {
if (!_registry.containsKey(key)) { if (!_registry.containsKey(key)) {
throw ArgumentError.value(key, 'key "$key" not found.'); return null;
// throw ArgumentError.value(key, 'key "$key" not found.');
} }
final origin = _registry[key]!; final origin = _registry[key]!;
final attribute = clone(origin, value); final attribute = clone(origin, value);

@ -18,7 +18,8 @@ class Style {
final result = attributes.map((key, dynamic value) { final result = attributes.map((key, dynamic value) {
final attr = Attribute.fromKeyValue(key, value); final attr = Attribute.fromKeyValue(key, value);
return MapEntry<String, Attribute>(key, attr); // ignore: lines_longer_than_80_chars
return MapEntry<String, Attribute>(key, attr??Attribute(key, AttributeScope.INLINE, value));
}); });
return Style.attr(result); return Style.attr(result);
} }

@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import '../../models/documents/attribute.dart';
import '../models/documents/nodes/leaf.dart'; import '../models/documents/nodes/leaf.dart';
import 'editor.dart'; import 'editor.dart';
@ -9,7 +10,7 @@ import 'text_selection.dart';
typedef EmbedBuilder = Widget Function( typedef EmbedBuilder = Widget Function(
BuildContext context, Embed node, bool readOnly); BuildContext context, Embed node, bool readOnly);
typedef StyleBuilder = TextStyle Function(Attribute<dynamic> attribute);
abstract class EditorTextSelectionGestureDetectorBuilderDelegate { abstract class EditorTextSelectionGestureDetectorBuilderDelegate {
GlobalKey<EditorState> getEditableTextKey(); GlobalKey<EditorState> getEditableTextKey();

@ -144,7 +144,7 @@ String _standardizeImageUrl(String url) {
} }
bool _isMobile() => io.Platform.isAndroid || io.Platform.isIOS; bool _isMobile() => io.Platform.isAndroid || io.Platform.isIOS;
TextStyle _defaultStyleBuilder(_)=>const TextStyle();
Widget _defaultEmbedBuilder( Widget _defaultEmbedBuilder(
BuildContext context, leaf.Embed node, bool readOnly) { BuildContext context, leaf.Embed node, bool readOnly) {
assert(!kIsWeb, 'Please provide EmbedBuilder for Web'); assert(!kIsWeb, 'Please provide EmbedBuilder for Web');
@ -225,33 +225,35 @@ Widget _defaultEmbedBuilder(
} }
class QuillEditor extends StatefulWidget { class QuillEditor extends StatefulWidget {
const QuillEditor( const QuillEditor({
{required this.controller, required this.controller,
required this.focusNode, required this.focusNode,
required this.scrollController, required this.scrollController,
required this.scrollable, required this.scrollable,
required this.padding, required this.padding,
required this.autoFocus, required this.autoFocus,
required this.readOnly, required this.readOnly,
required this.expands, required this.expands,
this.showCursor, this.showCursor,
this.paintCursorAboveText, this.paintCursorAboveText,
this.placeholder, this.placeholder,
this.enableInteractiveSelection = true, this.enableInteractiveSelection = true,
this.scrollBottomInset = 0, this.scrollBottomInset = 0,
this.minHeight, this.minHeight,
this.maxHeight, this.maxHeight,
this.customStyles, this.customStyles,
this.textCapitalization = TextCapitalization.sentences, this.textCapitalization = TextCapitalization.sentences,
this.keyboardAppearance = Brightness.light, this.keyboardAppearance = Brightness.light,
this.scrollPhysics, this.scrollPhysics,
this.onLaunchUrl, this.onLaunchUrl,
this.onTapDown, this.onTapDown,
this.onTapUp, this.onTapUp,
this.onSingleLongTapStart, this.onSingleLongTapStart,
this.onSingleLongTapMoveUpdate, this.onSingleLongTapMoveUpdate,
this.onSingleLongTapEnd, this.onSingleLongTapEnd,
this.embedBuilder = _defaultEmbedBuilder}); this.embedBuilder = _defaultEmbedBuilder,
this.styleBuilder = _defaultStyleBuilder,
});
factory QuillEditor.basic({ factory QuillEditor.basic({
required QuillController controller, required QuillController controller,
@ -310,6 +312,7 @@ class QuillEditor extends StatefulWidget {
onSingleLongTapEnd; onSingleLongTapEnd;
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
final StyleBuilder styleBuilder;
@override @override
_QuillEditorState createState() => _QuillEditorState(); _QuillEditorState createState() => _QuillEditorState();
@ -413,7 +416,9 @@ class _QuillEditorState extends State<QuillEditor>
widget.keyboardAppearance, widget.keyboardAppearance,
widget.enableInteractiveSelection, widget.enableInteractiveSelection,
widget.scrollPhysics, widget.scrollPhysics,
widget.embedBuilder), widget.embedBuilder,
widget.styleBuilder,
),
); );
} }

@ -57,6 +57,7 @@ class RawEditor extends StatefulWidget {
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.scrollPhysics, this.scrollPhysics,
this.embedBuilder, this.embedBuilder,
this.styleBuilder,
) : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'), ) : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'),
assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'), assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'),
assert(maxHeight == null || minHeight == null || maxHeight >= minHeight, assert(maxHeight == null || minHeight == null || maxHeight >= minHeight,
@ -89,7 +90,7 @@ class RawEditor extends StatefulWidget {
final bool enableInteractiveSelection; final bool enableInteractiveSelection;
final ScrollPhysics? scrollPhysics; final ScrollPhysics? scrollPhysics;
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
final StyleBuilder styleBuilder;
@override @override
State<StatefulWidget> createState() => RawEditorState(); State<StatefulWidget> createState() => RawEditorState();
} }
@ -244,6 +245,7 @@ class RawEditorState extends EditorState
? const EdgeInsets.all(16) ? const EdgeInsets.all(16)
: null, : null,
widget.embedBuilder, widget.embedBuilder,
widget.styleBuilder,
_cursorCont, _cursorCont,
indentLevelCounts, indentLevelCounts,
_handleCheckboxTap, _handleCheckboxTap,
@ -262,6 +264,7 @@ class RawEditorState extends EditorState
line: node, line: node,
textDirection: _textDirection, textDirection: _textDirection,
embedBuilder: widget.embedBuilder, embedBuilder: widget.embedBuilder,
styleBuilder: widget.styleBuilder,
styles: _styles!, styles: _styles!,
readOnly: widget.readOnly, readOnly: widget.readOnly,
); );

@ -37,6 +37,7 @@ class QuillSimpleViewer extends StatefulWidget {
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
this.embedBuilder, this.embedBuilder,
Key? key, Key? key,
this.styleBuilder,
}) : assert(truncate || }) : assert(truncate ||
((truncateScale == null) && ((truncateScale == null) &&
(truncateAlignment == null) && (truncateAlignment == null) &&
@ -54,6 +55,7 @@ class QuillSimpleViewer extends StatefulWidget {
final double scrollBottomInset; final double scrollBottomInset;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final EmbedBuilder? embedBuilder; final EmbedBuilder? embedBuilder;
final StyleBuilder? styleBuilder;
final bool readOnly; final bool readOnly;
@override @override
@ -100,6 +102,7 @@ class _QuillSimpleViewerState extends State<QuillSimpleViewer>
} }
EmbedBuilder get embedBuilder => widget.embedBuilder ?? _defaultEmbedBuilder; EmbedBuilder get embedBuilder => widget.embedBuilder ?? _defaultEmbedBuilder;
StyleBuilder get styleBuilder => widget.styleBuilder ??(a)=>const TextStyle();
Widget _defaultEmbedBuilder( Widget _defaultEmbedBuilder(
BuildContext context, leaf.Embed node, bool readOnly) { BuildContext context, leaf.Embed node, bool readOnly) {
@ -218,6 +221,7 @@ class _QuillSimpleViewerState extends State<QuillSimpleViewer>
? const EdgeInsets.all(16) ? const EdgeInsets.all(16)
: null, : null,
embedBuilder, embedBuilder,
styleBuilder,
_cursorCont, _cursorCont,
indentLevelCounts, indentLevelCounts,
_handleCheckboxTap, _handleCheckboxTap,
@ -247,6 +251,7 @@ class _QuillSimpleViewerState extends State<QuillSimpleViewer>
line: node, line: node,
textDirection: _textDirection, textDirection: _textDirection,
embedBuilder: embedBuilder, embedBuilder: embedBuilder,
styleBuilder: styleBuilder,
styles: _styles, styles: _styles,
readOnly: widget.readOnly, readOnly: widget.readOnly,
); );

@ -59,6 +59,7 @@ class EditableTextBlock extends StatelessWidget {
this.hasFocus, this.hasFocus,
this.contentPadding, this.contentPadding,
this.embedBuilder, this.embedBuilder,
this.styleBuilder,
this.cursorCont, this.cursorCont,
this.indentLevelCounts, this.indentLevelCounts,
this.onCheckboxTap, this.onCheckboxTap,
@ -76,6 +77,7 @@ class EditableTextBlock extends StatelessWidget {
final bool hasFocus; final bool hasFocus;
final EdgeInsets? contentPadding; final EdgeInsets? contentPadding;
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
final StyleBuilder styleBuilder;
final CursorCont cursorCont; final CursorCont cursorCont;
final Map<int, int> indentLevelCounts; final Map<int, int> indentLevelCounts;
final Function(int, bool) onCheckboxTap; final Function(int, bool) onCheckboxTap;
@ -123,6 +125,7 @@ class EditableTextBlock extends StatelessWidget {
line: line, line: line,
textDirection: textDirection, textDirection: textDirection,
embedBuilder: embedBuilder, embedBuilder: embedBuilder,
styleBuilder: styleBuilder,
styles: styles!, styles: styles!,
readOnly: readOnly, readOnly: readOnly,
), ),

@ -24,6 +24,7 @@ class TextLine extends StatelessWidget {
const TextLine({ const TextLine({
required this.line, required this.line,
required this.embedBuilder, required this.embedBuilder,
required this.styleBuilder,
required this.styles, required this.styles,
required this.readOnly, required this.readOnly,
this.textDirection, this.textDirection,
@ -35,7 +36,7 @@ class TextLine extends StatelessWidget {
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
final DefaultStyles styles; final DefaultStyles styles;
final bool readOnly; final bool readOnly;
final StyleBuilder? styleBuilder;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
@ -150,6 +151,20 @@ class TextLine extends StatelessWidget {
textStyle = textStyle.merge(toMerge); textStyle = textStyle.merge(toMerge);
if (styleBuilder != null) {
line.style.attributes.keys.forEach((key) {
final attribute =
Attribute.fromKeyValue(key, line.style.attributes[key]);
if (attribute != null) {
///
///Unkown Attribute
///
final call = styleBuilder?.call(attribute);
textStyle = textStyle.merge(call);
}
});
}
return textStyle; return textStyle;
} }

Loading…
Cancel
Save