diff --git a/app/src/main/java/com/starry/greenstash/ui/screens/input/InputViewModel.kt b/app/src/main/java/com/starry/greenstash/ui/screens/input/InputViewModel.kt index c184f0db..471cbbae 100644 --- a/app/src/main/java/com/starry/greenstash/ui/screens/input/InputViewModel.kt +++ b/app/src/main/java/com/starry/greenstash/ui/screens/input/InputViewModel.kt @@ -66,7 +66,7 @@ data class IconsState( val icons: List> = emptyList(), val currentIcon: IconItem? = null, val selectedIcon: IconItem? = null, - val loading: Boolean = true + val isLoading: Boolean = true ) data class InputScreenState( @@ -194,7 +194,7 @@ class InputViewModel @Inject constructor( delay(400) withContext(Dispatchers.Main) { - _iconState.value = _iconState.value.copy(loading = true) + _iconState.value = _iconState.value.copy(isLoading = true) } val icons = getNamesIcons(context) @@ -204,7 +204,7 @@ class InputViewModel @Inject constructor( val chunks = icons.chunked(3) withContext(Dispatchers.Main) { - _iconState.value = _iconState.value.copy(icons = chunks, loading = false) + _iconState.value = _iconState.value.copy(icons = chunks, isLoading = false) } } } diff --git a/app/src/main/java/com/starry/greenstash/ui/screens/input/composables/IconPickerDialog.kt b/app/src/main/java/com/starry/greenstash/ui/screens/input/composables/IconPickerDialog.kt index 60b002d1..9aca5f17 100644 --- a/app/src/main/java/com/starry/greenstash/ui/screens/input/composables/IconPickerDialog.kt +++ b/app/src/main/java/com/starry/greenstash/ui/screens/input/composables/IconPickerDialog.kt @@ -32,7 +32,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -44,38 +43,45 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Image +import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog import com.starry.greenstash.R import com.starry.greenstash.ui.screens.input.IconItem import com.starry.greenstash.ui.screens.input.IconsState import com.starry.greenstash.ui.screens.input.InputViewModel import com.starry.greenstash.ui.theme.greenstashFont +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +@OptIn(ExperimentalMaterial3Api::class) @Composable fun IconPickerDialog( viewModel: InputViewModel, @@ -89,9 +95,19 @@ fun IconPickerDialog( viewModel.updateIconSearch(context = context, search = "") } + val sheetState = rememberModalBottomSheetState() + val coroutineScope = rememberCoroutineScope() + if (showDialog.value) { - Dialog( - onDismissRequest = {} + ModalBottomSheet( + sheetState = sheetState, + onDismissRequest = { + coroutineScope.launch { + sheetState.hide() + delay(300) + showDialog.value = false + } + } ) { Column( modifier = Modifier.fillMaxWidth(0.99f) @@ -116,9 +132,9 @@ fun IconPickerDialog( } ) - Spacer(modifier = Modifier.height(10.dp)) + Spacer(modifier = Modifier.height(18.dp)) - IconsList( + IconsGirdList( iconState = state, onIconClick = { viewModel.updateCurrentIcon(it) } ) @@ -130,11 +146,16 @@ fun IconPickerDialog( ) { Spacer(modifier = Modifier.weight(1f)) + // Cancel button TextButton(onClick = { if (viewModel.iconState.value.searchText.isNotEmpty()) { viewModel.updateIconSearch(context = context, search = "") } else { - showDialog.value = false + coroutineScope.launch { + sheetState.hide() + delay(300) + showDialog.value = false + } } }) { Text( @@ -145,9 +166,14 @@ fun IconPickerDialog( Spacer(modifier = Modifier.width(10.dp)) + // Confirm button Button(onClick = { onIconSelected(state.currentIcon) - showDialog.value = false + coroutineScope.launch { + sheetState.hide() + delay(300) + showDialog.value = false + } }) { Text( text = stringResource(id = R.string.confirm), @@ -155,6 +181,8 @@ fun IconPickerDialog( ) } } + + Spacer(modifier = Modifier.height(10.dp)) } } } @@ -169,74 +197,78 @@ private fun SearchTextField( viewModel: InputViewModel, onSearchChanged: (String) -> Unit ) { - - Text( - modifier = Modifier.padding(12.dp), - text = stringResource(id = R.string.input_icon_dialog), - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.SemiBold, - fontFamily = greenstashFont, - fontSize = 20.sp - ) - OutlinedTextField( - modifier = Modifier.height(60.dp), + modifier = Modifier.fillMaxWidth(0.9f), label = { Text( text = stringResource(id = R.string.home_search_label), - color = MaterialTheme.colorScheme.primary, fontFamily = greenstashFont ) }, value = viewModel.iconState.value.searchText, onValueChange = { onSearchChanged(it) }, colors = OutlinedTextFieldDefaults.colors( - unfocusedBorderColor = MaterialTheme.colorScheme.primary, - unfocusedTextColor = MaterialTheme.colorScheme.primary, - focusedTextColor = MaterialTheme.colorScheme.primary + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(4.dp), + disabledContainerColor = Color.Transparent, + cursorColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f), + focusedBorderColor = MaterialTheme.colorScheme.primary, + unfocusedBorderColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f), ), trailingIcon = { Icon( - Icons.Filled.Image, "Image", - tint = MaterialTheme.colorScheme.primary + Icons.Filled.Search, stringResource(id = R.string.home_search_label), ) }, maxLines = 1, - shape = RoundedCornerShape(16.dp) + shape = RoundedCornerShape(24.dp) ) } @Composable -private fun IconsList( +private fun IconsGirdList( iconState: IconsState, onIconClick: (IconItem) -> Unit ) { - val icons = iconState.icons Column( - modifier = Modifier.fillMaxHeight(0.4f), horizontalAlignment = Alignment.CenterHorizontally ) { - if (iconState.loading) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } - } else { - LazyColumn { - items( - items = icons, - itemContent = { iconItems -> - IconListRow( - icons = iconItems, - selectedIcon = iconState.currentIcon, - onClick = { onIconClick(it) } - ) - } - ) + Card( + modifier = Modifier + .fillMaxWidth(0.9f) + .height(180.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(4.dp) + ), + shape = RoundedCornerShape(16.dp) + ) { + if (iconState.isLoading) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } else { + val icons = iconState.icons + LazyColumn(modifier = Modifier.padding(8.dp)) { + items( + items = icons, + itemContent = { iconItems -> + IconListRow( + icons = iconItems, + selectedIcon = iconState.currentIcon, + onClick = { onIconClick(it) } + ) + } + ) + } } } } } + @Composable private fun IconListRow( icons: List, diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ef240249..2bbee7ad 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -109,7 +109,6 @@ Selecciona ícono para tu objetivo. …O si el minimalismo es tu estilo, agrega un icono para tu objetivo. Los iconos de objetivo se usarán en las tarjetas de objetivo con estilo compacto, Configuración > Estilo de Tarjeta de Objetivo - Selecciona un ícono Imagen de la meta ¡Agrega imágenes a tus objetivos para darles un aspecto personalizado! Haz clic en el botón de acción flotante para agregar una imagen a tu objetivo. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index f518c071..e9526707 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -110,7 +110,6 @@ Hedefiniz için bir simge seçin. …Ya da minimalizm tarzınızsa, hedefiniz için bir simge ekleyin. Hedef simgeleri, kompakt stil hedef kartlarında kullanılacaktır, Ayarlar > Hedef Kartı Stili - Bir simge seçin Hedef Resmi Hedeflerinize kişisel bir görünüm kazandırmak için resimler ekleyin! Hedefinize bir resim eklemek için hareketli işlem düğmesine tıklayın. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 46821fb2..f5910df0 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -109,7 +109,6 @@ 为您的目标选择一个图标。 …或者如果简约风格是您的风格,请为您的目标添加图标。 目标图标将用于紧凑样式的目标卡上,设置 > 目标卡样式 - 选择图标 目标图片 为您的目标添加图片,赋予它们个性化的外观! 点击浮动操作按钮为您的目标添加图片。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 58129e2e..44d8543a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -109,7 +109,6 @@ 為您的目標選擇一個圖示。 …或者如果您喜歡簡約樣式,為您的目標新增一個圖示。 目標圖示將用於緊湊型目標卡片,設定 > 目標卡片樣式 - 選擇一個圖示 目標圖片 為您的目標新增圖片,讓它們看起來更個性化! 點選浮動動作按鈕以為您的目標新增圖片。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4af8d97..fafd4e87 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -109,7 +109,6 @@ Select icon for your goal. …Or if minimalism is your style, add an icon for your goal. Goal icons will be used on compact syled goal cards, Settings > Goal Card Style - Select an icon Goal Image Add images to your goals to give them a personalized look! Click on the floating action button to add an image to your goal.