diff --git a/lib/src/editor/editor.dart b/lib/src/editor/editor.dart index 117819392..e12aed026 100644 --- a/lib/src/editor/editor.dart +++ b/lib/src/editor/editor.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:math' as math; import 'package:flutter/cupertino.dart' @@ -221,6 +222,20 @@ class QuillEditorState extends State _editorKey.currentState?.hideToolbar(); } }); + + controller.addListener(_controllerListener); + } + + @override + void dispose() { + controller.removeListener(_controllerListener); + _selectionGestureDetectorBuilder.dispose(); + super.dispose(); + } + + void _controllerListener() { + final position = controller.selection.extentOffset; + _selectionGestureDetectorBuilder.setCurrentCursorPosition(position); } @override @@ -499,6 +514,45 @@ class _QuillEditorSelectionGestureDetectorBuilder pressed.contains(LogicalKeyboardKey.shiftRight)); } + int? _previousCursorPosition; + int? _currentCursorPosition; + + Timer? _timer; + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + @override + void setCurrentCursorPosition(int? position) { + if (_currentCursorPosition != null) { + _previousCursorPosition = _currentCursorPosition; + } + + _currentCursorPosition = position; + } + + void _handleToggleToolbar() { + final position = renderEditor!.selection.extentOffset; + + final shouldShow = _currentCursorPosition != null && + _currentCursorPosition == _previousCursorPosition; + + _currentCursorPosition = position; + _previousCursorPosition = position; + + if (shouldShow) { + SchedulerBinding.instance.addPostFrameCallback((_) { + editor!.showToolbar(); + _currentCursorPosition = null; + }); + } else { + editor!.hideToolbar(); + } + } + @override void onSingleTapUp(TapUpDetails details) { if (_state.config.onTapUp != null && @@ -510,7 +564,8 @@ class _QuillEditorSelectionGestureDetectorBuilder return; } - editor!.hideToolbar(); + _timer?.cancel(); + _timer = Timer(const Duration(milliseconds: 100), _handleToggleToolbar); try { if (delegate.selectionEnabled && !_isPositionSelected(details)) { diff --git a/lib/src/editor/widgets/delegate.dart b/lib/src/editor/widgets/delegate.dart index 20216dfa2..3b089fe92 100644 --- a/lib/src/editor/widgets/delegate.dart +++ b/lib/src/editor/widgets/delegate.dart @@ -387,4 +387,8 @@ class EditorTextSelectionGestureDetectorBuilder { child: child, ); } + + void dispose() {} + + void setCurrentCursorPosition(int? position) {} } diff --git a/lib/src/l10n/generated/quill_localizations.dart b/lib/src/l10n/generated/quill_localizations.dart index 8fef06a0d..0b9610b54 100644 --- a/lib/src/l10n/generated/quill_localizations.dart +++ b/lib/src/l10n/generated/quill_localizations.dart @@ -106,13 +106,15 @@ import 'quill_localizations_zh.dart'; /// property. abstract class FlutterQuillLocalizations { FlutterQuillLocalizations(String locale) - : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + : localeName = intl.Intl.canonicalizedLocale(locale.toString()); final String localeName; static FlutterQuillLocalizations? of(BuildContext context) { return Localizations.of( - context, FlutterQuillLocalizations); + context, + FlutterQuillLocalizations, + ); } static const LocalizationsDelegate delegate = @@ -130,11 +132,11 @@ abstract class FlutterQuillLocalizations { /// of delegates is preferred or required. static const List> localizationsDelegates = >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ @@ -188,7 +190,7 @@ abstract class FlutterQuillLocalizations { Locale('vi'), Locale('zh'), Locale('zh', 'CN'), - Locale('zh', 'HK') + Locale('zh', 'HK'), ]; /// No description provided for @pasteLink. @@ -835,57 +837,58 @@ class _FlutterQuillLocalizationsDelegate @override Future load(Locale locale) { return SynchronousFuture( - lookupFlutterQuillLocalizations(locale)); + lookupFlutterQuillLocalizations(locale), + ); } @override bool isSupported(Locale locale) => [ - 'ar', - 'bg', - 'bn', - 'bs', - 'ca', - 'cs', - 'da', - 'de', - 'el', - 'en', - 'es', - 'fa', - 'fi', - 'fr', - 'gu', - 'he', - 'hi', - 'hr', - 'hu', - 'id', - 'it', - 'ja', - 'km', - 'ko', - 'ku', - 'mk', - 'ms', - 'ne', - 'nl', - 'no', - 'pl', - 'pt', - 'ro', - 'ru', - 'sk', - 'sr', - 'sv', - 'sw', - 'th', - 'tk', - 'tr', - 'uk', - 'ur', - 'vi', - 'zh' - ].contains(locale.languageCode); + 'ar', + 'bg', + 'bn', + 'bs', + 'ca', + 'cs', + 'da', + 'de', + 'el', + 'en', + 'es', + 'fa', + 'fi', + 'fr', + 'gu', + 'he', + 'hi', + 'hr', + 'hu', + 'id', + 'it', + 'ja', + 'km', + 'ko', + 'ku', + 'mk', + 'ms', + 'ne', + 'nl', + 'no', + 'pl', + 'pt', + 'ro', + 'ru', + 'sk', + 'sr', + 'sv', + 'sw', + 'th', + 'tk', + 'tr', + 'uk', + 'ur', + 'vi', + 'zh', + ].contains(locale.languageCode); @override bool shouldReload(_FlutterQuillLocalizationsDelegate old) => false; @@ -1033,8 +1036,9 @@ FlutterQuillLocalizations lookupFlutterQuillLocalizations(Locale locale) { } throw FlutterError( - 'FlutterQuillLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.'); + 'FlutterQuillLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.', + ); } diff --git a/lib/src/toolbar/buttons/link_style/link_dialog.dart b/lib/src/toolbar/buttons/link_style/link_dialog.dart index a443793c3..5cdd41760 100644 --- a/lib/src/toolbar/buttons/link_style/link_dialog.dart +++ b/lib/src/toolbar/buttons/link_style/link_dialog.dart @@ -79,8 +79,12 @@ class LinkDialogState extends State { decoration: InputDecoration( labelText: context.loc.text, hintText: context.loc.pleaseEnterTextForYourLink, + hintStyle: widget.dialogTheme?.inputHintTextStyle, labelStyle: widget.dialogTheme?.labelTextStyle, floatingLabelStyle: widget.dialogTheme?.labelTextStyle, + border: widget.dialogTheme?.inputBorder, + enabledBorder: widget.dialogTheme?.inputBorder, + focusedBorder: widget.dialogTheme?.inputFocusedBorder, ), autofocus: true, onChanged: _textChanged, @@ -98,8 +102,12 @@ class LinkDialogState extends State { decoration: InputDecoration( labelText: context.loc.link, hintText: context.loc.pleaseEnterTheLinkURL, + hintStyle: widget.dialogTheme?.inputHintTextStyle, labelStyle: widget.dialogTheme?.labelTextStyle, floatingLabelStyle: widget.dialogTheme?.labelTextStyle, + border: widget.dialogTheme?.inputBorder, + enabledBorder: widget.dialogTheme?.inputBorder, + focusedBorder: widget.dialogTheme?.inputFocusedBorder, ), onChanged: _linkChanged, controller: _linkController, diff --git a/lib/src/toolbar/theme/quill_dialog_theme.dart b/lib/src/toolbar/theme/quill_dialog_theme.dart index 423296ba1..034f617f2 100644 --- a/lib/src/toolbar/theme/quill_dialog_theme.dart +++ b/lib/src/toolbar/theme/quill_dialog_theme.dart @@ -9,6 +9,9 @@ class QuillDialogTheme with Diagnosticable { this.buttonTextStyle, this.labelTextStyle, this.inputTextStyle, + this.inputHintTextStyle, + this.inputBorder, + this.inputFocusedBorder, this.dialogBackgroundColor, this.shape, this.buttonStyle, @@ -29,6 +32,15 @@ class QuillDialogTheme with Diagnosticable { ///The text style to use for the input text shown in the link-input dialog final TextStyle? inputTextStyle; + /// The text style to use for the hint text shown in the input text field + final TextStyle? inputHintTextStyle; + + /// The border to use for the input text field + final InputBorder? inputBorder; + + /// The border to use for the focused input text field + final InputBorder? inputFocusedBorder; + ///The background color for the Quill dialog final Color? dialogBackgroundColor;