M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +5 -250
@@ 1,44 1,21 @@
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
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 kotlinx.coroutines.launch
-import java.util.GregorianCalendar
-class MainActivity : ComponentActivity() {
-
- private var nfcCharacter = MutableStateFlow<NfcCharacter?>(null)
-
- private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
+class MainActivity : ComponentActivity() {
private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>()
private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) {
@@ 53,12 30,9 @@ class MainActivity : ComponentActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
- registerFileActivityResult()
-
val application = applicationContext as VBHelper
val scanScreenController = ScanScreenControllerImpl(
application.container.dataStoreSecretsRepository.secretsFlow,
- this::handleReceivedNfcCharacter,
this,
this::registerActivityLifecycleListener,
this::unregisterActivityLifecycleListener
@@ 67,7 41,9 @@ class MainActivity : ComponentActivity() {
val itemsScreenController = ItemsScreenControllerImpl(this)
super.onCreate(savedInstanceState)
+
enableEdgeToEdge()
+
setContent {
VBHelperTheme {
MainApplication(
@@ 77,6 53,7 @@ class MainActivity : ComponentActivity() {
)
}
}
+
Log.i("MainActivity", "Activity onCreated")
}
@@ 96,240 73,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<Character>()
-
- 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)
- }
- )
- }
-
- 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!"
+ )
}
}
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +1 -3
@@ 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) {
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt +0 -3
@@ 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!!,
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreenControllerImpl.kt +123 -17
@@ 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<Secrets>,
- 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
M app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreen.kt +3 -2
@@ 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") { }
M app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenController.kt +1 -0
@@ 4,4 4,5 @@ interface SettingsScreenController {
fun onClickOpenDirectory()
fun onClickImportDatabase()
fun onClickImportApk()
+ fun onClickImportCard()
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt +110 -0
@@ 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<String>
private val filePickerOpenerLauncher: ActivityResultLauncher<Array<String>>
private val filePickerApk: ActivityResultLauncher<Array<String>>
+ private val filePickerCard: ActivityResultLauncher<Array<String>>
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<Character>()
+
+ 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 {