@@ -204,6 +204,12 @@ class SQLiteActivity : ComponentActivity() {
204204 /* * Incremented on each tap that runs SQL. Used to retrigger the detail box's outline shimmer. */
205205 private var runTick by mutableStateOf(0 )
206206
207+ /* * True while a demo or reset is running SQL on a background thread. */
208+ private var dbOperationInFlight by mutableStateOf(false )
209+
210+ /* * True for the duration of a reset; disables the reset button immediately (no debounce). */
211+ private var resetInProgress by mutableStateOf(false )
212+
207213 /* *
208214 * The shared trace used when [shareScreenTrace] is enabled: one trace per visit to this screen.
209215 * onResume() generates a fresh one each time the screen is (re)entered.
@@ -316,7 +322,10 @@ class SQLiteActivity : ComponentActivity() {
316322 )
317323 }
318324
319- ResetButton ()
325+ ResetButton (
326+ dbOperationInFlight = dbOperationInFlight,
327+ resetInProgress = resetInProgress,
328+ )
320329
321330 // Same [CONTROL_SECTION_GAP] above as the other sections, separating the controls from
322331 // the detail output.
@@ -348,12 +357,17 @@ class SQLiteActivity : ComponentActivity() {
348357 runTick++ // shimmer the detail box outline in the integration color
349358
350359 lifecycleScope.launch {
351- latestResult =
352- withContext(Dispatchers .IO ) {
353- runInTransaction(variant.transactionName, variant.op) {
354- SqlStatements .execute(applicationContext, variant.demo, heavyWork)
360+ dbOperationInFlight = true
361+ try {
362+ latestResult =
363+ withContext(Dispatchers .IO ) {
364+ runInTransaction(variant.transactionName, variant.op) {
365+ SqlStatements .execute(applicationContext, variant.demo, heavyWork)
366+ }
355367 }
356- }
368+ } finally {
369+ dbOperationInFlight = false
370+ }
357371 }
358372 }
359373
@@ -488,15 +502,38 @@ class SQLiteActivity : ComponentActivity() {
488502 }
489503
490504 @androidx.compose.runtime.Composable
491- private fun ResetButton () {
505+ private fun ResetButton (dbOperationInFlight : Boolean , resetInProgress : Boolean ) {
506+ // Debounce demo-driven disablement so fast taps don't flicker the button; reset disables
507+ // immediately via [resetInProgress]. [dbOperationInFlight] still guards [onClick] either way.
508+ var enabled by remember { mutableStateOf(true ) }
509+ LaunchedEffect (dbOperationInFlight, resetInProgress) {
510+ when {
511+ resetInProgress -> enabled = false
512+ dbOperationInFlight -> {
513+ delay(RESET_DISABLE_DEBOUNCE_MS )
514+ enabled = false
515+ }
516+ else -> enabled = true
517+ }
518+ }
519+
492520 Button (
493521 modifier = Modifier .fillMaxWidth().padding(top = 8 .dp),
522+ enabled = enabled,
494523 colors = ButtonDefaults .buttonColors(containerColor = Color .Gray , contentColor = Color .White ),
495524 onClick = {
525+ if (dbOperationInFlight) return @Button
496526 lifecycleScope.launch {
497- val message = withContext(Dispatchers .IO ) { resetDatabases() }
498- latestResult = message
499- sqlDetail = " DROP: deletes every demo database file, resetting all row counts to 0."
527+ this @SQLiteActivity.resetInProgress = true
528+ this @SQLiteActivity.dbOperationInFlight = true
529+ try {
530+ val message = withContext(Dispatchers .IO ) { resetDatabases() }
531+ latestResult = message
532+ sqlDetail = " DROP: deletes every demo database file, resetting all row counts to 0."
533+ } finally {
534+ this @SQLiteActivity.dbOperationInFlight = false
535+ this @SQLiteActivity.resetInProgress = false
536+ }
500537 }
501538 },
502539 ) {
@@ -568,6 +605,9 @@ class SQLiteActivity : ComponentActivity() {
568605
569606 private companion object {
570607
608+ /* * Demo SQL shorter than this won't visibly disable the reset button. */
609+ private const val RESET_DISABLE_DEBOUNCE_MS = 300L
610+
571611 /* *
572612 * Builds a fresh sentry-trace header ("<traceId>-<spanId>-<sampled>") representing this screen
573613 * visit's trace. The trailing "-1" marks it sampled so the whole session is kept.
0 commit comments