From 61c73942fee0d7bf4c0fcbb4c9dd688b01c517a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 2 Oct 2023 13:23:15 +0100 Subject: [PATCH] chore: Small refactoring. #275 --- .../widgets/editor/emoji_picker_widget.dart | 12 +- .../widgets/editor/todo_editor.dart | 151 +++++++++--------- 2 files changed, 78 insertions(+), 85 deletions(-) diff --git a/lib/presentation/widgets/editor/emoji_picker_widget.dart b/lib/presentation/widgets/editor/emoji_picker_widget.dart index 45b71e1e..3717a7cb 100644 --- a/lib/presentation/widgets/editor/emoji_picker_widget.dart +++ b/lib/presentation/widgets/editor/emoji_picker_widget.dart @@ -9,12 +9,12 @@ const emojiPickerWidgetKey = Key('emojiPickerWidgetKey'); /// Shows an emoji picker when [offstageEmojiPicker] is `false`. class OffstageEmojiPicker extends StatefulWidget { /// `QuillController` controller that is passed so the controller document is changed when emojis are inserted. - final QuillController? quillController; + final QuillController? editorController; /// Determines if the emoji picker is offstage or not. final bool offstageEmojiPicker; - const OffstageEmojiPicker({required this.offstageEmojiPicker, this.quillController, super.key}); + const OffstageEmojiPicker({required this.offstageEmojiPicker, this.editorController, super.key}); @override State createState() => _OffstageEmojiPickerState(); @@ -47,13 +47,13 @@ class _OffstageEmojiPickerState extends State { child: EmojiPicker( key: emojiPickerWidgetKey, onEmojiSelected: (category, emoji) { - if (widget.quillController != null) { + if (widget.editorController != null) { // Get pointer selection and insert emoji there - final selection = widget.quillController?.selection; - widget.quillController?.document.insert(selection!.end, emoji.emoji); + final selection = widget.editorController?.selection; + widget.editorController?.document.insert(selection!.end, emoji.emoji); // Update the pointer after the emoji we've just inserted - widget.quillController?.updateSelection(TextSelection.collapsed(offset: selection!.end + emoji.emoji.length), ChangeSource.REMOTE); + widget.editorController?.updateSelection(TextSelection.collapsed(offset: selection!.end + emoji.emoji.length), ChangeSource.REMOTE); } }, config: _buildEmojiPickerConfig(context), diff --git a/lib/presentation/widgets/editor/todo_editor.dart b/lib/presentation/widgets/editor/todo_editor.dart index 7f8196b9..d95bd564 100644 --- a/lib/presentation/widgets/editor/todo_editor.dart +++ b/lib/presentation/widgets/editor/todo_editor.dart @@ -46,7 +46,6 @@ class DeltaTodoEditor extends StatefulWidget { } class DeltaTodoEditorState extends State { - /// Focus node used to obtain keyboard focus and events final FocusNode _focusNode = FocusNode(); @@ -63,83 +62,6 @@ class DeltaTodoEditorState extends State { @override Widget build(BuildContext context) { - /// Returning scaffold with editor as body - return _buildEditor(context); - } - - /// Callback called whenever the person taps on the text. - /// It will select nothing, then the word if another tap is detected - /// and then the whole text if another tap is detected (triple). - bool _onTripleClickSelection() { - final controller = widget.editorController; - - // If nothing is selected, selection type is `none` - if (controller.selection.isCollapsed) { - _selectionType = _SelectionType.none; - } - - // If nothing is selected, selection type becomes `word - if (_selectionType == _SelectionType.none) { - _selectionType = _SelectionType.word; - return false; - } - - // If the word is selected, select all text - if (_selectionType == _SelectionType.word) { - final child = controller.document.queryChild( - controller.selection.baseOffset, - ); - final offset = child.node?.documentOffset ?? 0; - final length = child.node?.length ?? 0; - - final selection = TextSelection( - baseOffset: offset, - extentOffset: offset + length, - ); - - // Select all text and make next selection to `none` - controller.updateSelection(selection, ChangeSource.REMOTE); - - _selectionType = _SelectionType.none; - - return true; - } - - return false; - } - - /// Callback called whenever the person taps on the emoji button in the toolbar. - /// It shows/hides the emoji picker and focus/unfocusses the keyboard accordingly. - void _onEmojiButtonPressed(BuildContext context) { - final isEmojiPickerShown = !_offstageEmojiPickerOffstage; - - // If emoji picker is being shown, we show the keyboard and hide the emoji picker. - if (isEmojiPickerShown) { - _focusNode.requestFocus(); - setState(() { - _offstageEmojiPickerOffstage = true; - }); - } - - // Otherwise, we do the inverse. - else { - // Unfocusing when the person clicks away. This is to hide the keyboard. - // See https://flutterigniter.com/dismiss-keyboard-form-lose-focus/ - // and https://www.youtube.com/watch?v=MKrEJtheGPk&t=40s&ab_channel=HeyFlutter%E2%80%A4com. - final currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus) { - SystemChannels.textInput.invokeMethod('TextInput.hide'); - //currentFocus.unfocus(); - } - - setState(() { - _offstageEmojiPickerOffstage = false; - }); - } - } - - /// Build the `flutter-quill` editor to be shown on screen. - Widget _buildEditor(BuildContext context) { // Default editor (for mobile devices) Widget quillEditor = QuillEditor( controller: widget.editorController, @@ -365,13 +287,84 @@ class DeltaTodoEditorState extends State { Container(child: toolbar), OffstageEmojiPicker( offstageEmojiPicker: _offstageEmojiPickerOffstage, - quillController: widget.editorController, + editorController: widget.editorController, ), ], ), ); } + /// Callback called whenever the person taps on the text. + /// It will select nothing, then the word if another tap is detected + /// and then the whole text if another tap is detected (triple). + bool _onTripleClickSelection() { + final controller = widget.editorController; + + // If nothing is selected, selection type is `none` + if (controller.selection.isCollapsed) { + _selectionType = _SelectionType.none; + } + + // If nothing is selected, selection type becomes `word + if (_selectionType == _SelectionType.none) { + _selectionType = _SelectionType.word; + return false; + } + + // If the word is selected, select all text + if (_selectionType == _SelectionType.word) { + final child = controller.document.queryChild( + controller.selection.baseOffset, + ); + final offset = child.node?.documentOffset ?? 0; + final length = child.node?.length ?? 0; + + final selection = TextSelection( + baseOffset: offset, + extentOffset: offset + length, + ); + + // Select all text and make next selection to `none` + controller.updateSelection(selection, ChangeSource.REMOTE); + + _selectionType = _SelectionType.none; + + return true; + } + + return false; + } + + /// Callback called whenever the person taps on the emoji button in the toolbar. + /// It shows/hides the emoji picker and focus/unfocusses the keyboard accordingly. + void _onEmojiButtonPressed(BuildContext context) { + final isEmojiPickerShown = !_offstageEmojiPickerOffstage; + + // If emoji picker is being shown, we show the keyboard and hide the emoji picker. + if (isEmojiPickerShown) { + _focusNode.requestFocus(); + setState(() { + _offstageEmojiPickerOffstage = true; + }); + } + + // Otherwise, we do the inverse. + else { + // Unfocusing when the person clicks away. This is to hide the keyboard. + // See https://flutterigniter.com/dismiss-keyboard-form-lose-focus/ + // and https://www.youtube.com/watch?v=MKrEJtheGPk&t=40s&ab_channel=HeyFlutter%E2%80%A4com. + final currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + SystemChannels.textInput.invokeMethod('TextInput.hide'); + //currentFocus.unfocus(); + } + + setState(() { + _offstageEmojiPickerOffstage = false; + }); + } + } + /// Renders the image picked by imagePicker from local file storage /// You can also upload the picked image to any server (eg : AWS s3 /// or Firebase) and then return the uploaded image URL.