~cytrogen/vbhelper

0e61723db15244246ce12dc76534ebff4301f3a0 — nacabaro 2 months ago 6cce33c + 8815907
Merge pull request #46 from nacabaro/ui/cardIcon

Card icon in home screen
M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +19 -0
@@ 43,6 43,7 @@ import androidx.compose.ui.res.stringResource
fun CharacterEntry(
    icon: BitmapData,
    modifier: Modifier = Modifier,
    cardIcon: BitmapData? = null,
    obscure: Boolean = false,
    disabled: Boolean = false,
    shape: Shape = MaterialTheme.shapes.medium,


@@ 55,6 56,7 @@ fun CharacterEntry(
    val bitmap = remember (icon.bitmap) {
        if(obscure) icon.getObscuredBitmap() else icon.getBitmap()
    }
    val iconSizeMultiplier = 3
    val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
    val density: Float = LocalContext.current.resources.displayMetrics.density
    val dpSize = (icon.width * multiplier / density).dp


@@ 86,7 88,24 @@ fun CharacterEntry(
                },
                modifier = Modifier
                    .size(dpSize)
                    .align(Alignment.BottomCenter)
            )

            if (cardIcon != null) {
                val bitmap = remember (icon.bitmap) { cardIcon.getBitmap() }
                val iconBitmap = remember(bitmap) { bitmap.asImageBitmap() }
                val dpSize = (icon.width * iconSizeMultiplier /density).dp

                Image(
                    bitmap = iconBitmap,
                    contentDescription = "Card icon",
                    filterQuality = FilterQuality.None,
                    modifier = Modifier
                        .size(dpSize)
                        .align(Alignment.BottomEnd)
                        .padding(8.dp)
                )
            }
        }
    }
}

M app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt +12 -0
@@ 5,6 5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.card.Card
import com.github.nacabaro.vbhelper.dtos.CardDtos
import kotlinx.coroutines.flow.Flow

@Dao


@@ 34,4 35,15 @@ interface CardDao {

    @Query("DELETE FROM Card WHERE id = :id")
    suspend fun deleteCard(id: Long)

    @Query("""
        SELECT 
            c.logo as cardIcon,
            c.logoWidth as cardIconWidth,
            c.logoHeight as cardIconHeight
        FROM Card c
        JOIN CardCharacter cc ON cc.cardId = c.id
        WHERE cc.id = :charaId
    """)
    fun getCardIconByCharaId(charaId: Long): Flow<CardDtos.CardIcon>
}
\ 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 +5 -5
@@ 53,7 53,7 @@ interface UserCharacterDao {
        WHERE monId = :monId
    """
    )
    suspend fun getTransformationHistory(monId: Long): List<CharacterDtos.TransformationHistory>?
    fun getTransformationHistory(monId: Long): Flow<List<CharacterDtos.TransformationHistory>>

    @Query(
        """


@@ 110,13 110,13 @@ interface UserCharacterDao {
    suspend fun getCharacter(id: Long): UserCharacter

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

    @Query("SELECT * FROM VBCharacterData WHERE id = :id")
    suspend fun getVbData(id: Long): VBCharacterData
    fun getVbData(id: Long): Flow<VBCharacterData>

    @Query("SELECT * FROM SpecialMissions WHERE characterId = :id")
    suspend fun getSpecialMissions(id: Long): List<SpecialMissions>
    fun getSpecialMissions(id: Long): Flow<List<SpecialMissions>>

    @Query(
        """


@@ 143,7 143,7 @@ interface UserCharacterDao {
        LIMIT 1
    """
    )
    suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites?
    fun getActiveCharacter(): Flow<CharacterDtos.CharacterWithSprites?>

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

M app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt => app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt +6 -0
@@ 24,4 24,10 @@ object CardDtos {
        val characterHp: Int,
        val steps: Int,
    )

    data class CardIcon (
        val cardIcon: ByteArray,
        val cardIconWidth: Int,
        val cardIconHeight: Int
    )
}
\ 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 +4 -11
@@ 1,13 1,12 @@
package com.github.nacabaro.vbhelper.navigation

import android.util.Log
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember


@@ 99,20 98,14 @@ fun AppNavigation(
            composable(NavigationItems.Scan.route) {
                val characterIdString = it.arguments?.getString("characterId")
                var characterId by remember { mutableStateOf(characterIdString?.toLongOrNull()) }
                Log.d("ScanScreen", "characterId: $characterId")
                val launchedFromHomeScreen = (characterIdString?.toLongOrNull() == null)

                if (characterId == null) {
                    val context = LocalContext.current.applicationContext as VBHelper
                    val storageRepository = StorageRepository(context.container.db)

                    LaunchedEffect(characterId) {
                        if (characterId == null) {
                            val characterData = storageRepository.getActiveCharacter()
                            if (characterData != null) {
                                characterId = characterData.id
                            }
                        }
                    val characterData by storageRepository.getActiveCharacter().collectAsState(null)
                    if (characterData != null) {
                        characterId = characterData!!.id
                    }
                }


M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt +81 -40
@@ 11,6 11,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember


@@ 28,9 29,7 @@ import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.utils.DeviceType
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.screens.homeScreens.screens.BEBEmHomeScreen


@@ 38,9 37,12 @@ import com.github.nacabaro.vbhelper.screens.homeScreens.screens.BEDiMHomeScreen
import com.github.nacabaro.vbhelper.screens.homeScreens.screens.VBDiMHomeScreen
import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
import com.github.nacabaro.vbhelper.source.StorageRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.dtos.CardDtos
import com.github.nacabaro.vbhelper.source.CardRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
import kotlinx.coroutines.flow.flowOf
import kotlin.collections.emptyList

@Composable
fun HomeScreen(


@@ 49,30 51,60 @@ fun HomeScreen(
) {
    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) }
    val vbSpecialMissions = remember { mutableStateOf<List<SpecialMissions>>(emptyList()) }
    val cardRepository = CardRepository(application.container.db)

    val activeMon by storageRepository
        .getActiveCharacter()
        .collectAsState(initial = null)

    val cardIconData by (
        activeMon
            ?.let { chara ->
                cardRepository.getCardIconByCharaId(chara.charId)
            }
            ?: flowOf<CardDtos.CardIcon?>(null)
    ).collectAsState(initial = null)

    val transformationHistory by (
        activeMon
            ?.let { chara ->
                storageRepository.getTransformationHistory(chara.id)
            }
            ?: flowOf(emptyList())
    ).collectAsState(initial = emptyList())

    val vbSpecialMissions by (
        activeMon
            ?.takeIf { it.characterType == DeviceType.VBDevice }
            ?.let { chara ->
                storageRepository.getSpecialMissions(chara.id)
            }
            ?: flowOf(emptyList())
    ).collectAsState(initial = emptyList())

    val vbData by (
        activeMon
            ?.takeIf { it.characterType == DeviceType.VBDevice }
            ?.let { chara ->
                storageRepository.getCharacterVbData(chara.id)
            }
            ?: flowOf<VBCharacterData?>(null)
    ).collectAsState(initial = null)

    val beData by (
        activeMon
            ?.takeIf { it.characterType == DeviceType.BEDevice }
            ?.let { chara ->
                storageRepository.getCharacterBeData(chara.id)
            }
            ?: flowOf<BECharacterData?>(null)
    ).collectAsState(initial = null)

    var adventureMissionsFinished by rememberSaveable { mutableStateOf(false) }
    var betaWarning by rememberSaveable { mutableStateOf(true) }
    var collectedItem by remember { mutableStateOf<ItemDtos.PurchasedItem?>(null) }
    var collectedCurrency by remember { mutableStateOf<Int?>(null) }

    LaunchedEffect(storageRepository, activeMon, collectedItem) {
        withContext(Dispatchers.IO) {
            activeMon.value = storageRepository.getActiveCharacter()
            if (activeMon.value != null && activeMon.value!!.characterType == DeviceType.BEDevice) {
                beData.value = storageRepository.getCharacterBeData(activeMon.value!!.id)
                transformationHistory.value = storageRepository.getTransformationHistory(activeMon.value!!.id)
            } else if (activeMon.value != null && activeMon.value!!.characterType == DeviceType.VBDevice) {
                vbData.value = storageRepository.getCharacterVbData(activeMon.value!!.id)
                vbSpecialMissions.value = storageRepository.getSpecialMissions(activeMon.value!!.id)
                transformationHistory.value = storageRepository.getTransformationHistory(activeMon.value!!.id)
            }
        }
    }

    LaunchedEffect(true) {
        homeScreenController
            .didAdventureMissionsFinish {


@@ 93,7 125,7 @@ fun HomeScreen(
            )
        }
    ) { contentPadding ->
        if (activeMon.value == null || (beData.value == null && vbData.value == null) || transformationHistory.value == null) {
        if (activeMon == null || (beData == null && vbData == null) || cardIconData == null || transformationHistory.isEmpty()) {
            Column (
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center,


@@ 104,32 136,41 @@ fun HomeScreen(
                Text(text = stringResource(R.string.adventure_empty_state))
            }
        } else {
            if (activeMon.value!!.isBemCard) {
            val cardIcon = BitmapData(
                bitmap = cardIconData!!.cardIcon,
                width = cardIconData!!.cardIconWidth,
                height = cardIconData!!.cardIconHeight
            )

            if (activeMon!!.isBemCard && beData != null) {
                BEBEmHomeScreen(
                    activeMon = activeMon.value!!,
                    beData = beData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                    activeMon = activeMon!!,
                    beData = beData!!,
                    transformationHistory = transformationHistory,
                    contentPadding = contentPadding,
                    cardIcon = cardIcon
                )
            } else if (!activeMon.value!!.isBemCard && activeMon.value!!.characterType == DeviceType.BEDevice) {
            } else if (!activeMon!!.isBemCard && activeMon!!.characterType == DeviceType.BEDevice && beData != null) {
                BEDiMHomeScreen(
                    activeMon = activeMon.value!!,
                    beData = beData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                    activeMon = activeMon!!,
                    beData = beData!!,
                    transformationHistory = transformationHistory,
                    contentPadding = contentPadding,
                    cardIcon = cardIcon
                )
            } else {
            } else if (vbData != null) {
                VBDiMHomeScreen(
                    activeMon = activeMon.value!!,
                    vbData = vbData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    activeMon = activeMon!!,
                    vbData = vbData!!,
                    transformationHistory = transformationHistory,
                    contentPadding = contentPadding,
                    specialMissions = vbSpecialMissions.value,
                    specialMissions = vbSpecialMissions,
                    homeScreenController = homeScreenController,
                    onClickCollect = { item, currency ->
                        collectedItem = item
                        collectedCurrency = currency
                    }
                    },
                    cardIcon = cardIcon
                )
            }
        }

M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt +2 -0
@@ 26,6 26,7 @@ import java.util.Locale
fun BEBEmHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    beData: BECharacterData,
    cardIcon: BitmapData,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues
) {


@@ 46,6 47,7 @@ fun BEBEmHomeScreen(
                ),
                multiplier = 8,
                shape = androidx.compose.material.MaterialTheme.shapes.small,
                cardIcon = cardIcon,
                modifier = Modifier
                    .weight(1f)
                    .aspectRatio(1f)

M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt +2 -0
@@ 26,6 26,7 @@ import kotlin.text.format
@Composable
fun BEDiMHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    cardIcon: BitmapData,
    beData: BECharacterData,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues


@@ 45,6 46,7 @@ fun BEDiMHomeScreen(
                    width = activeMon.spriteWidth,
                    height = activeMon.spriteHeight
                ),
                cardIcon = cardIcon,
                multiplier = 8,
                shape = androidx.compose.material.MaterialTheme.shapes.small,
                modifier = Modifier

M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt +2 -0
@@ 31,6 31,7 @@ import androidx.compose.ui.res.stringResource
@Composable
fun VBDiMHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    cardIcon: BitmapData,
    vbData: VBCharacterData,
    specialMissions: List<SpecialMissions>,
    homeScreenController: HomeScreenControllerImpl,


@@ 53,6 54,7 @@ fun VBDiMHomeScreen(
                    width = activeMon.spriteWidth,
                    height = activeMon.spriteHeight
                ),
                cardIcon = cardIcon,
                multiplier = 8,
                shape = androidx.compose.material.MaterialTheme.shapes.small,
                modifier = Modifier

M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt +12 -3
@@ 11,6 11,8 @@ import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.utils.DeviceType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext



@@ 52,9 54,16 @@ class ItemsScreenControllerImpl (
                var vbCharacterData: VBCharacterData? = null

                if (characterData.characterType == DeviceType.BEDevice) {
                    beCharacterData = database.userCharacterDao().getBeData(characterId)
                    beCharacterData = database
                        .userCharacterDao()
                        .getBeData(characterId)
                        .firstOrNull()

                } else if (characterData.characterType == DeviceType.VBDevice) {
                    vbCharacterData = database.userCharacterDao().getVbData(characterId)
                    vbCharacterData = database
                        .userCharacterDao()
                        .getVbData(characterId)
                        .firstOrNull()
                }

                if (


@@ 161,7 170,7 @@ class ItemsScreenControllerImpl (
        var firstUnavailableMissionSlot: Long = 0
        var watchId = 0

        for ((index, mission) in availableSpecialMissions.withIndex()) {
        for ((index, mission) in availableSpecialMissions.first().withIndex()) {
            if (
                mission.status == SpecialMission.Status.UNAVAILABLE
            ) {

M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt +5 -1
@@ 55,6 55,7 @@ class ToNfcConverter(
        val vbData = database
            .userCharacterDao()
            .getVbData(characterId)
            .first()

        val paddedTransformationArray = generateTransformationHistory(characterId, 9)



@@ 116,6 117,7 @@ class ToNfcConverter(
        val specialMissions = database
            .userCharacterDao()
            .getSpecialMissions(characterId)
            .first()

        val watchSpecialMissions = specialMissions.map {
            SpecialMission(


@@ 175,6 177,7 @@ class ToNfcConverter(
        val beData = database
            .userCharacterDao()
            .getBeData(characterId)
            .first()

        val paddedTransformationArray = generateTransformationHistory(characterId)



@@ 237,7 240,8 @@ class ToNfcConverter(
    ): Array<NfcCharacter.Transformation> {
        val transformationHistory = database
            .userCharacterDao()
            .getTransformationHistory(characterId)!!
            .getTransformationHistory(characterId)
            .first()
            .map {
                val date = Date(it.transformationDate)
                val calendar = android.icu.util.GregorianCalendar(TimeZone.getTimeZone("UTC"))

A app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt +15 -0
@@ 0,0 1,15 @@
package com.github.nacabaro.vbhelper.source

import com.github.nacabaro.vbhelper.database.AppDatabase
import com.github.nacabaro.vbhelper.dtos.CardDtos
import kotlinx.coroutines.flow.Flow

class CardRepository (
    private val db: AppDatabase
) {
    fun getCardIconByCharaId(charaId: Long): Flow<CardDtos.CardIcon> {
        return db
            .cardDao()
            .getCardIconByCharaId(charaId = charaId)
    }
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +5 -5
@@ 19,19 19,19 @@ class StorageRepository (
        return db.userCharacterDao().getCharacterWithSprites(id)
    }

    suspend fun getCharacterBeData(id: Long): BECharacterData {
    fun getCharacterBeData(id: Long): Flow<BECharacterData> {
        return db.userCharacterDao().getBeData(id)
    }

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

    suspend fun getCharacterVbData(id: Long): VBCharacterData {
    fun getCharacterVbData(id: Long): Flow<VBCharacterData> {
        return db.userCharacterDao().getVbData(id)
    }

    suspend fun getSpecialMissions(id: Long): List<SpecialMissions> {
    fun getSpecialMissions(id: Long): Flow<List<SpecialMissions>> {
        return db.userCharacterDao().getSpecialMissions(id)
    }



@@ 39,7 39,7 @@ class StorageRepository (
        return db.itemDao().getItem(id)
    }

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


M gradle/libs.versions.toml => gradle/libs.versions.toml +1 -1
@@ 1,5 1,5 @@
[versions]
agp = "8.13.1"
agp = "8.13.2"
datastore = "1.1.2"
kotlin = "2.0.0"
coreKtx = "1.15.0"