M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +9 -4
@@ 14,6 14,7 @@ import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImp
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.cardScreen.CardScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
@@ 47,6 48,7 @@ class MainActivity : ComponentActivity() {
val storageScreenController = StorageScreenControllerImpl(this)
val homeScreenController = HomeScreenControllerImpl(this)
val spriteViewerController = SpriteViewerControllerImpl(this)
+ val cardScreenController = CardScreenControllerImpl(this)
super.onCreate(savedInstanceState)
@@ 61,7 63,8 @@ class MainActivity : ComponentActivity() {
adventureScreenController = adventureScreenController,
homeScreenController = homeScreenController,
storageScreenController = storageScreenController,
- spriteViewerController = spriteViewerController
+ spriteViewerController = spriteViewerController,
+ cardScreenController = cardScreenController
)
}
}
@@ 93,8 96,9 @@ class MainActivity : ComponentActivity() {
adventureScreenController: AdventureScreenControllerImpl,
storageScreenController: StorageScreenControllerImpl,
homeScreenController: HomeScreenControllerImpl,
- spriteViewerController: SpriteViewerControllerImpl
- ) {
+ spriteViewerController: SpriteViewerControllerImpl,
+ cardScreenController: CardScreenControllerImpl
+ ) {
AppNavigation(
applicationNavigationHandlers = AppNavigationHandlers(
settingsScreenController,
@@ 103,7 107,8 @@ class MainActivity : ComponentActivity() {
adventureScreenController,
storageScreenController,
homeScreenController,
- spriteViewerController
+ spriteViewerController,
+ cardScreenController
)
)
}
M app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt +22 -10
@@ 24,7 24,8 @@ fun TopBanner(
onGearClick: (() -> Unit)? = null,
onBackClick: (() -> Unit)? = null,
onScanClick: (() -> Unit)? = null,
- onAdventureClick: (() -> Unit)? = null
+ onAdventureClick: (() -> Unit)? = null,
+ onModifyClick: (() -> Unit)? = null
) {
Box( // Use Box to overlay elements
modifier = modifier
@@ 37,16 38,16 @@ fun TopBanner(
textAlign = TextAlign.Center,
fontSize = 24.sp,
modifier = Modifier
- .align(Alignment.Center) // Center the text
+ .align(Alignment.Center)
)
if (onGearClick != null) {
IconButton(
onClick = onGearClick,
modifier = Modifier
- .align(Alignment.CenterEnd) // Place gear icon at the end
+ .align(Alignment.CenterEnd)
) {
Icon(
- painter = painterResource(R.drawable.baseline_settings_24), // Use a gear icon
+ painter = painterResource(R.drawable.baseline_settings_24),
contentDescription = "Settings"
)
}
@@ 54,23 55,34 @@ fun TopBanner(
IconButton(
onClick = onAdventureClick,
modifier = Modifier
- .align(Alignment.CenterEnd) // Place gear icon at the end
+ .align(Alignment.CenterEnd)
) {
Icon(
- painter = painterResource(R.drawable.baseline_fort_24), // Use a gear icon
+ painter = painterResource(R.drawable.baseline_fort_24),
contentDescription = "Adventure"
)
}
+ } else if (onModifyClick != null) {
+ IconButton(
+ onClick = onModifyClick,
+ modifier = Modifier
+ .align(Alignment.CenterEnd)
+ ) {
+ Icon(
+ painter = painterResource(R.drawable.baseline_edit_24),
+ contentDescription = "Adventure"
+ )
+ }
}
if (onScanClick != null) {
IconButton(
onClick = onScanClick,
modifier = Modifier
- .align(Alignment.CenterStart) // Place gear icon at the end
+ .align(Alignment.CenterStart)
) {
Icon(
- painter = painterResource(R.drawable.baseline_nfc_24), // Use a gear icon
+ painter = painterResource(R.drawable.baseline_nfc_24),
contentDescription = "Scan"
)
}
@@ 78,10 90,10 @@ fun TopBanner(
IconButton(
onClick = onBackClick,
modifier = Modifier
- .align(Alignment.CenterStart) // Place gear icon at the end
+ .align(Alignment.CenterStart)
) {
Icon(
- painter = painterResource(R.drawable.baseline_arrow_back_24), // Use a gear icon
+ painter = painterResource(R.drawable.baseline_arrow_back_24),
contentDescription = "Settings"
)
}
M app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt +20 -2
@@ 9,8 9,26 @@ import com.github.nacabaro.vbhelper.domain.card.Card
@Dao
interface CardDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
- suspend fun insertNewDim(card: Card): Long
+ suspend fun insertNewCard(card: Card): Long
@Query("SELECT * FROM Card WHERE cardId = :id")
- fun getDimById(id: Int): Card?
+ fun getCardByCardId(id: Int): List<Card>
+
+ @Query("SELECT * FROM Card WHERE id = :id")
+ fun getCardById(id: Long): Card?
+
+ @Query("""
+ SELECT ca.*
+ FROM Card ca
+ JOIN Character ch ON ca.id = ch.dimId
+ JOIN UserCharacter uc ON ch.id = uc.charId
+ WHERE uc.id = :id
+ """)
+ suspend fun getCardByCharacterId(id: Long): Card
+
+ @Query("UPDATE Card SET name = :newName WHERE id = :id")
+ suspend fun renameCard(id: Int, newName: String)
+
+ @Query("DELETE FROM Card WHERE id = :id")
+ suspend fun deleteCard(id: Long)
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +9 -6
@@ 19,8 19,8 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.screens.BattlesScreen
-import com.github.nacabaro.vbhelper.screens.DexScreen
-import com.github.nacabaro.vbhelper.screens.DiMScreen
+import com.github.nacabaro.vbhelper.screens.cardScreen.CardsScreen
+import com.github.nacabaro.vbhelper.screens.cardScreen.CardViewScreen
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreen
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
@@ 34,6 34,7 @@ import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImp
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreen
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.cardScreen.CardScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.CreditsScreen
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
@@ 46,7 47,8 @@ data class AppNavigationHandlers(
val adventureScreenController: AdventureScreenControllerImpl,
val storageScreenController: StorageScreenControllerImpl,
val homeScreenController: HomeScreenControllerImpl,
- val spriteViewerController: SpriteViewerControllerImpl
+ val spriteViewerController: SpriteViewerControllerImpl,
+ val cardScreenController: CardScreenControllerImpl
)
@Composable
@@ 121,8 123,9 @@ fun AppNavigation(
)
}
composable(NavigationItems.Dex.route) {
- DexScreen(
- navController = navController
+ CardsScreen(
+ navController = navController,
+ cardScreenController = applicationNavigationHandlers.cardScreenController
)
}
composable(NavigationItems.Settings.route) {
@@ 140,7 143,7 @@ fun AppNavigation(
composable(NavigationItems.CardView.route) {
val cardId = it.arguments?.getString("cardId")
if (cardId != null) {
- DiMScreen(
+ CardViewScreen(
navController = navController,
dimId = cardId.toLong()
)
A app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardEntry.kt +109 -0
@@ 0,0 1,109 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Delete
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material3.Card
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getBitmap
+
+@Composable
+fun CardEntry(
+ name: String,
+ logo: BitmapData,
+ obtainedCharacters: Int,
+ totalCharacters: Int,
+ onClick: () -> Unit,
+ displayModify: Boolean,
+ onClickModify: () -> Unit,
+ onClickDelete: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ val bitmap = remember (logo.bitmap) { logo.getBitmap() }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+ val density: Float = LocalContext.current.resources.displayMetrics.density
+ val dpSize = (logo.width * 4 / density).dp
+
+ Card (
+ shape = MaterialTheme.shapes.medium,
+ modifier = modifier,
+ onClick = if (!displayModify) {
+ onClick
+ } else {
+ { }
+ }
+ ) {
+ Row (
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .padding(8.dp)
+ ) {
+ Image (
+ bitmap = imageBitmap,
+ contentDescription = name,
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .padding(8.dp)
+ .size(dpSize)
+ )
+ Column(
+ modifier = Modifier
+ .padding(8.dp)
+ .weight(1f)
+ ) {
+ Text(
+ text = name,
+ modifier = Modifier
+ )
+ Text(
+ text = "$obtainedCharacters of $totalCharacters characters obtained",
+ fontFamily = MaterialTheme.typography.labelSmall.fontFamily,
+ fontSize = MaterialTheme.typography.labelSmall.fontSize,
+ modifier = Modifier
+ )
+ }
+ if (displayModify) {
+ Row (
+ modifier = Modifier,
+ horizontalArrangement = Arrangement.End,
+ ) {
+ IconButton(
+ onClick = onClickModify
+ ) {
+ Icon(
+ imageVector = Icons.Default.Edit,
+ contentDescription = "Edit"
+ )
+ }
+ IconButton(
+ onClick = onClickDelete
+ ) {
+ Icon(
+ imageVector = Icons.Default.Delete,
+ contentDescription = "Delete"
+ )
+ }
+ }
+ }
+ }
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardScreenController.kt +6 -0
@@ 0,0 1,6 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen
+
+interface CardScreenController {
+ fun renameCard(cardId: Long, newName: String, onRenamed: (String) -> Unit)
+ fun deleteCard(cardId: Long, onDeleted: () -> Unit)
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardScreenControllerImpl.kt +34 -0
@@ 0,0 1,34 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen
+
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.lifecycleScope
+import com.github.nacabaro.vbhelper.di.VBHelper
+import kotlinx.coroutines.launch
+
+class CardScreenControllerImpl(
+ private val componentActivity: ComponentActivity,
+) : CardScreenController {
+ private val application = componentActivity.applicationContext as VBHelper
+ private val database = application.container.db
+
+
+ override fun renameCard(cardId: Long, newName: String, onRenamed: (String) -> Unit) {
+ componentActivity.lifecycleScope.launch {
+ database
+ .cardDao()
+ .renameCard(cardId.toInt(), newName)
+
+ onRenamed(newName)
+ }
+ }
+
+ override fun deleteCard(cardId: Long, onDeleted: () -> Unit) {
+ componentActivity.lifecycleScope.launch {
+ database
+ .cardDao()
+ .deleteCard(cardId)
+
+ onDeleted()
+ }
+ }
+}<
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/screens/DimScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardViewScreen.kt +2 -3
@@ 1,4 1,4 @@
-package com.github.nacabaro.vbhelper.screens
+package com.github.nacabaro.vbhelper.screens.cardScreen
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
@@ 14,14 14,13 @@ import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.TopBanner
-import com.github.nacabaro.vbhelper.domain.characters.Character
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.source.DexRepository
import kotlinx.coroutines.launch
@Composable
-fun DiMScreen(
+fun CardViewScreen(
navController: NavController,
dimId: Long
) {
R app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/CardsScreen.kt +73 -11
@@ 1,5 1,6 @@
-package com.github.nacabaro.vbhelper.screens
+package com.github.nacabaro.vbhelper.screens.cardScreen
+import android.util.Log
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@@ 7,45 8,54 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold
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.rememberCoroutineScope
+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.utils.BitmapData
-import com.github.nacabaro.vbhelper.components.DexDiMEntry
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.CardDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
+import com.github.nacabaro.vbhelper.screens.cardScreen.dialogs.CardDeleteDialog
+import com.github.nacabaro.vbhelper.screens.cardScreen.dialogs.CardRenameDialog
import com.github.nacabaro.vbhelper.source.DexRepository
import kotlinx.coroutines.launch
@Composable
-fun DexScreen(
- navController: NavController
+fun CardsScreen(
+ navController: NavController,
+ cardScreenController: CardScreenControllerImpl
) {
val coroutineScope = rememberCoroutineScope()
val application = LocalContext.current.applicationContext as VBHelper
val dexRepository = DexRepository(application.container.db)
-
val cardList = remember { mutableStateOf<List<CardDtos.CardProgress>>(emptyList()) }
+ val selectedCard = remember { mutableStateOf<CardDtos.CardProgress?>(null) }
+ var clickedDelete by remember { mutableStateOf(false) }
+ var clickedRename by remember { mutableStateOf(false) }
+
+ var modifyCards by remember { mutableStateOf(false) }
+
LaunchedEffect(dexRepository) {
coroutineScope.launch {
val newDimList = dexRepository.getAllDims()
- cardList.value = newDimList // Replace the entire list atomically
+ cardList.value = newDimList
}
}
Scaffold (
topBar = {
TopBanner(
- text = "Discovered characters",
- onGearClick = {
- navController.navigate(NavigationItems.Viewer.route)
+ text = "My cards",
+ onModifyClick = {
+ modifyCards = !modifyCards
}
)
}
@@ 55,7 65,7 @@ fun DexScreen(
.padding(top = contentPadding.calculateTopPadding())
) {
items(cardList.value) {
- DexDiMEntry(
+ CardEntry(
name = it.cardName,
logo = BitmapData(
bitmap = it.cardLogo,
@@ 74,10 84,62 @@ fun DexScreen(
totalCharacters = it.totalCharacters,
modifier = Modifier
.fillMaxWidth()
- .padding(8.dp)
+ .padding(8.dp),
+ displayModify = modifyCards,
+ onClickModify = {
+ selectedCard.value = it
+ clickedRename = true
+ },
+ onClickDelete = {
+ selectedCard.value = it
+ clickedDelete = true
+ }
)
}
}
}
+
+ if (clickedRename) {
+ CardRenameDialog(
+ onDismiss = {
+ clickedRename = false
+ selectedCard.value = null
+ },
+ onRename = { newName ->
+ Log.d("CardsScreen", "New name: $newName")
+ Log.d("CardsScreen", "Card: ${selectedCard.value.toString()}")
+ cardScreenController
+ .renameCard(
+ cardId = selectedCard.value!!.cardId,
+ newName = newName,
+ onRenamed = {
+ clickedRename = false
+ selectedCard.value = null
+ }
+ )
+ },
+ currentName = selectedCard.value!!.cardName
+ )
+ }
+
+ if (clickedDelete) {
+ CardDeleteDialog(
+ cardName = selectedCard.value!!.cardName,
+ onDismiss = {
+ clickedDelete = false
+ selectedCard.value = null
+ },
+ onConfirm = {
+ cardScreenController
+ .deleteCard(
+ cardId = selectedCard.value!!.cardId,
+ onDeleted = {
+ clickedDelete = false
+ selectedCard.value = null
+ }
+ )
+ }
+ )
+ }
}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/dialogs/CardDeleteDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/dialogs/CardDeleteDialog.kt +51 -0
@@ 0,0 1,51 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+
+@Composable
+fun CardDeleteDialog(
+ cardName: String,
+ onDismiss: () -> Unit,
+ onConfirm: () -> Unit
+) {
+ Dialog(
+ onDismissRequest = onDismiss
+
+ ) {
+ Card ( ) {
+ Column (
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Text(text = "Are you sure you want to delete $cardName. This action will also delete all the characters raised from this card.")
+ Spacer(modifier = Modifier.padding(8.dp))
+ Row {
+ Button(
+ onClick = {
+ onDismiss()
+ }
+ ) {
+ Text(text = "Confirm")
+ }
+ Button(
+ onClick = {
+ onConfirm()
+ }
+ ) {
+ Text(text = "Delete")
+ }
+ }
+ }
+ }
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/dialogs/CardRenameDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/cardScreen/dialogs/CardRenameDialog.kt +52 -0
@@ 0,0 1,52 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+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.compose.ui.window.Dialog
+
+@Composable
+fun CardRenameDialog(
+ onDismiss: () -> Unit,
+ onRename: (String) -> Unit,
+ currentName: String
+) {
+ var cardName by remember { mutableStateOf(currentName) }
+
+ Dialog(
+ onDismissRequest = onDismiss
+
+ ) {
+ Card ( ) {
+ Column (
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ TextField(
+ value = cardName,
+ onValueChange = { cardName = it }
+ )
+ Spacer(modifier = Modifier.padding(8.dp))
+ Button(
+ onClick = {
+ onRename(cardName)
+ onDismiss()
+ }
+ ) {
+ Text(text = "Rename")
+ }
+ }
+ }
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt +41 -9
@@ 30,7 30,9 @@ import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.navigation.NavigationItems
+import com.github.nacabaro.vbhelper.screens.cardScreen.ChooseCard
import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.source.isMissingSecrets
import com.github.nacabaro.vbhelper.source.proto.Secrets
@@ 53,6 55,8 @@ fun ScanScreen(
val storageRepository = StorageRepository(application.container.db)
var nfcCharacter by remember { mutableStateOf<NfcCharacter?>(null) }
+ var cardsRead by remember { mutableStateOf<List<Card>?>(null) }
+
val context = LocalContext.current
LaunchedEffect(storageRepository) {
@@ 71,6 75,7 @@ fun ScanScreen(
var readingScreen by remember { mutableStateOf(false) }
var writingScreen by remember { mutableStateOf(false) }
+ var cardSelectScreen by remember { mutableStateOf(false) }
var isDoneReadingCharacter by remember { mutableStateOf(false) }
var isDoneSendingCard by remember { mutableStateOf(false) }
var isDoneWritingCharacter by remember { mutableStateOf(false) }
@@ 85,15 90,33 @@ fun ScanScreen(
}
override fun onResume() {
- scanScreenController.onClickRead(secrets!!) {
- isDoneReadingCharacter = true
- }
+ scanScreenController.onClickRead(
+ secrets = secrets!!,
+ onComplete = {
+ isDoneReadingCharacter = true
+ },
+ onMultipleCards = { cards ->
+ cardsRead = cards
+ readingScreen = false
+ cardSelectScreen = true
+ isDoneReadingCharacter = true
+ }
+ )
}
}
)
- scanScreenController.onClickRead(secrets!!) {
- isDoneReadingCharacter = true
- }
+ scanScreenController.onClickRead(
+ secrets = secrets!!,
+ onComplete = {
+ isDoneReadingCharacter = true
+ },
+ onMultipleCards = { cards ->
+ cardsRead = cards
+ readingScreen = false
+ cardSelectScreen = true
+ isDoneReadingCharacter = true
+ }
+ )
}
onDispose {
if(readingScreen) {
@@ 149,7 172,7 @@ fun ScanScreen(
}
}
- if (isDoneReadingCharacter) {
+ if (isDoneReadingCharacter && !cardSelectScreen) {
readingScreen = false
navController.navigate(NavigationItems.Home.route)
} else if (isDoneSendingCard && isDoneWritingCharacter) {
@@ 181,6 204,14 @@ fun ScanScreen(
scanScreenController.cancelRead()
}
}
+ } else if (cardSelectScreen) {
+ ChooseCard(
+ cards = cardsRead!!,
+ onCardSelected = { card ->
+ cardSelectScreen = false
+ scanScreenController.flushCharacter(card.id)
+ }
+ )
} else {
ChooseConnectOption(
onClickRead = when {
@@ 290,11 321,12 @@ fun ScanScreenPreview() {
) {
}
- override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) {}
+ override fun flushCharacter(cardId: Long) {}
+ override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {}
override fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
override fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
override fun cancelRead() {}
- override fun characterFromNfc(nfcCharacter: NfcCharacter): String { return "" }
+ override fun characterFromNfc(nfcCharacter: NfcCharacter, onMultipleCards: (List<Card>, NfcCharacter) -> Unit): String { return "" }
override suspend fun characterToNfc(characterId: Long): NfcCharacter? { return null }
},
characterId = null,
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt +8 -2
@@ 2,12 2,13 @@ package com.github.nacabaro.vbhelper.screens.scanScreen
import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
+import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.source.proto.Secrets
import kotlinx.coroutines.flow.Flow
interface ScanScreenController {
val secretsFlow: Flow<Secrets>
- fun onClickRead(secrets: Secrets, onComplete: ()->Unit)
+ fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit)
fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
@@ 16,6 17,11 @@ interface ScanScreenController {
fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener)
fun unregisterActivityLifecycleListener(key: String)
- fun characterFromNfc(nfcCharacter: NfcCharacter): String
+ fun flushCharacter(cardId: Long)
+
+ fun characterFromNfc(
+ nfcCharacter: NfcCharacter,
+ onMultipleCards: (List<Card>, NfcCharacter) -> Unit
+ ): String
suspend fun characterToNfc(characterId: Long): NfcCharacter?
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt +26 -5
@@ 15,6 15,7 @@ import com.github.cfogrady.vbnfc.be.BENfcCharacter
import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
+import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.FromNfcConverter
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.ToNfcConverter
import com.github.nacabaro.vbhelper.source.getCryptographicTransformerMap
@@ 31,7 32,7 @@ class ScanScreenControllerImpl(
private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit,
private val unregisterActivityLifecycleListener: (String)->Unit,
): ScanScreenController {
-
+ private var lastScannedCharacter: NfcCharacter? = null
private val nfcAdapter: NfcAdapter
init {
@@ 43,10 44,14 @@ class ScanScreenControllerImpl(
checkSecrets()
}
- override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) {
+ override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {
handleTag(secrets) { tagCommunicator ->
val character = tagCommunicator.receiveCharacter()
- val resultMessage = characterFromNfc(character)
+ val resultMessage = characterFromNfc(character) { cards, nfcCharacter ->
+ lastScannedCharacter = nfcCharacter
+ onMultipleCards(cards)
+
+ }
onComplete.invoke()
resultMessage
}
@@ 156,11 161,14 @@ class ScanScreenControllerImpl(
componentActivity.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
}
- override fun characterFromNfc(nfcCharacter: NfcCharacter): String {
+ override fun characterFromNfc(
+ nfcCharacter: NfcCharacter,
+ onMultipleCards: (List<Card>, NfcCharacter) -> Unit
+ ): String {
val nfcConverter = FromNfcConverter(
componentActivity = componentActivity
)
- return nfcConverter.addCharacter(nfcCharacter)
+ return nfcConverter.addCharacter(nfcCharacter, onMultipleCards)
}
override suspend fun characterToNfc(characterId: Long): NfcCharacter {
@@ 172,4 180,17 @@ class ScanScreenControllerImpl(
Log.d("CharacterType", character.toString())
return character
}
+
+ override fun flushCharacter(cardId: Long) {
+ val nfcConverter = FromNfcConverter(
+ componentActivity = componentActivity
+ )
+
+ componentActivity.lifecycleScope.launch(Dispatchers.IO) {
+ if (lastScannedCharacter != null) {
+ nfcConverter.addCharacterUsingCard(lastScannedCharacter!!, cardId)
+ lastScannedCharacter = null
+ }
+ }
+ }
}=
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/cardSelect/ChooseCard.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/cardSelect/ChooseCard.kt +48 -0
@@ 0,0 1,48 @@
+package com.github.nacabaro.vbhelper.screens.cardScreen
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.domain.card.Card
+import com.github.nacabaro.vbhelper.screens.scanScreen.cardSelect.ScanCardEntry
+import com.github.nacabaro.vbhelper.utils.BitmapData
+
+@Composable
+fun ChooseCard(
+ cards: List<Card>,
+ onCardSelected: (Card) -> Unit
+) {
+ Scaffold (
+ topBar = {
+ TopBanner(
+ text = "Choose card",
+ )
+ }
+ ) { contentPadding ->
+ LazyColumn (
+ modifier = Modifier
+ .padding(top = contentPadding.calculateTopPadding())
+ ) {
+ items(cards) {
+ ScanCardEntry(
+ name = it.name,
+ logo = BitmapData(
+ it.logo,
+ it.logoWidth,
+ it.logoHeight
+ ),
+ onClick = {
+ onCardSelected(it)
+ },
+ modifier = Modifier
+ .padding(8.dp)
+ )
+ }
+ }
+ }
+}<
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/components/DexDimEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/cardSelect/ScanCardEntry.kt +3 -10
@@ 1,4 1,4 @@
-package com.github.nacabaro.vbhelper.components
+package com.github.nacabaro.vbhelper.screens.scanScreen.cardSelect
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
@@ 21,11 21,9 @@ import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.utils.getBitmap
@Composable
-fun DexDiMEntry(
+fun ScanCardEntry(
name: String,
logo: BitmapData,
- obtainedCharacters: Int,
- totalCharacters: Int,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
@@ 56,17 54,12 @@ fun DexDiMEntry(
Column(
modifier = Modifier
.padding(8.dp)
+ .weight(1f)
) {
Text(
text = name,
modifier = Modifier
)
- Text(
- text = "$obtainedCharacters of $totalCharacters characters obtained",
- fontFamily = MaterialTheme.typography.labelSmall.fontFamily,
- fontSize = MaterialTheme.typography.labelSmall.fontSize,
- modifier = Modifier
- )
}
}
}
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt +60 -7
@@ 21,17 21,70 @@ class FromNfcConverter (
) {
private val application = componentActivity.applicationContext as VBHelper
private val database = application.container.db
-
-
-
- fun addCharacter(nfcCharacter: NfcCharacter): String {
+
+
+ fun addCharacterUsingCard(
+ nfcCharacter: NfcCharacter,
+ cardId: Long
+ ): String {
val cardData = database
.cardDao()
- .getDimById(nfcCharacter.dimId.toInt())
+ .getCardById(cardId)
- if (cardData == null)
+ if (cardData == null) {
return "Card not found"
+ }
+
+ return insertCharacter(nfcCharacter, cardData)
+ }
+
+
+ fun addCharacter(
+ nfcCharacter: NfcCharacter,
+ onMultipleCards: (List<Card>, NfcCharacter) -> Unit
+ ): String {
+ val appReservedCardId = nfcCharacter
+ .appReserved2[0].toLong()
+
+ var cardData: Card? = null
+
+ if (appReservedCardId != 0L) {
+ val fetchedCard = database
+ .cardDao()
+ .getCardById(appReservedCardId)
+
+ if (fetchedCard == null) {
+ return "Card not found"
+ } else if (fetchedCard.cardId == nfcCharacter.dimId.toInt()) {
+ cardData = fetchedCard
+ }
+ }
+
+ if (cardData == null) {
+ val allCards = database
+ .cardDao()
+ .getCardByCardId(nfcCharacter.dimId.toInt())
+ if (allCards.isEmpty())
+ return "Card not found"
+
+ if (allCards.size > 1) {
+ onMultipleCards(allCards, nfcCharacter)
+ return "Multiple cards found"
+ }
+
+ cardData = allCards[0]
+ }
+
+ return insertCharacter(nfcCharacter, cardData)
+ }
+
+
+
+ private fun insertCharacter(
+ nfcCharacter: NfcCharacter,
+ cardData: Card
+ ): String {
val cardCharData = database
.characterDao()
.getCharacterByMonIndex(nfcCharacter.charIndex.toInt(), cardData.id)
@@ 92,7 145,7 @@ class FromNfcConverter (
return "Done reading character!"
}
-
+
private fun updateCardProgress(
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt +18 -1
@@ 84,7 84,7 @@ class ToNfcConverter(
transformationHistory = paddedTransformationArray,
vitalHistory = generateVitalsHistoryArray(characterId),
appReserved1 = ByteArray(12) {0},
- appReserved2 = Array(3) {0u},
+ appReserved2 = generateUShortAppReserved(userCharacter),
generation = vbData.generation.toUShort(),
totalTrophies = vbData.totalTrophies.toUShort(),
specialMissions = watchSpecialMissions.toTypedArray()
@@ 94,6 94,23 @@ class ToNfcConverter(
}
+ private suspend fun generateUShortAppReserved(
+ userCharacter: UserCharacter
+ ): Array<UShort> {
+ val cardData = database
+ .cardDao()
+ .getCardByCharacterId(userCharacter.id)
+
+ val appReserved = Array<UShort>(3) {
+ 0u
+ }
+
+ appReserved[0] = cardData.id.toUShort()
+
+ return appReserved
+ }
+
+
private suspend fun generateSpecialMissionsArray(
characterId: Long
M app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt +1 -1
@@ 129,7 129,7 @@ class SettingsScreenControllerImpl(
val dimId = database
.cardDao()
- .insertNewDim(cardModel)
+ .insertNewCard(cardModel)
val cardProgress = CardProgress(
cardId = dimId,
A app/src/main/res/drawable/baseline_edit_24.xml => app/src/main/res/drawable/baseline_edit_24.xml +9 -0
@@ 0,0 1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:pathData="M200,760h57l391,-391 -57,-57 -391,391v57ZM120,840v-170l528,-527q12,-11 26.5,-17t30.5,-6q16,0 31,6t26,18l55,56q12,11 17.5,26t5.5,30q0,16 -5.5,30.5T817,313L290,840L120,840ZM760,256 L704,200 760,256ZM619,341 L591,312 648,369 619,341Z"
+ android:fillColor="#000000"/>
+</vector>