~cytrogen/vbhelper

f8ce81e932dd5c6163724cbe7231983a55f3d677 — Nacho 8 months ago 7bb7693
Special missions
- Basic implementation is complete
- Added 8 different special missions, 4 are easy and more expensive, and 4 are cheaper and more difficult
- Added 9 missions of each so people can test themselves
- Also added checks to disallow BE digimon to have special missions
- UI elements to display the status of the missions
- Finishing a mission awards a random price (TODO: Make the price be based on the mission difficulty)
18 files changed, 410 insertions(+), 23 deletions(-)

M app/src/main/assets/items.db
M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt
M app/src/main/java/com/github/nacabaro/vbhelper/daos/ItemDao.kt
A app/src/main/java/com/github/nacabaro/vbhelper/daos/SpecialMissionDao.kt
M app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt
M app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt
M app/src/main/java/com/github/nacabaro/vbhelper/domain/items/Items.kt
M app/src/main/java/com/github/nacabaro/vbhelper/dtos/ItemDtos.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenControllerImpl.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt
R app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/{ => screens}/BEBEmHomeScreen.kt
R app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/{ => screens}/BEDiMHomeScreen.kt
R app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/{ => screens}/VBDiMHomeScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ChooseCharacterScreen.kt
M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreenControllerImpl.kt
M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt
M app/src/main/assets/items.db => app/src/main/assets/items.db +0 -0
M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +92 -0
@@ 5,11 5,14 @@ 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.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
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.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text


@@ 28,6 31,9 @@ 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 com.github.cfogrady.vbnfc.vb.SpecialMission
import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
import com.github.nacabaro.vbhelper.utils.getObscuredBitmap

@Composable


@@ 114,4 120,90 @@ fun ItemDisplay(
            )
        }
    }
}

@Composable
fun SpecialMissionsEntry(
    specialMission: SpecialMissions,
    modifier: Modifier = Modifier,
    onClickCard: () -> Unit = {  },
) {
    val textValue = when (specialMission.missionType) {
        SpecialMission.Type.NONE -> "No mission selected"
        SpecialMission.Type.STEPS -> "Walk ${specialMission.goal} steps"
        SpecialMission.Type.BATTLES -> "Battle ${specialMission.goal} times"
        SpecialMission.Type.WINS -> "Win ${specialMission.goal} battles"
        SpecialMission.Type.VITALS -> "Earn ${specialMission.goal} vitals"
    }

    val progress = if (specialMission.status == SpecialMission.Status.COMPLETED) {
        specialMission.goal
    } else {
        specialMission.progress
    }

    val completion = when (specialMission.missionType) {
        SpecialMission.Type.NONE -> ""
        SpecialMission.Type.STEPS -> "Walked $progress steps"
        SpecialMission.Type.BATTLES -> "Battled $progress times"
        SpecialMission.Type.WINS -> "Won $progress battles"
        SpecialMission.Type.VITALS -> "Earned $progress vitals"
    }

    val icon = when (specialMission.missionType) {
        SpecialMission.Type.NONE -> R.drawable.baseline_free_24
        SpecialMission.Type.STEPS -> R.drawable.baseline_agility_24
        SpecialMission.Type.BATTLES -> R.drawable.baseline_swords_24
        SpecialMission.Type.WINS -> R.drawable.baseline_trophy_24
        SpecialMission.Type.VITALS -> R.drawable.baseline_vitals_24
    }

    val color = when (specialMission.status)
    {
        SpecialMission.Status.IN_PROGRESS -> MaterialTheme.colorScheme.secondary
        SpecialMission.Status.COMPLETED -> MaterialTheme.colorScheme.primary
        SpecialMission.Status.FAILED -> MaterialTheme.colorScheme.error
        else -> MaterialTheme.colorScheme.surfaceContainerHighest
    }

    Card(
        modifier = modifier,
        shape = androidx.compose.material.MaterialTheme.shapes.small,
        onClick = if (specialMission.status == SpecialMission.Status.COMPLETED) {
            onClickCard
        } else {
            {  }
        },
        colors = CardDefaults.cardColors(
            containerColor = color
        )

    ) {
        Row (
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp)
        ) {
            Icon(
                painter = painterResource(icon),
                contentDescription = "Vitals",
                modifier = Modifier
                    .fillMaxHeight()
                    .padding(16.dp)
            )
            Column {
                Text(
                    text = textValue,
                    fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
                    fontWeight = FontWeight.Bold,
                )
                Text(
                    text = completion,
                    fontFamily = MaterialTheme.typography.titleSmall.fontFamily,
                )
            }
        }
    }
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/daos/ItemDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/ItemDao.kt +2 -2
@@ 31,7 31,7 @@ interface ItemDao {
        WHERE Items.id = :itemId
    """
    )
    fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities
    suspend fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities

    @Query(
        """


@@ 40,7 40,7 @@ interface ItemDao {
        WHERE id = :itemId
    """
    )
    fun useItem(itemId: Long)
    suspend fun useItem(itemId: Long)

    @Query(
        """

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

import androidx.room.Dao
import androidx.room.Query

@Dao
interface SpecialMissionDao {
    @Query("""
        UPDATE SpecialMissions SET 
            missionType = "NONE",
            status = "UNAVAILABLE"
        WHERE id = :id
    """)
    suspend fun clearSpecialMission(id: 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 +51 -1
@@ 34,7 34,7 @@ interface UserCharacterDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertTransformationHistory(vararg transformationHistory: TransformationHistory)

    @Insert
    @Upsert
    fun insertSpecialMissions(vararg specialMissions: SpecialMissions)

    @Query("""


@@ 172,4 172,54 @@ interface UserCharacterDao {

    @Query("""SELECT * FROM VitalsHistory WHERE charId = :charId ORDER BY id ASC""")
    suspend fun getVitalsHistory(charId: Long): List<VitalsHistory>

    @Query(
        """
        SELECT
            uc.*,
            c.stage,
            c.attribute,
            s.spriteIdle1 AS spriteIdle,
            s.spriteIdle2 AS spriteIdle2,
            s.width AS spriteWidth,
            s.height AS spriteHeight,
            c.name as nameSprite,
            c.nameWidth as nameSpriteWidth,
            c.nameHeight as nameSpriteHeight,
            d.isBEm as isBemCard,
            a.characterId = uc.id as isInAdventure
        FROM UserCharacter uc
        JOIN Character c ON uc.charId = c.id
        JOIN Card d ON  d.id = c.dimId
        JOIN Sprite s ON s.id = c.spriteId
        LEFT JOIN Adventure a ON a.characterId = uc.id
        WHERE d.isBEm = 1
        """
    )
    suspend fun getBEBemCharacters(): List<CharacterDtos.CharacterWithSprites>

    @Query(
        """
        SELECT
            uc.*,
            c.stage,
            c.attribute,
            s.spriteIdle1 AS spriteIdle,
            s.spriteIdle2 AS spriteIdle2,
            s.width AS spriteWidth,
            s.height AS spriteHeight,
            c.name as nameSprite,
            c.nameWidth as nameSpriteWidth,
            c.nameHeight as nameSpriteHeight,
            d.isBEm as isBemCard,
            a.characterId = uc.id as isInAdventure
        FROM UserCharacter uc
        JOIN Character c ON uc.charId = c.id
        JOIN Card d ON  d.id = c.dimId
        JOIN Sprite s ON s.id = c.spriteId
        LEFT JOIN Adventure a ON a.characterId = uc.id
        WHERE uc.characterType = "VBDevice"
        """
    )
    suspend fun getVBDimCharacters(): List<CharacterDtos.CharacterWithSprites>
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt => app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt +2 -0
@@ 8,6 8,7 @@ import com.github.nacabaro.vbhelper.daos.DexDao
import com.github.nacabaro.vbhelper.daos.CardDao
import com.github.nacabaro.vbhelper.daos.CardProgressDao
import com.github.nacabaro.vbhelper.daos.ItemDao
import com.github.nacabaro.vbhelper.daos.SpecialMissionDao
import com.github.nacabaro.vbhelper.daos.SpriteDao
import com.github.nacabaro.vbhelper.daos.UserCharacterDao
import com.github.nacabaro.vbhelper.domain.characters.Character


@@ 51,4 52,5 @@ abstract class AppDatabase : RoomDatabase() {
    abstract fun itemDao(): ItemDao
    abstract fun adventureDao(): AdventureDao
    abstract fun spriteDao(): SpriteDao
    abstract fun specialMissionDao(): SpecialMissionDao
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/domain/items/Items.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/items/Items.kt +9 -1
@@ 3,6 3,13 @@ package com.github.nacabaro.vbhelper.domain.items
import androidx.room.Entity
import androidx.room.PrimaryKey

enum class ItemType {
    VBITEM,
    BEITEM,
    UNIVERSAL,
    SPECIALMISSION
}

@Entity
data class Items(
    @PrimaryKey val id: Long,


@@ 11,5 18,6 @@ data class Items(
    val itemIcon: Int,
    val itemLength: Int,
    val price: Int,
    val quantity: Int
    val quantity: Int,
    val itemType: ItemType
)

M app/src/main/java/com/github/nacabaro/vbhelper/dtos/ItemDtos.kt => app/src/main/java/com/github/nacabaro/vbhelper/dtos/ItemDtos.kt +5 -1
@@ 1,5 1,7 @@
package com.github.nacabaro.vbhelper.dtos

import com.github.nacabaro.vbhelper.domain.items.ItemType


object ItemDtos {
    data class ItemsWithQuantities(


@@ 10,6 12,7 @@ object ItemDtos {
        val itemLength: Int,
        val price: Int,
        val quantity: Int,
        val itemType: ItemType
    )

    data class PurchasedItem(


@@ 18,6 21,7 @@ object ItemDtos {
        val itemDescription: String,
        val itemIcon: Int,
        val itemLength: Int,
        val itemAmount: Int
        val itemAmount: Int,
        val itemType: ItemType
    )
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenControllerImpl.kt +2 -1
@@ 94,7 94,8 @@ class AdventureScreenControllerImpl(
            itemName = randomItem.name,
            itemIcon = randomItem.itemIcon,
            itemLength = randomItem.itemLength,
            itemDescription = randomItem.description
            itemDescription = randomItem.description,
            itemType = randomItem.itemType
        )
    }
}
\ No newline at end of file

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 +25 -2
@@ 28,9 28,15 @@ 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
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


@@ 46,10 52,12 @@ fun HomeScreen(
    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()) }
    var adventureMissionsFinished by rememberSaveable { mutableStateOf(false) }
    var betaWarning by rememberSaveable { mutableStateOf(true) }
    var collectedItem by remember { mutableStateOf<ItemDtos.PurchasedItem?>(null) }

    LaunchedEffect(storageRepository, activeMon) {
    LaunchedEffect(storageRepository, activeMon, collectedItem) {
        withContext(Dispatchers.IO) {
            activeMon.value = storageRepository.getActiveCharacter()
            if (activeMon.value != null && activeMon.value!!.characterType == DeviceType.BEDevice) {


@@ 57,6 65,7 @@ fun HomeScreen(
                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)
            }
        }


@@ 114,12 123,26 @@ fun HomeScreen(
                    activeMon = activeMon.value!!,
                    vbData = vbData.value!!,
                    transformationHistory = transformationHistory.value!!,
                    contentPadding = contentPadding
                    contentPadding = contentPadding,
                    specialMissions = vbSpecialMissions.value,
                    homeScreenController = homeScreenController,
                    onClickCollect = { item ->
                        collectedItem = item
                    }
                )
            }
        }
    }

    if (collectedItem != null) {
        ObtainedItemDialog(
            obtainedItem = collectedItem!!,
            onClickDismiss = {
                collectedItem = null
            }
        )
    }

    if (adventureMissionsFinished) {
        Dialog(
            onDismissRequest = { adventureMissionsFinished = false },

M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt +3 -0
@@ 1,5 1,8 @@
package com.github.nacabaro.vbhelper.screens.homeScreens

import com.github.nacabaro.vbhelper.dtos.ItemDtos

interface HomeScreenController {
    fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit)
    fun clearSpecialMission(missionId: Long, onCleared: (ItemDtos.PurchasedItem) -> Unit)
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt +37 -0
@@ 3,8 3,11 @@ package com.github.nacabaro.vbhelper.screens.homeScreens
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import kotlinx.coroutines.launch
import java.time.Instant
import kotlin.math.roundToInt
import kotlin.random.Random

class HomeScreenControllerImpl(
    private val componentActivity: ComponentActivity,


@@ 26,4 29,38 @@ class HomeScreenControllerImpl(
            onCompletion(finishedAdventureCharacters.isNotEmpty())
        }
    }

    override fun clearSpecialMission(missionId: Long, onCleared: (ItemDtos.PurchasedItem) -> Unit) {
        componentActivity.lifecycleScope.launch {
            database
                .specialMissionDao()
                .clearSpecialMission(missionId)

            val randomItem = database
                .itemDao()
                .getAllItems()
                .random()

            val randomItemAmount = (Random.nextFloat() * 5).roundToInt()

            database
                .itemDao()
                .purchaseItem(
                    itemId = randomItem.id,
                    itemAmount = randomItemAmount
                )

            val purchasedItem = ItemDtos.PurchasedItem(
                itemId = randomItem.id,
                itemName = randomItem.name,
                itemDescription = randomItem.description,
                itemIcon = randomItem.itemIcon,
                itemLength = randomItem.itemLength,
                itemAmount = randomItemAmount,
                itemType = randomItem.itemType
            )

            onCleared(purchasedItem)
        }
    }
}
\ No newline at end of file

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

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues

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

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues

R app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/VBDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/screens/VBDiMHomeScreen.kt +36 -2
@@ 1,4 1,4 @@
package com.github.nacabaro.vbhelper.screens.homeScreens
package com.github.nacabaro.vbhelper.screens.homeScreens.screens

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues


@@ 8,15 8,21 @@ 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.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
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.SpecialMissionsEntry
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
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.screens.homeScreens.HomeScreenControllerImpl
import com.github.nacabaro.vbhelper.utils.BitmapData
import java.util.Locale



@@ 24,8 30,11 @@ import java.util.Locale
fun VBDiMHomeScreen(
    activeMon: CharacterDtos.CharacterWithSprites,
    vbData: VBCharacterData,
    specialMissions: List<SpecialMissions>,
    homeScreenController: HomeScreenControllerImpl,
    transformationHistory: List<CharacterDtos.TransformationHistory>,
    contentPadding: PaddingValues
    contentPadding: PaddingValues,
    onClickCollect: (ItemDtos.PurchasedItem) -> Unit
) {
    Column(
        modifier = Modifier


@@ 151,5 160,30 @@ fun VBDiMHomeScreen(
                    .padding(8.dp)
            )
        }
        Row (
            modifier = Modifier
                .padding(16.dp)
        ) {
            Text(
                text = "Special missions",
                fontSize = 24.sp
                )
        }
        for (mission in specialMissions) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
            ) {
                SpecialMissionsEntry(
                    specialMission = mission,
                    modifier = Modifier
                        .weight(1f)
                        .padding(8.dp),
                ) {
                    homeScreenController
                        .clearSpecialMission(mission.id, onClickCollect)
                }
            }
        }
    }
}
\ No newline at end of file

M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ChooseCharacterScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ChooseCharacterScreen.kt +18 -1
@@ 19,7 19,9 @@ import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.items.ItemType
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
import kotlinx.coroutines.launch


@@ 39,10 41,25 @@ fun ChooseCharacterScreen(
    }

    var selectedCharacter by remember { mutableStateOf<Long?>(null) }
    var selectedItem by remember { mutableStateOf<ItemDtos.ItemsWithQuantities?>(null) }

    LaunchedEffect(storageRepository) {
        coroutineScope.launch {
            characterList.value = storageRepository.getAllCharacters()
            selectedItem = storageRepository.getItem(itemId)
            when (selectedItem?.itemType) {
                ItemType.BEITEM -> {
                    characterList.value = storageRepository.getBEBEmCharacters()
                }
                ItemType.VBITEM -> {
                    characterList.value = storageRepository.getVBCharacters()
                }
                ItemType.SPECIALMISSION-> {
                    characterList.value = storageRepository.getVBCharacters()
                }
                else -> {
                    characterList.value = storageRepository.getAllCharacters()
                }
            }
        }
    }


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 +93 -10
@@ 2,9 2,12 @@ package com.github.nacabaro.vbhelper.screens.itemsScreen

import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import com.github.cfogrady.vbnfc.vb.SpecialMission
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
import com.github.nacabaro.vbhelper.database.AppDatabase
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
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


@@ 24,7 27,15 @@ class ItemsScreenControllerImpl (
        AllTraining(5),
        EvoTimer(6),
        LimitTimer(7),
        Vitals(8)
        Vitals(8),
        Step8k(9),
        Step4k(10),
        Vitals1000(11),
        Vitals250(12),
        Battle20(13),
        Battle5(14),
        Win10(15),
        Win4(16)
    }

    init {


@@ 37,17 48,20 @@ class ItemsScreenControllerImpl (
            withContext(Dispatchers.IO) {
                val item = getItem(itemId)
                val characterData = database.userCharacterDao().getCharacter(characterId)
                val beCharacterData: BECharacterData
                //var vbCharacterData: VBCharacterData
                var beCharacterData: BECharacterData? = null
                var vbCharacterData: VBCharacterData? = null

                if (characterData.characterType == DeviceType.BEDevice) {
                    beCharacterData = database.userCharacterDao().getBeData(characterId)
                } else {
                    TODO("Not implemented")
                    //vbCharacterData = database.userCharacterDao().getVbData(characterId)
                } else if (characterData.characterType == DeviceType.VBDevice) {
                    vbCharacterData = database.userCharacterDao().getVbData(characterId)
                }

                if (item.itemIcon in 1 .. 5 && characterData.characterType == DeviceType.BEDevice) {
                if (
                    item.itemIcon in 1 .. 5 &&
                    characterData.characterType == DeviceType.BEDevice &&
                    beCharacterData != null
                ) {
                    beCharacterData.itemType = item.itemIcon
                    beCharacterData.itemMultiplier = 3
                    beCharacterData.itemRemainingTime = item.itemLength


@@ 72,7 86,11 @@ class ItemsScreenControllerImpl (
                        .userCharacterDao()
                        .updateCharacter(characterData)

                } else if (item.itemIcon == ItemTypes.LimitTimer.id) {
                } else if (
                    item.itemIcon == ItemTypes.LimitTimer.id &&
                    characterData.characterType == DeviceType.BEDevice &&
                    beCharacterData != null
                ) {
                    beCharacterData.remainingTrainingTimeInMinutes += item.itemLength
                    if (beCharacterData.remainingTrainingTimeInMinutes > 6000) {
                        beCharacterData.remainingTrainingTimeInMinutes = 6000


@@ 93,6 111,12 @@ class ItemsScreenControllerImpl (
                    database
                        .userCharacterDao()
                        .updateCharacter(characterData)

                } else if (item.itemIcon in ItemTypes.Step8k.id  .. ItemTypes.Win4.id &&
                    characterData.characterType == DeviceType.VBDevice &&
                    vbCharacterData != null
                ) {
                    applySpecialMission(item.itemIcon, item.itemLength, characterId)
                }

                consumeItem(item.id)


@@ 104,13 128,72 @@ class ItemsScreenControllerImpl (
        }
    }

    private fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities {
    private suspend fun applySpecialMission(itemIcon: Int, itemLength: Int, characterId: Long) {
        // Hello, it's me, naca! No! I don't like this, I'll see how I can improve it later on...
        val specialMissionType = when (itemIcon) {
            ItemTypes.Step8k.id -> SpecialMission.Type.STEPS
            ItemTypes.Step4k.id -> SpecialMission.Type.STEPS
            ItemTypes.Vitals1000.id -> SpecialMission.Type.VITALS
            ItemTypes.Vitals250.id -> SpecialMission.Type.VITALS
            ItemTypes.Battle20.id -> SpecialMission.Type.BATTLES
            ItemTypes.Battle5.id -> SpecialMission.Type.BATTLES
            ItemTypes.Win10.id -> SpecialMission.Type.WINS
            ItemTypes.Win4.id -> SpecialMission.Type.WINS
            else -> SpecialMission.Type.NONE
        }

        val specialMissionGoal = when (itemIcon) {
            ItemTypes.Step8k.id -> 8000
            ItemTypes.Step4k.id -> 4000
            ItemTypes.Vitals1000.id -> 1000
            ItemTypes.Vitals250.id -> 250
            ItemTypes.Battle20.id -> 20
            ItemTypes.Battle5.id -> 5
            ItemTypes.Win10.id -> 10
            ItemTypes.Win4.id -> 4
            else -> 0
        }

        val availableSpecialMissions = database
            .userCharacterDao()
            .getSpecialMissions(characterId)

        var firstUnavailableMissionSlot: Long = 0
        var watchId = 0

        for ((index, mission) in availableSpecialMissions.withIndex()) {
            if (
                mission.status == SpecialMission.Status.UNAVAILABLE
            ) {
                firstUnavailableMissionSlot = mission.id
                watchId = index + 1
            }
        }

        val newSpecialMission = SpecialMissions(
            id = firstUnavailableMissionSlot,
            characterId = characterId,
            missionType = specialMissionType,
            goal = specialMissionGoal,
            timeLimitInMinutes = itemLength,
            watchId = watchId,
            status = SpecialMission.Status.AVAILABLE,
            progress = 0,
            timeElapsedInMinutes = 0
        )

        database
            .userCharacterDao()
            .insertSpecialMissions(newSpecialMission)
    }

    private suspend fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities {
        return database
            .itemDao()
            .getItem(itemId)
    }

    private fun consumeItem(itemId: Long) {
    private suspend fun consumeItem(itemId: Long) {
        database
            .itemDao()
            .useItem(itemId)

M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +18 -0
@@ 2,8 2,10 @@ package com.github.nacabaro.vbhelper.source

import com.github.nacabaro.vbhelper.database.AppDatabase
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

class StorageRepository (
    private val db: AppDatabase


@@ 28,6 30,14 @@ class StorageRepository (
        return db.userCharacterDao().getVbData(id)
    }

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

    suspend fun getItem(id: Long): ItemDtos.ItemsWithQuantities {
        return db.itemDao().getItem(id)
    }

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


@@ 39,4 49,12 @@ class StorageRepository (
    suspend fun getAdventureCharacters(): List<CharacterDtos.AdventureCharacterWithSprites> {
        return db.adventureDao().getAdventureCharacters()
    }

    suspend fun getBEBEmCharacters(): List<CharacterDtos.CharacterWithSprites> {
        return db.userCharacterDao().getBEBemCharacters()
    }

    suspend fun getVBCharacters(): List<CharacterDtos.CharacterWithSprites> {
        return db.userCharacterDao().getVBDimCharacters()
    }
}
\ No newline at end of file