From bb5f66d167e6e28027c96928688c00fc537eb012 Mon Sep 17 00:00:00 2001 From: Nacho Date: Tue, 21 Jan 2025 12:42:52 +0100 Subject: [PATCH 1/2] Moved import card logic outside of the MainActivity --- .../github/nacabaro/vbhelper/MainActivity.kt | 124 +----------------- .../vbhelper/navigation/AppNavigation.kt | 4 +- .../screens/settingsScreen/SettingsScreen.kt | 5 +- .../SettingsScreenController.kt | 1 + .../SettingsScreenControllerImpl.kt | 110 ++++++++++++++++ 5 files changed, 119 insertions(+), 125 deletions(-) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt b/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt index eaa7d0e..cee99cb 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt @@ -1,26 +1,16 @@ package com.github.nacabaro.vbhelper -import android.content.Intent import android.os.Bundle import android.util.Log -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable -import androidx.lifecycle.lifecycleScope -import com.github.cfogrady.vb.dim.card.BemCard -import com.github.cfogrady.vb.dim.card.DimReader import com.github.nacabaro.vbhelper.navigation.AppNavigation 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.di.VBHelper -import com.github.nacabaro.vbhelper.domain.characters.Card -import com.github.nacabaro.vbhelper.domain.Sprites -import com.github.nacabaro.vbhelper.domain.characters.Character import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers @@ -30,15 +20,12 @@ import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControl import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme import com.github.nacabaro.vbhelper.utils.DeviceType import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.launch import java.util.GregorianCalendar class MainActivity : ComponentActivity() { private var nfcCharacter = MutableStateFlow(null) - private lateinit var activityResultLauncher: ActivityResultLauncher - private val onActivityLifecycleListeners = HashMap() private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) { @@ -53,8 +40,6 @@ class MainActivity : ComponentActivity() { } override fun onCreate(savedInstanceState: Bundle?) { - registerFileActivityResult() - val application = applicationContext as VBHelper val scanScreenController = ScanScreenControllerImpl( application.container.dataStoreSecretsRepository.secretsFlow, @@ -67,7 +52,9 @@ class MainActivity : ComponentActivity() { val itemsScreenController = ItemsScreenControllerImpl(this) super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { VBHelperTheme { MainApplication( @@ -77,6 +64,7 @@ class MainActivity : ComponentActivity() { ) } } + Log.i("MainActivity", "Activity onCreated") } @@ -96,122 +84,18 @@ class MainActivity : ComponentActivity() { } } - private fun registerFileActivityResult() { - activityResultLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - lifecycleScope.launch { - val application = applicationContext as VBHelper - val storageRepository = application.container.db - - if (it.resultCode != RESULT_OK) { - Toast.makeText(applicationContext, "Import operation cancelled.", Toast.LENGTH_SHORT).show() - } - val contentResolver = applicationContext.contentResolver - val inputStream = contentResolver.openInputStream(it.data!!.data!!) - inputStream.use { fileReader -> - val dimReader = DimReader() - val card = dimReader.readCard(fileReader, false) - - Log.i("MainActivity", "Card name: ${card is BemCard}") - - val cardModel = Card( - dimId = card.header.dimId, - logo = card.spriteData.sprites[0].pixelData, - name = card.spriteData.text, // TODO Make user write card name - stageCount = card.adventureLevels.levels.size, - logoHeight = card.spriteData.sprites[0].height, - logoWidth = card.spriteData.sprites[0].width, - isBEm = card is BemCard - ) - - val dimId = storageRepository - .dimDao() - .insertNewDim(cardModel) - - val characters = card.characterStats.characterEntries - - var spriteCounter = when (card is BemCard) { - true -> 55 - false -> 10 - } - - val domainCharacters = mutableListOf() - - for (index in 0 until characters.size) { - domainCharacters.add( - Character( - dimId = dimId, - monIndex = index, - name = card.spriteData.sprites[spriteCounter].pixelData, - stage = characters[index].stage, - attribute = characters[index].attribute, - baseHp = characters[index].hp, - baseBp = characters[index].dp, - baseAp = characters[index].ap, - sprite1 = card.spriteData.sprites[spriteCounter + 1].pixelData, - sprite2 = card.spriteData.sprites[spriteCounter + 2].pixelData, - nameWidth = card.spriteData.sprites[spriteCounter].width, - nameHeight = card.spriteData.sprites[spriteCounter].height, - spritesWidth = card.spriteData.sprites[spriteCounter + 1].width, - spritesHeight = card.spriteData.sprites[spriteCounter + 1].height - ) - ) - - // TODO: Improve this - if (card is BemCard) { - spriteCounter += 14 - } else { - when (index) { - 0 -> spriteCounter += 6 - 1 -> spriteCounter += 7 - else -> spriteCounter += 14 - } - } - } - - storageRepository - .characterDao() - .insertCharacter(*domainCharacters.toTypedArray()) - - val sprites = card.spriteData.sprites.map { sprite -> - Sprites( - id = 0, - sprite = sprite.pixelData, - width = sprite.width, - height = sprite.height - ) - } - storageRepository - .characterDao() - .insertSprite(*sprites.toTypedArray()) - } - inputStream?.close() - Toast.makeText(applicationContext, "Import successful!", Toast.LENGTH_SHORT).show() - } - } - } - @Composable private fun MainApplication( scanScreenController: ScanScreenControllerImpl, settingsScreenController: SettingsScreenControllerImpl, itemsScreenController: ItemsScreenControllerImpl ) { - AppNavigation( applicationNavigationHandlers = AppNavigationHandlers( settingsScreenController, scanScreenController, itemsScreenController - ), - onClickImportCard = { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/*" - } - activityResultLauncher.launch(intent) - } + ) ) } 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 13e8fd4..541a80c 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 @@ -30,7 +30,6 @@ data class AppNavigationHandlers( @Composable fun AppNavigation( applicationNavigationHandlers: AppNavigationHandlers, - onClickImportCard: () -> Unit, ) { val navController = rememberNavController() @@ -76,8 +75,7 @@ fun AppNavigation( composable(NavigationItems.Settings.route) { SettingsScreen( navController = navController, - settingsScreenController = applicationNavigationHandlers.settingsScreenController, - onClickImportCard = onClickImportCard, + settingsScreenController = applicationNavigationHandlers.settingsScreenController ) } composable(NavigationItems.Viewer.route) { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt index 6c0051f..02dfc6a 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt @@ -23,7 +23,6 @@ import com.github.nacabaro.vbhelper.components.TopBanner fun SettingsScreen( navController: NavController, settingsScreenController: SettingsScreenControllerImpl, - onClickImportCard: () -> Unit ) { Scaffold ( topBar = { @@ -55,7 +54,9 @@ fun SettingsScreen( settingsScreenController.onClickImportDatabase() } SettingsSection("DiM/BEm management") - SettingsEntry(title = "Import DiM card", description = "Import DiM/BEm card file", onClick = onClickImportCard) + SettingsEntry(title = "Import DiM card", description = "Import DiM/BEm card file") { + settingsScreenController.onClickImportCard() + } SettingsEntry(title = "Rename DiM/BEm", description = "Set card name") { } SettingsSection("About and credits") SettingsEntry(title = "Credits", description = "Credits") { } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt index 94fffee..ea0fb19 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt @@ -4,4 +4,5 @@ interface SettingsScreenController { fun onClickOpenDirectory() fun onClickImportDatabase() fun onClickImportApk() + fun onClickImportCard() } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt index 8cae654..94be077 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt @@ -9,7 +9,13 @@ import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts +import com.github.cfogrady.vb.dim.card.BemCard +import com.github.cfogrady.vb.dim.card.DimReader +import com.github.nacabaro.vbhelper.database.AppDatabase import com.github.nacabaro.vbhelper.di.VBHelper +import com.github.nacabaro.vbhelper.domain.Sprites +import com.github.nacabaro.vbhelper.domain.characters.Card +import com.github.nacabaro.vbhelper.domain.characters.Character import com.github.nacabaro.vbhelper.source.ApkSecretsImporter import com.github.nacabaro.vbhelper.source.SecretsImporter import com.github.nacabaro.vbhelper.source.SecretsRepository @@ -27,9 +33,11 @@ class SettingsScreenControllerImpl( private val filePickerLauncher: ActivityResultLauncher private val filePickerOpenerLauncher: ActivityResultLauncher> private val filePickerApk: ActivityResultLauncher> + private val filePickerCard: ActivityResultLauncher> private val secretsImporter: SecretsImporter = ApkSecretsImporter() private val application = context.applicationContext as VBHelper private val secretsRepository: SecretsRepository = application.container.dataStoreSecretsRepository + private val database: AppDatabase = application.container.db init { filePickerLauncher = context.registerForActivityResult( @@ -68,6 +76,18 @@ class SettingsScreenControllerImpl( } } } + + filePickerCard = context.registerForActivityResult( + ActivityResultContracts.OpenDocument() + ) { uri -> + if (uri != null) { + importCard(uri) + } else { + context.runOnUiThread { + Toast.makeText(context, "Card import cancelled", Toast.LENGTH_SHORT).show() + } + } + } } override fun onClickOpenDirectory() { @@ -82,6 +102,96 @@ class SettingsScreenControllerImpl( filePickerApk.launch(arrayOf("*/*")) } + override fun onClickImportCard() { + filePickerCard.launch(arrayOf("*/*")) + } + + private fun importCard(uri: Uri) { + context.lifecycleScope.launch(Dispatchers.IO) { + val contentResolver = context.contentResolver + val inputStream = contentResolver.openInputStream(uri) + inputStream.use { fileReader -> + val dimReader = DimReader() + val card = dimReader.readCard(fileReader, false) + + val cardModel = Card( + dimId = card.header.dimId, + logo = card.spriteData.sprites[0].pixelData, + name = card.spriteData.text, // TODO Make user write card name// TODO Make user write card name + stageCount = card.adventureLevels.levels.size, + logoHeight = card.spriteData.sprites[0].height, + logoWidth = card.spriteData.sprites[0].width, + isBEm = card is BemCard + ) + + val dimId = database + .dimDao() + .insertNewDim(cardModel) + + val characters = card.characterStats.characterEntries + + var spriteCounter = when (card is BemCard) { + true -> 55 + false -> 10 + } + + val domainCharacters = mutableListOf() + + for (index in 0 until characters.size) { + domainCharacters.add( + Character( + dimId = dimId, + monIndex = index, + name = card.spriteData.sprites[spriteCounter].pixelData, + stage = characters[index].stage, + attribute = characters[index].attribute, + baseHp = characters[index].hp, + baseBp = characters[index].dp, + baseAp = characters[index].ap, + sprite1 = card.spriteData.sprites[spriteCounter + 1].pixelData, + sprite2 = card.spriteData.sprites[spriteCounter + 2].pixelData, + nameWidth = card.spriteData.sprites[spriteCounter].width, + nameHeight = card.spriteData.sprites[spriteCounter].height, + spritesWidth = card.spriteData.sprites[spriteCounter + 1].width, + spritesHeight = card.spriteData.sprites[spriteCounter + 1].height + ) + ) + + spriteCounter += if (card is BemCard) { + 14 + } else { + when (index) { + 0 -> 6 + 1 -> 7 + else -> 14 + } + } + } + + database + .characterDao() + .insertCharacter(*domainCharacters.toTypedArray()) + + val sprites = card.spriteData.sprites.map { sprite -> + Sprites( + id = 0, + sprite = sprite.pixelData, + width = sprite.width, + height = sprite.height + ) + } + database + .characterDao() + .insertSprite(*sprites.toTypedArray()) + } + + inputStream?.close() + context.runOnUiThread { + Toast.makeText(context, "Import successful!", Toast.LENGTH_SHORT).show() + } + } + } + private fun exportDatabase(destinationUri: Uri) { context.lifecycleScope.launch(Dispatchers.IO) { try { From a974bd366e8a906691f6f5d53c601bb1e365ef45 Mon Sep 17 00:00:00 2001 From: Nacho Date: Tue, 21 Jan 2025 13:02:45 +0100 Subject: [PATCH 2/2] Moved read character from watch to its corresponding controller --- .../github/nacabaro/vbhelper/MainActivity.kt | 131 +--------------- .../screens/homeScreens/HomeScreen.kt | 3 - .../scanScreen/ScanScreenControllerImpl.kt | 140 +++++++++++++++--- 3 files changed, 124 insertions(+), 150 deletions(-) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt b/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt index cee99cb..039b322 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt @@ -7,25 +7,15 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.Composable import com.github.nacabaro.vbhelper.navigation.AppNavigation -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.di.VBHelper -import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData -import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme -import com.github.nacabaro.vbhelper.utils.DeviceType -import kotlinx.coroutines.flow.MutableStateFlow -import java.util.GregorianCalendar + class MainActivity : ComponentActivity() { - - private var nfcCharacter = MutableStateFlow(null) - private val onActivityLifecycleListeners = HashMap() private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) { @@ -43,7 +33,6 @@ class MainActivity : ComponentActivity() { val application = applicationContext as VBHelper val scanScreenController = ScanScreenControllerImpl( application.container.dataStoreSecretsRepository.secretsFlow, - this::handleReceivedNfcCharacter, this, this::registerActivityLifecycleListener, this::unregisterActivityLifecycleListener @@ -98,122 +87,4 @@ class MainActivity : ComponentActivity() { ) ) } - - private fun handleReceivedNfcCharacter(character: NfcCharacter): String { - nfcCharacter.value = character - - val importStatus = addCharacterScannedIntoDatabase() - - return importStatus - } - - // - /* - TODO: - - Support for regular VB - - The good news is that the theory behind inserting to the database should be working - now, it's a matter of implementing the functionality to parse dim/bem cards and use my - domain model. - */ - private fun addCharacterScannedIntoDatabase(): String { - val application = applicationContext as VBHelper - val storageRepository = application.container.db - - val dimData = storageRepository - .dimDao() - .getDimById(nfcCharacter.value!!.dimId.toInt()) - - if (dimData == null) return "Card not found" - - val cardCharData = storageRepository - .characterDao() - .getCharacterByMonIndex(nfcCharacter.value!!.charIndex.toInt(), dimData.id) - - val characterData = UserCharacter( - charId = cardCharData.id, - stage = nfcCharacter.value!!.stage.toInt(), - attribute = nfcCharacter.value!!.attribute, - ageInDays = nfcCharacter.value!!.ageInDays.toInt(), - nextAdventureMissionStage = nfcCharacter.value!!.nextAdventureMissionStage.toInt(), - mood = nfcCharacter.value!!.mood.toInt(), - vitalPoints = nfcCharacter.value!!.vitalPoints.toInt(), - transformationCountdown = nfcCharacter.value!!.transformationCountdownInMinutes.toInt(), - injuryStatus = nfcCharacter.value!!.injuryStatus, - trophies = nfcCharacter.value!!.trophies.toInt(), - currentPhaseBattlesWon = nfcCharacter.value!!.currentPhaseBattlesWon.toInt(), - currentPhaseBattlesLost = nfcCharacter.value!!.currentPhaseBattlesLost.toInt(), - totalBattlesWon = nfcCharacter.value!!.totalBattlesWon.toInt(), - totalBattlesLost = nfcCharacter.value!!.totalBattlesLost.toInt(), - activityLevel = nfcCharacter.value!!.activityLevel.toInt(), - heartRateCurrent = nfcCharacter.value!!.heartRateCurrent.toInt(), - characterType = when (nfcCharacter.value) { - is BENfcCharacter -> DeviceType.BEDevice - else -> DeviceType.VBDevice - }, - isActive = true - ) - - storageRepository - .userCharacterDao() - .clearActiveCharacter() - - val characterId: Long = storageRepository - .userCharacterDao() - .insertCharacterData(characterData) - - if (nfcCharacter.value is BENfcCharacter) { - val beCharacter = nfcCharacter.value as BENfcCharacter - val extraCharacterData = BECharacterData( - id = characterId, - trainingHp = beCharacter.trainingHp.toInt(), - trainingAp = beCharacter.trainingAp.toInt(), - trainingBp = beCharacter.trainingBp.toInt(), - remainingTrainingTimeInMinutes = beCharacter.remainingTrainingTimeInMinutes.toInt(), - itemEffectActivityLevelValue = beCharacter.itemEffectActivityLevelValue.toInt(), - itemEffectMentalStateValue = beCharacter.itemEffectMentalStateValue.toInt(), - itemEffectMentalStateMinutesRemaining = beCharacter.itemEffectMentalStateMinutesRemaining.toInt(), - itemEffectActivityLevelMinutesRemaining = beCharacter.itemEffectActivityLevelMinutesRemaining.toInt(), - itemEffectVitalPointsChangeValue = beCharacter.itemEffectVitalPointsChangeValue.toInt(), - itemEffectVitalPointsChangeMinutesRemaining = beCharacter.itemEffectVitalPointsChangeMinutesRemaining.toInt(), - abilityRarity = beCharacter.abilityRarity, - abilityType = beCharacter.abilityType.toInt(), - abilityBranch = beCharacter.abilityBranch.toInt(), - abilityReset = beCharacter.abilityReset.toInt(), - rank = beCharacter.abilityReset.toInt(), - itemType = beCharacter.itemType.toInt(), - itemMultiplier = beCharacter.itemMultiplier.toInt(), - itemRemainingTime = beCharacter.itemRemainingTime.toInt(), - otp0 = "", //beCharacter.value!!.otp0.toString(), - otp1 = "", //beCharacter.value!!.otp1.toString(), - minorVersion = beCharacter.characterCreationFirmwareVersion.minorVersion.toInt(), - majorVersion = beCharacter.characterCreationFirmwareVersion.majorVersion.toInt(), - ) - - storageRepository - .userCharacterDao() - .insertBECharacterData(extraCharacterData) - - val transformationHistoryWatch = beCharacter.transformationHistory - transformationHistoryWatch.map { item -> - if (item.toCharIndex.toInt() != 255) { - val date = GregorianCalendar(item.year.toInt(), item.month.toInt(), item.day.toInt()) - .time - .time - - storageRepository - .characterDao() - .insertTransformation(characterId, item.toCharIndex.toInt(), dimData.id, date) - - storageRepository - .dexDao() - .insertCharacter(item.toCharIndex.toInt(), dimData.id, date) - } - } - } else if (nfcCharacter.value is VBNfcCharacter) { - return "Not implemented yet" - } - - return "Done reading character!" - } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt index 35863a7..2ad2a19 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt @@ -1,6 +1,5 @@ package com.github.nacabaro.vbhelper.screens.homeScreens -import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -72,7 +71,6 @@ fun HomeScreen( } } else { if (activeMon.value!!.isBemCard) { - Log.d("HomeScreen", "BEDeviceBEm") BEBEmHomeScreen( activeMon = activeMon.value!!, beData = beData.value!!, @@ -80,7 +78,6 @@ fun HomeScreen( contentPadding = contentPadding ) } else if (!activeMon.value!!.isBemCard && activeMon.value!!.characterType == DeviceType.BEDevice) { - Log.d("HomeScreen", "BEDevice") BEDiMHomeScreen( activeMon = activeMon.value!!, beData = beData.value!!, 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 99155bc..d7caf92 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 @@ -11,20 +11,26 @@ import android.widget.Toast import androidx.activity.ComponentActivity import androidx.lifecycle.lifecycleScope import com.github.cfogrady.vbnfc.TagCommunicator +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.di.VBHelper +import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData +import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.source.getCryptographicTransformerMap import com.github.nacabaro.vbhelper.source.isMissingSecrets import com.github.nacabaro.vbhelper.source.proto.Secrets +import com.github.nacabaro.vbhelper.utils.DeviceType import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import java.util.GregorianCalendar class ScanScreenControllerImpl( override val secretsFlow: Flow, - private val nfcHandler: (NfcCharacter)->String, - private val context: ComponentActivity, + private val componentActivity: ComponentActivity, private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit, private val unregisterActivityLifecycleListener: (String)->Unit, ): ScanScreenController { @@ -32,9 +38,9 @@ class ScanScreenControllerImpl( private val nfcAdapter: NfcAdapter init { - val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(context) + val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(componentActivity) if (maybeNfcAdapter == null) { - Toast.makeText(context, "No NFC on device!", Toast.LENGTH_SHORT).show() + Toast.makeText(componentActivity, "No NFC on device!", Toast.LENGTH_SHORT).show() } nfcAdapter = maybeNfcAdapter checkSecrets() @@ -43,7 +49,7 @@ class ScanScreenControllerImpl( override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) { handleTag(secrets) { tagCommunicator -> val character = tagCommunicator.receiveCharacter() - val resultMessage = nfcHandler(character) + val resultMessage = addCharacterScannedIntoDatabase(character) onComplete.invoke() resultMessage } @@ -51,7 +57,7 @@ class ScanScreenControllerImpl( override fun cancelRead() { if(nfcAdapter.isEnabled) { - nfcAdapter.disableReaderMode(context) + nfcAdapter.disableReaderMode(componentActivity) } } @@ -74,7 +80,7 @@ class ScanScreenControllerImpl( val options = Bundle() // Work around for some broken Nfc firmware implementations that poll the card too fast options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250) - nfcAdapter.enableReaderMode(context, buildOnReadTag(secrets, handlerFunc), NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, + nfcAdapter.enableReaderMode(componentActivity, buildOnReadTag(secrets, handlerFunc), NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, options ) } @@ -85,26 +91,26 @@ class ScanScreenControllerImpl( return { tag-> val nfcData = NfcA.get(tag) if (nfcData == null) { - context.runOnUiThread { - Toast.makeText(context, "Tag detected is not VB", Toast.LENGTH_SHORT).show() + componentActivity.runOnUiThread { + Toast.makeText(componentActivity, "Tag detected is not VB", Toast.LENGTH_SHORT).show() } } nfcData.connect() nfcData.use { val tagCommunicator = TagCommunicator.getInstance(nfcData, secrets.getCryptographicTransformerMap()) val successText = handlerFunc(tagCommunicator) - context.runOnUiThread { - Toast.makeText(context, successText, Toast.LENGTH_SHORT).show() + componentActivity.runOnUiThread { + Toast.makeText(componentActivity, successText, Toast.LENGTH_SHORT).show() } } } } private fun checkSecrets() { - context.lifecycleScope.launch(Dispatchers.IO) { - if(secretsFlow.stateIn(context.lifecycleScope).value.isMissingSecrets()) { - context.runOnUiThread { - Toast.makeText(context, "Missing Secrets. Go to settings and import Vital Arena APK", Toast.LENGTH_SHORT).show() + componentActivity.lifecycleScope.launch(Dispatchers.IO) { + if(secretsFlow.stateIn(componentActivity.lifecycleScope).value.isMissingSecrets()) { + componentActivity.runOnUiThread { + Toast.makeText(componentActivity, "Missing Secrets. Go to settings and import Vital Arena APK", Toast.LENGTH_SHORT).show() } } } @@ -141,7 +147,107 @@ class ScanScreenControllerImpl( // EXTRACTED DIRECTLY FROM EXAMPLE APP private fun showWirelessSettings() { - Toast.makeText(context, "NFC must be enabled", Toast.LENGTH_SHORT).show() - context.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS)) + Toast.makeText(componentActivity, "NFC must be enabled", Toast.LENGTH_SHORT).show() + componentActivity.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS)) + } + + private fun addCharacterScannedIntoDatabase(nfcCharacter: NfcCharacter): String { + val application = componentActivity.applicationContext as VBHelper + val storageRepository = application.container.db + + val dimData = storageRepository + .dimDao() + .getDimById(nfcCharacter.dimId.toInt()) + + if (dimData == null) return "Card not found" + + val cardCharData = storageRepository + .characterDao() + .getCharacterByMonIndex(nfcCharacter.charIndex.toInt(), dimData.id) + + val characterData = UserCharacter( + charId = cardCharData.id, + stage = nfcCharacter.stage.toInt(), + attribute = nfcCharacter.attribute, + ageInDays = nfcCharacter.ageInDays.toInt(), + nextAdventureMissionStage = nfcCharacter.nextAdventureMissionStage.toInt(), + mood = nfcCharacter.mood.toInt(), + vitalPoints = nfcCharacter.vitalPoints.toInt(), + transformationCountdown = nfcCharacter.transformationCountdownInMinutes.toInt(), + injuryStatus = nfcCharacter.injuryStatus, + trophies = nfcCharacter.trophies.toInt(), + currentPhaseBattlesWon = nfcCharacter.currentPhaseBattlesWon.toInt(), + currentPhaseBattlesLost = nfcCharacter.currentPhaseBattlesLost.toInt(), + totalBattlesWon = nfcCharacter.totalBattlesWon.toInt(), + totalBattlesLost = nfcCharacter.totalBattlesLost.toInt(), + activityLevel = nfcCharacter.activityLevel.toInt(), + heartRateCurrent = nfcCharacter.heartRateCurrent.toInt(), + characterType = when (nfcCharacter) { + is BENfcCharacter -> DeviceType.BEDevice + else -> DeviceType.VBDevice + }, + isActive = true + ) + + storageRepository + .userCharacterDao() + .clearActiveCharacter() + + val characterId: Long = storageRepository + .userCharacterDao() + .insertCharacterData(characterData) + + if (nfcCharacter is BENfcCharacter) { + val extraCharacterData = BECharacterData( + id = characterId, + trainingHp = nfcCharacter.trainingHp.toInt(), + trainingAp = nfcCharacter.trainingAp.toInt(), + trainingBp = nfcCharacter.trainingBp.toInt(), + remainingTrainingTimeInMinutes = nfcCharacter.remainingTrainingTimeInMinutes.toInt(), + itemEffectActivityLevelValue = nfcCharacter.itemEffectActivityLevelValue.toInt(), + itemEffectMentalStateValue = nfcCharacter.itemEffectMentalStateValue.toInt(), + itemEffectMentalStateMinutesRemaining = nfcCharacter.itemEffectMentalStateMinutesRemaining.toInt(), + itemEffectActivityLevelMinutesRemaining = nfcCharacter.itemEffectActivityLevelMinutesRemaining.toInt(), + itemEffectVitalPointsChangeValue = nfcCharacter.itemEffectVitalPointsChangeValue.toInt(), + itemEffectVitalPointsChangeMinutesRemaining = nfcCharacter.itemEffectVitalPointsChangeMinutesRemaining.toInt(), + abilityRarity = nfcCharacter.abilityRarity, + abilityType = nfcCharacter.abilityType.toInt(), + abilityBranch = nfcCharacter.abilityBranch.toInt(), + abilityReset = nfcCharacter.abilityReset.toInt(), + rank = nfcCharacter.abilityReset.toInt(), + itemType = nfcCharacter.itemType.toInt(), + itemMultiplier = nfcCharacter.itemMultiplier.toInt(), + itemRemainingTime = nfcCharacter.itemRemainingTime.toInt(), + otp0 = "", //nfcCharacter.value!!.otp0.toString(), + otp1 = "", //nfcCharacter.value!!.otp1.toString(), + minorVersion = nfcCharacter.characterCreationFirmwareVersion.minorVersion.toInt(), + majorVersion = nfcCharacter.characterCreationFirmwareVersion.majorVersion.toInt(), + ) + + storageRepository + .userCharacterDao() + .insertBECharacterData(extraCharacterData) + + val transformationHistoryWatch = nfcCharacter.transformationHistory + transformationHistoryWatch.map { item -> + if (item.toCharIndex.toInt() != 255) { + val date = GregorianCalendar(item.year.toInt(), item.month.toInt(), item.day.toInt()) + .time + .time + + storageRepository + .characterDao() + .insertTransformation(characterId, item.toCharIndex.toInt(), dimData.id, date) + + storageRepository + .dexDao() + .insertCharacter(item.toCharIndex.toInt(), dimData.id, date) + } + } + } else if (nfcCharacter is VBNfcCharacter) { + return "Not implemented yet" + } + + return "Done reading character!" } } \ No newline at end of file