From 0a33bd734d45d7f0ea64078ee28bd91c38947718 Mon Sep 17 00:00:00 2001 From: Mohamad Hamade Date: Mon, 14 Jul 2025 22:16:19 +0300 Subject: [PATCH 1/2] Bugfix: Handled single or triple clicked at once instead of executing them as separate events This commit introduces a new `singleOrTripleClickable` Modifier extension function. This function allows distinguishing between single and triple clicks on a Composable element. The `ChatHeader` was updated to utilize this new Modifier for handling clicks on the "bitchat*" title, where a single click shows app info and a triple click triggers a separate action. --- .../android/core/ui/utils/ModifierExt.kt | 57 +++++++++++++++++++ .../java/com/bitchat/android/ui/ChatHeader.kt | 18 +++--- 2 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/bitchat/android/core/ui/utils/ModifierExt.kt diff --git a/app/src/main/java/com/bitchat/android/core/ui/utils/ModifierExt.kt b/app/src/main/java/com/bitchat/android/core/ui/utils/ModifierExt.kt new file mode 100644 index 00000000..19dabb57 --- /dev/null +++ b/app/src/main/java/com/bitchat/android/core/ui/utils/ModifierExt.kt @@ -0,0 +1,57 @@ +package com.bitchat.android.core.ui.utils + +import androidx.compose.foundation.clickable +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +fun Modifier.singleOrTripleClickable( + onSingleClick: () -> Unit, + onTripleClick: () -> Unit, + clickTimeThreshold: Long = 300L +): Modifier = composed { + var tapCount by remember { mutableIntStateOf(0) } + var lastTapTime by remember { mutableLongStateOf(0L) } + var singleClickJob by remember { mutableStateOf(null) } + val coroutineScope = rememberCoroutineScope() + + this.clickable { + val currentTime = System.currentTimeMillis() + + if (currentTime - lastTapTime < clickTimeThreshold) { + tapCount++ + } else { + tapCount = 1 + } + + lastTapTime = currentTime + + // Cancel any pending single click action + singleClickJob?.cancel() + singleClickJob = null + + when (tapCount) { + 1 -> { + // Wait to see if more taps come + singleClickJob = coroutineScope.launch { + delay(clickTimeThreshold) + if (tapCount == 1) { + onSingleClick() + } + } + } + 3 -> { + // Triple click detected - execute immediately + onTripleClick() + tapCount = 0 + } + } + + // Reset after threshold if no triple click + if (tapCount > 3) { + tapCount = 0 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt index 65e2ee8e..1b9fd098 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.bitchat.android.core.ui.utils.singleOrTripleClickable /** * Header components for ChatScreen @@ -181,15 +182,8 @@ fun ChatHeaderContent( MainHeader( nickname = nickname, onNicknameChange = viewModel::setNickname, - onTitleClick = { - tripleClickCount++ - if (tripleClickCount >= 3) { - tripleClickCount = 0 - onTripleClick() - } else { - onShowAppInfo() - } - }, + onTitleClick = onShowAppInfo, + onTripleTitleClick = onTripleClick, onSidebarClick = onSidebarClick, viewModel = viewModel ) @@ -345,6 +339,7 @@ private fun MainHeader( nickname: String, onNicknameChange: (String) -> Unit, onTitleClick: () -> Unit, + onTripleTitleClick: () -> Unit, onSidebarClick: () -> Unit, viewModel: ChatViewModel ) { @@ -365,7 +360,10 @@ private fun MainHeader( text = "bitchat*", style = MaterialTheme.typography.headlineSmall, color = colorScheme.primary, - modifier = Modifier.clickable { onTitleClick() } + modifier = Modifier.singleOrTripleClickable( + onSingleClick = onTitleClick, + onTripleClick = onTripleTitleClick + ) ) Spacer(modifier = Modifier.width(8.dp)) From 17472a18541e4ffcdc844458132cbb2a429c26c1 Mon Sep 17 00:00:00 2001 From: Mohamad Hamade Date: Tue, 15 Jul 2025 13:18:29 +0300 Subject: [PATCH 2/2] Refactor: Remove unused tripleClickCount state variable The `tripleClickCount` mutable state variable in the `ChatHeader` composable was not being used and has been removed to simplify the code --- app/src/main/java/com/bitchat/android/ui/ChatHeader.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt index 1b9fd098..ee9c699d 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatHeader.kt @@ -149,8 +149,7 @@ fun ChatHeaderContent( onShowAppInfo: () -> Unit ) { val colorScheme = MaterialTheme.colorScheme - var tripleClickCount by remember { mutableStateOf(0) } - + when { selectedPrivatePeer != null -> { // Private chat header - ensure state synchronization