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 0931d878be2b30c89d851a47fd3a2898b1f270ad..7b0642f93461fd5014dc93261a76ddaaf519223f 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 f6a4ed6b948a57c81edcf1c89bfa19b8b78e9821..450cec9170816e22c94c53c743467fb23b794b53 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 93df0a84f69510a849c71ed9ffc0d4db5e7e7929..f7514cbe6ee2c12e8d948237c76ed057ddd53366 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 727b5fc96fdb20a3047016cb25af336f009f45d9..24220ed841706ede5930cccc4c2e6156d62f05bc 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 cb938398c36dd59a4d1a127cb99d252b78588075..0000000000000000000000000000000000000000 --- 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 24eb2300834eccade2ade5861f12be9ae172eee9..36aabc02fbc76d11bada930b84b3169e9c74bcea 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 0000000000000000000000000000000000000000..5e92c7c56da2b7d9d220691307b0537d468ab054 --- /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 710d5938f77e4fa8f5cd11c0b6d83f8d33451d33..da9d9e688b8cc8a132919c529a4786658afeb8e5 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 03b698549cac9c7fe02daed3ed3b57074b5a46cf..5491405b44533afa65d7216dae24d58b0ec3bf46 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 4801c9c99d1a0d16c7fef2580e100d5758186dda..c2370723a9fe7ee517496224012a7c87c822f67a 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 9c7a2dc4856ab7d5182b04e3cde6569dd2a987c0..89ce2ed7594dd57f0c175a04037d6b32c912d8a2 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 9b545e9919a294097c8c4f0472689f34612aa9a8..ed2a6dc3fa881578d8fd6d1fbd977ba86085a4ea 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 061e737d3601969189294e2911d2e5c9600c3542..609ab50b3b86c580a085f843d201414477405137 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 c31061bbbd5dcf838996ee807803883578a3b9e7..849c7428625c1067cce86c07fc9b84e84cf531b4 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 8aa03ae43fa9cd296cfb8d469f94f71208640557..8e1f753b460b1f3f061a0f56d1ea2a431e1b3e43 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 0000000000000000000000000000000000000000..8d37cbf30a965bbc7d73ef994c671067861fa648 --- /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