Few things, again!

- From "Battles" to "Battle"
- Added a settings screen, to import keys and cards
- Added a way to access the settings from home
- Get character details
This commit is contained in:
Nacho 2025-01-05 01:58:08 +01:00
parent 59033e6459
commit e8f441ba2b
10 changed files with 278 additions and 16 deletions

View File

@ -1,25 +1,63 @@
package com.github.nacabaro.vbhelper.components package com.github.nacabaro.vbhelper.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.github.nacabaro.vbhelper.R
@Composable @Composable
fun TopBanner( fun TopBanner(
text: String, text: String,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
onGearClick: (() -> Unit)? = null,
onBackClick: (() -> Unit)? = null
) { ) {
Text( Box( // Use Box to overlay elements
text = text,
textAlign = TextAlign.Center,
fontSize = 24.sp,
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp)
) ) {
Text(
text = text,
textAlign = TextAlign.Center,
fontSize = 24.sp,
modifier = Modifier
.align(Alignment.Center) // Center the text
)
if (onGearClick != null) {
IconButton(
onClick = onGearClick,
modifier = Modifier
.align(Alignment.CenterEnd) // Place gear icon at the end
) {
Icon(
painter = painterResource(R.drawable.baseline_settings_24), // Use a gear icon
contentDescription = "Settings"
)
}
}
if (onBackClick != null) {
IconButton(
onClick = onBackClick,
modifier = Modifier
.align(Alignment.CenterStart) // Place gear icon at the end
) {
Icon(
painter = painterResource(R.drawable.baseline_arrow_back_24), // Use a gear icon
contentDescription = "Settings"
)
}
}
}
} }

View File

@ -11,6 +11,7 @@ import com.github.nacabaro.vbhelper.screens.BattlesScreen
import com.github.nacabaro.vbhelper.screens.DexScreen import com.github.nacabaro.vbhelper.screens.DexScreen
import com.github.nacabaro.vbhelper.screens.HomeScreen import com.github.nacabaro.vbhelper.screens.HomeScreen
import com.github.nacabaro.vbhelper.screens.ScanScreen import com.github.nacabaro.vbhelper.screens.ScanScreen
import com.github.nacabaro.vbhelper.screens.SettingsScreen
import com.github.nacabaro.vbhelper.screens.StorageScreen import com.github.nacabaro.vbhelper.screens.StorageScreen
@Composable @Composable
@ -36,7 +37,9 @@ fun AppNavigation(
BattlesScreen() BattlesScreen()
} }
composable(BottomNavItem.Home.route) { composable(BottomNavItem.Home.route) {
HomeScreen() HomeScreen(
navController = navController
)
} }
composable(BottomNavItem.Storage.route) { composable(BottomNavItem.Storage.route) {
StorageScreen() StorageScreen()
@ -52,6 +55,11 @@ fun AppNavigation(
composable(BottomNavItem.Dex.route) { composable(BottomNavItem.Dex.route) {
DexScreen() DexScreen()
} }
composable(BottomNavItem.Settings.route) {
SettingsScreen(
navController = navController
)
}
} }
} }
} }

View File

@ -8,8 +8,9 @@ sealed class BottomNavItem (
var label: String var label: String
) { ) {
object Scan : BottomNavItem("Scan", R.drawable.baseline_nfc_24, "Scan") object Scan : BottomNavItem("Scan", R.drawable.baseline_nfc_24, "Scan")
object Battles : BottomNavItem("Battles", R.drawable.baseline_swords_24, "Battles") object Battles : BottomNavItem("Battle", R.drawable.baseline_swords_24, "Battle")
object Home : BottomNavItem("Home", R.drawable.baseline_cottage_24, "Home") object Home : BottomNavItem("Home", R.drawable.baseline_cottage_24, "Home")
object Dex : BottomNavItem("Dex", R.drawable.baseline_menu_book_24, "Dex") object Dex : BottomNavItem("Dex", R.drawable.baseline_menu_book_24, "Dex")
object Storage : BottomNavItem("Storage", R.drawable.baseline_catching_pokemon_24, "Storage") object Storage : BottomNavItem("Storage", R.drawable.baseline_catching_pokemon_24, "Storage")
object Settings : BottomNavItem("Settings", R.drawable.baseline_settings_24, "Settings")
} }

View File

@ -1,9 +1,34 @@
package com.github.nacabaro.vbhelper.screens package com.github.nacabaro.vbhelper.screens
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
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.ui.Modifier
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.BottomNavItem
@Composable @Composable
fun HomeScreen() { fun HomeScreen(
Text("Home Screen") navController: NavController
) {
Scaffold (
topBar = {
TopBanner(
text = "VB Helper",
onGearClick = {
navController.navigate(BottomNavItem.Settings.route)
}
)
}
) { contentPadding ->
Box (
modifier = Modifier
.padding(top = contentPadding.calculateTopPadding())
) {
Text("Home Screen")
}
}
} }

View File

@ -0,0 +1,96 @@
package com.github.nacabaro.vbhelper.screens
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
@Composable
fun SettingsScreen(
navController: NavController
) {
Scaffold (
topBar = {
TopBanner(
text = "Settings",
onBackClick = {
navController.popBackStack()
}
)
},
modifier = Modifier
.fillMaxSize()
) { contentPadding ->
Column (
modifier = Modifier
.padding(top = contentPadding.calculateTopPadding())
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
SettingsSection("General")
SettingsEntry(title = "Import VB key", description = "Import standard vital bracelet keys") { }
SettingsEntry(title = "Import VB Characters key", description = "Import standard vital bracelet keys") { }
SettingsEntry(title = "Import VB BE key", description = "Import standard vital bracelet keys") { }
SettingsEntry(title = "Import transform functions", description = "Import standard vital bracelet keys") { }
SettingsEntry(title = "Import decryption key", description = "Import standard vital bracelet keys") { }
SettingsSection("DiM/BEm management")
SettingsEntry(title = "Import DiM card", description = "Import DiM card file") { }
SettingsEntry(title = "Import BEm card", description = "Import BEm card file") { }
SettingsSection("About and credits")
SettingsEntry(title = "Credits", description = "Credits") { }
SettingsEntry(title = "About", description = "About") { }
}
}
}
@Composable
fun SettingsEntry(
title: String,
description: String,
onClick: () -> Unit
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clickable { onClick() }
.padding(16.dp)
) {
Text(text = title)
Text(
text = description,
fontSize = 12.sp,
color = MaterialTheme.colorScheme.outline
)
}
}
@Composable
fun SettingsSection(
title: String
) {
Box (
modifier = Modifier
.padding(start = 16.dp)
) {
Text(
text = title,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
}
}

View File

@ -4,6 +4,7 @@ import android.util.Log
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -12,7 +13,10 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardElevation
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -23,12 +27,16 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
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.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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.components.TopBanner import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.di.VBHelper
@ -45,6 +53,7 @@ fun StorageScreen() {
val storageRepository = StorageRepository(application.container.db) val storageRepository = StorageRepository(application.container.db)
val monList = remember { mutableStateListOf<TemporaryCharacterData>() } val monList = remember { mutableStateListOf<TemporaryCharacterData>() }
var selectedCharacter by remember { mutableStateOf<Long?>(null) }
LaunchedEffect(storageRepository) { LaunchedEffect(storageRepository) {
coroutineScope.launch { coroutineScope.launch {
@ -60,11 +69,19 @@ fun StorageScreen() {
topBar = { TopBanner(text = "My Digimon") } topBar = { TopBanner(text = "My Digimon") }
) { contentPadding -> ) { contentPadding ->
if (monList.isEmpty()) { if (monList.isEmpty()) {
Text( Column (
text = "Nothing to see here", horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(contentPadding)
) .fillMaxSize()
) {
Text(
text = "Nothing to see here",
textAlign = TextAlign.Center,
modifier = Modifier
)
}
} }
LazyVerticalGrid( LazyVerticalGrid(
@ -74,12 +91,22 @@ fun StorageScreen() {
.padding(top = contentPadding.calculateTopPadding()) .padding(top = contentPadding.calculateTopPadding())
) { ) {
items(monList) { index -> items(monList) { index ->
var showDialog by rememberSaveable { mutableStateOf(false) }
StorageEntry( StorageEntry(
name = index.dimId.toString() + " - " + index.charIndex.toString(), name = index.dimId.toString() + " - " + index.charIndex.toString(),
icon = R.drawable.ic_launcher_foreground, icon = R.drawable.ic_launcher_foreground,
onClick = { selectedCharacter = index.id },
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
) )
if (selectedCharacter != null) {
StorageDialog(
characterId = selectedCharacter!!,
onDismissRequest = { selectedCharacter = null }
)
}
} }
} }
} }
@ -89,14 +116,16 @@ fun StorageScreen() {
fun StorageEntry( fun StorageEntry(
name: String, name: String,
icon: Int, icon: Int,
onClick: () -> Unit = {},
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Card ( Card(
shape = MaterialTheme.shapes.medium, shape = MaterialTheme.shapes.medium,
onClick = onClick,
modifier = modifier modifier = modifier
.padding(8.dp) .padding(8.dp)
) { ) {
Column ( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -117,3 +146,51 @@ fun StorageEntry(
} }
} }
} }
@Composable
fun StorageDialog(
characterId: Long,
onDismissRequest: () -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val application = LocalContext.current.applicationContext as VBHelper
val storageRepository = StorageRepository(application.container.db)
val character = remember { mutableStateOf<TemporaryCharacterData?>(null) }
LaunchedEffect(storageRepository) {
coroutineScope.launch {
character.value = storageRepository.getSingleCharacter(characterId)
}
}
Dialog(
onDismissRequest = onDismissRequest,
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
)
) {
Card(
shape = RoundedCornerShape(16.dp)
) {
Column (
modifier = Modifier
.padding(16.dp)
) {
if (character.value != null) {
Text(
text = character.value?.toString() ?: "Loading...",
textAlign = TextAlign.Center,
modifier = Modifier
.padding(8.dp)
)
}
Button(
onClick = onDismissRequest
) {
Text(text = "Close")
}
}
}
}
}

View File

@ -9,4 +9,8 @@ class StorageRepository (
suspend fun getAllCharacters(): List<TemporaryCharacterData> { suspend fun getAllCharacters(): List<TemporaryCharacterData> {
return db.temporaryMonsterDao().getAllCharacters() return db.temporaryMonsterDao().getAllCharacters()
} }
suspend fun getSingleCharacter(id: Long): TemporaryCharacterData {
return db.temporaryMonsterDao().getCharacter(id)
}
} }

View File

@ -24,4 +24,7 @@ interface TemporaryMonsterDao {
@Query("SELECT * FROM TemporaryCharacterData") @Query("SELECT * FROM TemporaryCharacterData")
suspend fun getAllCharacters(): List<TemporaryCharacterData> suspend fun getAllCharacters(): List<TemporaryCharacterData>
@Query("SELECT * FROM TemporaryCharacterData WHERE id = :id")
suspend fun getCharacter(id: Long): TemporaryCharacterData
} }

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>