M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +120 -4
@@ 10,25 10,31 @@ 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.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.ui.platform.LocalContext
+import androidx.lifecycle.lifecycleScope
+import com.github.cfogrady.vb.dim.card.DimReader
import com.github.nacabaro.vbhelper.navigation.AppNavigation
import com.github.cfogrady.vbnfc.CryptographicTransformer
-import com.github.cfogrady.vbnfc.R
import com.github.cfogrady.vbnfc.TagCommunicator
import com.github.cfogrady.vbnfc.be.BENfcCharacter
import com.github.cfogrady.vbnfc.data.DeviceType
import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.domain.Dim
+import com.github.nacabaro.vbhelper.domain.Sprites
+import com.github.nacabaro.vbhelper.domain.Character
import com.github.nacabaro.vbhelper.temporary_domain.TemporaryBECharacterData
import com.github.nacabaro.vbhelper.temporary_domain.TemporaryCharacterData
import com.github.nacabaro.vbhelper.temporary_domain.TemporaryTransformationHistory
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private lateinit var nfcAdapter: NfcAdapter
@@ 36,10 42,14 @@ class MainActivity : ComponentActivity() {
private var nfcCharacter = MutableStateFlow<NfcCharacter?>(null)
+ private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
+
// EXTRACTED DIRECTLY FROM EXAMPLE APP
override fun onCreate(savedInstanceState: Bundle?) {
deviceToCryptographicTransformers = getMapOfCryptographicTransformers()
+ registerFileActivityResult()
+
val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(this)
if (maybeNfcAdapter == null) {
Toast.makeText(this, "No NFC on device!", Toast.LENGTH_SHORT).show()
@@ 57,11 67,109 @@ class MainActivity : ComponentActivity() {
}
}
+ private fun registerFileActivityResult() {
+ activityResultLauncher = registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) {
+ lifecycleScope.launch {
+ 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)
+ val dimModel = Dim(
+ id = 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
+ )
+ val application = applicationContext as VBHelper
+ val storageRepository = application.container.db
+ storageRepository.dimDao().insertNewDim(dimModel)
+
+ val characters = card.characterStats.characterEntries
+
+ /*
+ Confusing math for me ahead
+ sprite[0] logo
+ sprite[10] name
+ sprite[10 + 1] character_1
+ sprite[10 + 2] character_2
+ sprite[16] name 1
+ sprite[17] character_1
+ sprite[18] character_2
+ sprite[23] name 2
+ sprite[24] character_1
+ sprite[25] character_2
+ sprite[23 + 12 + 1] name 3
+ sprite[23 + 12 + 2] character_1
+ sprite[23 + 12 + 3] character_2
+ */
+
+ var spriteCounter = 10
+ var domainCharacters = mutableListOf<Character>()
+
+ for (index in 0 until characters.size) {
+ domainCharacters.add(
+ Character(
+ id = 0,
+ dimId = card.header.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
+ )
+ )
+
+ if (index == 0) {
+ spriteCounter += 6
+ } else if (index == 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() {
var isDoneReadingCharacter by remember { mutableStateOf(false) }
- val application = LocalContext.current.applicationContext as VBHelper
- val storageRepository = application.container.db
+
AppNavigation(
isDoneReadingCharacter = isDoneReadingCharacter,
onClickRead = {
@@ 75,6 183,13 @@ class MainActivity : ComponentActivity() {
},
onClickScan = {
isDoneReadingCharacter = false
+ },
+ onClickImportCard = {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "*/*"
+ }
+ activityResultLauncher.launch(intent)
}
)
}
@@ 160,6 275,7 @@ class MainActivity : ComponentActivity() {
*/
private fun addCharacterScannedIntoDatabase() {
val beCharacter = nfcCharacter as MutableStateFlow<BENfcCharacter?>
+
val temporaryCharacterData = TemporaryCharacterData(
dimId = nfcCharacter.value!!.dimId.toInt(),
charIndex = nfcCharacter.value!!.charIndex.toInt(),
A app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +37 -0
@@ 0,0 1,37 @@
+package com.github.nacabaro.vbhelper.components
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Card
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun CharacterEntry(
+ icon: ImageBitmap,
+ modifier: Modifier = Modifier,
+ onClick: () -> Unit = { }
+) {
+ Card(
+ shape = MaterialTheme.shapes.medium,
+ onClick = onClick,
+ modifier = modifier
+ .padding(8.dp)
+ .size(96.dp)
+ ) {
+ Image(
+ bitmap = icon,
+ contentDescription = "Icon",
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .padding(8.dp)
+ .fillMaxSize()
+ )
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/components/StorageEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/StorageEntry.kt +64 -0
@@ 0,0 1,64 @@
+package com.github.nacabaro.vbhelper.components
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Card
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun StorageEntry(
+ name: String,
+ nameBitmap: ImageBitmap? = null,
+ modifier: Modifier = Modifier,
+ icon: Int? = null,
+ bitmap: ImageBitmap? = null,
+ onClick: () -> Unit = { }
+) {
+ Card(
+ shape = MaterialTheme.shapes.medium,
+ onClick = onClick,
+ modifier = modifier
+ .padding(8.dp)
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .fillMaxSize()
+ ) {
+ if (bitmap != null) {
+ Image(
+ bitmap = bitmap,
+ contentDescription = name,
+ modifier = Modifier
+ .padding(8.dp)
+ .size(64.dp)
+ )
+ } else if (icon != null) {
+ Image(
+ painter = painterResource(id = icon),
+ contentDescription = name,
+ modifier = Modifier
+ .padding(8.dp)
+ .size(64.dp)
+ )
+ }
+ Text(
+ text = name,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(8.dp)
+ )
+ }
+ }
+}
M app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt +4 -1
@@ 1,10 1,12 @@
package com.github.nacabaro.vbhelper.components
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ 20,10 22,11 @@ fun TopBanner(
text: String,
modifier: Modifier = Modifier,
onGearClick: (() -> Unit)? = null,
- onBackClick: (() -> Unit)? = null
+ onBackClick: (() -> Unit)? = null,
) {
Box( // Use Box to overlay elements
modifier = modifier
+ .background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.padding(16.dp)
) {
A app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt +26 -0
@@ 0,0 1,26 @@
+package com.github.nacabaro.vbhelper.daos
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.Query
+import com.github.nacabaro.vbhelper.domain.Character
+import com.github.nacabaro.vbhelper.domain.Sprites
+import org.w3c.dom.CharacterData
+
+@Dao
+interface CharacterDao {
+ @Insert
+ suspend fun insertCharacter(vararg characterData: Character)
+
+ @Query("SELECT * FROM Character")
+ suspend fun getAllCharacters(): List<Character>
+
+ @Query("SELECT * FROM Character WHERE dimId = :dimId")
+ suspend fun getCharacterByDimId(dimId: Int): List<Character>
+
+ @Insert
+ suspend fun insertSprite(vararg sprite: Sprites)
+
+ @Query("SELECT * FROM Sprites")
+ suspend fun getAllSprites(): List<Sprites>
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/daos/DiMDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/DiMDao.kt +3 -3
@@ 2,15 2,15 @@ package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao
import androidx.room.Insert
+import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.Dim
-import kotlinx.coroutines.flow.Flow
@Dao
interface DiMDao {
- @Insert
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertNewDim(dim: Dim)
@Query("SELECT * FROM Dim")
- fun getAllDims(): Flow<List<Dim>>
+ suspend fun getAllDims(): List<Dim>
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt => app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt +11 -2
@@ 2,6 2,11 @@ package com.github.nacabaro.vbhelper.database
import androidx.room.Database
import androidx.room.RoomDatabase
+import com.github.nacabaro.vbhelper.daos.CharacterDao
+import com.github.nacabaro.vbhelper.daos.DiMDao
+import com.github.nacabaro.vbhelper.domain.Character
+import com.github.nacabaro.vbhelper.domain.Dim
+import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.temporary_daos.TemporaryMonsterDao
import com.github.nacabaro.vbhelper.temporary_domain.TemporaryBECharacterData
import com.github.nacabaro.vbhelper.temporary_domain.TemporaryCharacterData
@@ 12,10 17,14 @@ import com.github.nacabaro.vbhelper.temporary_domain.TemporaryTransformationHist
entities = [
TemporaryCharacterData::class,
TemporaryBECharacterData::class,
- TemporaryTransformationHistory::class
+ TemporaryTransformationHistory::class,
+ Dim::class,
+ Character::class,
+ Sprites::class
]
)
abstract class AppDatabase : RoomDatabase() {
abstract fun temporaryMonsterDao(): TemporaryMonsterDao
-
+ abstract fun dimDao(): DiMDao
+ abstract fun characterDao(): CharacterDao
}=
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/domain/Mon.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/Character.kt +9 -4
@@ 14,15 14,20 @@ import androidx.room.ForeignKey
)
]
)
-data class Mon (
- @PrimaryKey val id: Int,
+data class Character (
+ @PrimaryKey(autoGenerate = true) val id: Long,
val dimId: Int,
val monIndex: Int,
- val name: String,
+ val name: ByteArray,
val stage: Int, // These should be replaced with enums
val attribute: Int, // This one too
val baseHp: Int,
val baseBp: Int,
val baseAp: Int,
- val evoTime: Int, // In minutes
+ val sprite1: ByteArray,
+ val sprite2: ByteArray,
+ val nameWidth: Int,
+ val nameHeight: Int,
+ val spritesWidth: Int,
+ val spritesHeight: Int
)=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/domain/Dim.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/Dim.kt +4 -0
@@ 1,5 1,6 @@
package com.github.nacabaro.vbhelper.domain
+import android.icu.text.ListFormatter.Width
import androidx.room.Entity
import androidx.room.PrimaryKey
@@ 7,6 8,9 @@ import androidx.room.PrimaryKey
data class Dim(
@PrimaryKey(autoGenerate = true)
val id: Int,
+ val logo: ByteArray,
+ val logoWidth: Int,
+ val logoHeight: Int,
val name: String,
val stageCount: Int
)
M app/src/main/java/com/github/nacabaro/vbhelper/domain/Evolutions.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/Evolutions.kt +2 -2
@@ 7,13 7,13 @@ import androidx.room.PrimaryKey
@Entity(
foreignKeys = [
ForeignKey(
- entity = Mon::class,
+ entity = Character::class,
parentColumns = ["id"],
childColumns = ["monId"],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
- entity = Mon::class,
+ entity = Character::class,
parentColumns = ["id"],
childColumns = ["nextMon"],
onDelete = ForeignKey.CASCADE
A app/src/main/java/com/github/nacabaro/vbhelper/domain/Sprites.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/Sprites.kt +12 -0
@@ 0,0 1,12 @@
+package com.github.nacabaro.vbhelper.domain
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity
+data class Sprites(
+ @PrimaryKey(autoGenerate = true) val id : Int,
+ val sprite: ByteArray,
+ val width: Int,
+ val height: Int
+)
M app/src/main/java/com/github/nacabaro/vbhelper/domain/UserMonsters.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/UserMonsters.kt +1 -1
@@ 13,7 13,7 @@ import androidx.room.PrimaryKey
onDelete = ForeignKey.CASCADE
),
ForeignKey(
- entity = Mon::class,
+ entity = Character::class,
parentColumns = ["id"],
childColumns = ["monId"],
onDelete = ForeignKey.CASCADE
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +23 -1
@@ 1,5 1,6 @@
package com.github.nacabaro.vbhelper.navigation
+import android.util.Log
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
@@ 9,15 10,18 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.github.nacabaro.vbhelper.screens.BattlesScreen
import com.github.nacabaro.vbhelper.screens.DexScreen
+import com.github.nacabaro.vbhelper.screens.DiMScreen
import com.github.nacabaro.vbhelper.screens.HomeScreen
import com.github.nacabaro.vbhelper.screens.ScanScreen
import com.github.nacabaro.vbhelper.screens.SettingsScreen
+import com.github.nacabaro.vbhelper.screens.SpriteViewer
import com.github.nacabaro.vbhelper.screens.StorageScreen
@Composable
fun AppNavigation(
onClickRead: () -> Unit,
onClickScan: () -> Unit,
+ onClickImportCard: () -> Unit,
isDoneReadingCharacter: Boolean
) {
val navController = rememberNavController()
@@ 53,13 57,31 @@ fun AppNavigation(
)
}
composable(BottomNavItem.Dex.route) {
- DexScreen()
+ DexScreen(
+ navController = navController
+ )
}
composable(BottomNavItem.Settings.route) {
SettingsScreen(
+ navController = navController,
+ onClickImportCard = onClickImportCard
+ )
+ }
+ composable(BottomNavItem.Viewer.route) {
+ SpriteViewer(
navController = navController
)
}
+ composable(BottomNavItem.CardView.route) {
+ val dimId = it.arguments?.getString("dimId")
+ Log.d("dimId", dimId.toString())
+ if (dimId != null) {
+ DiMScreen(
+ navController = navController,
+ dimId = dimId.toInt()
+ )
+ }
+ }
}
}
}
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavItem.kt +2 -0
@@ 13,4 13,6 @@ sealed class BottomNavItem (
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
M app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/DexScreen.kt +63 -14
@@ 1,5 1,6 @@
package com.github.nacabaro.vbhelper.screens
+import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
@@ 7,38 8,85 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
-import com.github.nacabaro.vbhelper.R
+import androidx.navigation.NavController
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.source.DexRepository
+import kotlinx.coroutines.launch
+import java.nio.ByteBuffer
@Composable
-fun DexScreen() {
+fun DexScreen(
+ navController: NavController
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val application = LocalContext.current.applicationContext as VBHelper
+ val dexRepository = DexRepository(application.container.db)
+
+ val dimList = remember { mutableStateOf<List<Dim>>(emptyList()) }
+
+ LaunchedEffect(dexRepository) {
+ coroutineScope.launch {
+ val newDimList = dexRepository.getAllDims()
+ dimList.value = newDimList // Replace the entire list atomically
+ }
+ }
+
Scaffold (
- topBar = { TopBanner("Discovered Digimon") }
+ topBar = {
+ TopBanner(
+ text = "Discovered Digimon",
+ onGearClick = {
+ navController.navigate(BottomNavItem.Viewer.route)
+ }
+ )
+ }
) { contentPadding ->
LazyColumn (
modifier = Modifier
.padding(top = contentPadding.calculateTopPadding())
) {
- items(100) { i ->
+ items(dimList.value) {
+ val bitmap = remember (it.logo) {
+ Bitmap.createBitmap(it.logoWidth, it.logoHeight, Bitmap.Config.RGB_565).apply {
+ copyPixelsFromBuffer(ByteBuffer.wrap(it.logo))
+ }
+ }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+
DexDiMEntry(
- name = "Digimon $i",
- icon = R.drawable.baseline_egg_24,
- onClick = {},
+ name = it.name,
+ logo = imageBitmap,
+ onClick = {
+ navController
+ .navigate(
+ BottomNavItem
+ .CardView.route
+ .replace("{dimId}", "${it.id}")
+ )
+ },
modifier = Modifier
.fillMaxWidth()
- .padding(
- vertical = 8.dp,
- horizontal = 16.dp
- )
+ .padding(8.dp)
)
}
}
@@ 48,7 96,7 @@ fun DexScreen() {
@Composable
fun DexDiMEntry(
name: String,
- icon: Int,
+ logo: ImageBitmap,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
@@ 64,8 112,9 @@ fun DexDiMEntry(
.padding(8.dp)
) {
Image (
- painter = painterResource(id = icon),
+ bitmap = logo,
contentDescription = name,
+ filterQuality = FilterQuality.None,
modifier = Modifier
.padding(8.dp)
.size(64.dp)
A app/src/main/java/com/github/nacabaro/vbhelper/screens/DimScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/DimScreen.kt +70 -0
@@ 0,0 1,70 @@
+package com.github.nacabaro.vbhelper.screens
+
+import android.graphics.Bitmap
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.navigation.NavController
+import com.github.nacabaro.vbhelper.components.CharacterEntry
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.domain.Character
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.source.DexRepository
+import kotlinx.coroutines.launch
+import java.nio.ByteBuffer
+
+@Composable
+fun DiMScreen(
+ navController: NavController,
+ dimId: Int
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val application = LocalContext.current.applicationContext as VBHelper
+ val dexRepository = DexRepository(application.container.db)
+
+ val characterList = remember { mutableStateOf<List<Character>>(emptyList()) }
+
+ LaunchedEffect(dexRepository) {
+ coroutineScope.launch {
+ val newCharacterList = dexRepository.getCharactersByDimId(dimId)
+ characterList.value = newCharacterList
+ }
+ }
+
+ Scaffold (
+ topBar = {
+ TopBanner(
+ text = "Discovered Digimon",
+ onBackClick = {
+ navController.popBackStack()
+ }
+ )
+ }
+ ) { contentPadding ->
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(3),
+ contentPadding = contentPadding
+ ) {
+ items(characterList.value) { character ->
+ val bitmapCharacter = remember (character.sprite1) {
+ Bitmap.createBitmap(character.spritesWidth, character.spritesHeight, Bitmap.Config.RGB_565).apply {
+ copyPixelsFromBuffer(ByteBuffer.wrap(character.sprite1))
+ }
+ }
+ val imageBitmapCharacter = remember(bitmapCharacter) { bitmapCharacter.asImageBitmap() }
+ CharacterEntry(
+ icon = imageBitmapCharacter,
+ onClick = { }
+ )
+ }
+ }
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/SettingsScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/SettingsScreen.kt +3 -24
@@ 17,19 17,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
-import com.github.cfogrady.vb.dim.card.BemCard
-import com.github.cfogrady.vb.dim.card.DimCard
-import com.github.cfogrady.vb.dim.card.DimReader
-import com.github.cfogrady.vb.dim.sprite.SpriteData
-import com.github.cfogrady.vb.dim.sprite.SpriteData.Sprite
import com.github.nacabaro.vbhelper.components.TopBanner
-import java.io.File
-import java.io.FileInputStream
@Composable
fun SettingsScreen(
navController: NavController,
- dimReader: DimReader = DimReader()
+ onClickImportCard: () -> Unit
) {
Scaffold (
topBar = {
@@ 56,22 49,8 @@ fun SettingsScreen(
SettingsEntry(title = "Import transform functions", description = "Import standard vital bracelet keys") { }
SettingsEntry(title = "Import decryption key", description = "Import standard vital bracelet keys") { }
SettingsSection("DiM/BEm management")
- SettingsEntry(title = "Import DiM card", description = "Import DiM card file") {
- // placeholder
-// val file = File("dummy_file.bin") //filePicker()
-// val fileInputStream = FileInputStream(file)
-// fileInputStream.use {
-// val card = dimReader.readCard(fileInputStream, false)
-// if (card is DimCard) {
-// val logo = card.spriteData.sprites[0]
-// }
-// val beMemory = card as BemCard
-// val logo = beMemory.spriteData.sprites[0]
-// }
- }
- SettingsEntry(title = "Import BEm card", description = "Import BEm card file") {
- // placeholder
- }
+ SettingsEntry(title = "Import DiM card", description = "Import DiM/BEm card file", onClick = onClickImportCard)
+ SettingsEntry(title = "Rename DiM/BEm", description = "Set card name") { }
SettingsSection("About and credits")
SettingsEntry(title = "Credits", description = "Credits") { }
SettingsEntry(title = "About", description = "About") { }
A app/src/main/java/com/github/nacabaro/vbhelper/screens/SpriteViewer.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/SpriteViewer.kt +89 -0
@@ 0,0 1,89 @@
+package com.github.nacabaro.vbhelper.screens
+
+import android.graphics.Bitmap
+import android.util.Log
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.domain.Sprites
+import com.github.nacabaro.vbhelper.source.SpriteRepo
+import kotlinx.coroutines.launch
+import java.nio.ByteBuffer
+
+@Composable
+fun SpriteViewer(
+ navController: NavController
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val application = LocalContext.current.applicationContext as VBHelper
+ val db = application.container.db
+ val spriteRepo = SpriteRepo(db)
+
+ val spriteList = remember { mutableStateListOf<Sprites>() }
+
+ Log.d("SpriteViewer", "spriteList: $spriteList")
+
+ LaunchedEffect(spriteRepo) {
+ coroutineScope.launch {
+ spriteList.clear()
+ spriteList.addAll(spriteRepo.getAllSprites())
+ }
+ }
+
+ Scaffold (
+ topBar = {
+ TopBanner(
+ text = "Sprite viewer",
+ onBackClick = {
+ navController.popBackStack()
+ }
+ )
+ },
+ modifier = Modifier
+ .fillMaxSize()
+ ) { contentPadding ->
+ LazyColumn (
+ modifier = Modifier
+ .padding(top = contentPadding.calculateTopPadding())
+ ) {
+ items(spriteList) { sprite ->
+ val bitmap = remember (sprite.sprite) {
+ Log.d("SpriteViewer", "sprite: $sprite")
+ Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
+ copyPixelsFromBuffer(ByteBuffer.wrap(sprite.sprite))
+ }
+ }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = "Sprite",
+ modifier = Modifier
+ .size(256.dp)
+ )
+ }
+ }
+ }
+}
+
M app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt +1 -35
@@ 38,6 38,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.github.nacabaro.vbhelper.R
+import com.github.nacabaro.vbhelper.components.StorageEntry
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.source.StorageRepository
@@ 113,41 114,6 @@ fun StorageScreen() {
}
@Composable
-fun StorageEntry(
- name: String,
- icon: Int,
- onClick: () -> Unit = {},
- modifier: Modifier = Modifier
-) {
- Card(
- shape = MaterialTheme.shapes.medium,
- onClick = onClick,
- modifier = modifier
- .padding(8.dp)
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier
- .fillMaxSize()
- ) {
- Image(
- painter = painterResource(id = icon),
- contentDescription = name,
- modifier = Modifier
- .padding(8.dp)
- .size(64.dp)
- )
- Text(
- text = name,
- textAlign = TextAlign.Center,
- modifier = Modifier
- .padding(8.dp)
- )
- }
- }
-}
-
-@Composable
fun StorageDialog(
characterId: Long,
onDismissRequest: () -> Unit
A app/src/main/java/com/github/nacabaro/vbhelper/source/DexRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/DexRepository.kt +18 -0
@@ 0,0 1,18 @@
+package com.github.nacabaro.vbhelper.source
+
+import com.github.nacabaro.vbhelper.database.AppDatabase
+import com.github.nacabaro.vbhelper.domain.Character
+import com.github.nacabaro.vbhelper.domain.Dim
+import kotlinx.coroutines.flow.Flow
+
+class DexRepository (
+ private val db: AppDatabase
+) {
+ suspend fun getAllDims(): List<Dim> {
+ return db.dimDao().getAllDims()
+ }
+
+ suspend fun getCharactersByDimId(dimId: Int): List<Character> {
+ return db.characterDao().getCharacterByDimId(dimId)
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/source/SpriteRepo.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/SpriteRepo.kt +12 -0
@@ 0,0 1,12 @@
+package com.github.nacabaro.vbhelper.source
+
+import com.github.nacabaro.vbhelper.database.AppDatabase
+import com.github.nacabaro.vbhelper.domain.Sprites
+
+class SpriteRepo (
+ private val db: AppDatabase
+) {
+ suspend fun getAllSprites(): List<Sprites> {
+ return db.characterDao().getAllSprites()
+ }
+}
A app/src/main/res/drawable/baseline_image_24.xml => app/src/main/res/drawable/baseline_image_24.xml +5 -0
@@ 0,0 1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+
+ <path android:fillColor="@android:color/white" android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
+
+</vector>