Moved import card logic outside of the MainActivity

This commit is contained in:
Nacho 2025-01-21 12:42:52 +01:00
parent 09394871e5
commit bb5f66d167
5 changed files with 119 additions and 125 deletions

View File

@ -1,26 +1,16 @@
package com.github.nacabaro.vbhelper package com.github.nacabaro.vbhelper
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable 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.nacabaro.vbhelper.navigation.AppNavigation
import com.github.cfogrady.vbnfc.be.BENfcCharacter import com.github.cfogrady.vbnfc.be.BENfcCharacter
import com.github.cfogrady.vbnfc.data.NfcCharacter import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
import com.github.nacabaro.vbhelper.di.VBHelper 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.BECharacterData
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers 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.ui.theme.VBHelperTheme
import com.github.nacabaro.vbhelper.utils.DeviceType import com.github.nacabaro.vbhelper.utils.DeviceType
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import java.util.GregorianCalendar import java.util.GregorianCalendar
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private var nfcCharacter = MutableStateFlow<NfcCharacter?>(null) private var nfcCharacter = MutableStateFlow<NfcCharacter?>(null)
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>() private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>()
private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) { private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) {
@ -53,8 +40,6 @@ class MainActivity : ComponentActivity() {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
registerFileActivityResult()
val application = applicationContext as VBHelper val application = applicationContext as VBHelper
val scanScreenController = ScanScreenControllerImpl( val scanScreenController = ScanScreenControllerImpl(
application.container.dataStoreSecretsRepository.secretsFlow, application.container.dataStoreSecretsRepository.secretsFlow,
@ -67,7 +52,9 @@ class MainActivity : ComponentActivity() {
val itemsScreenController = ItemsScreenControllerImpl(this) val itemsScreenController = ItemsScreenControllerImpl(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
VBHelperTheme { VBHelperTheme {
MainApplication( MainApplication(
@ -77,6 +64,7 @@ class MainActivity : ComponentActivity() {
) )
} }
} }
Log.i("MainActivity", "Activity onCreated") 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<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 @Composable
private fun MainApplication( private fun MainApplication(
scanScreenController: ScanScreenControllerImpl, scanScreenController: ScanScreenControllerImpl,
settingsScreenController: SettingsScreenControllerImpl, settingsScreenController: SettingsScreenControllerImpl,
itemsScreenController: ItemsScreenControllerImpl itemsScreenController: ItemsScreenControllerImpl
) { ) {
AppNavigation( AppNavigation(
applicationNavigationHandlers = AppNavigationHandlers( applicationNavigationHandlers = AppNavigationHandlers(
settingsScreenController, settingsScreenController,
scanScreenController, scanScreenController,
itemsScreenController itemsScreenController
), )
onClickImportCard = {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
}
activityResultLauncher.launch(intent)
}
) )
} }

View File

@ -30,7 +30,6 @@ data class AppNavigationHandlers(
@Composable @Composable
fun AppNavigation( fun AppNavigation(
applicationNavigationHandlers: AppNavigationHandlers, applicationNavigationHandlers: AppNavigationHandlers,
onClickImportCard: () -> Unit,
) { ) {
val navController = rememberNavController() val navController = rememberNavController()
@ -76,8 +75,7 @@ fun AppNavigation(
composable(NavigationItems.Settings.route) { composable(NavigationItems.Settings.route) {
SettingsScreen( SettingsScreen(
navController = navController, navController = navController,
settingsScreenController = applicationNavigationHandlers.settingsScreenController, settingsScreenController = applicationNavigationHandlers.settingsScreenController
onClickImportCard = onClickImportCard,
) )
} }
composable(NavigationItems.Viewer.route) { composable(NavigationItems.Viewer.route) {

View File

@ -23,7 +23,6 @@ import com.github.nacabaro.vbhelper.components.TopBanner
fun SettingsScreen( fun SettingsScreen(
navController: NavController, navController: NavController,
settingsScreenController: SettingsScreenControllerImpl, settingsScreenController: SettingsScreenControllerImpl,
onClickImportCard: () -> Unit
) { ) {
Scaffold ( Scaffold (
topBar = { topBar = {
@ -55,7 +54,9 @@ fun SettingsScreen(
settingsScreenController.onClickImportDatabase() settingsScreenController.onClickImportDatabase()
} }
SettingsSection("DiM/BEm management") 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") { } SettingsEntry(title = "Rename DiM/BEm", description = "Set card name") { }
SettingsSection("About and credits") SettingsSection("About and credits")
SettingsEntry(title = "Credits", description = "Credits") { } SettingsEntry(title = "Credits", description = "Credits") { }

View File

@ -4,4 +4,5 @@ interface SettingsScreenController {
fun onClickOpenDirectory() fun onClickOpenDirectory()
fun onClickImportDatabase() fun onClickImportDatabase()
fun onClickImportApk() fun onClickImportApk()
fun onClickImportCard()
} }

View File

@ -9,7 +9,13 @@ import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts 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.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.ApkSecretsImporter
import com.github.nacabaro.vbhelper.source.SecretsImporter import com.github.nacabaro.vbhelper.source.SecretsImporter
import com.github.nacabaro.vbhelper.source.SecretsRepository import com.github.nacabaro.vbhelper.source.SecretsRepository
@ -27,9 +33,11 @@ class SettingsScreenControllerImpl(
private val filePickerLauncher: ActivityResultLauncher<String> private val filePickerLauncher: ActivityResultLauncher<String>
private val filePickerOpenerLauncher: ActivityResultLauncher<Array<String>> private val filePickerOpenerLauncher: ActivityResultLauncher<Array<String>>
private val filePickerApk: ActivityResultLauncher<Array<String>> private val filePickerApk: ActivityResultLauncher<Array<String>>
private val filePickerCard: ActivityResultLauncher<Array<String>>
private val secretsImporter: SecretsImporter = ApkSecretsImporter() private val secretsImporter: SecretsImporter = ApkSecretsImporter()
private val application = context.applicationContext as VBHelper private val application = context.applicationContext as VBHelper
private val secretsRepository: SecretsRepository = application.container.dataStoreSecretsRepository private val secretsRepository: SecretsRepository = application.container.dataStoreSecretsRepository
private val database: AppDatabase = application.container.db
init { init {
filePickerLauncher = context.registerForActivityResult( 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() { override fun onClickOpenDirectory() {
@ -82,6 +102,96 @@ class SettingsScreenControllerImpl(
filePickerApk.launch(arrayOf("*/*")) 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) { private fun exportDatabase(destinationUri: Uri) {
context.lifecycleScope.launch(Dispatchers.IO) { context.lifecycleScope.launch(Dispatchers.IO) {
try { try {