~cytrogen/vbhelper

bb5f66d167e6e28027c96928688c00fc537eb012 — Nacho 1 year, 3 months ago 0939487
Moved import card logic outside of the MainActivity
M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +4 -120
@@ 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<NfcCharacter?>(null)

    private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>

    private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>()

    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<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)
            }
            )
        )
    }


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/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 {