Skip to content

Commit 9ada96f

Browse files
committed
Add debounce click to prevent double navigations
1 parent 0dabe0d commit 9ada96f

4 files changed

Lines changed: 44 additions & 10 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.linuxcommandlibrary.app.ui.composables
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.mutableStateOf
7+
import androidx.compose.runtime.remember
8+
import androidx.compose.runtime.setValue
9+
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.composed
11+
import kotlin.time.Duration
12+
import kotlin.time.Duration.Companion.milliseconds
13+
import kotlin.time.TimeMark
14+
import kotlin.time.TimeSource
15+
16+
@Composable
17+
fun rememberDebouncedClick(
18+
debounceTime: Duration = 300.milliseconds,
19+
onClick: () -> Unit,
20+
): () -> Unit {
21+
var lastClickMark by remember { mutableStateOf<TimeMark?>(null) }
22+
return {
23+
val last = lastClickMark
24+
if (last == null || last.elapsedNow() >= debounceTime) {
25+
lastClickMark = TimeSource.Monotonic.markNow()
26+
onClick()
27+
}
28+
}
29+
}
30+
31+
fun Modifier.debouncedClickable(
32+
debounceTime: Duration = 300.milliseconds,
33+
onClick: () -> Unit,
34+
): Modifier = composed {
35+
clickable(onClick = rememberDebouncedClick(debounceTime, onClick))
36+
}

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/screens/basiccategories/BasicCategoriesScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.linuxcommandlibrary.app.ui.screens.basiccategories
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.clickable
54
import androidx.compose.foundation.layout.fillMaxSize
65
import androidx.compose.foundation.layout.size
76
import androidx.compose.foundation.lazy.grid.GridCells
@@ -20,6 +19,7 @@ import androidx.compose.ui.input.pointer.pointerHoverIcon
2019
import androidx.compose.ui.unit.dp
2120
import com.linuxcommandlibrary.app.NavEvent
2221
import com.linuxcommandlibrary.app.ui.composables.AppIcon
22+
import com.linuxcommandlibrary.app.ui.composables.debouncedClickable
2323
import com.linuxcommandlibrary.app.ui.composables.getIconId
2424
import com.linuxcommandlibrary.app.ui.composables.rememberIconPainter
2525
import com.linuxcommandlibrary.app.ui.theme.LocalCustomColors
@@ -54,7 +54,7 @@ fun BasicCategoriesScreen(
5454
},
5555
modifier = Modifier
5656
.pointerHoverIcon(PointerIcon.Hand)
57-
.clickable {
57+
.debouncedClickable {
5858
onNavigate(
5959
NavEvent.ToBasicGroups(basicCategory.id, basicCategory.title),
6060
)

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/screens/commanddetail/CommandDetailScreen.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.compose.ui.unit.sp
3030
import com.linuxcommandlibrary.app.NavEvent
3131
import com.linuxcommandlibrary.app.data.CommandSectionInfo
3232
import com.linuxcommandlibrary.app.ui.composables.TipSectionContent
33+
import com.linuxcommandlibrary.app.ui.composables.rememberDebouncedClick
3334
import com.linuxcommandlibrary.app.ui.theme.LocalCustomColors
3435
import com.linuxcommandlibrary.shared.MarkdownParser
3536
import kotlinx.collections.immutable.ImmutableList
@@ -112,7 +113,7 @@ private fun SeeAlsoSectionContent(
112113
seeAlsoCommands.forEach { name ->
113114
SuggestionChip(
114115
modifier = Modifier.pointerHoverIcon(PointerIcon.Hand),
115-
onClick = {
116+
onClick = rememberDebouncedClick {
116117
onNavigate(NavEvent.ToCommand(name))
117118
},
118119
label = {

composeApp/src/commonMain/kotlin/com/linuxcommandlibrary/app/ui/screens/commandlist/CommandListScreen.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.linuxcommandlibrary.app.ui.screens.commandlist
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.clickable
54
import androidx.compose.foundation.layout.Box
65
import androidx.compose.foundation.layout.fillMaxSize
76
import androidx.compose.foundation.lazy.LazyColumn
@@ -13,7 +12,6 @@ import androidx.compose.material3.MaterialTheme
1312
import androidx.compose.runtime.Composable
1413
import androidx.compose.runtime.collectAsState
1514
import androidx.compose.runtime.getValue
16-
import androidx.compose.runtime.remember
1715
import androidx.compose.ui.Alignment
1816
import androidx.compose.ui.Modifier
1917
import androidx.compose.ui.input.pointer.PointerIcon
@@ -23,6 +21,7 @@ import com.linuxcommandlibrary.app.data.CommandInfo
2321
import com.linuxcommandlibrary.app.ui.composables.AppIcon
2422
import com.linuxcommandlibrary.app.ui.composables.FastScrollBar
2523
import com.linuxcommandlibrary.app.ui.composables.HighlightedText
24+
import com.linuxcommandlibrary.app.ui.composables.debouncedClickable
2625
import com.linuxcommandlibrary.app.ui.composables.rememberIconPainter
2726
import com.linuxcommandlibrary.app.ui.theme.LocalCustomColors
2827

@@ -93,10 +92,8 @@ fun CommandListItem(
9392
},
9493
modifier = Modifier
9594
.pointerHoverIcon(PointerIcon.Hand)
96-
.clickable(
97-
onClick = remember(command.name, onNavigate) {
98-
{ onNavigate(NavEvent.ToCommand(command.name)) }
99-
},
100-
),
95+
.debouncedClickable {
96+
onNavigate(NavEvent.ToCommand(command.name))
97+
},
10198
)
10299
}

0 commit comments

Comments
 (0)