diff --git a/app/src/main/java/com/auth0/android/sample/ui/components/SampleTopBar.kt b/app/src/main/java/com/auth0/android/sample/ui/components/SampleTopBar.kt index 3fadb3d..7d81a1c 100644 --- a/app/src/main/java/com/auth0/android/sample/ui/components/SampleTopBar.kt +++ b/app/src/main/java/com/auth0/android/sample/ui/components/SampleTopBar.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp +import com.auth0.android.sample.ui.util.rememberDebouncedOnClick import com.auth0.universalcomponents.theme.Auth0Theme @OptIn(ExperimentalMaterial3Api::class) @@ -50,7 +51,8 @@ fun SampleTopBar( }, navigationIcon = { if (showBackNavigation) { - IconButton(onClick = onBackClick) { + val debouncedOnBackClick = rememberDebouncedOnClick(onClick = onBackClick) + IconButton(onClick = debouncedOnBackClick) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Navigate back", diff --git a/app/src/main/java/com/auth0/android/sample/ui/screens/EmbeddedLoginScreen.kt b/app/src/main/java/com/auth0/android/sample/ui/screens/EmbeddedLoginScreen.kt index aa6514d..f91c89d 100644 --- a/app/src/main/java/com/auth0/android/sample/ui/screens/EmbeddedLoginScreen.kt +++ b/app/src/main/java/com/auth0/android/sample/ui/screens/EmbeddedLoginScreen.kt @@ -41,6 +41,7 @@ import com.auth0.android.sample.ui.components.OrDivider import com.auth0.android.sample.ui.theme.auth0ScreenBackground import com.auth0.android.sample.ui.theme.isAuth0DarkTheme import com.auth0.android.sample.ui.components.SampleGradientButton +import com.auth0.android.sample.ui.util.rememberDebouncedOnClick import com.auth0.universalcomponents.theme.Auth0Theme /** @@ -82,7 +83,8 @@ fun EmbeddedLoginScreen( horizontalAlignment = Alignment.CenterHorizontally ) { Row(modifier = Modifier.fillMaxWidth()) { - IconButton(onClick = onBack) { + val debouncedOnBack = rememberDebouncedOnClick(onClick = onBack) + IconButton(onClick = debouncedOnBack) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back", diff --git a/app/src/main/java/com/auth0/android/sample/ui/util/ClickDebounce.kt b/app/src/main/java/com/auth0/android/sample/ui/util/ClickDebounce.kt new file mode 100644 index 0000000..298e3ed --- /dev/null +++ b/app/src/main/java/com/auth0/android/sample/ui/util/ClickDebounce.kt @@ -0,0 +1,30 @@ +package com.auth0.android.sample.ui.util + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState + +/** + * Wraps [onClick] so it fires at most once per [windowMs]. Compose can dispatch several queued taps + * within the same frame, before recomposition removes the composable; for back navigation that + * over-pops past the start destination and leaves an empty NavHost (blank screen). Letting only the + * first tap of a burst through avoids that. + */ +@Composable +internal fun rememberDebouncedOnClick( + windowMs: Long = 500L, + onClick: () -> Unit +): () -> Unit { + val latestOnClick by rememberUpdatedState(onClick) + return remember(windowMs) { + var lastClickMs = 0L + { + val now = System.currentTimeMillis() + if (now - lastClickMs >= windowMs) { + lastClickMs = now + latestOnClick() + } + } + } +}