Coverage Summary for Class: SurferSwipeToDeleteTransactionKt (com.georgeci.moneysurfer.uikit.components.transaction)

Class Class, % Method, % Branch, % Line, % Instruction, %
SurferSwipeToDeleteTransactionKt 100% (1/1) 62.5% (5/8) 38.9% (7/18) 75.8% (25/33) 78.4% (389/496)


 package com.georgeci.moneysurfer.uikit.components.transaction
 
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.georgeci.moneysurfer.uikit.components.base.SurferSwipeAccessibilityAction
 import com.georgeci.moneysurfer.uikit.components.base.SurferSwipeAction
 import com.georgeci.moneysurfer.uikit.components.base.SurferSwipeRevealRow
 import com.georgeci.moneysurfer.uikit.icons.SurferIcons
 import com.georgeci.moneysurfer.uikit.theme.AppTheme
 import moneysurfer.uikit.generated.resources.Res
 import moneysurfer.uikit.generated.resources.uikit_transaction_delete
 import org.jetbrains.compose.resources.stringResource
 
 /**
  * Total swipe travel: one 72dp action button plus the reveal row's 6dp gutters. Narrower than the
  * manage screens' two-action track, because a transaction row reveals only Delete.
  */
 private val REVEAL_WIDTH = 84.dp
 
 /**
  * A transaction row that can be swiped left to delete, with the deletion routed through a
  * confirmation dialog and (via the caller) an Undo snackbar.
  *
  * Two details that are easy to get wrong and are handled here rather than at each call site:
  *
  * - The row is filled with the surface colour. [SurferTransactionLine] draws no background of its
  *   own, so without this the Delete button underneath shows straight through the text as the row
  *   slides.
  * - The gesture is also published as a custom accessibility action, since a horizontal drag is not
  *   something a screen reader user can perform. That is the non-gesture equivalent — no extra
  *   visible affordance is added for it.
  *
  * The confirmation is kept even though an Undo follows it: deleting is confirmed everywhere else
  * in the app, and a swipe is easy enough to trigger by accident while scrolling that the dialog is
  * also what tells a mis-swipe apart from an intent.
  *
  * @param transactionTitle the row's title, shown in the dialog so the user can see which row is
  *   about to go; blank falls back to the dialog's generic wording.
  * @param isTransfer whether the row is one leg of a transfer, which both legs of are deleted
  *   together — the dialog says so.
  * @param isSplit whether the row stands for a receipt split across categories, every leg of which
  *   is deleted together — the dialog says so.
  */
 @Composable
 fun SurferSwipeToDeleteTransaction(
     transactionTitle: String,
     onDelete: () -> Unit,
     modifier: Modifier = Modifier,
     isTransfer: Boolean = false,
     isSplit: Boolean = false,
     content: @Composable () -> Unit,
 ) {
     // Survives configuration changes and process death: the dialog is a question already put to
     // the user, and re-asking it (or worse, dropping it) on rotation loses their place.
     var showConfirmation by rememberSaveable { mutableStateOf(false) }
     val deleteLabel = stringResource(Res.string.uikit_transaction_delete)
 
     SurferSwipeRevealRow(
         revealWidth = REVEAL_WIDTH,
         modifier = modifier,
         accessibilityActions = listOf(
             SurferSwipeAccessibilityAction(label = deleteLabel) { showConfirmation = true },
         ),
         actions = {
             SurferSwipeAction(
                 icon = SurferIcons.Delete,
                 label = deleteLabel,
                 onClick = { showConfirmation = true },
                 destructive = true,
             )
         },
     ) {
         Box(modifier = Modifier.background(AppTheme.materialColors.surface)) {
             content()
         }
     }
 
     if (showConfirmation) {
         SurferDeleteTransactionDialog(
             titleOrNull = transactionTitle.takeIf { it.isNotBlank() },
             onConfirm = {
                 showConfirmation = false
                 onDelete()
             },
             onDismiss = { showConfirmation = false },
             isTransfer = isTransfer,
             isSplit = isSplit,
         )
     }
 }