I've been experimenting a bit with the new Jetpack Compose for the last few days and it's been great but now I'm stuck on something that should be quite simple. All I want to do is from a LazyColumn (RecyclerView) show an AlertDialog when the user clicks (or long presses) an item in the list AND pass the clicked item as an argument to the AlertDialog. I've managed to do it without passing any arguments and just showing an AlertDialog with preset info. It also works fine to show a Toast message with the clicked item. Here is my code (it is basically the same as the Rally app from the compose-samples on GitHub):
@ExperimentalFoundationApi
@Composable
fun AccountsBody(navController: NavController, viewModel: AccountsViewModel) {
val accountsFromVM = viewModel.accounts.observeAsState()
accountsFromVM.value?.let { accounts ->
StatementBody(
items = accounts, // this is important for the question
// NOT IMPORTANT
amounts = { account -> account.balance },
colors = { account -> HexToColor.getColor(account.colorHEX) },
amountsTotal = accounts.map { account -> account.balance }.sum(),
circleLabel = stringResource(R.string.total),
buttonLabel = DialogScreen.NewAccount.route,
navController = navController,
onLongPress = { } // show alert
) { account, _ -> // this is important for the question
AccountRow(
name = account.name,
bank = account.bank,
amount = account.balance,
color = HexToColor.getColor(account.colorHEX),
account = account,
onClick = { },
onlongPress = { clickedItem ->
// Show alert dialog here and pass in clickedItem
}
)
}
}
}
@Composable
fun <T> StatementBody(
items: List<T>,
// NOT IMPORTANT
colors: (T) -> Color,
amounts: (T) -> Float,
amountsTotal: Float,
circleLabel: String,
buttonLabel: String,
navController: NavController,
onLongPress: (T) -> Unit,
rows: @Composable (T, (T) -> Unit) -> Unit
) {
Column {
// Animating circle and balance box
// NOT IMPORTANT - (see last few rows for the important part)
Box(Modifier.padding(16.dp)) {
val accountsProportion = items.extractProportions { amounts(it).absoluteValue }
val circleColors = items.map { colors(it) }
AnimatedCircle(
accountsProportion,
circleColors,
Modifier
.height(300.dp)
.align(Alignment.Center)
.fillMaxWidth()
)
Column(modifier = Modifier.align(Alignment.Center)) {
Text(
text = circleLabel,
style = MaterialTheme.typography.body1,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
text = formatAmount(amountsTotal),
style = MaterialTheme.typography.h2,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Button(onClick = { navController.navigate("${buttonLabel}/Nytt sparkonto") }) {
Text(text = buttonLabel)
}
}
}
Spacer(Modifier.height(10.dp))
// Recycler view
// THIS IS THE IMPORTANT PART
Card {
LazyColumn(modifier = Modifier.padding(12.dp)) {
itemsIndexed(items) { idx, item ->
rows(item, onLongPress) // rows is the Composable you pass in
}
}
}
}
}
@ExperimentalFoundationApi
@Composable
fun AccountRow(
name: String,
bank: String,
amount: Float,
color: Color,
account: AccountData,
onClick: () -> Unit,
onlongPress: (AccountData) -> Unit
) {
BaseRow(
color = color,
title = name,
subtitle = bank,
amount = amount,
rowType = account,
onClick = onClick,
onLongPress = onlongPress
)
}
@ExperimentalFoundationApi
@Composable
private fun <T> BaseRow(
color: Color,
title: String,
subtitle: String,
amount: Float,
rowType: T,
onClick: () -> Unit,
onLongPress: (T) -> Unit
) {
val formattedAmount = formatAmount(amount)
Row(
modifier = Modifier
.height(68.dp)
.combinedClickable(
onClick = onClick,
onLongClick = { onLongPress(rowType) } //HERE IS THE IMPORTANT PART
),
verticalAlignment = Alignment.CenterVertically
) {
val typography = MaterialTheme.typography
AccountIndicator(color = color, modifier = Modifier)
Spacer(Modifier.width(12.dp))
Column(Modifier) {
Text(text = title, style = typography.body1)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(text = subtitle, style = typography.subtitle1)
}
}
Spacer(Modifier.weight(1f))
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Text(
text = "$formattedAmount kr",
style = typography.h6,
modifier = Modifier.align(Alignment.CenterVertically)
)
}
Spacer(Modifier.width(16.dp))
}
RallyDivider()
}
Any help on how to accomplish this would be appreciated. I'm kind of new to android development and programming in general so I have probably made this more complex than it has to be heh.
This can be easily done by saving the selected item as a MutableState and whether to show the dialog or not is another MutableState.
Here is simplified example that could work as a starting point:
val items = emptyList<String>()
val currentSelectedItem = remember { mutableStateOf(items[0]) }
val showDialog = remember { mutableStateOf(false) }
if (showDialog.value) ShowDialog(currentSelectedItem.value)
Card {
LazyColumn(modifier = Modifier.padding(12.dp)) {
itemsIndexed(items) { idx, item ->
Row() {
Text(
text = item,
Modifier.clickable {
currentSelectedItem.value = item
showDialog.value=true
}
)
} // rows is the Composable you pass in
}
}
}