Skip to content

Commit

Permalink
Improve UI of icon picker dialog
Browse files Browse the repository at this point in the history
Signed-off-by: starry-shivam <[email protected]>
  • Loading branch information
starry-shivam committed Apr 27, 2024
1 parent 8d57c93 commit 8b41c10
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ data class IconsState(
val icons: List<List<IconItem>> = emptyList(),
val currentIcon: IconItem? = null,
val selectedIcon: IconItem? = null,
val loading: Boolean = true
val isLoading: Boolean = true
)

data class InputScreenState(
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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)
Expand All @@ -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) }
)
Expand All @@ -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(
Expand All @@ -145,16 +166,23 @@ 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),
fontFamily = greenstashFont,
)
}
}

Spacer(modifier = Modifier.height(10.dp))
}
}
}
Expand All @@ -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<IconItem>,
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
<string name="input_pick_icon">Selecciona ícono para tu objetivo.</string>
<string name="input_pick_icon_onboarding_title">…O si el minimalismo es tu estilo, agrega un icono para tu objetivo.</string>
<string name="input_pick_icon_onboarding_desc">Los iconos de objetivo se usarán en las tarjetas de objetivo con estilo compacto, Configuración > Estilo de Tarjeta de Objetivo</string>
<string name="input_icon_dialog">Selecciona un ícono</string>
<string name="input_pick_image_fab">Imagen de la meta</string>
<string name="input_pick_image_onboarding_title">¡Agrega imágenes a tus objetivos para darles un aspecto personalizado!</string>
<string name="input_pick_image_onboarding_desc">Haz clic en el botón de acción flotante para agregar una imagen a tu objetivo.</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@
<string name="input_pick_icon">Hedefiniz için bir simge seçin.</string>
<string name="input_pick_icon_onboarding_title">…Ya da minimalizm tarzınızsa, hedefiniz için bir simge ekleyin.</string>
<string name="input_pick_icon_onboarding_desc">Hedef simgeleri, kompakt stil hedef kartlarında kullanılacaktır, Ayarlar > Hedef Kartı Stili</string>
<string name="input_icon_dialog">Bir simge seçin</string>
<string name="input_pick_image_fab">Hedef Resmi</string>
<string name="input_pick_image_onboarding_title">Hedeflerinize kişisel bir görünüm kazandırmak için resimler ekleyin!</string>
<string name="input_pick_image_onboarding_desc">Hedefinize bir resim eklemek için hareketli işlem düğmesine tıklayın.</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
<string name="input_pick_icon">为您的目标选择一个图标。</string>
<string name="input_pick_icon_onboarding_title">…或者如果简约风格是您的风格,请为您的目标添加图标。</string>
<string name="input_pick_icon_onboarding_desc">目标图标将用于紧凑样式的目标卡上,设置 > 目标卡样式</string>
<string name="input_icon_dialog">选择图标</string>
<string name="input_pick_image_fab">目标图片</string>
<string name="input_pick_image_onboarding_title">为您的目标添加图片,赋予它们个性化的外观!</string>
<string name="input_pick_image_onboarding_desc">点击浮动操作按钮为您的目标添加图片。</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values-zh-rTW/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
<string name="input_pick_icon">為您的目標選擇一個圖示。</string>
<string name="input_pick_icon_onboarding_title">…或者如果您喜歡簡約樣式,為您的目標新增一個圖示。</string>
<string name="input_pick_icon_onboarding_desc">目標圖示將用於緊湊型目標卡片,設定 > 目標卡片樣式</string>
<string name="input_icon_dialog">選擇一個圖示</string>
<string name="input_pick_image_fab">目標圖片</string>
<string name="input_pick_image_onboarding_title">為您的目標新增圖片,讓它們看起來更個性化!</string>
<string name="input_pick_image_onboarding_desc">點選浮動動作按鈕以為您的目標新增圖片。</string>
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
<string name="input_pick_icon">Select icon for your goal.</string>
<string name="input_pick_icon_onboarding_title">…Or if minimalism is your style, add an icon for your goal.</string>
<string name="input_pick_icon_onboarding_desc">Goal icons will be used on compact syled goal cards, Settings > Goal Card Style</string>
<string name="input_icon_dialog">Select an icon</string>
<string name="input_pick_image_fab">Goal Image</string>
<string name="input_pick_image_onboarding_title">Add images to your goals to give them a personalized look!</string>
<string name="input_pick_image_onboarding_desc">Click on the floating action button to add an image to your goal.</string>
Expand Down

0 comments on commit 8b41c10

Please sign in to comment.