From cac51984888b42b4e2a5f9c2abaabfb67c5b47f7 Mon Sep 17 00:00:00 2001 From: Nacho Date: Sun, 12 Jan 2025 00:57:34 +0100 Subject: [PATCH] A few things, again... - Added ability to write character (incomplete) - Renamed BottomNavItem.kt to NavigationItems.kt, as it covers the entire application navigation, not just the bottom navigation bar - Modified the ScanScreenController and the Impl to accomodate writing characters on the BE (need to do the VB later on) - Modified repositories to fetch data from the database and additional information needed to convert back to NfcCharacter - Function to convert to NfcCharacter Originally this was also going to cover the home screen, since my idea was to have marked as active (the one shown in the home screen) be the one sent to the watch, but for testing I have added a "send to bracelet" button on the pop-up on the storage screen. --- .../nacabaro/vbhelper/daos/CharacterDao.kt | 12 ++ .../vbhelper/daos/UserCharacterDao.kt | 5 +- .../nacabaro/vbhelper/dtos/CharacterDtos.kt | 6 +- .../vbhelper/navigation/AppNavigation.kt | 26 ++-- .../vbhelper/navigation/BottomNavItem.kt | 18 --- .../navigation/BottomNavigationBar.kt | 10 +- .../vbhelper/navigation/NavigationItems.kt | 18 +++ .../nacabaro/vbhelper/screens/DexScreen.kt | 6 +- .../nacabaro/vbhelper/screens/HomeScreen.kt | 4 +- .../vbhelper/screens/StorageScreen.kt | 44 ++++-- .../screens/scanScreen/ReadingCharacter.kt | 3 +- .../vbhelper/screens/scanScreen/ScanScreen.kt | 136 +++++++++++++++--- .../scanScreen/ScanScreenController.kt | 4 + .../scanScreen/ScanScreenControllerImpl.kt | 24 ++++ .../vbhelper/source/StorageRepository.kt | 14 ++ .../vbhelper/utils/CharacterToNFCCharacter.kt | 86 +++++++++++ 16 files changed, 343 insertions(+), 73 deletions(-) delete mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt index 0931d87..7b0642f 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt @@ -5,6 +5,7 @@ import androidx.room.Insert import androidx.room.Query import com.github.nacabaro.vbhelper.domain.Character import com.github.nacabaro.vbhelper.domain.Sprites +import com.github.nacabaro.vbhelper.dtos.CharacterDtos @Dao interface CharacterDao { @@ -25,4 +26,15 @@ interface CharacterDao { @Query("SELECT * FROM Sprites") suspend fun getAllSprites(): List + + @Query(""" + SELECT + d.dimId as cardId, + c.monIndex as charId + FROM Character c + JOIN UserCharacter uc ON c.id = uc.charId + JOIN Dim d ON c.dimId = d.id + WHERE uc.id = :charId + """) + suspend fun getCharacterInfo(charId: Long): CharacterDtos.DiMInfo } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt index f6a4ed6..450cec9 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt @@ -21,7 +21,7 @@ interface UserCharacterDao { fun insertTransformationHistory(vararg transformationHistory: TransformationHistory) @Query("SELECT * FROM TransformationHistory WHERE monId = :monId") - fun getTransformationHistory(monId: Int): List + fun getTransformationHistory(monId: Long): List @Query(""" SELECT @@ -36,4 +36,7 @@ interface UserCharacterDao { @Query("SELECT * FROM UserCharacter WHERE id = :id") suspend fun getCharacter(id: Long): UserCharacter + + @Query("SELECT * FROM BECharacterData WHERE id = :id") + suspend fun getBeData(id: Long): BECharacterData } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt index 93df0a8..f7514cb 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt @@ -1,6 +1,5 @@ package com.github.nacabaro.vbhelper.dtos -import androidx.room.PrimaryKey import com.github.cfogrady.vbnfc.data.NfcCharacter import com.github.nacabaro.vbhelper.domain.DeviceType @@ -29,4 +28,9 @@ object CharacterDtos { val spriteWidth: Int, val spriteHeight: Int ) + + data class DiMInfo( + val cardId: Int, + val charId: Int + ) } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt index 727b5fc..24220ed 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt @@ -35,45 +35,51 @@ fun AppNavigation( ) { contentPadding -> NavHost( navController = navController, - startDestination = BottomNavItem.Home.route, + startDestination = NavigationItems.Home.route, modifier = Modifier .padding(contentPadding) ) { - composable(BottomNavItem.Battles.route) { + composable(NavigationItems.Battles.route) { BattlesScreen() } - composable(BottomNavItem.Home.route) { + composable(NavigationItems.Home.route) { HomeScreen( navController = navController ) } - composable(BottomNavItem.Storage.route) { - StorageScreen() + composable(NavigationItems.Storage.route) { + StorageScreen( + navController = navController + ) } - composable(BottomNavItem.Scan.route) { + composable(NavigationItems.Scan.route) { + val characterIdString = it.arguments?.getString("characterId") + val characterId = characterIdString?.toLongOrNull() + ScanScreen( navController = navController, scanScreenController = applicationNavigationHandlers.scanScreenController, + characterId = characterId ) } - composable(BottomNavItem.Dex.route) { + composable(NavigationItems.Dex.route) { DexScreen( navController = navController ) } - composable(BottomNavItem.Settings.route) { + composable(NavigationItems.Settings.route) { SettingsScreen( navController = navController, settingsScreenController = applicationNavigationHandlers.settingsScreenController, onClickImportCard = onClickImportCard ) } - composable(BottomNavItem.Viewer.route) { + composable(NavigationItems.Viewer.route) { SpriteViewer( navController = navController ) } - composable(BottomNavItem.CardView.route) { + composable(NavigationItems.CardView.route) { val dimId = it.arguments?.getString("dimId") Log.d("dimId", dimId.toString()) if (dimId != null) { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt deleted file mode 100644 index cb93839..0000000 --- a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.github.nacabaro.vbhelper.navigation - -import com.github.nacabaro.vbhelper.R - -sealed class BottomNavItem ( - var route: String, - var icon: Int, - var label: String -) { - object Scan : BottomNavItem("Scan", R.drawable.baseline_nfc_24, "Scan") - object Battles : BottomNavItem("Battle", R.drawable.baseline_swords_24, "Battle") - object Home : BottomNavItem("Home", R.drawable.baseline_cottage_24, "Home") - object Dex : BottomNavItem("Dex", R.drawable.baseline_menu_book_24, "Dex") - object Storage : BottomNavItem("Storage", R.drawable.baseline_catching_pokemon_24, "Storage") - object Settings : BottomNavItem("Settings", R.drawable.baseline_settings_24, "Settings") - object Viewer : BottomNavItem("Viewer", R.drawable.baseline_image_24, "Viewer") - object CardView : BottomNavItem("Card/{dimId}", R.drawable.baseline_image_24, "Card") -} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt index 24eb230..36aabc0 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt @@ -13,11 +13,11 @@ import androidx.navigation.compose.currentBackStackEntryAsState @Composable fun BottomNavigationBar(navController: NavController) { val items = listOf( - BottomNavItem.Scan, - BottomNavItem.Battles, - BottomNavItem.Home, - BottomNavItem.Dex, - BottomNavItem.Storage, + NavigationItems.Scan, + NavigationItems.Battles, + NavigationItems.Home, + NavigationItems.Dex, + NavigationItems.Storage, ) NavigationBar { val currentBackStackEntry = navController.currentBackStackEntryAsState() diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt new file mode 100644 index 0000000..5e92c7c --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt @@ -0,0 +1,18 @@ +package com.github.nacabaro.vbhelper.navigation + +import com.github.nacabaro.vbhelper.R + +sealed class NavigationItems ( + var route: String, + var icon: Int, + var label: String +) { + object Scan : NavigationItems("Scan/{characterId}", R.drawable.baseline_nfc_24, "Scan") + object Battles : NavigationItems("Battle", R.drawable.baseline_swords_24, "Battle") + object Home : NavigationItems("Home", R.drawable.baseline_cottage_24, "Home") + object Dex : NavigationItems("Dex", R.drawable.baseline_menu_book_24, "Dex") + object Storage : NavigationItems("Storage", R.drawable.baseline_catching_pokemon_24, "Storage") + object Settings : NavigationItems("Settings", R.drawable.baseline_settings_24, "Settings") + object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer") + object CardView : NavigationItems("Card/{dimId}", R.drawable.baseline_image_24, "Card") +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt index 710d593..da9d9e6 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt @@ -19,7 +19,7 @@ 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.domain.Dim -import com.github.nacabaro.vbhelper.navigation.BottomNavItem +import com.github.nacabaro.vbhelper.navigation.NavigationItems import com.github.nacabaro.vbhelper.source.DexRepository import kotlinx.coroutines.launch @@ -45,7 +45,7 @@ fun DexScreen( TopBanner( text = "Discovered Digimon", onGearClick = { - navController.navigate(BottomNavItem.Viewer.route) + navController.navigate(NavigationItems.Viewer.route) } ) } @@ -65,7 +65,7 @@ fun DexScreen( onClick = { navController .navigate( - BottomNavItem + NavigationItems .CardView.route .replace("{dimId}", "${it.id}") ) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt index 03b6985..5491405 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt @@ -8,7 +8,7 @@ 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 +import com.github.nacabaro.vbhelper.navigation.NavigationItems @Composable fun HomeScreen( @@ -19,7 +19,7 @@ fun HomeScreen( TopBanner( text = "VB Helper", onGearClick = { - navController.navigate(BottomNavItem.Settings.route) + navController.navigate(NavigationItems.Settings.route) } ) } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt index 4801c9c..c237072 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt @@ -1,11 +1,11 @@ package com.github.nacabaro.vbhelper.screens import android.util.Log -import androidx.compose.foundation.Image import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -21,11 +21,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember 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.Modifier @@ -34,18 +32,22 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties +import androidx.navigation.NavController import com.github.nacabaro.vbhelper.components.CharacterEntry import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.dtos.CharacterDtos +import com.github.nacabaro.vbhelper.navigation.NavigationItems import com.github.nacabaro.vbhelper.source.StorageRepository import com.github.nacabaro.vbhelper.utils.BitmapData import kotlinx.coroutines.launch @Composable -fun StorageScreen() { +fun StorageScreen( + navController: NavController +) { val coroutineScope = rememberCoroutineScope() val application = LocalContext.current.applicationContext as VBHelper val storageRepository = StorageRepository(application.container.db) @@ -96,14 +98,24 @@ fun StorageScreen() { ), modifier = Modifier .padding(8.dp) - .size(96.dp) - + .size(96.dp), + onClick = { + selectedCharacter = index.id + } ) if (selectedCharacter != null) { StorageDialog( characterId = selectedCharacter!!, - onDismissRequest = { selectedCharacter = null } + onDismissRequest = { selectedCharacter = null }, + onSendToBracelet = { + navController.navigate( + NavigationItems.Scan.route.replace( + "{characterId}", + selectedCharacter.toString() + ) + ) + } ) } } @@ -114,7 +126,8 @@ fun StorageScreen() { @Composable fun StorageDialog( characterId: Long, - onDismissRequest: () -> Unit + onDismissRequest: () -> Unit, + onSendToBracelet: () -> Unit ) { val coroutineScope = rememberCoroutineScope() val application = LocalContext.current.applicationContext as VBHelper @@ -149,10 +162,17 @@ fun StorageDialog( .padding(8.dp) ) } - Button( - onClick = onDismissRequest - ) { - Text(text = "Close") + Row { + Button( + onClick = onSendToBracelet + ) { + Text(text = "Send to bracelet") + } + Button( + onClick = onDismissRequest + ) { + Text(text = "Close") + } } } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ReadingCharacter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ReadingCharacter.kt index 9c7a2dc..89ce2ed 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ReadingCharacter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ReadingCharacter.kt @@ -15,11 +15,12 @@ import com.github.nacabaro.vbhelper.components.TopBanner @Composable fun ReadingCharacterScreen( + topBannerText: String, onClickCancel: () -> Unit, ) { Scaffold ( topBar = { - TopBanner("Reading Character") + TopBanner(topBannerText) } ) { innerPadding -> Column ( diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt index 9b545e9..ed2a6dc 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -25,25 +26,48 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController +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.navigation.BottomNavItem +import com.github.nacabaro.vbhelper.di.VBHelper +import com.github.nacabaro.vbhelper.navigation.NavigationItems +import com.github.nacabaro.vbhelper.source.StorageRepository import com.github.nacabaro.vbhelper.source.isMissingSecrets import com.github.nacabaro.vbhelper.source.proto.Secrets +import com.github.nacabaro.vbhelper.utils.characterToNfc +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.withContext const val SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER = "SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER" @Composable fun ScanScreen( navController: NavController, + characterId: Long?, scanScreenController: ScanScreenController, ) { val secrets by scanScreenController.secretsFlow.collectAsState(null) var readingScreen by remember { mutableStateOf(false) } + var writingScreen by remember { mutableStateOf(false) } var isDoneReadingCharacter by remember { mutableStateOf(false) } + var isDoneSendingCard by remember { mutableStateOf(false) } + var isDoneWritingCharacter by remember { mutableStateOf(false) } - DisposableEffect(readingScreen) { + val application = LocalContext.current.applicationContext as VBHelper + val storageRepository = StorageRepository(application.container.db) + var nfcCharacter by remember { mutableStateOf(null) } + + val context = LocalContext.current + LaunchedEffect(storageRepository) { + withContext(Dispatchers.IO) { + if(characterId != null) { + nfcCharacter = characterToNfc(context, characterId) + } + } + } + + DisposableEffect(readingScreen || writingScreen) { if(readingScreen) { scanScreenController.registerActivityLifecycleListener(SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER, object: ActivityLifecycleListener { override fun onPause() { @@ -60,9 +84,39 @@ fun ScanScreen( scanScreenController.onClickRead(secrets!!) { isDoneReadingCharacter = true } + } else if (writingScreen) { + scanScreenController.registerActivityLifecycleListener( + SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER, + object : ActivityLifecycleListener { + override fun onPause() { + scanScreenController.cancelRead() + } + + override fun onResume() { + if (!isDoneSendingCard) { + scanScreenController.onClickCheckCard(secrets!!, nfcCharacter!!) { + isDoneSendingCard = true + } + } else if (!isDoneWritingCharacter) { + scanScreenController.onClickWrite(secrets!!, nfcCharacter!!) { + isDoneWritingCharacter = true + } + } + } + } + ) + if (!isDoneSendingCard) { + scanScreenController.onClickCheckCard(secrets!!, nfcCharacter!!) { + isDoneSendingCard = true + } + } else if (!isDoneWritingCharacter) { + scanScreenController.onClickWrite(secrets!!, nfcCharacter!!) { + isDoneWritingCharacter = true + } + } } onDispose { - if(readingScreen) { + if(readingScreen || writingScreen) { scanScreenController.unregisterActivityLifecycleListener(SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER) scanScreenController.cancelRead() } @@ -71,33 +125,68 @@ fun ScanScreen( if (isDoneReadingCharacter) { readingScreen = false - navController.navigate(BottomNavItem.Home.route) + navController.navigate(NavigationItems.Home.route) + } else if (isDoneSendingCard && isDoneWritingCharacter) { + writingScreen = false + navController.navigate(NavigationItems.Home.route) } if (readingScreen) { - ReadingCharacterScreen { + ReadingCharacterScreen("Reading character") { readingScreen = false scanScreenController.cancelRead() } + } else if (writingScreen) { + if (!isDoneSendingCard) { + ReadingCharacterScreen("Sending card") { + isDoneSendingCard = true + scanScreenController.cancelRead() + } + } else if (!isDoneWritingCharacter) { + ReadingCharacterScreen("Writing character") { + isDoneWritingCharacter = true + writingScreen = false + scanScreenController.cancelRead() + } + } } else { - val context = LocalContext.current ChooseConnectOption( - onClickRead = { - if(secrets == null) { - Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show() - } else if(secrets?.isMissingSecrets() == true) { - Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show() - } else { - readingScreen = true // kicks off nfc adapter in DisposableEffect + onClickRead = when { + characterId != null -> null + else -> { + { + if(secrets == null) { + Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show() + } else if(secrets?.isMissingSecrets() == true) { + Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show() + } else { + readingScreen = true // kicks off nfc adapter in DisposableEffect + } + } } }, + onClickWrite = when { + nfcCharacter == null -> null + else -> { + { + if(secrets == null) { + Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show() + } else if(secrets?.isMissingSecrets() == true) { + Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show() + } else { + writingScreen = true // kicks off nfc adapter in DisposableEffect + } + } + } + } ) } } @Composable -private fun ChooseConnectOption( - onClickRead: () -> Unit, +fun ChooseConnectOption( + onClickRead: (() -> Unit)? = null, + onClickWrite: (() -> Unit)? = null, ) { Scaffold( topBar = { TopBanner(text = "Scan a Vital Bracelet") } @@ -111,12 +200,14 @@ private fun ChooseConnectOption( ) { ScanButton( text = "Vital Bracelet to App", - onClick = onClickRead, + disabled = onClickRead == null, + onClick = onClickRead?: { }, ) Spacer(modifier = Modifier.height(16.dp)) ScanButton( text = "App to Vital Bracelet", - onClick = {} + disabled = onClickWrite == null, + onClick = onClickWrite?: { }, ) } } @@ -127,11 +218,13 @@ private fun ChooseConnectOption( fun ScanButton( text: String, onClick: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + disabled: Boolean = false, ) { Button( onClick = onClick, - modifier = modifier + modifier = modifier, + enabled = !disabled, ) { Text( text = text, @@ -157,7 +250,10 @@ fun ScanScreenPreview() { } override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) {} + override fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {} + override fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {} override fun cancelRead() {} - } + }, + characterId = null ) } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt index 061e737..609ab50 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenController.kt @@ -1,5 +1,6 @@ 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.source.proto.Secrets import kotlinx.coroutines.flow.Flow @@ -7,6 +8,9 @@ import kotlinx.coroutines.flow.Flow interface ScanScreenController { val secretsFlow: Flow fun onClickRead(secrets: Secrets, onComplete: ()->Unit) + fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) + fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) + fun cancelRead() fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt index c31061b..849c742 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt @@ -109,6 +109,30 @@ class ScanScreenControllerImpl( } } + override fun onClickWrite( + secrets: Secrets, + nfcCharacter: NfcCharacter, + onComplete: () -> Unit + ) { + handleTag(secrets) { tagCommunicator -> + tagCommunicator.sendCharacter(nfcCharacter) + onComplete.invoke() + "Sent character successfully!" + } + } + + override fun onClickCheckCard( + secrets: Secrets, + nfcCharacter: NfcCharacter, + onComplete: () -> Unit + ) { + handleTag(secrets) { tagCommunicator -> + tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId) + onComplete.invoke() + "Sent DIM successfully!" + } + } + // EXTRACTED DIRECTLY FROM EXAMPLE APP private fun showWirelessSettings() { Toast.makeText(context, "NFC must be enabled", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt index 8aa03ae..8e1f753 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt @@ -1,6 +1,8 @@ package com.github.nacabaro.vbhelper.source import com.github.nacabaro.vbhelper.database.AppDatabase +import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData +import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.dtos.CharacterDtos @@ -14,4 +16,16 @@ class StorageRepository ( suspend fun getSingleCharacter(id: Long): UserCharacter { return db.userCharacterDao().getCharacter(id) } + + suspend fun getCharacterBeData(id: Long): BECharacterData { + return db.userCharacterDao().getBeData(id) + } + + fun getTransformationHistory(characterId: Long): List { + return db.userCharacterDao().getTransformationHistory(characterId) + } + + suspend fun getCharacterData(id: Long): CharacterDtos.DiMInfo { + return db.characterDao().getCharacterInfo(id) + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt new file mode 100644 index 0000000..8d37cbf --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt @@ -0,0 +1,86 @@ +package com.github.nacabaro.vbhelper.utils + +import android.content.Context +import com.github.cfogrady.vbnfc.be.BENfcCharacter +import com.github.cfogrady.vbnfc.be.FirmwareVersion +import com.github.cfogrady.vbnfc.data.NfcCharacter +import com.github.nacabaro.vbhelper.di.VBHelper +import com.github.nacabaro.vbhelper.domain.DeviceType +import com.github.nacabaro.vbhelper.source.StorageRepository + +suspend fun characterToNfc(context: Context, characterId: Long): NfcCharacter? { + val app = context.applicationContext as VBHelper + val database = app.container.db + val storageRepository = StorageRepository(database) + val userCharacter = storageRepository.getSingleCharacter(characterId) + val characterInfo = storageRepository.getCharacterData(characterId) + + if (userCharacter.characterType == DeviceType.BEDevice) { + val beData = storageRepository.getCharacterBeData(characterId) + val transformationHistory = storageRepository + .getTransformationHistory(characterId) + .map { + NfcCharacter.Transformation( + toCharIndex = it.toCharIndex.toUByte(), + year = it.year.toUShort(), + month = it.month.toUByte(), + day = it.day.toUByte() + ) + }.toTypedArray() + + // Maybe this is the issue? + val dummyVitalHistory = arrayOf() + + val nfcData = BENfcCharacter( + dimId = characterInfo.cardId.toUShort(), + charIndex = characterInfo.charId.toUShort(), + stage = userCharacter.stage.toByte(), + attribute = userCharacter.attribute, + ageInDays = userCharacter.ageInDays.toByte(), + nextAdventureMissionStage = userCharacter.nextAdventureMissionStage.toByte(), + mood = userCharacter.mood.toByte(), + vitalPoints = userCharacter.vitalPoints.toUShort(), + itemEffectMentalStateValue = beData.itemEffectMentalStateValue.toByte(), + itemEffectMentalStateMinutesRemaining = beData.itemEffectMentalStateMinutesRemaining.toByte(), + itemEffectActivityLevelValue = beData.itemEffectActivityLevelValue.toByte(), + itemEffectActivityLevelMinutesRemaining = beData.itemEffectActivityLevelMinutesRemaining.toByte(), + itemEffectVitalPointsChangeValue = beData.itemEffectVitalPointsChangeValue.toByte(), + itemEffectVitalPointsChangeMinutesRemaining = beData.itemEffectVitalPointsChangeMinutesRemaining.toByte(), + transformationCountdownInMinutes = userCharacter.transformationCountdown.toUShort(), + injuryStatus = userCharacter.injuryStatus, + trainingPp = userCharacter.trophies.toUShort(), + currentPhaseBattlesWon = userCharacter.currentPhaseBattlesWon.toUShort(), + currentPhaseBattlesLost = userCharacter.currentPhaseBattlesLost.toUShort(), + totalBattlesWon = userCharacter.totalBattlesWon.toUShort(), + totalBattlesLost = userCharacter.totalBattlesLost.toUShort(), + activityLevel = userCharacter.activityLevel.toByte(), + heartRateCurrent = userCharacter.heartRateCurrent.toUByte(), + transformationHistory = transformationHistory, + vitalHistory = arrayOf(), + appReserved1 = byteArrayOf(), + appReserved2 = Array(2, { 0u }), + trainingHp = beData.trainingHp.toUShort(), + trainingAp = beData.trainingAp.toUShort(), + trainingBp = beData.trainingBp.toUShort(), + remainingTrainingTimeInMinutes = beData.remainingTrainingTimeInMinutes.toUShort(), + abilityRarity = beData.abilityRarity, + abilityType = beData.abilityType.toUShort(), + abilityBranch = beData.abilityBranch.toUShort(), + abilityReset = beData.abilityReset.toByte(), + rank = beData.rank.toByte(), + itemType = beData.itemType.toByte(), + itemMultiplier = beData.itemMultiplier.toByte(), + itemRemainingTime = beData.itemRemainingTime.toByte(), + otp0 = byteArrayOf(8), + otp1 = byteArrayOf(8), + characterCreationFirmwareVersion = FirmwareVersion( + minorVersion = beData.minorVersion.toByte(), + majorVersion = beData.majorVersion.toByte() + ) + ) + + return nfcData + } + + return null +} \ No newline at end of file