From 99b92dd388d57eb9ce8d233cf010d65a66695b0b Mon Sep 17 00:00:00 2001 From: vedasjad <96325125+vedasjad@users.noreply.github.com> Date: Sat, 16 Dec 2023 13:06:41 +0530 Subject: [PATCH] Delete word by word after 3 seconds have passed since pressed --- lib/src/default_emoji_picker_view.dart | 41 ++++++++++++++++++-- lib/src/emoji_picker.dart | 52 ++++++++++++++++++++++++++ lib/src/emoji_view_state.dart | 4 ++ 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/lib/src/default_emoji_picker_view.dart b/lib/src/default_emoji_picker_view.dart index df14486..88019db 100644 --- a/lib/src/default_emoji_picker_view.dart +++ b/lib/src/default_emoji_picker_view.dart @@ -211,15 +211,48 @@ class _DefaultEmojiPickerViewState extends State closeSkinToneOverlay(); } + /// Start the callback for long-pressing the backspace button. void _startOnBackspacePressedCallback() { - const callbackInterval = Duration(milliseconds: 75); + // Initial callback interval for short presses + var callbackInterval = const Duration(milliseconds: 75); + var millisecondsSincePressed = 0; + + // Callback function executed on each timer tick + void _callback(Timer timer) { + // Accumulate elapsed time since the last tick + millisecondsSincePressed += callbackInterval.inMilliseconds; + + // If the long-press duration exceeds 3 seconds + if (millisecondsSincePressed > 3000 && + callbackInterval == const Duration(milliseconds: 75)) { + // Switch to a longer callback interval for word-by-word deletion + callbackInterval = const Duration(milliseconds: 300); + + // Cancel the existing timer and start a new one with the updated interval + _onBackspacePressedCallbackTimer?.cancel(); + _onBackspacePressedCallbackTimer = + Timer.periodic(callbackInterval, _callback); + + // Reset the elapsed time for the new interval + millisecondsSincePressed = 0; + } + + // Trigger the appropriate callback based on the interval + if (callbackInterval == const Duration(milliseconds: 75)) { + widget.state.onBackspacePressed!(); // Short-press callback + } else { + widget.state.onBackspaceLongPressed(); // Long-press callback + } + } + + // Start the initial timer with the short-press interval _onBackspacePressedCallbackTimer = - Timer.periodic(callbackInterval, (timer) { - widget.state.onBackspacePressed!(); - }); + Timer.periodic(callbackInterval, _callback); } + /// Stop the callback for long-pressing the backspace button. void _stopOnBackspacePressedCallback() { + // Cancel the active timer _onBackspacePressedCallbackTimer?.cancel(); } } diff --git a/lib/src/emoji_picker.dart b/lib/src/emoji_picker.dart index 9adf0b4..ae714a2 100644 --- a/lib/src/emoji_picker.dart +++ b/lib/src/emoji_picker.dart @@ -98,6 +98,9 @@ typedef void OnSkinToneDialogRequested( /// Callback function for backspace button typedef void OnBackspacePressed(); +/// Callback function for backspace button when long pressed +typedef void OnBackspaceLongPressed(); + /// Callback function for custom view typedef EmojiViewBuilder = Widget Function(Config config, EmojiViewState state); @@ -220,6 +223,54 @@ class EmojiPickerState extends State { widget.onBackspacePressed?.call(); } + OnBackspaceLongPressed _onBackspaceLongPressed() { + return () { + if (widget.textEditingController != null) { + final controller = widget.textEditingController!; + + final text = controller.value.text; + var cursorPosition = controller.selection.base.offset; + + // If cursor is not set, then place it at the end of the textfield + if (cursorPosition < 0) { + controller.selection = TextSelection( + baseOffset: controller.text.length, + extentOffset: controller.text.length, + ); + cursorPosition = controller.selection.base.offset; + } + + if (cursorPosition >= 0) { + final selection = controller.value.selection; + final newTextBeforeCursor = _deleteWordByWord( + selection.textBefore(text).toString(), + ); + controller + ..text = newTextBeforeCursor + selection.textAfter(text) + ..selection = TextSelection.fromPosition( + TextPosition(offset: newTextBeforeCursor.length), + ); + } + } + }; + } + + String _deleteWordByWord(String text) { + // Trim trailing spaces + text = text.trimRight(); + + // Find the last space to determine the start of the last word + final lastSpaceIndex = text.lastIndexOf(' '); + + // If there is a space, remove the last word and spaces before it + if (lastSpaceIndex != -1) { + return text.substring(0, lastSpaceIndex).trimRight(); + } + + // If there is no space, remove the entire text + return ''; + } + // Add recent emoji handling to tap listener OnEmojiSelected _getOnEmojiListener() { return (category, emoji) { @@ -290,6 +341,7 @@ class EmojiPickerState extends State { _categoryEmoji, _getOnEmojiListener(), widget.onBackspacePressed == null ? null : _onBackspacePressed, + _onBackspaceLongPressed(), ); if (mounted) { setState(() { diff --git a/lib/src/emoji_view_state.dart b/lib/src/emoji_view_state.dart index 3405167..36ba999 100644 --- a/lib/src/emoji_view_state.dart +++ b/lib/src/emoji_view_state.dart @@ -7,6 +7,7 @@ class EmojiViewState { this.categoryEmoji, this.onEmojiSelected, this.onBackspacePressed, + this.onBackspaceLongPressed, ); /// List of all category including their emoji @@ -17,4 +18,7 @@ class EmojiViewState { /// Callback when pressed on backspace final OnBackspacePressed? onBackspacePressed; + + /// Callback when long pressed on backspace + final OnBackspaceLongPressed onBackspaceLongPressed; }