From 88159075630f366e22734c359aa8c86ebe6864a2 Mon Sep 17 00:00:00 2001 From: nacabaro Date: Sun, 25 Jan 2026 17:35:54 +0100 Subject: [PATCH 1/4] Card icon in home screen Together with character sprite --- .../vbhelper/components/CharacterEntry.kt | 19 +++ .../github/nacabaro/vbhelper/daos/CardDao.kt | 12 ++ .../vbhelper/daos/UserCharacterDao.kt | 10 +- .../github/nacabaro/vbhelper/dtos/CardDtos.kt | 6 + .../vbhelper/navigation/AppNavigation.kt | 15 +- .../screens/homeScreens/HomeScreen.kt | 129 ++++++++++++------ .../homeScreens/screens/BEBEmHomeScreen.kt | 2 + .../homeScreens/screens/BEDiMHomeScreen.kt | 2 + .../homeScreens/screens/VBDiMHomeScreen.kt | 2 + .../itemsScreen/ItemsScreenControllerImpl.kt | 15 +- .../scanScreen/converters/ToNfcConverter.kt | 6 +- .../vbhelper/source/CardRepository.kt | 15 ++ .../vbhelper/source/StorageRepository.kt | 10 +- gradle/libs.versions.toml | 2 +- 14 files changed, 175 insertions(+), 70 deletions(-) create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt b/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt index 539b044..4d8110b 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt @@ -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) + ) + } } } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt index e9511f2..c87a1f7 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt @@ -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 } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt index 1bc97fc..986ce01 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt @@ -53,7 +53,7 @@ interface UserCharacterDao { WHERE monId = :monId """ ) - suspend fun getTransformationHistory(monId: Long): List? + fun getTransformationHistory(monId: Long): Flow> @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 @Query("SELECT * FROM VBCharacterData WHERE id = :id") - suspend fun getVbData(id: Long): VBCharacterData + fun getVbData(id: Long): Flow @Query("SELECT * FROM SpecialMissions WHERE characterId = :id") - suspend fun getSpecialMissions(id: Long): List + fun getSpecialMissions(id: Long): Flow> @Query( """ @@ -143,7 +143,7 @@ interface UserCharacterDao { LIMIT 1 """ ) - suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites? + fun getActiveCharacter(): Flow @Query("DELETE FROM UserCharacter WHERE id = :id") fun deleteCharacterById(id: Long) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt index 252b553..78c5d27 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt @@ -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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt index 013b083..7d207b2 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/navigation/AppNavigation.kt @@ -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 } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt index 7036fb8..0cacb5d 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt @@ -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(null) } - val transformationHistory = remember { mutableStateOf?>(null) } - val beData = remember { mutableStateOf(null) } - val vbData = remember { mutableStateOf(null) } - val vbSpecialMissions = remember { mutableStateOf>(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(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(null) + ).collectAsState(initial = null) + + val beData by ( + activeMon + ?.takeIf { it.characterType == DeviceType.BEDevice } + ?.let { chara -> + storageRepository.getCharacterBeData(chara.id) + } + ?: flowOf(null) + ).collectAsState(initial = null) + var adventureMissionsFinished by rememberSaveable { mutableStateOf(false) } var betaWarning by rememberSaveable { mutableStateOf(true) } var collectedItem by remember { mutableStateOf(null) } var collectedCurrency by remember { mutableStateOf(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 - ) - } else if (!activeMon.value!!.isBemCard && activeMon.value!!.characterType == DeviceType.BEDevice) { - BEDiMHomeScreen( - activeMon = activeMon.value!!, - beData = beData.value!!, - transformationHistory = transformationHistory.value!!, - contentPadding = contentPadding - ) - } else { - VBDiMHomeScreen( - activeMon = activeMon.value!!, - vbData = vbData.value!!, - transformationHistory = transformationHistory.value!!, + activeMon = activeMon!!, + beData = beData!!, + transformationHistory = transformationHistory, contentPadding = contentPadding, - specialMissions = vbSpecialMissions.value, + cardIcon = cardIcon + ) + } else if (!activeMon!!.isBemCard && activeMon!!.characterType == DeviceType.BEDevice && beData != null) { + BEDiMHomeScreen( + activeMon = activeMon!!, + beData = beData!!, + transformationHistory = transformationHistory, + contentPadding = contentPadding, + cardIcon = cardIcon + ) + } else if (vbData != null) { + VBDiMHomeScreen( + activeMon = activeMon!!, + vbData = vbData!!, + transformationHistory = transformationHistory, + contentPadding = contentPadding, + specialMissions = vbSpecialMissions, homeScreenController = homeScreenController, onClickCollect = { item, currency -> collectedItem = item collectedCurrency = currency - } + }, + cardIcon = cardIcon ) } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt index a35d577..432824b 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEBEmHomeScreen.kt @@ -26,6 +26,7 @@ import java.util.Locale fun BEBEmHomeScreen( activeMon: CharacterDtos.CharacterWithSprites, beData: BECharacterData, + cardIcon: BitmapData, transformationHistory: List, 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) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt index 065b6c6..6a03e3c 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/BEDiMHomeScreen.kt @@ -26,6 +26,7 @@ import kotlin.text.format @Composable fun BEDiMHomeScreen( activeMon: CharacterDtos.CharacterWithSprites, + cardIcon: BitmapData, beData: BECharacterData, transformationHistory: List, 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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt index 54fe76c..f29c7c0 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.res.stringResource @Composable fun VBDiMHomeScreen( activeMon: CharacterDtos.CharacterWithSprites, + cardIcon: BitmapData, vbData: VBCharacterData, specialMissions: List, 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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt index db9194d..e3397d9 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt @@ -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 ) { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt index 2078238..143fef8 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt @@ -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 { val transformationHistory = database .userCharacterDao() - .getTransformationHistory(characterId)!! + .getTransformationHistory(characterId) + .first() .map { val date = Date(it.transformationDate) val calendar = android.icu.util.GregorianCalendar(TimeZone.getTimeZone("UTC")) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt new file mode 100644 index 0000000..86f21ff --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/CardRepository.kt @@ -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 { + return db + .cardDao() + .getCardIconByCharaId(charaId = charaId) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt index f74da0d..da15e26 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt @@ -19,19 +19,19 @@ class StorageRepository ( return db.userCharacterDao().getCharacterWithSprites(id) } - suspend fun getCharacterBeData(id: Long): BECharacterData { + fun getCharacterBeData(id: Long): Flow { return db.userCharacterDao().getBeData(id) } - suspend fun getTransformationHistory(characterId: Long): List? { + fun getTransformationHistory(characterId: Long): Flow> { return db.userCharacterDao().getTransformationHistory(characterId) } - suspend fun getCharacterVbData(id: Long): VBCharacterData { + fun getCharacterVbData(id: Long): Flow { return db.userCharacterDao().getVbData(id) } - suspend fun getSpecialMissions(id: Long): List { + fun getSpecialMissions(id: Long): Flow> { return db.userCharacterDao().getSpecialMissions(id) } @@ -39,7 +39,7 @@ class StorageRepository ( return db.itemDao().getItem(id) } - suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites? { + fun getActiveCharacter(): Flow { return db.userCharacterDao().getActiveCharacter() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1db28ca..94c3f7d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" From c990a495b77035ec486af782561974df3123ffe1 Mon Sep 17 00:00:00 2001 From: nacabaro Date: Sun, 25 Jan 2026 19:58:03 +0100 Subject: [PATCH 2/4] Fix Special Missions a bit more Now they should behave a bit better, and it will not allow the watch to have multiple missions of the same type, plus you can now delete special missions. --- .../vbhelper/components/CharacterEntry.kt | 11 ++-- .../vbhelper/daos/SpecialMissionDao.kt | 9 +++ .../homeScreens/HomeScreenController.kt | 3 +- .../homeScreens/HomeScreenControllerImpl.kt | 10 +++- .../dialogs/DeleteSpecialMissionDialog.kt | 56 +++++++++++++++++++ .../homeScreens/screens/VBDiMHomeScreen.kt | 32 +++++++++-- .../itemsScreen/ItemsScreenControllerImpl.kt | 42 +++++++------- app/src/main/res/values/strings.xml | 3 + 8 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/dialogs/DeleteSpecialMissionDialog.kt diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt b/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt index 4d8110b..767d1cc 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt @@ -152,7 +152,8 @@ fun ItemDisplay( fun SpecialMissionsEntry( specialMission: SpecialMissions, modifier: Modifier = Modifier, - onClickCard: () -> Unit = { }, + onClickMission: (Long) -> Unit = { }, + onClickCollect: (Long) -> Unit = { } ) { val textValue = when (specialMission.missionType) { SpecialMission.Type.NONE -> stringResource(R.string.special_mission_none) @@ -219,10 +220,12 @@ fun SpecialMissionsEntry( Card( modifier = modifier, shape = androidx.compose.material.MaterialTheme.shapes.small, - onClick = if (specialMission.status == SpecialMission.Status.COMPLETED || specialMission.status == SpecialMission.Status.FAILED) { - onClickCard + onClick = if (specialMission.status == SpecialMission.Status.COMPLETED) { + { onClickCollect(specialMission.id) } + } else if (specialMission.status == SpecialMission.Status.UNAVAILABLE) { + { } } else { - { } + { onClickMission(specialMission.id) } }, colors = CardDefaults.cardColors( containerColor = color diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/SpecialMissionDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/SpecialMissionDao.kt index 7dc5c74..ccc864c 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/SpecialMissionDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/SpecialMissionDao.kt @@ -2,6 +2,8 @@ package com.github.nacabaro.vbhelper.daos import androidx.room.Dao import androidx.room.Query +import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions +import kotlinx.coroutines.flow.Flow @Dao interface SpecialMissionDao { @@ -12,4 +14,11 @@ interface SpecialMissionDao { WHERE id = :id """) suspend fun clearSpecialMission(id: Long) + + @Query(""" + SELECT * + FROM SpecialMissions + WHERE id = :id + """) + fun getSpecialMission(id: Long): Flow } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt index 1c0093b..0e06410 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt @@ -1,9 +1,8 @@ package com.github.nacabaro.vbhelper.screens.homeScreens -import com.github.cfogrady.vbnfc.vb.SpecialMission import com.github.nacabaro.vbhelper.dtos.ItemDtos interface HomeScreenController { fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit) - fun clearSpecialMission(missionId: Long, missionCompletion: SpecialMission.Status, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit) + fun clearSpecialMission(missionId: Long, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit) } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt index e8824e8..6a126fa 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt @@ -33,13 +33,18 @@ class HomeScreenControllerImpl( } } - override fun clearSpecialMission(missionId: Long, missionCompletion: SpecialMission.Status, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit) { + override fun clearSpecialMission(missionId: Long, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit) { componentActivity.lifecycleScope.launch { + val missionStatus = database + .specialMissionDao() + .getSpecialMission(missionId) + .first() + database .specialMissionDao() .clearSpecialMission(missionId) - if (missionCompletion == SpecialMission.Status.COMPLETED) { + if (missionStatus.status == SpecialMission.Status.COMPLETED) { val randomItem = database .itemDao() .getAllItems() @@ -73,7 +78,6 @@ class HomeScreenControllerImpl( } else { onCleared(null, null) } - } } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/dialogs/DeleteSpecialMissionDialog.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/dialogs/DeleteSpecialMissionDialog.kt new file mode 100644 index 0000000..df5d9dc --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/dialogs/DeleteSpecialMissionDialog.kt @@ -0,0 +1,56 @@ +package com.github.nacabaro.vbhelper.screens.homeScreens.dialogs + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.github.nacabaro.vbhelper.R + +@Composable +fun DeleteSpecialMissionDialog( + onClickDismiss: () -> Unit, + onClickDelete: () -> Unit +) { + Dialog( + onDismissRequest = onClickDismiss + ) { + Card { + Column( + modifier = Modifier + .padding(16.dp) + ) { + Text( + text = stringResource(R.string.home_special_mission_delete_main), + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.padding(8.dp)) + Row { + Button( + onClick = onClickDismiss, + modifier = Modifier + .padding(8.dp) + ) { + Text(text = stringResource(R.string.home_special_mission_delete_dismiss)) + } + + Button( + onClick = onClickDelete, + modifier = Modifier + .padding(8.dp) + ) { + Text(text = stringResource(R.string.home_special_mission_delete_remove)) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt index f29c7c0..8460b49 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt @@ -10,6 +10,10 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -26,6 +30,7 @@ import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl import com.github.nacabaro.vbhelper.utils.BitmapData import java.util.Locale import androidx.compose.ui.res.stringResource +import com.github.nacabaro.vbhelper.screens.homeScreens.dialogs.DeleteSpecialMissionDialog @Composable @@ -39,6 +44,8 @@ fun VBDiMHomeScreen( contentPadding: PaddingValues, onClickCollect: (ItemDtos.PurchasedItem?, Int?) -> Unit ) { + var selectedSpecialMissionId by remember { mutableStateOf(-1) } + Column( modifier = Modifier .padding(top = contentPadding.calculateTopPadding()) @@ -183,11 +190,28 @@ fun VBDiMHomeScreen( modifier = Modifier .weight(1f) .padding(8.dp), - ) { - homeScreenController - .clearSpecialMission(mission.id, mission.status, onClickCollect) - } + onClickMission = { missionId -> + selectedSpecialMissionId = missionId + }, + onClickCollect = { + homeScreenController + .clearSpecialMission(selectedSpecialMissionId, onClickCollect) + } + ) } } } + + if (selectedSpecialMissionId.toInt() != -1) { + DeleteSpecialMissionDialog( + onClickDismiss = { + selectedSpecialMissionId = -1 + }, + onClickDelete = { + homeScreenController + .clearSpecialMission(selectedSpecialMissionId, onClickCollect) + selectedSpecialMissionId = -1 + } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt index e3397d9..eb3f477 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt @@ -162,33 +162,35 @@ class ItemsScreenControllerImpl ( ItemTypes.Win4.id -> 4 else -> 0 } + + val specialMissionSlot = when (itemIcon) { + ItemTypes.Step8k.id -> 0 + ItemTypes.Step4k.id -> 0 + ItemTypes.Vitals1000.id -> 1 + ItemTypes.Vitals250.id -> 1 + ItemTypes.Battle20.id -> 2 + ItemTypes.Battle5.id -> 2 + ItemTypes.Win10.id -> 3 + ItemTypes.Win4.id -> 3 + else -> 0 + } val availableSpecialMissions = database .userCharacterDao() .getSpecialMissions(characterId) + .first() - var firstUnavailableMissionSlot: Long = 0 - var watchId = 0 - - for ((index, mission) in availableSpecialMissions.first().withIndex()) { - if ( - mission.status == SpecialMission.Status.UNAVAILABLE - ) { - firstUnavailableMissionSlot = mission.id - watchId = index + 1 - } - } - - val newSpecialMission = SpecialMissions( - id = firstUnavailableMissionSlot, - characterId = characterId, - missionType = specialMissionType, + var newSpecialMission = availableSpecialMissions[specialMissionSlot] + newSpecialMission = SpecialMissions( + id = newSpecialMission.id, + characterId = newSpecialMission.characterId, goal = specialMissionGoal, - timeLimitInMinutes = itemLength, - watchId = watchId, - status = SpecialMission.Status.AVAILABLE, + watchId = newSpecialMission.watchId, progress = 0, - timeElapsedInMinutes = 0 + status = SpecialMission.Status.AVAILABLE, + timeElapsedInMinutes = 0, + timeLimitInMinutes = itemLength, + missionType = specialMissionType ) database diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c9f31a3..b5c51fd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -222,5 +222,8 @@ Won %1$d battles Earned %1$d vitals Special mission icon + Are you sure you want to delete this special mission with this progress? + Dismiss + Remove \ No newline at end of file From 37076a9bf0c296a6730a4d9e995432f1fed3e77c Mon Sep 17 00:00:00 2001 From: nacabaro Date: Sun, 25 Jan 2026 20:00:55 +0100 Subject: [PATCH 3/4] VERSION UP --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7e4a241..01387d5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,7 +15,7 @@ android { minSdk = 28 targetSdk = 35 versionCode = 1 - versionName = "Alpha 0.6.2" + versionName = "Alpha 0.6.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } From 366f425539376176482467b24d0464076b86cae9 Mon Sep 17 00:00:00 2001 From: nacabaro Date: Wed, 28 Jan 2026 02:05:43 +0100 Subject: [PATCH 4/4] Updated libraries Moved library definitions to the catalog, and updated the catalog --- app/build.gradle.kts | 43 ++++++++++++++++++++++++--------------- gradle/libs.versions.toml | 31 ++++++++++++++++++---------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 01387d5..0ff1234 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,19 +1,21 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) - id("com.google.devtools.ksp") version "2.0.21-1.0.27" + id("com.google.devtools.ksp") version "2.3.0" id("com.google.protobuf") } android { namespace = "com.github.nacabaro.vbhelper" - compileSdk = 35 + compileSdk = 36 defaultConfig { applicationId = "com.github.nacabaro.vbhelper" minSdk = 28 - targetSdk = 35 + targetSdk = 36 versionCode = 1 versionName = "Alpha 0.6.3" @@ -33,9 +35,7 @@ android { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } - kotlinOptions { - jvmTarget = "11" - } + buildFeatures { compose = true } @@ -45,6 +45,12 @@ android { } } +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_11 + } +} + protobuf { protoc { artifact = "com.google.protobuf:protoc:4.27.0" @@ -68,10 +74,13 @@ dependencies { implementation(libs.androidx.room.runtime) implementation(libs.vb.nfc.reader) implementation(libs.dim.reader) - ksp(libs.androidx.room.compiler) - annotationProcessor(libs.androidx.room.compiler) implementation(libs.androidx.core.ktx) - implementation("androidx.room:room-ktx:2.6.1") + implementation(libs.androidx.room.ktx) + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.navigation.compose) + implementation(libs.material) + implementation(libs.protobuf.javalite) + implementation(libs.androidx.compose.material) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) @@ -80,16 +89,18 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) + implementation(libs.androidx.compose.material.icons.extended) + + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) + testImplementation(libs.junit) + + ksp(libs.androidx.room.compiler) + annotationProcessor(libs.androidx.room.compiler) + androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.ui.test.junit4) - debugImplementation(libs.androidx.ui.tooling) - debugImplementation(libs.androidx.ui.test.manifest) - implementation("androidx.navigation:navigation-compose:2.7.0") - implementation("com.google.android.material:material:1.2.0") - implementation(libs.protobuf.javalite) - implementation("androidx.compose.material:material") - implementation("androidx.datastore:datastore-preferences:1.1.7") } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 94c3f7d..7e4875e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,24 +1,32 @@ [versions] agp = "8.13.2" -datastore = "1.1.2" -kotlin = "2.0.0" -coreKtx = "1.15.0" +datastore = "1.2.0" +datastorePreferences = "1.2.0" +kotlin = "2.3.0" +coreKtx = "1.17.0" junit = "4.13.2" -junitVersion = "1.2.1" -espressoCore = "3.6.1" -lifecycleRuntimeKtx = "2.8.7" -activityCompose = "1.10.0" -composeBom = "2025.01.00" -protobufGradlePlugin = "0.9.4" -protobufJavalite = "4.27.0" -roomRuntime = "2.6.1" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +lifecycleRuntimeKtx = "2.10.0" +activityCompose = "1.12.2" +composeBom = "2026.01.00" +material = "1.13.0" +navigationCompose = "2.9.6" +protobufGradlePlugin = "0.9.6" +protobufJavalite = "4.33.4" +roomRuntime = "2.8.4" vbNfcReader = "0.2.0-SNAPSHOT" dimReader = "2.1.0" [libraries] +androidx-compose-material = { module = "androidx.compose.material:material" } +androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } +androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } +androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomRuntime" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } @@ -33,6 +41,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +material = { module = "com.google.android.material:material", version.ref = "material" } protobuf-gradle-plugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version.ref = "protobufGradlePlugin" } protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" } vb-nfc-reader = { module = "com.github.cfogrady:vb-nfc-reader", version.ref = "vbNfcReader" }