import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/widgets/controller.dart'; import 'package:flutter_quill/widgets/delegate.dart'; import 'package:flutter_quill/widgets/editor.dart'; class QuillField extends StatefulWidget { final QuillController controller; final FocusNode focusNode; final ScrollController scrollController; final bool scrollable; final EdgeInsetsGeometry padding; final bool autofocus; final bool showCursor; final bool readOnly; final bool enableInteractiveSelection; final double minHeight; final double maxHeight; final bool expands; final TextCapitalization textCapitalization; final Brightness keyboardAppearance; final ScrollPhysics scrollPhysics; final ValueChanged<String> onLaunchUrl; final InputDecoration decoration; final Widget toolbar; final EmbedBuilder embedBuilder; QuillField({ Key key, @required this.controller, this.focusNode, this.scrollController, this.scrollable = true, this.padding = EdgeInsets.zero, this.autofocus = false, this.showCursor = true, this.readOnly = false, this.enableInteractiveSelection = true, this.minHeight, this.maxHeight, this.expands = false, this.textCapitalization = TextCapitalization.sentences, this.keyboardAppearance = Brightness.light, this.scrollPhysics, this.onLaunchUrl, this.decoration, this.toolbar, this.embedBuilder, }) : super(key: key); @override _QuillFieldState createState() => _QuillFieldState(); } class _QuillFieldState extends State<QuillField> { bool _focused; void _editorFocusChanged() { setState(() { _focused = widget.focusNode.hasFocus; }); } @override void initState() { super.initState(); _focused = widget.focusNode.hasFocus; widget.focusNode.addListener(_editorFocusChanged); } @override void didUpdateWidget(covariant QuillField oldWidget) { super.didUpdateWidget(oldWidget); if (widget.focusNode != oldWidget.focusNode) { oldWidget.focusNode.removeListener(_editorFocusChanged); widget.focusNode.addListener(_editorFocusChanged); _focused = widget.focusNode.hasFocus; } } @override Widget build(BuildContext context) { Widget child = QuillEditor( controller: widget.controller, focusNode: widget.focusNode, scrollController: widget.scrollController, scrollable: widget.scrollable, padding: widget.padding, autoFocus: widget.autofocus, showCursor: widget.showCursor, readOnly: widget.readOnly, enableInteractiveSelection: widget.enableInteractiveSelection, minHeight: widget.minHeight, maxHeight: widget.maxHeight, expands: widget.expands, textCapitalization: widget.textCapitalization, keyboardAppearance: widget.keyboardAppearance, scrollPhysics: widget.scrollPhysics, onLaunchUrl: widget.onLaunchUrl, embedBuilder: widget.embedBuilder, ); if (widget.toolbar != null) { child = Column( children: [ child, Visibility( child: widget.toolbar, visible: _focused, maintainSize: true, maintainAnimation: true, maintainState: true, ), ], ); } return AnimatedBuilder( animation: Listenable.merge(<Listenable>[widget.focusNode, widget.controller]), builder: (BuildContext context, Widget child) { return InputDecorator( decoration: _getEffectiveDecoration(), isFocused: widget.focusNode.hasFocus, // TODO: Document should be considered empty of it has single empty line with no styles applied isEmpty: widget.controller.document.length == 1, child: child, ); }, child: child, ); } InputDecoration _getEffectiveDecoration() { return (widget.decoration ?? const InputDecoration()) .applyDefaults(Theme.of(context).inputDecorationTheme) .copyWith( enabled: !widget.readOnly, hintMaxLines: widget.decoration?.hintMaxLines, ); } }