- Added items store and a way to switch between the store and your items
- Added an items dialog, click on it to see details of the item (description, amount) and use it
- Added items store, it lists all the items available
This commit is contained in:
Nacho 2025-01-19 13:41:50 +01:00
parent c0a67e382b
commit 305b776b52
11 changed files with 343 additions and 53 deletions

Binary file not shown.

View File

@ -1,20 +1,37 @@
package com.github.nacabaro.vbhelper.components package com.github.nacabaro.vbhelper.components
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.util.EventLogTags.Description
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box 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.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.github.nacabaro.vbhelper.R import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
@Composable @Composable
fun ItemElement( fun ItemElement(
@ -23,20 +40,6 @@ fun ItemElement(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: (() -> Unit) = { } onClick: (() -> Unit) = { }
) { ) {
val iconResource = when (itemIcon) {
1 -> R.drawable.baseline_agility_24
2 -> R.drawable.baseline_attack_24
3 -> R.drawable.baseline_shield_24
else -> R.drawable.baseline_question_mark_24
}
val lengthResource = when (lengthIcon) {
1 -> R.drawable.baseline_15_min_timer
2 -> R.drawable.baseline_30_min_timer
3 -> R.drawable.baseline_60_min_timer
else -> R.drawable.baseline_question_mark_24
}
Card ( Card (
onClick = onClick, onClick = onClick,
modifier = modifier modifier = modifier
@ -44,20 +47,151 @@ fun ItemElement(
) { ) {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
// Background image (full size) // Background image (full size)
Image( Icon(
painter = painterResource(id = iconResource), painter = painterResource(id = itemIcon),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Image(
painter = painterResource(id = lengthResource),
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.size(100.dp) // Set the size of the overlay image .size(96.dp)
.align(Alignment.TopEnd) // Align to the top end (top-right corner) .align(Alignment.Center)
.padding(16.dp) // Add some padding from the edges )
Icon(
painter = painterResource(id = lengthIcon),
contentDescription = null,
tint = MaterialTheme.colorScheme.surfaceTint,
modifier = Modifier
.size(48.dp) // Set the size of the overlay image
.padding(4.dp
)
.align(Alignment.TopStart) // Align to the top end (top-right corner)
) )
} }
} }
} }
@Composable
fun ItemDialog(
name: String,
description: String,
itemIcon: Int,
lengthIcon: Int,
amount: Int,
onClickUse: () -> Unit,
onClickCancel: () -> Unit
) {
Dialog(
onDismissRequest = onClickCancel,
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
)
) {
Card (
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Column (
modifier = Modifier
.padding(16.dp)
) {
Row {
Box(modifier = Modifier) {
// Background image (full size)
Icon(
painter = painterResource(id = itemIcon),
contentDescription = null,
modifier = Modifier
.size(96.dp)
.align(Alignment.Center)
)
Icon(
painter = painterResource(id = lengthIcon),
contentDescription = null,
tint = MaterialTheme.colorScheme.outline,
modifier = Modifier
.size(64.dp) // Set the size of the overlay image
.align(Alignment.BottomEnd) // Align to the top end (top-right corner)
)
}
Column (
modifier = Modifier
.padding(16.dp)
) {
Text(
fontSize = MaterialTheme.typography.titleLarge.fontSize,
text = name,
modifier = Modifier
.fillMaxWidth()
)
}
}
Text(
textAlign = TextAlign.Center,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
fontFamily = MaterialTheme.typography.bodyMedium.fontFamily,
text = description
)
Text(
textAlign = TextAlign.Center,
fontSize = MaterialTheme.typography.bodySmall.fontSize,
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
text = "You have $amount of this item",
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
Row (
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
) {
Button(
onClick = onClickUse
) {
Text("Use item")
}
Spacer(modifier = Modifier.size(8.dp))
Button(
onClick = onClickCancel
) {
Text("Cancel")
}
}
}
}
}
}
fun getIconResource(index: Int): Int {
return when (index) {
1 -> R.drawable.baseline_agility_24
2 -> R.drawable.baseline_attack_24
3 -> R.drawable.baseline_shield_24
else -> R.drawable.baseline_question_mark_24
}
}
fun getLengthResource(index: Int): Int {
return when (index) {
1 -> R.drawable.baseline_15_min_timer
2 -> R.drawable.baseline_30_min_timer
3 -> R.drawable.baseline_60_min_timer
else -> R.drawable.baseline_question_mark_24
}
}
@Composable
@Preview(showBackground = true)
fun PreviewItemDialog() {
VBHelperTheme {
ItemDialog(
name = "AP Training x3 (60 min)",
description = "Boosts AP during training (for 60 minutes)",
itemIcon = R.drawable.baseline_attack_24,
lengthIcon = R.drawable.baseline_60_min_timer,
onClickUse = { },
onClickCancel = { },
amount = 19
)
}
}

View File

@ -7,8 +7,12 @@ import com.github.nacabaro.vbhelper.dtos.ItemDtos
@Dao @Dao
interface ItemDao { interface ItemDao {
@Query("SELECT * FROM Items") @Query("""
suspend fun getAllItems(): List<Items> SELECT Items.*, UserItems.quantity
FROM Items
LEFT JOIN UserItems ON Items.id = UserItems.itemId
""")
suspend fun getAllItems(): List<ItemDtos.ItemsWithQuantities>
@Query(""" @Query("""
SELECT Items.*, UserItems.quantity SELECT Items.*, UserItems.quantity

View File

@ -93,7 +93,7 @@ fun AppNavigation(
} }
} }
composable(NavigationItems.Items.route) { composable(NavigationItems.Items.route) {
MyItems( ItemsScreen(
navController = navController navController = navController
) )
} }

View File

@ -16,4 +16,6 @@ sealed class NavigationItems (
object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer") object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer")
object CardView : NavigationItems("Card/{cardId}", R.drawable.baseline_image_24, "Card") object CardView : NavigationItems("Card/{cardId}", R.drawable.baseline_image_24, "Card")
object Items : NavigationItems("Items", R.drawable.baseline_data_24, "Items") object Items : NavigationItems("Items", R.drawable.baseline_data_24, "Items")
object MyItems : NavigationItems("MyItems", R.drawable.baseline_data_24, "My items")
object ItemsStore : NavigationItems("ItemsStore", R.drawable.baseline_data_24, "Items store")
} }

View File

@ -1,12 +1,65 @@
package com.github.nacabaro.vbhelper.screens package com.github.nacabaro.vbhelper.screens
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsStore
import com.github.nacabaro.vbhelper.screens.itemsScreen.MyItems
@Composable @Composable
fun ItemsScreen( fun ItemsScreen(
navController: NavController navController: NavController,
) { ) {
Text(text = "Items") var selectedTabItem by remember { mutableStateOf(0) }
val items = listOf(
NavigationItems.MyItems,
NavigationItems.ItemsStore
)
Scaffold(
topBar = {
Column {
TopBanner("Items")
TabRow(
selectedTabIndex = selectedTabItem,
modifier = Modifier
) {
items.forEachIndexed { index, item ->
Tab(
text = { Text(item.label) },
selected = selectedTabItem == index,
onClick = { selectedTabItem = index }
)
}
}
}
}
) { contentPadding ->
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = contentPadding.calculateTopPadding())
) {
when (selectedTabItem) {
0 -> MyItems(navController)
1 -> ItemsStore(navController)
}
}
}
} }

View File

@ -66,7 +66,7 @@ fun StorageScreen(
} }
Scaffold ( Scaffold (
topBar = { TopBanner(text = "My Digimon") } topBar = { TopBanner(text = "My characters") }
) { contentPadding -> ) { contentPadding ->
if (monList.value.isEmpty()) { if (monList.value.isEmpty()) {
Column ( Column (

View File

@ -0,0 +1,77 @@
package com.github.nacabaro.vbhelper.screens.itemsScreen
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Text
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.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.ItemDialog
import com.github.nacabaro.vbhelper.components.ItemElement
import com.github.nacabaro.vbhelper.components.getIconResource
import com.github.nacabaro.vbhelper.components.getLengthResource
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.source.ItemsRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun ItemsStore(
navController: NavController
) {
val application = LocalContext.current.applicationContext as VBHelper
val itemsRepository = ItemsRepository(application.container.db)
val myItems = remember { mutableStateOf(emptyList<ItemDtos.ItemsWithQuantities>()) }
var showDialog by remember { mutableStateOf(false) }
var selectedElementIndex by remember { mutableStateOf<Int?>(null) }
LaunchedEffect(itemsRepository) {
withContext(Dispatchers.IO) {
myItems.value = itemsRepository.getAllItems()
}
}
if (myItems.value.isEmpty()) {
Text("No items")
} else {
LazyVerticalGrid(
columns = GridCells.Fixed(3),
modifier = Modifier
) {
items(myItems.value) { index ->
ItemElement(
itemIcon = getIconResource(index.itemIcon),
lengthIcon = getLengthResource(index.lengthIcon),
modifier = Modifier
.padding(8.dp),
onClick = {
showDialog = true
selectedElementIndex = myItems.value.indexOf(index)
}
)
if (showDialog && selectedElementIndex != null) {
ItemDialog(
name = myItems.value[selectedElementIndex!!].name,
description = myItems.value[selectedElementIndex!!].description,
itemIcon = getIconResource(myItems.value[selectedElementIndex!!].itemIcon),
lengthIcon = getLengthResource(myItems.value[selectedElementIndex!!].lengthIcon),
amount = myItems.value[selectedElementIndex!!].quantity,
onClickUse = { },
onClickCancel = { showDialog = false }
)
}
}
}
}
}

View File

@ -1,5 +1,6 @@
package com.github.nacabaro.vbhelper.screens.itemsScreen package com.github.nacabaro.vbhelper.screens.itemsScreen
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
@ -8,14 +9,20 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
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.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.components.ItemDialog
import com.github.nacabaro.vbhelper.components.ItemElement import com.github.nacabaro.vbhelper.components.ItemElement
import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.components.getIconResource
import com.github.nacabaro.vbhelper.components.getLengthResource
import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.ItemDtos import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.source.ItemsRepository import com.github.nacabaro.vbhelper.source.ItemsRepository
@ -29,6 +36,8 @@ fun MyItems(
val application = LocalContext.current.applicationContext as VBHelper val application = LocalContext.current.applicationContext as VBHelper
val itemsRepository = ItemsRepository(application.container.db) val itemsRepository = ItemsRepository(application.container.db)
val myItems = remember { mutableStateOf(emptyList<ItemDtos.ItemsWithQuantities>()) } val myItems = remember { mutableStateOf(emptyList<ItemDtos.ItemsWithQuantities>()) }
var showDialog by remember { mutableStateOf(false) }
var selectedElementIndex by remember { mutableStateOf<Int?>(null) }
LaunchedEffect(itemsRepository) { LaunchedEffect(itemsRepository) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
@ -36,23 +45,34 @@ fun MyItems(
} }
} }
Scaffold (
topBar = { TopBanner("Available items") }
) { contentPadding ->
if (myItems.value.isEmpty()) { if (myItems.value.isEmpty()) {
Text("No items") Text("No items")
} else { } else {
LazyVerticalGrid( LazyVerticalGrid(
columns = GridCells.Fixed(3), columns = GridCells.Fixed(3),
contentPadding = contentPadding modifier = Modifier
) { ) {
items(myItems.value) { index -> items(myItems.value) { index ->
ItemElement( ItemElement(
itemIcon = index.itemIcon, itemIcon = getIconResource(index.itemIcon),
lengthIcon = index.lengthIcon, lengthIcon = getLengthResource(index.lengthIcon),
modifier = Modifier modifier = Modifier
.padding(8.dp), .padding(8.dp),
onClick = { } onClick = {
showDialog = true
selectedElementIndex = myItems.value.indexOf(index)
}
)
if (showDialog && selectedElementIndex != null) {
ItemDialog(
name = myItems.value[selectedElementIndex!!].name,
description = myItems.value[selectedElementIndex!!].description,
itemIcon = getIconResource(myItems.value[selectedElementIndex!!].itemIcon),
lengthIcon = getLengthResource(myItems.value[selectedElementIndex!!].lengthIcon),
amount = myItems.value[selectedElementIndex!!].quantity,
onClickUse = { },
onClickCancel = { showDialog = false }
) )
} }
} }

View File

@ -7,7 +7,7 @@ import com.github.nacabaro.vbhelper.dtos.ItemDtos
class ItemsRepository( class ItemsRepository(
private val db: AppDatabase private val db: AppDatabase
) { ) {
suspend fun getAllItems(): List<Items> { suspend fun getAllItems(): List<ItemDtos.ItemsWithQuantities> {
return db.itemDao().getAllItems() return db.itemDao().getAllItems()
} }

View File

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="960"
android:viewportHeight="24"> android:viewportHeight="960">
<path <path
android:fillColor="#FF000000" android:pathData="M480,880q-139,-35 -229.5,-159.5T160,444v-244l320,-120 320,120v244q0,152 -90.5,276.5T480,880ZM480,796q104,-33 172,-132t68,-220v-189l-240,-90 -240,90v189q0,121 68,220t172,132ZM480,480Z"
android:pathData="M12,1L3,5v6c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12V5l-9,-4z"/> android:fillColor="#000000"/>
</vector> </vector>