~cytrogen/vbhelper

586d6c01ef34c873357c27dcb8f1032c931bf307 — nacabaro 1 year, 3 months ago 074ced1 + 5d996ed
Merge pull request #18 from nacabaro/ui/home_screen

A lot more things
40 files changed, 1032 insertions(+), 127 deletions(-)

M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt
M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt
M app/src/main/java/com/github/nacabaro/vbhelper/components/DexDimEntry.kt
M app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt
A app/src/main/java/com/github/nacabaro/vbhelper/components/TransformationHistoryCard.kt
M app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt
M app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt
M app/src/main/java/com/github/nacabaro/vbhelper/domain/Dim.kt
M app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt
M app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt
M app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt
D app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt
A app/src/main/java/com/github/nacabaro/vbhelper/screens/ItemsScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/SpriteViewer.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEBEmHomeScreen.kt
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEDiMHomeScreen.kt
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/VBDiMHomeScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt
M app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt
A app/src/main/java/com/github/nacabaro/vbhelper/utils/padTransformationArray.kt
A app/src/main/res/drawable/baseline_age_24.xml
A app/src/main/res/drawable/baseline_agility_24.xml
A app/src/main/res/drawable/baseline_attack_24.xml
A app/src/main/res/drawable/baseline_data_24.xml
A app/src/main/res/drawable/baseline_free_24.xml
A app/src/main/res/drawable/baseline_health_24.xml
A app/src/main/res/drawable/baseline_mood_24.xml
A app/src/main/res/drawable/baseline_next_24.xml
A app/src/main/res/drawable/baseline_rank_24.xml
A app/src/main/res/drawable/baseline_timer_24.xml
A app/src/main/res/drawable/baseline_trophy_24.xml
A app/src/main/res/drawable/baseline_vaccine_24.xml
A app/src/main/res/drawable/baseline_virus_24.xml
A app/src/main/res/drawable/baseline_vitals_24.xml
M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +61 -45
@@ 11,10 11,12 @@ 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.Dim
import com.github.nacabaro.vbhelper.domain.Sprites


@@ 22,6 24,7 @@ import com.github.nacabaro.vbhelper.domain.Character
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.SettingsScreenController


@@ 29,6 32,8 @@ import com.github.nacabaro.vbhelper.source.ApkSecretsImporter
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import java.util.Date
import java.util.GregorianCalendar

class MainActivity : ComponentActivity() {



@@ 105,13 110,17 @@ class MainActivity : ComponentActivity() {
                inputStream.use { fileReader ->
                    val dimReader = DimReader()
                    val card = dimReader.readCard(fileReader, false)

                    Log.i("MainActivity", "Card name: ${card is BemCard}")

                    val dimModel = Dim(
                        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
                        logoWidth = card.spriteData.sprites[0].width,
                        isBEm = card is BemCard
                    )

                    val dimId = storageRepository


@@ 120,7 129,11 @@ class MainActivity : ComponentActivity() {

                    val characters = card.characterStats.characterEntries

                    var spriteCounter = 10
                    var spriteCounter = when (card is BemCard) {
                        true -> 55
                        false -> 10
                    }

                    val domainCharacters = mutableListOf<Character>()

                    for (index in 0 until characters.size) {


@@ 144,12 157,14 @@ class MainActivity : ComponentActivity() {
                        )

                        // TODO: Improve this
                        if (index == 0) {
                            spriteCounter += 6
                        } else if (index == 1) {
                            spriteCounter += 7
                        } else {
                        if (card is BemCard) {
                            spriteCounter += 14
                        } else {
                            when (index) {
                                0 -> spriteCounter += 6
                                1 -> spriteCounter += 7
                                else -> spriteCounter += 14
                            }
                        }
                    }



@@ 216,9 231,7 @@ class MainActivity : ComponentActivity() {
            .dimDao()
            .getDimById(nfcCharacter.value!!.dimId.toInt())

        if (dimData == null) {
            return "Card not found"
        }
        if (dimData == null) return "Card not found"

        val cardCharData = storageRepository
            .characterDao()


@@ 244,60 257,63 @@ class MainActivity : ComponentActivity() {
            characterType = when (nfcCharacter.value) {
                is BENfcCharacter -> com.github.nacabaro.vbhelper.domain.DeviceType.BEDevice
                else -> com.github.nacabaro.vbhelper.domain.DeviceType.VBDevice
            }
            },
            isActive = true
        )

        storageRepository
            .userCharacterDao()
            .clearActiveCharacter()

        val characterId: Long = storageRepository
            .userCharacterDao()
            .insertCharacterData(characterData)

        if (nfcCharacter.value is BENfcCharacter) {
            val beCharacter = nfcCharacter as MutableStateFlow<BENfcCharacter?>
            val beCharacter = nfcCharacter.value as BENfcCharacter
            val extraCharacterData = BECharacterData(
                id = characterId,
                trainingHp = beCharacter.value!!.trainingHp.toInt(),
                trainingAp = beCharacter.value!!.trainingAp.toInt(),
                trainingBp = beCharacter.value!!.trainingBp.toInt(),
                remainingTrainingTimeInMinutes = beCharacter.value!!.remainingTrainingTimeInMinutes.toInt(),
                itemEffectActivityLevelValue = beCharacter.value!!.itemEffectActivityLevelValue.toInt(),
                itemEffectMentalStateValue = beCharacter.value!!.itemEffectMentalStateValue.toInt(),
                itemEffectMentalStateMinutesRemaining = beCharacter.value!!.itemEffectMentalStateMinutesRemaining.toInt(),
                itemEffectActivityLevelMinutesRemaining = beCharacter.value!!.itemEffectActivityLevelMinutesRemaining.toInt(),
                itemEffectVitalPointsChangeValue = beCharacter.value!!.itemEffectVitalPointsChangeValue.toInt(),
                itemEffectVitalPointsChangeMinutesRemaining = beCharacter.value!!.itemEffectVitalPointsChangeMinutesRemaining.toInt(),
                abilityRarity = beCharacter.value!!.abilityRarity,
                abilityType = beCharacter.value!!.abilityType.toInt(),
                abilityBranch = beCharacter.value!!.abilityBranch.toInt(),
                abilityReset = beCharacter.value!!.abilityReset.toInt(),
                rank = beCharacter.value!!.abilityReset.toInt(),
                itemType = beCharacter.value!!.itemType.toInt(),
                itemMultiplier = beCharacter.value!!.itemMultiplier.toInt(),
                itemRemainingTime = beCharacter.value!!.itemRemainingTime.toInt(),
                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.value!!.characterCreationFirmwareVersion.minorVersion.toInt(),
                majorVersion = beCharacter.value!!.characterCreationFirmwareVersion.majorVersion.toInt(),
                minorVersion = beCharacter.characterCreationFirmwareVersion.minorVersion.toInt(),
                majorVersion = beCharacter.characterCreationFirmwareVersion.majorVersion.toInt(),
            )

            storageRepository
                .userCharacterDao()
                .insertBECharacterData(extraCharacterData)

            val transformationHistoryWatch = beCharacter.value!!.transformationHistory
            val domainTransformationHistory = transformationHistoryWatch.map { item ->
                TransformationHistory(
                    monId = characterId,
                    toCharIndex = item.toCharIndex.toInt(),
                    year = item.year.toInt(),
                    month = item.month.toInt(),
                    day = item.day.toInt()
                )
            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
                .userCharacterDao()
                .insertTransformationHistory(*domainTransformationHistory.toTypedArray())
        } else {
        } else if (nfcCharacter.value is VBNfcCharacter) {
            return "Not implemented yet"
        }


M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +76 -10
@@ 1,21 1,36 @@
package com.github.nacabaro.vbhelper.components

import android.graphics.Bitmap
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
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.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.domain.Sprites
import androidx.compose.ui.unit.sp
import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.utils.getBitmap
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import com.github.nacabaro.vbhelper.utils.getObscuredBitmap
import java.nio.ByteBuffer



@@ 24,27 39,78 @@ fun CharacterEntry(
    icon: BitmapData,
    obscure: Boolean = false,
    modifier: Modifier = Modifier,
    shape: Shape = MaterialTheme.shapes.medium,
    multiplier: Int = 3,
    onClick: () -> Unit = {  }
) {
    val bitmap = remember (icon.bitmap) {
        if(obscure) icon.getObscuredBitmap() else icon.getBitmap()
    }
    val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
    val density: Float = LocalContext.current.resources.displayMetrics.density
    val dpSize = (icon.width * multiplier / density).dp

    Card(
        shape = MaterialTheme.shapes.medium,
        shape = shape,
        onClick = onClick,
        modifier = modifier
            .aspectRatio(1f)
            .padding(8.dp)
            .size(96.dp)
    ) {
        Image(
            bitmap = imageBitmap,
            contentDescription = "Icon",
            filterQuality = FilterQuality.None,
        Box(
            contentAlignment = Alignment.BottomCenter,
            modifier = Modifier
                .padding(8.dp)
                .fillMaxSize()
        )
                .padding(16.dp)
        ) {
            Image(
                bitmap = imageBitmap,
                contentDescription = "Icon",
                filterQuality = FilterQuality.None,
                modifier = Modifier
                    .size(dpSize)
            )
        }
    }
}

@Composable
fun ItemDisplay(
    icon: Int,
    textValue: String,
    modifier: Modifier = Modifier,
    iconSize: Dp = 48.dp,
    textSize: TextUnit = 24.sp,
    definition: String = "",
) {
    val context = LocalContext.current
    Card(
        modifier = modifier,
        shape = androidx.compose.material.MaterialTheme.shapes.small,
        onClick = {
            Toast.makeText(context, definition, Toast.LENGTH_SHORT).show()
        }
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
            modifier = Modifier
                .fillMaxSize()
        ) {
            Icon(
                painter = painterResource(icon),
                contentDescription = "Vitals",
                modifier = Modifier
                    .padding(8.dp)
                    .size(iconSize)
            )
            Text(
                text = textValue,
                textAlign = TextAlign.Center,
                fontSize = textSize,
                fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
                fontWeight = FontWeight.Bold
            )
        }
    }
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/components/DexDimEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/DexDimEntry.kt +5 -6
@@ 1,6 1,5 @@
package com.github.nacabaro.vbhelper.components

import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row


@@ 15,10 14,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.utils.getBitmap
import java.nio.ByteBuffer

@Composable
fun DexDiMEntry(


@@ 27,10 26,10 @@ fun DexDiMEntry(
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    val bitmap = remember (logo.bitmap) {
        logo.getBitmap()
    }
    val bitmap = remember (logo.bitmap) { logo.getBitmap() }
    val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
    val density: Float = LocalContext.current.resources.displayMetrics.density
    val dpSize = (logo.width * 4 / density).dp

    Card (
        shape = MaterialTheme.shapes.medium,


@@ 49,7 48,7 @@ fun DexDiMEntry(
                filterQuality = FilterQuality.None,
                modifier = Modifier
                    .padding(8.dp)
                    .size(64.dp)
                    .size(dpSize)
            )
            Text(
                text = name,

M app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt +14 -2
@@ 23,6 23,7 @@ fun TopBanner(
    modifier: Modifier = Modifier,
    onGearClick: (() -> Unit)? = null,
    onBackClick: (() -> Unit)? = null,
    onScanClick: (() -> Unit)? = null
) {
    Box( // Use Box to overlay elements
        modifier = modifier


@@ 37,7 38,7 @@ fun TopBanner(
            modifier = Modifier
                .align(Alignment.Center) // Center the text
        )
        if (onGearClick != null) {
         if (onGearClick != null) {
            IconButton(
                onClick = onGearClick,
                modifier = Modifier


@@ 50,7 51,18 @@ fun TopBanner(
            }
        }

        if (onBackClick != null) {
        if (onScanClick != null) {
            IconButton(
                onClick = onScanClick,
                modifier = Modifier
                    .align(Alignment.CenterStart) // Place gear icon at the end
            ) {
                Icon(
                    painter = painterResource(R.drawable.baseline_nfc_24), // Use a gear icon
                    contentDescription = "Scan"
                )
            }
        } else if (onBackClick != null) {
            IconButton(
                onClick = onBackClick,
                modifier = Modifier

A app/src/main/java/com/github/nacabaro/vbhelper/components/TransformationHistoryCard.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/TransformationHistoryCard.kt +76 -0
@@ 0,0 1,76 @@
package com.github.nacabaro.vbhelper.components

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.utils.getBitmap

@Composable
fun TransformationHistoryCard(
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    modifier: Modifier= Modifier
) {
    Card (
        shape = androidx.compose.material.MaterialTheme.shapes.small,
        modifier = modifier
    ) {
        LazyRow (
            modifier = Modifier
                .padding(8.dp)
        ) {
            items(transformationHistory) { transformation ->
                TransformationHistoryItem(transformation)
            }
        }
    }
}

@Composable
fun TransformationHistoryItem(
    transformation: CharacterDtos.TransformationHistory
) {
    val bitmapData = BitmapData(
        bitmap = transformation.spriteIdle,
        width = transformation.spriteWidth,
        height = transformation.spriteHeight
    )
    val bitmap = remember (bitmapData) { bitmapData.getBitmap() }
    val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
    val density: Float = LocalContext.current.resources.displayMetrics.density
    val dpSize = (bitmap.width * 3 / density).dp

    Box (
        contentAlignment = Alignment.BottomCenter,
        modifier = Modifier
            .aspectRatio(1f)
            .fillMaxWidth()
            .size((64*3/density).dp)
    ) {
        Image(
            bitmap = imageBitmap,
            contentDescription = "Transformation",
            filterQuality = FilterQuality.None,
            modifier = Modifier
                .size(dpSize)

        )
    }

}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/CharacterDao.kt +10 -0
@@ 6,6 6,7 @@ import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.Character
import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import java.util.GregorianCalendar

@Dao
interface CharacterDao {


@@ 37,4 38,13 @@ interface CharacterDao {
        WHERE uc.id = :charId
    """)
    suspend fun getCharacterInfo(charId: Long): CharacterDtos.DiMInfo

    @Query("""
        INSERT INTO TransformationHistory(monId, stageId, transformationDate)
        VALUES 
            (:monId, 
            (SELECT id FROM Character WHERE monIndex = :stage AND dimId = :dimId),
            :transformationDate)
    """)
    fun insertTransformation(monId: Long, stage: Int, dimId: Long, transformationDate: Long)
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt +40 -3
@@ 20,17 20,30 @@ interface UserCharacterDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertTransformationHistory(vararg transformationHistory: TransformationHistory)

    @Query("SELECT * FROM TransformationHistory WHERE monId = :monId")
    fun getTransformationHistory(monId: Long): List<TransformationHistory>
    @Query("""
        SELECT 
            c.id AS id,
            c.sprite1 AS spriteIdle,
            c.spritesWidth AS spriteWidth,
            c.spritesHeight AS spriteHeight,
            c.monIndex AS monIndex, 
            t.transformationDate AS transformationDate
        FROM TransformationHistory t 
        JOIN Character c ON c.id = t.stageId
        WHERE monId = :monId
    """)
    fun getTransformationHistory(monId: Long): List<CharacterDtos.TransformationHistory>?

    @Query("""
        SELECT
            uc.*,
            c.sprite1 AS spriteIdle,
            c.spritesWidth AS spriteWidth,
            c.spritesHeight AS spriteHeight
            c.spritesHeight AS spriteHeight,
            d.isBEm as isBemCard
        FROM UserCharacter uc
        JOIN Character c ON uc.charId = c.id
        JOIN Dim d ON c.dimId = d.id
        """)
    suspend fun getAllCharacters(): List<CharacterDtos.CharacterWithSprites>



@@ 39,4 52,28 @@ interface UserCharacterDao {

    @Query("SELECT * FROM BECharacterData WHERE id = :id")
    suspend fun getBeData(id: Long): BECharacterData

    @Query("""
        SELECT
            uc.*,
            c.sprite1 AS spriteIdle,
            c.spritesWidth AS spriteWidth,
            c.spritesHeight AS spriteHeight,
            d.isBEm as isBemCard
        FROM UserCharacter uc
        JOIN Character c ON uc.charId = c.id
        JOIN Dim d ON c.dimId = d.id
        WHERE uc.isActive = 1
        LIMIT 1
    """)
    suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites?

    @Query("DELETE FROM UserCharacter WHERE id = :id")
    fun deleteCharacterById(id: Long)

    @Query("UPDATE UserCharacter SET isActive = 0 WHERE isActive = 1")
    fun clearActiveCharacter()

    @Query("UPDATE UserCharacter SET isActive = 1 WHERE id = :id")
    fun setActiveCharacter(id: Long)
}
\ 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 +2 -1
@@ 13,5 13,6 @@ data class Dim(
    val logoWidth: Int,
    val logoHeight: Int,
    val name: String,
    val stageCount: Int
    val stageCount: Int,
    val isBEm: Boolean
)

M app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt +9 -4
@@ 3,6 3,7 @@ package com.github.nacabaro.vbhelper.domain.device_data
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.nacabaro.vbhelper.domain.Character

@Entity(
    foreignKeys = [


@@ 11,14 12,18 @@ import androidx.room.PrimaryKey
            parentColumns = ["id"],
            childColumns = ["monId"],
            onDelete = ForeignKey.CASCADE
        ),
        ForeignKey(
            entity = Character::class,
            parentColumns = ["id"],
            childColumns = ["stageId"],
            onDelete = ForeignKey.CASCADE
        )
    ]
)
data class TransformationHistory (
    @PrimaryKey(autoGenerate = true) val id: Long = 0,
    val monId: Long,
    val toCharIndex: Int,
    val year: Int,
    val month: Int,
    val day: Int
    val stageId: Long,
    val transformationDate: Long
)

M app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt +2 -1
@@ 35,5 35,6 @@ data class UserCharacter (
    var totalBattlesLost: Int,
    var activityLevel: Int,
    var heartRateCurrent: Int,
    var characterType: DeviceType
    var characterType: DeviceType,
    var isActive: Boolean
)
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt => app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt +11 -1
@@ 26,11 26,21 @@ object CharacterDtos {
        var characterType: DeviceType,
        val spriteIdle: ByteArray,
        val spriteWidth: Int,
        val spriteHeight: Int
        val spriteHeight: Int,
        val isBemCard: Boolean
    )

    data class DiMInfo(
        val cardId: Int,
        val charId: Int
    )

    data class TransformationHistory(
        val id: Long,
        val spriteIdle: ByteArray,
        val spriteWidth: Int,
        val spriteHeight: Int,
        val monIndex: Int,
        val transformationDate: Long
    )
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +7 -1
@@ 11,7 11,8 @@ 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.homeScreens.HomeScreen
import com.github.nacabaro.vbhelper.screens.ItemsScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.SettingsScreen


@@ 89,6 90,11 @@ fun AppNavigation(
                    )
                }
            }
            composable(NavigationItems.Items.route) {
                ItemsScreen(
                    navController = navController
                )
            }
        }
    }
}

M app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/BottomNavigationBar.kt +1 -1
@@ 13,7 13,7 @@ import androidx.navigation.compose.currentBackStackEntryAsState
@Composable
fun BottomNavigationBar(navController: NavController) {
    val items = listOf(
        NavigationItems.Scan,
        NavigationItems.Items,
        NavigationItems.Battles,
        NavigationItems.Home,
        NavigationItems.Dex,

M app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt +1 -0
@@ 15,4 15,5 @@ sealed class NavigationItems (
    object Settings : NavigationItems("Settings", R.drawable.baseline_settings_24, "Settings")
    object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer")
    object CardView : NavigationItems("Card/{dimId}", R.drawable.baseline_image_24, "Card")
    object Items : NavigationItems("Items", R.drawable.baseline_data_24, "Items")
}
\ No newline at end of file

D app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/HomeScreen.kt +0 -34
@@ 1,34 0,0 @@
package com.github.nacabaro.vbhelper.screens

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.navigation.NavigationItems

@Composable
fun HomeScreen(
    navController: NavController
) {
    Scaffold (
        topBar = {
            TopBanner(
                text = "VB Helper",
                onGearClick = {
                    navController.navigate(NavigationItems.Settings.route)
                }
            )
        }
    ) { contentPadding ->
        Box (
            modifier = Modifier
                .padding(top = contentPadding.calculateTopPadding())
        ) {
            Text("Home Screen")
        }
    }
}

A app/src/main/java/com/github/nacabaro/vbhelper/screens/ItemsScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/ItemsScreen.kt +12 -0
@@ 0,0 1,12 @@
package com.github.nacabaro.vbhelper.screens

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.navigation.NavController

@Composable
fun ItemsScreen(
    navController: NavController
) {
    Text(text = "Items")
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/screens/SpriteViewer.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/SpriteViewer.kt +1 -0
@@ 81,6 81,7 @@ fun SpriteViewer(
                    contentDescription = "Sprite",
                    modifier = Modifier
                        .size(256.dp)
                        .padding(8.dp)
                )
            }
        }

M app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt +24 -8
@@ 14,6 14,7 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Scaffold


@@ 41,7 42,9 @@ import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


@Composable


@@ 62,8 65,6 @@ fun StorageScreen(
        }
    }

    Log.d("StorageScreen", "monList: $monList")

    Scaffold (
        topBar = { TopBanner(text = "My Digimon") }
    ) { contentPadding ->


@@ 72,7 73,7 @@ fun StorageScreen(
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center,
                modifier = Modifier
                    .padding(contentPadding)
                    .padding(top = contentPadding.calculateTopPadding())
                    .fillMaxSize()
            ) {
                Text(


@@ 96,9 97,6 @@ fun StorageScreen(
                        width = index.spriteWidth,
                        height = index.spriteHeight
                    ),
                    modifier = Modifier
                        .padding(8.dp)
                        .size(96.dp),
                    onClick = {
                        selectedCharacter = index.id
                    }


@@ 108,6 106,15 @@ fun StorageScreen(
                    StorageDialog(
                        characterId = selectedCharacter!!,
                        onDismissRequest = { selectedCharacter = null },
                        onClickSetActive = {
                            coroutineScope.launch {
                                withContext(Dispatchers.IO) {
                                    storageRepository.setActiveCharacter(selectedCharacter!!)
                                    selectedCharacter = null
                                }
                                navController.navigate(NavigationItems.Home.route)
                            }
                        },
                        onSendToBracelet = {
                            navController.navigate(
                                NavigationItems.Scan.route.replace(


@@ 127,7 134,8 @@ fun StorageScreen(
fun StorageDialog(
    characterId: Long,
    onDismissRequest: () -> Unit,
    onSendToBracelet: () -> Unit
    onSendToBracelet: () -> Unit,
    onClickSetActive: () -> Unit
) {
    val coroutineScope = rememberCoroutineScope()
    val application = LocalContext.current.applicationContext as VBHelper


@@ 162,13 170,21 @@ fun StorageDialog(
                            .padding(8.dp)
                    )
                }
                Row {
                Row (
                    modifier = Modifier
                        .verticalScroll(rememberScrollState())
                ) {
                    Button(
                        onClick = onSendToBracelet
                    ) {
                        Text(text = "Send to bracelet")
                    }
                    Button(
                        onClick = onClickSetActive
                    ) {
                        Text(text = "Set active")
                    }
                    Button(
                        onClick = onDismissRequest
                    ) {
                        Text(text = "Close")

A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEBEmHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEBEmHomeScreen.kt +201 -0
@@ 0,0 1,201 @@
package com.github.nacabaro.vbhelper.screens.homeScreens

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.ItemDisplay
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.utils.BitmapData
import java.util.Locale

@Composable
fun BEBEmHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    beData: BECharacterData,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues
) {
    Column(
        modifier = Modifier
            .padding(top = contentPadding.calculateTopPadding())
            .verticalScroll(state = rememberScrollState())
    ) {
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            CharacterEntry(
                icon = BitmapData(
                    bitmap = activeMon.spriteIdle,
                    width = activeMon.spriteWidth,
                    height = activeMon.spriteHeight
                ),
                multiplier = 8,
                shape = androidx.compose.material.MaterialTheme.shapes.small,
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
            )
            Column (
                modifier = Modifier
                    .weight(0.5f)
                    .aspectRatio(0.5f)
            ) {
                ItemDisplay(
                    icon = R.drawable.baseline_vitals_24,
                    textValue = activeMon.vitalPoints.toString(),
                    definition = "Vitals",
                    modifier = Modifier
                        .weight(0.5f)
                        .aspectRatio(1f)
                        .padding(8.dp)
                )
                ItemDisplay(
                    icon = R.drawable.baseline_trophy_24,
                    textValue = activeMon.trophies.toString(),
                    definition = "Trophies",
                    modifier = Modifier
                        .weight(0.5f)
                        .aspectRatio(1f)
                        .padding(8.dp)
                )
            }
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            ItemDisplay(
                icon = R.drawable.baseline_mood_24,
                textValue = activeMon.mood.toString(),
                definition = "Mood",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            val timeInHours = (beData.remainingTrainingTimeInMinutes / 60)
            ItemDisplay(
                icon = R.drawable.baseline_timer_24,
                textValue = "$timeInHours h",
                definition = "Training limit",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_rank_24,
                textValue = beData.rank.toString(),
                definition = "Rank",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            val transformationCountdownInHours = activeMon.transformationCountdown / 60
            ItemDisplay(
                icon = R.drawable.baseline_next_24,
                textValue = when (transformationCountdownInHours) {
                    0 -> "${activeMon.transformationCountdown} m"
                    else -> "$transformationCountdownInHours h"
                },
                definition = "Next timer",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_swords_24,
                textValue = when {
                    activeMon.totalBattlesLost == 0 -> "0.00 %"
                    else -> {
                        val battleWinPercentage = activeMon.totalBattlesWon.toFloat() / (activeMon.totalBattlesWon + activeMon.totalBattlesLost).toFloat()
                        String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
                    }
                },
                definition = "Total battle win %",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_swords_24,
                textValue = when {
                    activeMon.totalBattlesLost == 0 -> "0.00 %"
                    else -> {
                        val battleWinPercentage = activeMon.currentPhaseBattlesWon.toFloat() / (activeMon.currentPhaseBattlesWon + activeMon.currentPhaseBattlesLost).toFloat()
                        String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
                    }
                },
                definition = "Current phase win %",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            TransformationHistoryCard(
                transformationHistory = transformationHistory,
                modifier = Modifier
                    .weight(1f)
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            ItemDisplay(
                icon = R.drawable.baseline_health_24,
                textValue = "+${beData.trainingHp}",
                definition = "Training HP",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_agility_24,
                textValue = "+${beData.trainingBp}",
                definition = "Training BP",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_attack_24,
                textValue = "+${beData.trainingAp}",
                definition = "Training AP",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
        }
    }
}
\ No newline at end of file

A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEDiMHomeScreen.kt +171 -0
@@ 0,0 1,171 @@
package com.github.nacabaro.vbhelper.screens.homeScreens

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import java.util.Locale
import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.ItemDisplay
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.utils.BitmapData
import kotlin.text.format

@Composable
fun BEDiMHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    beData: BECharacterData,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues
) {
    Column(
        modifier = Modifier
            .padding(top = contentPadding.calculateTopPadding())
            .verticalScroll(state = rememberScrollState())
    ) {
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            CharacterEntry(
                icon = BitmapData(
                    bitmap = activeMon.spriteIdle,
                    width = activeMon.spriteWidth,
                    height = activeMon.spriteHeight
                ),
                multiplier = 8,
                shape = androidx.compose.material.MaterialTheme.shapes.small,
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
            )
            Column (
                modifier = Modifier
                    .weight(0.5f)
                    .aspectRatio(0.5f)
            ) {
                ItemDisplay(
                    icon = R.drawable.baseline_vitals_24,
                    textValue = activeMon.vitalPoints.toString(),
                    definition = "Vitals",
                    modifier = Modifier
                        .weight(0.5f)
                        .aspectRatio(1f)
                        .padding(8.dp)
                )
                ItemDisplay(
                    icon = R.drawable.baseline_trophy_24,
                    textValue = activeMon.trophies.toString(),
                    definition = "Trophies",
                    modifier = Modifier
                        .weight(0.5f)
                        .aspectRatio(1f)
                        .padding(8.dp)
                )
            }
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            ItemDisplay(
                icon = R.drawable.baseline_mood_24,
                textValue = activeMon.mood.toString(),
                definition = "Mood",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            val timeInHours = (beData.remainingTrainingTimeInMinutes / 60)
            ItemDisplay(
                icon = R.drawable.baseline_timer_24,
                textValue = "$timeInHours h",
                definition = "Training limit",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            // Maybe get rid of this?
            ItemDisplay(
                icon = R.drawable.baseline_rank_24,
                textValue = beData.rank.toString(),
                definition = "Rank",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            val transformationCountdownInHours = activeMon.transformationCountdown / 60
            ItemDisplay(
                icon = R.drawable.baseline_next_24,
                textValue = when (transformationCountdownInHours) {
                    0 -> "${activeMon.transformationCountdown} m"
                    else -> "$transformationCountdownInHours h"
                },
                definition = "Next timer",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_swords_24,
                textValue = when {
                    activeMon.totalBattlesLost == 0 -> "0.00 %"
                    else -> {
                        val battleWinPercentage = activeMon.totalBattlesWon.toFloat() / (activeMon.totalBattlesWon + activeMon.totalBattlesLost).toFloat()
                        String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
                    }
                },
                definition = "Total battle win %",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
            ItemDisplay(
                icon = R.drawable.baseline_swords_24,
                textValue = when {
                    activeMon.totalBattlesLost == 0 -> "0.00 %"
                    else -> {
                        val battleWinPercentage = activeMon.currentPhaseBattlesWon.toFloat() / (activeMon.currentPhaseBattlesWon + activeMon.currentPhaseBattlesLost).toFloat()
                        String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
                    }
                },
                definition = "Current phase win %",
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .fillMaxWidth()
        ) {
            TransformationHistoryCard(
                transformationHistory = transformationHistory,
                modifier = Modifier
                    .weight(1f)
                    .padding(8.dp)
            )
        }
    }
}
\ No newline at end of file

A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt +102 -0
@@ 0,0 1,102 @@
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
import androidx.compose.foundation.layout.padding
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.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.DeviceType
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.source.StorageRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

@Composable
fun HomeScreen(
    navController: NavController
) {
    val application = LocalContext.current.applicationContext as VBHelper
    val storageRepository = StorageRepository(application.container.db)
    val activeMon = remember { mutableStateOf<CharacterDtos.CharacterWithSprites?>(null) }
    val transformationHistory = remember { mutableStateOf<List<CharacterDtos.TransformationHistory>?>(null) }
    val beData = remember { mutableStateOf<BECharacterData?>(null) }
    val vbData = remember { mutableStateOf<VBCharacterData?>(null) }

    LaunchedEffect(storageRepository, activeMon) {
        withContext(Dispatchers.IO) {
            activeMon.value = storageRepository.getActiveCharacter()
            if (activeMon.value != null) {
                beData.value = storageRepository.getCharacterBeData(activeMon.value!!.id)
                transformationHistory.value = storageRepository.getTransformationHistory(activeMon.value!!.id)
            }
        }
    }

    Scaffold (
        topBar = {
            TopBanner(
                text = "VB Helper",
                onScanClick = {
                    navController.navigate(NavigationItems.Scan.route)
                },
                onGearClick = {
                    navController.navigate(NavigationItems.Settings.route)
                }
            )
        }
    ) { contentPadding ->
        if (activeMon.value == null || (beData.value == null && vbData.value == null) || transformationHistory.value == null) {
            Column (
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center,
                modifier = Modifier
                    .fillMaxSize()
                    .padding(top = contentPadding.calculateTopPadding())
            ) {
                Text(text = "Nothing to see here")
            }
        } else {
            if (activeMon.value!!.isBemCard) {
                Log.d("HomeScreen", "BEDeviceBEm")
                BEBEmHomeScreen(
                    activeMon = activeMon.value!!,
                    beData = beData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                )
            } else if (!activeMon.value!!.isBemCard && activeMon.value!!.characterType == DeviceType.BEDevice) {
                Log.d("HomeScreen", "BEDevice")
                BEDiMHomeScreen(
                    activeMon = activeMon.value!!,
                    beData = beData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                )
            } else {
                VBDiMHomeScreen(
                    activeMon = activeMon.value!!,
                    vbData = vbData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                )
            }
        }
    }
}



A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/VBDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/VBDiMHomeScreen.kt +16 -0
@@ 0,0 1,16 @@
package com.github.nacabaro.vbhelper.screens.homeScreens

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos

@Composable
fun VBDiMHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    vbData: VBCharacterData,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues
) {
    TODO("Not implemented yet")
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt +7 -1
@@ 61,7 61,7 @@ fun ScanScreen(
    val context = LocalContext.current
    LaunchedEffect(storageRepository) {
        withContext(Dispatchers.IO) {
            if(characterId != null) {
            if(characterId != null && nfcCharacter == null) {
                nfcCharacter = characterToNfc(context, characterId)
            }
        }


@@ 129,6 129,12 @@ fun ScanScreen(
    } else if (isDoneSendingCard && isDoneWritingCharacter) {
        writingScreen = false
        navController.navigate(NavigationItems.Home.route)
        LaunchedEffect(storageRepository) {
            withContext(Dispatchers.IO) {
                storageRepository
                    .deleteCharacter(characterId!!)
            }
        }
    }

    if (readingScreen) {

M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +14 -1
@@ 21,11 21,24 @@ class StorageRepository (
        return db.userCharacterDao().getBeData(id)
    }

    fun getTransformationHistory(characterId: Long): List<TransformationHistory> {
    fun getTransformationHistory(characterId: Long): List<CharacterDtos.TransformationHistory>? {
        return db.userCharacterDao().getTransformationHistory(characterId)
    }

    suspend fun getCharacterData(id: Long): CharacterDtos.DiMInfo {
        return db.characterDao().getCharacterInfo(id)
    }

    suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites? {
        return db.userCharacterDao().getActiveCharacter()
    }

    fun deleteCharacter(id: Long) {
        return db.userCharacterDao().deleteCharacterById(id)
    }

    fun setActiveCharacter(id: Long) {
        db.userCharacterDao().clearActiveCharacter()
        return db.userCharacterDao().setActiveCharacter(id)
    }
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt => app/src/main/java/com/github/nacabaro/vbhelper/utils/CharacterToNFCCharacter.kt +20 -8
@@ 1,12 1,15 @@
package com.github.nacabaro.vbhelper.utils

import android.content.Context
import android.icu.util.Calendar
import android.icu.util.GregorianCalendar
import com.github.cfogrady.vbnfc.be.BENfcCharacter
import com.github.cfogrady.vbnfc.be.FirmwareVersion
import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.DeviceType
import com.github.nacabaro.vbhelper.source.StorageRepository
import java.util.Date

suspend fun characterToNfc(context: Context, characterId: Long): NfcCharacter? {
    val app = context.applicationContext as VBHelper


@@ 18,18 21,27 @@ suspend fun characterToNfc(context: Context, characterId: Long): NfcCharacter? {
    if (userCharacter.characterType == DeviceType.BEDevice) {
        val beData = storageRepository.getCharacterBeData(characterId)
        val transformationHistory = storageRepository
            .getTransformationHistory(characterId)
            .getTransformationHistory(characterId)!!
            .map {
                val date = Date(it.transformationDate)
                val calendar = GregorianCalendar()
                calendar.time = date

                NfcCharacter.Transformation(
                    toCharIndex = it.toCharIndex.toUByte(),
                    year = it.year.toUShort(),
                    month = it.month.toUByte(),
                    day = it.day.toUByte()
                    toCharIndex = it.monIndex.toUByte(),
                    year = calendar
                        .get(Calendar.YEAR)
                        .toUShort(),
                    month = calendar
                        .get(Calendar.MONTH)
                        .toUByte(),
                    day = calendar
                        .get(Calendar.DAY_OF_MONTH)
                        .toUByte()
                )
            }.toTypedArray()

        // Maybe this is the issue?
        val dummyVitalHistory = arrayOf<NfcCharacter.DailyVitals>()
        val paddedTransformationArray = padTransformationArray(transformationHistory)

        val nfcData = BENfcCharacter(
            dimId = characterInfo.cardId.toUShort(),


@@ 55,7 67,7 @@ suspend fun characterToNfc(context: Context, characterId: Long): NfcCharacter? {
            totalBattlesLost = userCharacter.totalBattlesLost.toUShort(),
            activityLevel = userCharacter.activityLevel.toByte(),
            heartRateCurrent = userCharacter.heartRateCurrent.toUByte(),
            transformationHistory = transformationHistory,
            transformationHistory = paddedTransformationArray,
            vitalHistory = Array(7) {
                NfcCharacter.DailyVitals(0u, 0u, 0u, 0u)
            },

A app/src/main/java/com/github/nacabaro/vbhelper/utils/padTransformationArray.kt => app/src/main/java/com/github/nacabaro/vbhelper/utils/padTransformationArray.kt +23 -0
@@ 0,0 1,23 @@
package com.github.nacabaro.vbhelper.utils

import com.github.cfogrady.vbnfc.data.NfcCharacter

fun padTransformationArray(
    transformationArray: Array<NfcCharacter.Transformation>
): Array<NfcCharacter.Transformation> {
    if (transformationArray.size >= 8) {
        return transformationArray
    }

    val paddedArray = Array(8) {
        NfcCharacter.Transformation(
            toCharIndex = 255u,
            year = 65535u,
            month = 255u,
            day = 255u
        )
    }

    System.arraycopy(transformationArray, 0, paddedArray, 0, transformationArray.size)
    return paddedArray
}
\ No newline at end of file

A app/src/main/res/drawable/baseline_age_24.xml => app/src/main/res/drawable/baseline_age_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M160,880q-17,0 -28.5,-11.5T120,840v-200q0,-33 23.5,-56.5T200,560v-160q0,-33 23.5,-56.5T280,320h160v-58q-18,-12 -29,-29t-11,-41q0,-15 6,-29.5t18,-26.5l56,-56 56,56q12,12 18,26.5t6,29.5q0,24 -11,41t-29,29v58h160q33,0 56.5,23.5T760,400v160q33,0 56.5,23.5T840,640v200q0,17 -11.5,28.5T800,880L160,880ZM280,560h400v-160L280,400v160ZM200,800h560v-160L200,640v160ZM280,560h400,-400ZM200,800h560,-560ZM760,560L200,560h560Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_agility_24.xml => app/src/main/res/drawable/baseline_agility_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M520,920v-240l-84,-80 -40,176 -276,-56 16,-80 192,40 64,-324 -72,28v136h-80v-188l158,-68q35,-15 51.5,-19.5T480,240q21,0 39,11t29,29l40,64q26,42 70.5,69T760,440v80q-66,0 -123.5,-27.5T540,420l-24,120 84,80v300h-80ZM540,220q-33,0 -56.5,-23.5T460,140q0,-33 23.5,-56.5T540,60q33,0 56.5,23.5T620,140q0,33 -23.5,56.5T540,220Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_attack_24.xml => app/src/main/res/drawable/baseline_attack_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M57,880 L1,824l146,-146 -44,-118q-7,-18 -3,-41.5t23,-42.5l132,-132q12,-12 26,-18t31,-6q17,0 31,6t26,18l80,78q27,27 66,42.5t84,15.5v80q-60,0 -112,-19t-90,-57l-28,-28 -94,94 84,86v244h-80v-210l-52,-48v88L57,880ZM599,880v-280l84,-80 -24,-140q-15,18 -33,32t-39,26q-33,-2 -62.5,-14T475,392q45,-8 79.5,-30.5T611,304l40,-64q17,-27 47,-36.5t59,2.5l202,86v188h-80v-136l-72,-28L919,880h-84l-72,-300 -84,80v220h-80ZM459,340q-33,0 -56.5,-23.5T379,260q0,-33 23.5,-56.5T459,180q33,0 56.5,23.5T539,260q0,33 -23.5,56.5T459,340ZM659,180q-33,0 -56.5,-23.5T579,100q0,-33 23.5,-56.5T659,20q33,0 56.5,23.5T739,100q0,33 -23.5,56.5T659,180Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_data_24.xml => app/src/main/res/drawable/baseline_data_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M440,777v-274L200,364v274l240,139ZM520,777 L760,638v-274L520,503v274ZM480,434 L717,297 480,160 243,297 480,434ZM160,708q-19,-11 -29.5,-29T120,639v-318q0,-22 10.5,-40t29.5,-29l280,-161q19,-11 40,-11t40,11l280,161q19,11 29.5,29t10.5,40v318q0,22 -10.5,40T800,708L520,869q-19,11 -40,11t-40,-11L160,708ZM480,480Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_free_24.xml => app/src/main/res/drawable/baseline_free_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M160,520v-80h640v80L160,520Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_health_24.xml => app/src/main/res/drawable/baseline_health_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="m480,840 l-58,-52q-101,-91 -167,-157T150,512.5Q111,460 95.5,416T80,326q0,-94 63,-157t157,-63q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,46 -15.5,90T810,512.5Q771,565 705,631T538,788l-58,52ZM480,732q96,-86 158,-147.5t98,-107q36,-45.5 50,-81t14,-70.5q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,280h-76q-15,-41 -55,-67.5T300,186q-60,0 -100,40t-40,100q0,35 14,70.5t50,81q36,45.5 98,107T480,732ZM480,459Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_mood_24.xml => app/src/main/res/drawable/baseline_mood_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M620,440q25,0 42.5,-17.5T680,380q0,-25 -17.5,-42.5T620,320q-25,0 -42.5,17.5T560,380q0,25 17.5,42.5T620,440ZM340,440q25,0 42.5,-17.5T400,380q0,-25 -17.5,-42.5T340,320q-25,0 -42.5,17.5T280,380q0,25 17.5,42.5T340,440ZM480,700q68,0 123.5,-38.5T684,560L276,560q25,63 80.5,101.5T480,700ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880ZM480,480ZM480,800q134,0 227,-93t93,-227q0,-134 -93,-227t-227,-93q-134,0 -227,93t-93,227q0,134 93,227t227,93Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_next_24.xml => app/src/main/res/drawable/baseline_next_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M660,720v-480h80v480h-80ZM220,720v-480l360,240 -360,240ZM300,480ZM300,570 L436,480 300,390v180Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_rank_24.xml => app/src/main/res/drawable/baseline_rank_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="m354,673 l126,-76 126,77 -33,-144 111,-96 -146,-13 -58,-136 -58,135 -146,13 111,97 -33,143ZM233,840l65,-281L80,370l288,-25 112,-265 112,265 288,25 -218,189 65,281 -247,-149 -247,149ZM480,490Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_timer_24.xml => app/src/main/res/drawable/baseline_timer_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M360,120v-80h240v80L360,120ZM440,560h80v-240h-80v240ZM480,880q-74,0 -139.5,-28.5T226,774q-49,-49 -77.5,-114.5T120,520q0,-74 28.5,-139.5T226,266q49,-49 114.5,-77.5T480,160q62,0 119,20t107,58l56,-56 56,56 -56,56q38,50 58,107t20,119q0,74 -28.5,139.5T734,774q-49,49 -114.5,77.5T480,880ZM480,800q116,0 198,-82t82,-198q0,-116 -82,-198t-198,-82q-116,0 -198,82t-82,198q0,116 82,198t198,82ZM480,520Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_trophy_24.xml => app/src/main/res/drawable/baseline_trophy_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M280,840v-80h160v-124q-49,-11 -87.5,-41.5T296,518q-75,-9 -125.5,-65.5T120,320v-40q0,-33 23.5,-56.5T200,200h80v-80h400v80h80q33,0 56.5,23.5T840,280v40q0,76 -50.5,132.5T664,518q-18,46 -56.5,76.5T520,636v124h160v80L280,840ZM280,432v-152h-80v40q0,38 22,68.5t58,43.5ZM480,560q50,0 85,-35t35,-85v-240L360,200v240q0,50 35,85t85,35ZM680,432q36,-13 58,-43.5t22,-68.5v-40h-80v152ZM480,380Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_vaccine_24.xml => app/src/main/res/drawable/baseline_vaccine_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M156,447q-11,-12 -11,-28.5t11,-28.5l112,-112 -43,-43 -12,12q-12,12 -28.5,12T156,247q-11,-11 -11,-28t11,-28l80,-80q12,-12 28.5,-12t28.5,12q11,11 11,28t-11,28l-12,12 43,43 112,-112q12,-12 28.5,-12t28.5,12q12,12 12,28.5T493,167l-27,26 295,295q23,23 23,56.5T761,601l-28,29 189,188L808,818L676,686l-28,29q-23,23 -56.5,23T535,715L240,420l-27,27q-12,11 -28.5,11T156,447ZM296,364 L591,659 704,545 644,484 588,540q-12,11 -28.5,11.5T532,541q-12,-12 -12,-28.5t12,-28.5l56,-56 -60,-60 -56,56q-12,11 -28.5,11T415,424q-11,-12 -11,-28.5t11,-28.5l56,-56 -61,-61 -114,114ZM296,364 L410,250 296,364Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_virus_24.xml => app/src/main/res/drawable/baseline_virus_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M600,880q-17,0 -28.5,-11.5T560,840v-43q-23,-4 -43.5,-11.5T478,765l-40,40q-12,11 -28.5,11.5T381,805q-12,-12 -12,-28.5t12,-28.5l41,-41q-3,-5 -6,-10.5t-6,-10.5l-27,-53 -49,49q-12,11 -28,11.5T278,682q-12,-12 -12,-28t12,-28l49,-50 -53,-26q-5,-2 -9,-4.5t-9,-5.5l-36,36q-12,11 -28.5,11.5T163,576q-12,-12 -12,-28t12,-28l35,-35q-14,-19 -22.5,-40.5T163,400h-43q-17,0 -28.5,-11.5T80,360q0,-17 11.5,-28.5T120,320h45q5,-19 12,-36t18,-33l-35,-35q-12,-12 -12,-28t12,-28q12,-12 28,-12t28,12l35,35q16,-11 33,-18t36,-12v-45q0,-17 11.5,-28.5T360,80q17,0 28.5,11.5T400,120v43q24,4 45.5,13t40.5,23l35,-35q12,-12 28.5,-12t28.5,12q12,12 12,28t-12,28l-37,37q2,4 4.5,8t4.5,9l25,50 46,-46q12,-12 28.5,-12t28.5,12q12,12 12,28.5T678,335l-48,47 56,28q6,3 12.5,6.5T710,424l40,-40q12,-12 28,-12t28,12q12,12 12,28.5T806,441l-40,39q12,18 19.5,38t11.5,42h43q17,0 28.5,11.5T880,600q0,17 -11.5,28.5T840,640h-45q-5,19 -12,35.5T765,708l34,34q12,12 12,28.5T799,799q-12,11 -28.5,11.5T742,799l-33,-34q-16,11 -33,18t-36,12v45q0,17 -11.5,28.5T600,880ZM594,720q58,0 95.5,-44T718,574q-5,-30 -22.5,-54T650,482l-66,-34q-23,-12 -41.5,-30.5T512,376l-34,-66q-16,-32 -46,-51t-66,-19q-58,0 -95.5,44T242,386q5,30 22.5,54t45.5,38l66,34q23,12 41.5,30.5T448,584l34,66q16,32 46,51t66,19ZM380,420q25,0 42.5,-17.5T440,360q0,-25 -17.5,-42.5T380,300q-25,0 -42.5,17.5T320,360q0,25 17.5,42.5T380,420ZM580,670q21,0 35.5,-14.5T630,620q0,-21 -14.5,-35.5T580,570q-21,0 -35.5,14.5T530,620q0,21 14.5,35.5T580,670ZM480,480Z"
      android:fillColor="#000000"/>
</vector>

A app/src/main/res/drawable/baseline_vitals_24.xml => app/src/main/res/drawable/baseline_vitals_24.xml +9 -0
@@ 0,0 1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="960"
    android:viewportHeight="960">
  <path
      android:pathData="M300,120q52,0 99,22t81,62q34,-40 81,-62t99,-22q94,0 157,63t63,157q0,5 -0.5,10t-0.5,10h-80q1,-5 1,-10v-10q0,-60 -40,-100t-100,-40q-47,0 -87,26.5T518,294h-76q-15,-41 -55,-67.5T300,200q-60,0 -100,40t-40,100v10q0,5 1,10L81,360q0,-5 -0.5,-10t-0.5,-10q0,-94 63,-157t157,-63ZM212,600h112q32,31 70,67t86,79q48,-43 86,-79t70,-67h113q-38,42 -90,91T538,802l-58,52 -58,-52q-69,-62 -120.5,-111T212,600ZM442,640q13,0 22.5,-7.5T478,613l54,-163 35,52q5,8 14,13t19,5h320v-80L623,440l-69,-102q-6,-9 -15.5,-13.5T518,320q-13,0 -22.5,7.5T482,347l-54,162 -34,-51q-5,-8 -14,-13t-19,-5L40,440v80h297l69,102q6,9 15.5,13.5T442,640ZM480,473Z"
      android:fillColor="#000000"/>
</vector>