From 000444e4e3930dba98567c1ef21755e898a399d5 Mon Sep 17 00:00:00 2001 From: Andrea Brighi Date: Tue, 20 Jun 2023 20:09:30 +0200 Subject: [PATCH] feat(app): create ui element LargeDropdownMenu --- .../app/ui/common/LargeDropdownMenu.kt | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 app/src/main/kotlin/com/intelligentbackpack/app/ui/common/LargeDropdownMenu.kt diff --git a/app/src/main/kotlin/com/intelligentbackpack/app/ui/common/LargeDropdownMenu.kt b/app/src/main/kotlin/com/intelligentbackpack/app/ui/common/LargeDropdownMenu.kt new file mode 100644 index 00000000..ab05128a --- /dev/null +++ b/app/src/main/kotlin/com/intelligentbackpack/app/ui/common/LargeDropdownMenu.kt @@ -0,0 +1,152 @@ +package com.intelligentbackpack.app.ui.common + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Divider +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TextFieldDefaults +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.ArrowDropUp +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog + +@Composable +fun LargeDropdownMenu( + modifier: Modifier = Modifier, + enabled: Boolean = true, + label: String, + notSetLabel: String? = null, + items: List, + selectedIndex: Int = -1, + onItemSelected: (index: Int, item: T) -> Unit, + selectedItemToString: (T) -> String = { it.toString() }, + drawItem: @Composable (T, Boolean, Boolean, () -> Unit) -> Unit = { item, _, itemEnabled, onClick -> + LargeDropdownMenuItem( + text = item.toString(), + enabled = itemEnabled, + onClick = onClick, + ) + }, +) { + var expanded by remember { mutableStateOf(false) } + + Box(modifier = modifier.height(IntrinsicSize.Min)) { + OutlinedTextField( + colors = TextFieldDefaults.outlinedTextFieldColors( + backgroundColor = MaterialTheme.colors.background, + trailingIconColor = MaterialTheme.colors.onBackground, + textColor = MaterialTheme.colors.onBackground, + ), + label = { Text(label) }, + value = items.getOrNull(selectedIndex)?.let { selectedItemToString(it) } ?: "", + enabled = enabled, + modifier = Modifier.fillMaxWidth(), + trailingIcon = { + val icon = if (expanded) { + Icons.Filled.ArrowDropUp + } else { + Icons.Filled.ArrowDropDown + } + Icon(icon, "") + }, + onValueChange = { }, + readOnly = true, + ) + + // Transparent clickable surface on top of OutlinedTextField + Surface( + modifier = Modifier + .fillMaxSize() + .padding(top = 8.dp) + .clip(MaterialTheme.shapes.small) + .clickable(enabled = enabled) { expanded = true }, + color = Color.Transparent, + ) {} + } + + if (expanded) { + Dialog( + onDismissRequest = { expanded = false }, + ) { + Surface( + shape = RoundedCornerShape(12.dp), + ) { + val listState = rememberLazyListState() + if (selectedIndex > -1) { + LaunchedEffect("ScrollToSelected") { + listState.scrollToItem(index = selectedIndex) + } + } + + LazyColumn(modifier = Modifier.fillMaxWidth(), state = listState) { + if (notSetLabel != null) { + item { + LargeDropdownMenuItem( + text = notSetLabel, + enabled = false, + onClick = { }, + ) + } + } + itemsIndexed(items) { index, item -> + val selectedItem = index == selectedIndex + drawItem( + item, + selectedItem, + true, + ) { + onItemSelected(index, item) + expanded = false + } + + if (index < items.lastIndex) { + Divider(modifier = Modifier.padding(horizontal = 16.dp)) + } + } + } + } + } + } +} + +@Composable +fun LargeDropdownMenuItem( + text: String, + enabled: Boolean, + onClick: () -> Unit, +) { + Box( + modifier = Modifier + .clickable(enabled) { onClick() } + .fillMaxWidth() + .padding(16.dp), + ) { + Text( + text = text, + style = MaterialTheme.typography.button, + ) + } +}