From b5058611127eaa4ac7ddd3cbd85370f73395b134 Mon Sep 17 00:00:00 2001 From: Asjad Date: Thu, 25 Jan 2024 19:38:40 +0530 Subject: [PATCH] Backspace onLongPress callback added (#178) --- lib/src/default_emoji_picker_view.dart | 60 ++++++++++++++++++++++++-- lib/src/emoji_picker.dart | 52 ++++++++++++++++++++++ lib/src/emoji_view_state.dart | 4 ++ 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/lib/src/default_emoji_picker_view.dart b/lib/src/default_emoji_picker_view.dart index 7d3fcc8..71c7ef6 100644 --- a/lib/src/default_emoji_picker_view.dart +++ b/lib/src/default_emoji_picker_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; import 'package:emoji_picker_flutter/src/skin_tone_overlay.dart'; import 'package:flutter/material.dart'; @@ -15,6 +17,7 @@ class DefaultEmojiPickerView extends EmojiPickerBuilder { class _DefaultEmojiPickerViewState extends State with SingleTickerProviderStateMixin, SkinToneOverlayStateMixin { final double _tabBarHeight = 46; + Timer? _onBackspacePressedCallbackTimer; late PageController _pageController; late TabController _tabController; @@ -45,6 +48,7 @@ class _DefaultEmojiPickerViewState extends State _pageController.dispose(); _tabController.dispose(); _scrollController.dispose(); + _onBackspacePressedCallbackTimer?.cancel(); super.dispose(); } @@ -112,15 +116,18 @@ class _DefaultEmojiPickerViewState extends State if (widget.state.onBackspacePressed != null) { return Material( type: MaterialType.transparency, - child: IconButton( + child: GestureDetector( + onLongPressStart: (_) => _startOnBackspacePressedCallback(), + onLongPressEnd: (_) => _stopOnBackspacePressedCallback(), + child: IconButton( padding: const EdgeInsets.only(bottom: 2), icon: Icon( Icons.backspace, color: widget.config.backspaceColor, ), - onPressed: () { - widget.state.onBackspacePressed!(); - }), + onPressed: () => widget.state.onBackspacePressed!(), + ), + ), ); } return const SizedBox.shrink(); @@ -203,4 +210,49 @@ class _DefaultEmojiPickerViewState extends State widget.state.onEmojiSelected(category, emoji); closeSkinToneOverlay(); } + + /// Start the callback for long-pressing the backspace button. + void _startOnBackspacePressedCallback() { + // 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); + + // Restart the timer 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, _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 140e576..20a4a57 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); @@ -230,6 +233,54 @@ class EmojiPickerState extends State { } } + 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) { @@ -305,6 +356,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; }