Skip to content
Snippets Groups Projects
Unverified Commit 073f54aa authored by AC5636's avatar AC5636 :ghost:
Browse files

Minor adjustment to input validation and initial message showing delay

parent c586f91c
No related branches found
No related tags found
No related merge requests found
package com.example.e13roomshoppinglist package com.example.e13roomshoppinglist
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
...@@ -12,6 +13,7 @@ import androidx.compose.runtime.collectAsState ...@@ -12,6 +13,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
...@@ -19,6 +21,10 @@ import androidx.lifecycle.ViewModel ...@@ -19,6 +21,10 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.room.Room import androidx.room.Room
import com.example.e13roomshoppinglist.ui.theme.E13RoomShoppingListTheme import com.example.e13roomshoppinglist.ui.theme.E13RoomShoppingListTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val db by lazy { private val db by lazy {
...@@ -36,6 +42,8 @@ class MainActivity : ComponentActivity() { ...@@ -36,6 +42,8 @@ class MainActivity : ComponentActivity() {
} }
} }
@OptIn(DelicateCoroutinesApi::class)
@SuppressLint("CoroutineCreationDuringComposition")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
...@@ -43,10 +51,14 @@ class MainActivity : ComponentActivity() { ...@@ -43,10 +51,14 @@ class MainActivity : ComponentActivity() {
val state by viewModel.state.collectAsState() val state by viewModel.state.collectAsState()
val ctx = LocalContext.current val ctx = LocalContext.current
var toast by remember { var toast by remember {
mutableStateOf<Toast?>(Toast.makeText(ctx, "Loaded data from room db!", Toast.LENGTH_SHORT)) mutableStateOf<Toast?>(null)
}
var isDataLoadMsgShown by rememberSaveable {
mutableStateOf(false)
} }
val showToast = { msg: String -> val showToast = { msg: String ->
toast?.cancel()
toast = Toast.makeText(ctx, msg, Toast.LENGTH_SHORT) toast = Toast.makeText(ctx, msg, Toast.LENGTH_SHORT)
toast?.show() toast?.show()
} }
...@@ -55,7 +67,25 @@ class MainActivity : ComponentActivity() { ...@@ -55,7 +67,25 @@ class MainActivity : ComponentActivity() {
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background color = MaterialTheme.colorScheme.background
) { ) {
ShoppingListScreen(state = state, onEvent = viewModel::onEvent, onShowToast = showToast) ShoppingListScreen(
state = state,
onEvent = viewModel::onEvent,
onShowToast = showToast
)
if (!isDataLoadMsgShown) {
GlobalScope.launch {
delay(2000)
runOnUiThread {
val itemCount = state.shoppingListItems.count()
if (itemCount == 0) {
showToast("Database is empty!")
} else {
showToast("Loaded $itemCount item${if (itemCount==1) "" else "s"} from database!")
}
isDataLoadMsgShown = true
}
}
}
} }
} }
} }
......
...@@ -38,7 +38,7 @@ data class ShoppingListItem( ...@@ -38,7 +38,7 @@ data class ShoppingListItem(
@Dao @Dao
interface ShoppingListDao{ interface ShoppingListDao{
@Upsert @Upsert
fun upsertShoppingListItem(shoppingListItem: ShoppingListItem) suspend fun upsertShoppingListItem(shoppingListItem: ShoppingListItem)
@Delete @Delete
suspend fun deleteShoppingListItem(shoppingListItem: ShoppingListItem) suspend fun deleteShoppingListItem(shoppingListItem: ShoppingListItem)
......
package com.example.e13roomshoppinglist package com.example.e13roomshoppinglist
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
...@@ -10,7 +9,6 @@ import androidx.compose.foundation.layout.Row ...@@ -10,7 +9,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
...@@ -124,6 +122,7 @@ fun ShoppingListScreen( ...@@ -124,6 +122,7 @@ fun ShoppingListScreen(
) )
} }
} }
Divider(thickness = 1.dp, color = Color.LightGray)
} }
item { item {
Row( Row(
...@@ -132,7 +131,7 @@ fun ShoppingListScreen( ...@@ -132,7 +131,7 @@ fun ShoppingListScreen(
.height(70.dp), .height(70.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text(text = "Empty item to fill up room so that the last item does not go under FAB.", fontSize = 12.sp, color = Color.Gray) Text(text = "Empty item to fill up room so that the last item's edit and delete button does not go under FAB.", fontSize = 12.sp, color = Color.Gray)
} }
} }
} }
...@@ -168,35 +167,26 @@ fun AddShoppingListItemDialog( ...@@ -168,35 +167,26 @@ fun AddShoppingListItemDialog(
placeholder = { Text(text = "Item Name") }, placeholder = { Text(text = "Item Name") },
) )
TextField( TextField(
value = if(shoppingListItem.count>0) shoppingListItem.count.toString() else "", value = shoppingListItem.count,
label = { Text(text = "Count") }, label = { Text(text = "Count") },
placeholder = { Text(text = "Count") }, placeholder = { Text(text = "Count") },
onValueChange = { onValueChange = {
var count = it.toIntOrNull() onEvent(ShoppingListEvent.SetCount(count = it))
if (count===null) {
onShowToast("Invalid value for Count!")
count = 0
}
onEvent(ShoppingListEvent.SetCount(count = count))
}, },
keyboardOptions = KeyboardOptions().copy( keyboardOptions = KeyboardOptions().copy(
autoCorrect = false, autoCorrect = false,
keyboardType = KeyboardType.Number keyboardType = KeyboardType.NumberPassword
), ),
leadingIcon = { leadingIcon = {
Text(text = "🧮", fontSize = 24.sp) Text(text = "🧮", fontSize = 24.sp)
} }
) )
TextField( TextField(
value = if(shoppingListItem.price>0) shoppingListItem.price.toString() else "", value = shoppingListItem.price,
label = { Text(text = "Price") }, label = { Text(text = "Price") },
placeholder = { Text(text = "Price") }, placeholder = { Text(text = "Price") },
onValueChange = { onValueChange = {
var price = it.toFloatOrNull() onEvent(ShoppingListEvent.SetPrice(price = it))
if (price===null) {
price = 0f
}
onEvent(ShoppingListEvent.SetPrice(price = price))
}, },
keyboardOptions = KeyboardOptions().copy( keyboardOptions = KeyboardOptions().copy(
autoCorrect = false, autoCorrect = false,
...@@ -211,13 +201,22 @@ fun AddShoppingListItemDialog( ...@@ -211,13 +201,22 @@ fun AddShoppingListItemDialog(
confirmButton = { confirmButton = {
Button(onClick = { Button(onClick = {
if (state.newShoppingListItem.name.length<3){ if (state.newShoppingListItem.name.length<3){
onShowToast("Item name should not be too short!") onShowToast("Item Name is too short!")
return@Button
}
if (state.newShoppingListItem.count.toIntOrNull()===null){
onShowToast("Invalid value for Count! Failed to convert value to Int.")
return@Button return@Button
} }
if (state.newShoppingListItem.price.toFloatOrNull()===null){
onShowToast("Invalid value for Price! Failed to convert value to Float.")
return@Button
}
if (state.isAddingNewShoppingListItem) { if (state.isAddingNewShoppingListItem) {
onEvent(ShoppingListEvent.InsertNewShoppingListItemToDb).also { onShowToast("Added new item to shopping list!") } onEvent(ShoppingListEvent.InsertNewShoppingListItemToDb).also { onShowToast("Added new item to shopping list!") }
} else if (state.isEditingShoppingListItem) { } else if (state.isEditingShoppingListItem) {
onEvent(ShoppingListEvent.UpdateCurrentlyEditingShoppingListItem).also { onShowToast("Updated shopping list item!") } onEvent(ShoppingListEvent.UpdateCurrentlyEditingShoppingListItem).also { onShowToast("Updated shopping list item ${state.currentlyEditingShoppingListItem?.name}!") }
} }
}) { }) {
Text(text = if (state.isEditingShoppingListItem) "Update" else "Insert") Text(text = if (state.isEditingShoppingListItem) "Update" else "Insert")
......
...@@ -28,8 +28,8 @@ sealed interface ShoppingListEvent{ ...@@ -28,8 +28,8 @@ sealed interface ShoppingListEvent{
data object OpenAddingNewShoppingListItemDialog: ShoppingListEvent data object OpenAddingNewShoppingListItemDialog: ShoppingListEvent
data object CloseAddingNewShoppingListItemDialog: ShoppingListEvent data object CloseAddingNewShoppingListItemDialog: ShoppingListEvent
data class SetName(val name: String): ShoppingListEvent data class SetName(val name: String): ShoppingListEvent
data class SetPrice(val price: Float): ShoppingListEvent data class SetPrice(val price: String): ShoppingListEvent
data class SetCount(val count: Int): ShoppingListEvent data class SetCount(val count: String): ShoppingListEvent
data object InsertNewShoppingListItemToDb: ShoppingListEvent data object InsertNewShoppingListItemToDb: ShoppingListEvent
data class OpenEditingShoppingListItem(val shoppingListItem: ShoppingListItem): ShoppingListEvent data class OpenEditingShoppingListItem(val shoppingListItem: ShoppingListItem): ShoppingListEvent
...@@ -42,8 +42,8 @@ sealed interface ShoppingListEvent{ ...@@ -42,8 +42,8 @@ sealed interface ShoppingListEvent{
data class NewShoppingListItem( data class NewShoppingListItem(
val name: String = "", val name: String = "",
val price: Float = 0f, val price: String = "",
val count: Int = 0 val count: String = ""
) )
data class ShoppingListState( data class ShoppingListState(
...@@ -103,12 +103,16 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() { ...@@ -103,12 +103,16 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() {
ShoppingListEvent.InsertNewShoppingListItemToDb -> { ShoppingListEvent.InsertNewShoppingListItemToDb -> {
val newShoppingListItem = _state.value.newShoppingListItem val newShoppingListItem = _state.value.newShoppingListItem
GlobalScope.launch { GlobalScope.launch {
val price = newShoppingListItem.price.toFloatOrNull()
val count = newShoppingListItem.count.toIntOrNull()
if (price===null || count===null) return@launch
dao.upsertShoppingListItem(ShoppingListItem( dao.upsertShoppingListItem(ShoppingListItem(
name = newShoppingListItem.name, name = newShoppingListItem.name,
price = newShoppingListItem.price, price = price,
count = newShoppingListItem.count)) count = count))
} }
_state.update { it.copy(newShoppingListItem=NewShoppingListItem()) } _state.update { it.copy(newShoppingListItem= NewShoppingListItem()) }
} }
ShoppingListEvent.CloseAddingNewShoppingListItemDialog -> { ShoppingListEvent.CloseAddingNewShoppingListItemDialog -> {
_state.update { it.copy(isAddingNewShoppingListItem = false) } _state.update { it.copy(isAddingNewShoppingListItem = false) }
...@@ -117,13 +121,14 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() { ...@@ -117,13 +121,14 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() {
is ShoppingListEvent.OpenEditingShoppingListItem -> { is ShoppingListEvent.OpenEditingShoppingListItem -> {
_state.update { _state.update {
val shoppingListItem = event.shoppingListItem val shoppingListItem = event.shoppingListItem
it.copy( it.copy(
isEditingShoppingListItem = true, isEditingShoppingListItem = true,
currentlyEditingShoppingListItem = shoppingListItem, currentlyEditingShoppingListItem = shoppingListItem,
newShoppingListItem = NewShoppingListItem( newShoppingListItem = NewShoppingListItem(
name = shoppingListItem.name, name = shoppingListItem.name,
price = shoppingListItem.price, price = shoppingListItem.price.toString(),
count = shoppingListItem.count count = shoppingListItem.count.toString()
)) ))
} }
} }
...@@ -131,10 +136,14 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() { ...@@ -131,10 +136,14 @@ class ShoppingListViewModel(private val dao: ShoppingListDao): ViewModel() {
val currentlyEditingShoppingListItem = _state.value.currentlyEditingShoppingListItem val currentlyEditingShoppingListItem = _state.value.currentlyEditingShoppingListItem
if (currentlyEditingShoppingListItem===null) return if (currentlyEditingShoppingListItem===null) return
val modifiedShoppingListItemAttrs = _state.value.newShoppingListItem val modifiedShoppingListItemAttrs = _state.value.newShoppingListItem
val price = modifiedShoppingListItemAttrs.price.toFloatOrNull()
val count = modifiedShoppingListItemAttrs.count.toIntOrNull()
if (price===null || count===null) return
val updatedShoppingListItem = currentlyEditingShoppingListItem.copy( val updatedShoppingListItem = currentlyEditingShoppingListItem.copy(
name = modifiedShoppingListItemAttrs.name, name = modifiedShoppingListItemAttrs.name,
price = modifiedShoppingListItemAttrs.price, price = price,
count = modifiedShoppingListItemAttrs.count count = count
) )
GlobalScope.launch { dao.upsertShoppingListItem(updatedShoppingListItem) } GlobalScope.launch { dao.upsertShoppingListItem(updatedShoppingListItem) }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment