M app/src/main/assets/items.db => app/src/main/assets/items.db +0 -0
M app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt => app/src/main/java/com/github/nacabaro/vbhelper/MainActivity.kt +20 -4
@@ 9,9 9,12 @@ import androidx.compose.runtime.Composable
import com.github.nacabaro.vbhelper.navigation.AppNavigation
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers
+import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
@@ 39,6 42,9 @@ class MainActivity : ComponentActivity() {
)
val settingsScreenController = SettingsScreenControllerImpl(this)
val itemsScreenController = ItemsScreenControllerImpl(this)
+ val adventureScreenController = AdventureScreenControllerImpl(this)
+ val storageScreenController = StorageScreenControllerImpl(this)
+ val homeScreenController = HomeScreenControllerImpl(this)
super.onCreate(savedInstanceState)
@@ 49,7 55,10 @@ class MainActivity : ComponentActivity() {
MainApplication(
scanScreenController = scanScreenController,
settingsScreenController = settingsScreenController,
- itemsScreenController = itemsScreenController
+ itemsScreenController = itemsScreenController,
+ adventureScreenController = adventureScreenController,
+ homeScreenController = homeScreenController,
+ storageScreenController = storageScreenController
)
}
}
@@ 77,13 86,20 @@ class MainActivity : ComponentActivity() {
private fun MainApplication(
scanScreenController: ScanScreenControllerImpl,
settingsScreenController: SettingsScreenControllerImpl,
- itemsScreenController: ItemsScreenControllerImpl
- ) {
+ itemsScreenController: ItemsScreenControllerImpl,
+ adventureScreenController: AdventureScreenControllerImpl,
+ storageScreenController: StorageScreenControllerImpl,
+ homeScreenController: HomeScreenControllerImpl,
+
+ ) {
AppNavigation(
applicationNavigationHandlers = AppNavigationHandlers(
settingsScreenController,
scanScreenController,
- itemsScreenController
+ itemsScreenController,
+ adventureScreenController,
+ storageScreenController,
+ homeScreenController
)
)
}
M app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/CharacterEntry.kt +5 -1
@@ 35,6 35,7 @@ fun CharacterEntry(
icon: BitmapData,
modifier: Modifier = Modifier,
obscure: Boolean = false,
+ disabled: Boolean = false,
shape: Shape = MaterialTheme.shapes.medium,
multiplier: Int = 4,
onClick: () -> Unit = { }
@@ 48,7 49,10 @@ fun CharacterEntry(
Card(
shape = shape,
- onClick = onClick,
+ onClick = when (disabled) {
+ true -> { {} }
+ false -> onClick
+ },
modifier = modifier
.aspectRatio(1f)
.padding(8.dp)
M app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt => app/src/main/java/com/github/nacabaro/vbhelper/components/TopBanner.kt +14 -2
@@ 23,7 23,8 @@ fun TopBanner(
modifier: Modifier = Modifier,
onGearClick: (() -> Unit)? = null,
onBackClick: (() -> Unit)? = null,
- onScanClick: (() -> Unit)? = null
+ onScanClick: (() -> Unit)? = null,
+ onAdventureClick: (() -> Unit)? = null
) {
Box( // Use Box to overlay elements
modifier = modifier
@@ 49,7 50,18 @@ fun TopBanner(
contentDescription = "Settings"
)
}
- }
+ } else if (onAdventureClick != null) {
+ IconButton(
+ onClick = onAdventureClick,
+ modifier = Modifier
+ .align(Alignment.CenterEnd) // Place gear icon at the end
+ ) {
+ Icon(
+ painter = painterResource(R.drawable.baseline_fort_24), // Use a gear icon
+ contentDescription = "Adventure"
+ )
+ }
+ }
if (onScanClick != null) {
IconButton(
A app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt +41 -0
@@ 0,0 1,41 @@
+package com.github.nacabaro.vbhelper.daos
+
+import androidx.room.Dao
+import androidx.room.Query
+import com.github.nacabaro.vbhelper.dtos.CharacterDtos
+
+
+@Dao
+interface AdventureDao {
+ @Query("""
+ INSERT INTO Adventure (characterId, finishesAdventure)
+ VALUES (:characterId, strftime('%s', 'now') + :timeInSeconds)
+ """)
+ fun insertNewAdventure(characterId: Long, timeInSeconds: Long)
+
+ @Query("""
+ SELECT COUNT(*) FROM Adventure
+ """)
+ fun getAdventureCount(): Int
+
+ @Query("""
+ SELECT
+ uc.*,
+ c.sprite1 AS spriteIdle,
+ c.spritesWidth AS spriteWidth,
+ c.spritesHeight AS spriteHeight,
+ d.isBEm as isBemCard,
+ a.finishesAdventure AS timeLeft
+ FROM UserCharacter uc
+ JOIN Character c ON uc.charId = c.id
+ JOIN Card d ON c.dimId = d.id
+ JOIN Adventure a ON uc.id = a.characterId
+ """)
+ suspend fun getAdventureCharacters(): List<CharacterDtos.AdventureCharacterWithSprites>
+
+ @Query("""
+ DELETE FROM Adventure
+ WHERE characterId = :characterId
+ """)
+ suspend fun deleteAdventure(characterId: Long)
+}<
\ 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 +31 -23
@@ 6,40 6,48 @@ import com.github.nacabaro.vbhelper.dtos.ItemDtos
@Dao
interface ItemDao {
- @Query("""
- SELECT Items.*, UserItems.quantity
+ @Query(
+ """
+ SELECT *
FROM Items
- LEFT JOIN UserItems ON Items.id = UserItems.itemId
ORDER BY Items.itemIcon ASC
- """)
+ """
+ )
suspend fun getAllItems(): List<ItemDtos.ItemsWithQuantities>
- @Query("""
- SELECT Items.*, UserItems.quantity
+ @Query(
+ """
+ SELECT *
FROM Items
- JOIN UserItems ON Items.id = UserItems.itemId
- """)
+ WHERE quantity > 0
+ """
+ )
suspend fun getAllUserItems(): List<ItemDtos.ItemsWithQuantities>
- @Query("""
- SELECT Items.*, UserItems.quantity
+ @Query(
+ """
+ SELECT *
FROM Items
- JOIN UserItems ON Items.id = UserItems.itemId
- WHERE UserItems.itemId = :itemId
- """)
- fun getUserItem(itemId: Long): ItemDtos.ItemsWithQuantities
+ WHERE Items.id = :itemId
+ """
+ )
+ fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities
- @Query("""
- UPDATE UserItems
+ @Query(
+ """
+ UPDATE Items
SET quantity = quantity - 1
- WHERE itemId = :itemId
- """)
+ WHERE id = :itemId
+ """
+ )
fun useItem(itemId: Long)
- @Query("""
- UPDATE UserItems
- SET quantity = quantity - :itemAmount
- WHERE itemId = :itemId
- """)
+ @Query(
+ """
+ UPDATE Items
+ SET quantity = quantity + :itemAmount
+ WHERE id = :itemId
+ """
+ )
suspend fun purchaseItem(itemId: Long, itemAmount: Int)
}=
\ 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 +33 -4
@@ 48,14 48,39 @@ interface UserCharacterDao {
c.sprite1 AS spriteIdle,
c.spritesWidth AS spriteWidth,
c.spritesHeight AS spriteHeight,
- d.isBEm as isBemCard
+ 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 c.dimId = d.id
+ LEFT JOIN Adventure a ON a.characterId = uc.id
"""
)
suspend fun getAllCharacters(): List<CharacterDtos.CharacterWithSprites>
+ @Query(
+ """
+ SELECT
+ uc.*,
+ c.sprite1 AS spriteIdle,
+ c.spritesWidth AS spriteWidth,
+ c.spritesHeight 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 c.dimId = d.id
+ LEFT JOIN Adventure a ON a.characterId = uc.id
+ WHERE uc.id = :id
+ """)
+ suspend fun getCharacterWithSprites(id: Long): CharacterDtos.CharacterWithSprites
+
@Query("SELECT * FROM UserCharacter WHERE id = :id")
suspend fun getCharacter(id: Long): UserCharacter
@@ 69,14 94,18 @@ interface UserCharacterDao {
c.sprite1 AS spriteIdle,
c.spritesWidth AS spriteWidth,
c.spritesHeight AS spriteHeight,
- d.isBEm as isBemCard
+ c.name as nameSprite,
+ c.nameWidth as nameSpriteWidth,
+ c.nameHeight as nameSpriteHeight,
+ d.isBEm as isBemCard,
+ a.characterId as isInAdventure
FROM UserCharacter uc
JOIN Character c ON uc.charId = c.id
JOIN Card d ON c.dimId = d.id
+ LEFT JOIN Adventure a ON a.characterId = uc.id
WHERE uc.isActive = 1
LIMIT 1
- """
- )
+ """)
suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites?
@Query("DELETE FROM UserCharacter WHERE id = :id")
M app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt => app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt +4 -2
@@ 2,6 2,7 @@ package com.github.nacabaro.vbhelper.database
import androidx.room.Database
import androidx.room.RoomDatabase
+import com.github.nacabaro.vbhelper.daos.AdventureDao
import com.github.nacabaro.vbhelper.daos.CharacterDao
import com.github.nacabaro.vbhelper.daos.DexDao
import com.github.nacabaro.vbhelper.daos.DiMDao
@@ 10,12 11,12 @@ import com.github.nacabaro.vbhelper.daos.UserCharacterDao
import com.github.nacabaro.vbhelper.domain.characters.Character
import com.github.nacabaro.vbhelper.domain.characters.Card
import com.github.nacabaro.vbhelper.domain.Sprites
+import com.github.nacabaro.vbhelper.domain.characters.Adventure
import com.github.nacabaro.vbhelper.domain.characters.Dex
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
import com.github.nacabaro.vbhelper.domain.items.Items
-import com.github.nacabaro.vbhelper.domain.items.UserItems
@Database(
version = 1,
@@ 28,7 29,7 @@ import com.github.nacabaro.vbhelper.domain.items.UserItems
TransformationHistory::class,
Dex::class,
Items::class,
- UserItems::class
+ Adventure::class
]
)
abstract class AppDatabase : RoomDatabase() {
@@ 37,4 38,5 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun userCharacterDao(): UserCharacterDao
abstract fun dexDao(): DexDao
abstract fun itemDao(): ItemDao
+ abstract fun adventureDao(): AdventureDao
}=
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/domain/items/UserItems.kt => app/src/main/java/com/github/nacabaro/vbhelper/domain/characters/Adventure.kt +7 -6
@@ 1,20 1,21 @@
-package com.github.nacabaro.vbhelper.domain.items
+package com.github.nacabaro.vbhelper.domain.characters
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
+import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
@Entity(
foreignKeys = [
ForeignKey(
- entity = Items::class,
+ entity = UserCharacter::class,
parentColumns = ["id"],
- childColumns = ["itemId"],
+ childColumns = ["characterId"],
onDelete = ForeignKey.CASCADE
)
]
)
-data class UserItems(
- @PrimaryKey val itemId: Long,
- val quantity: Int,
+data class Adventure(
+ @PrimaryKey val characterId: Long,
+ val finishesAdventure: Long
)
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 +2 -1
@@ 10,5 10,6 @@ data class Items(
val description: String,
val itemIcon: Int,
val itemLength: Int,
- val price: Int
+ val price: Int,
+ val quantity: Int
)
M app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt => app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt +31 -1
@@ 27,7 27,11 @@ object CharacterDtos {
val spriteIdle: ByteArray,
val spriteWidth: Int,
val spriteHeight: Int,
- val isBemCard: Boolean
+ val nameSprite: ByteArray,
+ val nameSpriteWidth: Int,
+ val nameSpriteHeight: Int,
+ val isBemCard: Boolean,
+ val isInAdventure: Boolean
)
data class DiMInfo(
@@ 51,4 55,30 @@ object CharacterDtos {
val spriteHeight: Int,
val discoveredOn: Long?
)
+
+ data class AdventureCharacterWithSprites(
+ var id: Long = 0,
+ var charId: Long,
+ var stage: Int,
+ var attribute: NfcCharacter.Attribute,
+ var ageInDays: Int,
+ var nextAdventureMissionStage: Int, // next adventure mission stage on the character's dim
+ var mood: Int,
+ var vitalPoints: Int,
+ var transformationCountdown: Int,
+ var injuryStatus: NfcCharacter.InjuryStatus,
+ var trophies: Int,
+ var currentPhaseBattlesWon: Int,
+ var currentPhaseBattlesLost: Int,
+ var totalBattlesWon: Int,
+ var totalBattlesLost: Int,
+ var activityLevel: Int,
+ var heartRateCurrent: Int,
+ var characterType: DeviceType,
+ val spriteIdle: ByteArray,
+ val spriteWidth: Int,
+ val spriteHeight: Int,
+ val isBemCard: Boolean,
+ val timeLeft: Long
+ )
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/dtos/ItemDtos.kt => app/src/main/java/com/github/nacabaro/vbhelper/dtos/ItemDtos.kt +10 -1
@@ 2,7 2,7 @@ package com.github.nacabaro.vbhelper.dtos
object ItemDtos {
- data class ItemsWithQuantities (
+ data class ItemsWithQuantities(
val id: Long,
val name: String,
val description: String,
@@ 11,4 11,13 @@ object ItemDtos {
val price: Int,
val quantity: Int,
)
+
+ data class PurchasedItem(
+ val itemId: Long,
+ val itemName: String,
+ val itemDescription: String,
+ val itemIcon: Int,
+ val itemLength: Int,
+ val itemAmount: 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 +21 -4
@@ 16,15 16,22 @@ import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreen
import com.github.nacabaro.vbhelper.screens.SpriteViewer
-import com.github.nacabaro.vbhelper.screens.StorageScreen
+import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreen
import com.github.nacabaro.vbhelper.screens.itemsScreen.ChooseCharacterScreen
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreen
+import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
+import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
data class AppNavigationHandlers(
val settingsScreenController: SettingsScreenControllerImpl,
val scanScreenController: ScanScreenControllerImpl,
- val itemsScreenController: ItemsScreenControllerImpl
+ val itemsScreenController: ItemsScreenControllerImpl,
+ val adventureScreenController: AdventureScreenControllerImpl,
+ val storageScreenController: StorageScreenControllerImpl,
+ val homeScreenController: HomeScreenControllerImpl
)
@Composable
@@ 49,12 56,15 @@ fun AppNavigation(
}
composable(NavigationItems.Home.route) {
HomeScreen(
- navController = navController
+ navController = navController,
+ homeScreenController = applicationNavigationHandlers.homeScreenController
)
}
composable(NavigationItems.Storage.route) {
StorageScreen(
- navController = navController
+ navController = navController,
+ adventureScreenController = applicationNavigationHandlers.adventureScreenController,
+ storageScreenController = applicationNavigationHandlers.storageScreenController
)
}
composable(NavigationItems.Scan.route) {
@@ 108,6 118,13 @@ fun AppNavigation(
)
}
}
+ composable(NavigationItems.Adventure.route) {
+ AdventureScreen(
+ navController = navController,
+ storageScreenController = applicationNavigationHandlers
+ .adventureScreenController
+ )
+ }
}
}
}
M app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt => app/src/main/java/com/github/nacabaro/vbhelper/navigation/NavigationItems.kt +1 -0
@@ 19,4 19,5 @@ sealed class NavigationItems (
object MyItems : NavigationItems("MyItems", R.drawable.baseline_data_24, "My items")
object ItemsStore : NavigationItems("ItemsStore", R.drawable.baseline_data_24, "Items store")
object ApplyItem : NavigationItems("ApplyItem/{itemId}", R.drawable.baseline_data_24, "Apply item")
+ object Adventure : NavigationItems("Adventure", R.drawable.baseline_fort_24, "Adventure")
}=
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureEntry.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureEntry.kt +68 -0
@@ 0,0 1,68 @@
+package com.github.nacabaro.vbhelper.screens.adventureScreen
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Text
+import androidx.compose.material3.Card
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getBitmap
+import java.util.Locale
+
+@Composable
+fun AdventureEntry(
+ icon: BitmapData,
+ timeLeft: Long,
+ modifier: Modifier = Modifier,
+ onClick: () -> Unit
+) {
+ val bitmap = remember (icon.bitmap) { icon.getBitmap() }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+ val density: Float = LocalContext.current.resources.displayMetrics.density
+ val dpSize = (icon.width * 4 / density).dp
+
+ Card(
+ onClick = onClick,
+ modifier = modifier
+ .padding(8.dp)
+ .fillMaxWidth()
+ ) {
+ Row(
+ modifier = Modifier
+ .padding(8.dp)
+ .height(96.dp)
+ ) {
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = null,
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .size(dpSize)
+ )
+ Text(
+ text = when {
+ timeLeft < 0 -> "Adventure finished"
+ else -> "Time left: ${formatSeconds(timeLeft)}"
+ }
+ )
+ }
+ }
+}
+
+fun formatSeconds(totalSeconds: Long): String {
+ val hours = totalSeconds / 3600
+ val minutes = (totalSeconds % 3600) / 60
+ val seconds = totalSeconds % 60
+
+ return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds)
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreen.kt +128 -0
@@ 0,0 1,128 @@
+package com.github.nacabaro.vbhelper.screens.adventureScreen
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.navigation.NavController
+import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.di.VBHelper
+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.source.StorageRepository
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import java.time.Instant
+
+@Composable
+fun AdventureScreen(
+ navController: NavController,
+ storageScreenController: AdventureScreenControllerImpl
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val application = LocalContext.current.applicationContext as VBHelper
+ val database = application.container.db
+ val storageRepository = StorageRepository(database)
+ val characterList = remember {
+ mutableStateOf<List<CharacterDtos.AdventureCharacterWithSprites>>(emptyList())
+ }
+ var obtainedItem by remember {
+ mutableStateOf<ItemDtos.PurchasedItem?>(null)
+ }
+
+ val currentTime by produceState(initialValue = Instant.now().epochSecond) {
+ while (true) {
+ value = Instant.now().epochSecond
+ delay(1000)
+ }
+ }
+
+ var cancelAdventureDialog by remember {
+ mutableStateOf<CharacterDtos.AdventureCharacterWithSprites?>(null)
+ }
+
+ LaunchedEffect(storageRepository) {
+ coroutineScope.launch {
+ characterList.value = storageRepository
+ .getAdventureCharacters()
+ }
+ }
+
+ Scaffold(
+ topBar = {
+ TopBanner(
+ text = "Adventure",
+ onBackClick = {
+ navController.popBackStack()
+ }
+ )
+ }
+ ) { contentPadding ->
+ LazyColumn(
+ modifier = Modifier
+ .padding(top = contentPadding.calculateTopPadding())
+ ) {
+ items(characterList.value) {
+ AdventureEntry(
+ icon = BitmapData(
+ bitmap = it.spriteIdle,
+ width = it.spriteWidth,
+ height = it.spriteHeight
+ ),
+ timeLeft = it.timeLeft - currentTime,
+ onClick = {
+ if (it.timeLeft < currentTime) {
+ storageScreenController
+ .getItemFromAdventure(it.id) { adventureResult ->
+ obtainedItem = adventureResult
+ }
+ } else {
+ cancelAdventureDialog = it
+ }
+ }
+ )
+ }
+ }
+ }
+
+ if (obtainedItem != null) {
+ ObtainedItemDialog(
+ obtainedItem = obtainedItem!!,
+ onClickDismiss = {
+ obtainedItem = null
+ }
+ )
+ }
+
+ if (cancelAdventureDialog != null) {
+ CancelAdventureDialog(
+ characterSprite = BitmapData(
+ bitmap = cancelAdventureDialog!!.spriteIdle,
+ width = cancelAdventureDialog!!.spriteWidth,
+ height = cancelAdventureDialog!!.spriteHeight
+ ),
+ onDismissRequest = {
+ cancelAdventureDialog = null
+ },
+ onClickConfirm = {
+ storageScreenController.cancelAdventure(cancelAdventureDialog!!.id) {
+ navController.navigate(NavigationItems.Storage.route)
+ }
+ cancelAdventureDialog = null
+ }
+ )
+ }
+}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenController.kt +9 -0
@@ 0,0 1,9 @@
+package com.github.nacabaro.vbhelper.screens.adventureScreen
+
+import com.github.nacabaro.vbhelper.dtos.ItemDtos
+
+interface AdventureScreenController {
+ fun sendCharacterToAdventure(characterId: Long, timeInMinutes: Long)
+ fun getItemFromAdventure(characterId: Long, onResult: (ItemDtos.PurchasedItem) -> Unit)
+ fun cancelAdventure(characterId: Long, onResult: () -> Unit)
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/AdventureScreenControllerImpl.kt +100 -0
@@ 0,0 1,100 @@
+package com.github.nacabaro.vbhelper.screens.adventureScreen
+
+import android.widget.Toast
+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.Dispatchers
+import kotlinx.coroutines.launch
+import kotlin.math.roundToInt
+import kotlin.random.Random
+
+class AdventureScreenControllerImpl(
+ private val componentActivity: ComponentActivity,
+) : AdventureScreenController {
+ private val application = componentActivity.applicationContext as VBHelper
+ private val database = application.container.db
+
+ override fun sendCharacterToAdventure(characterId: Long, timeInMinutes: Long) {
+ val timeInSeconds = timeInMinutes * 60
+ componentActivity.lifecycleScope.launch(Dispatchers.IO) {
+ val characterData = database
+ .userCharacterDao()
+ .getCharacter(characterId)
+
+ if (characterData.isActive) {
+ database
+ .userCharacterDao()
+ .clearActiveCharacter()
+ }
+
+ database
+ .adventureDao()
+ .insertNewAdventure(characterId, timeInSeconds)
+ }
+ }
+
+ override fun getItemFromAdventure(
+ characterId: Long,
+ onResult: (ItemDtos.PurchasedItem) -> Unit
+ ) {
+ componentActivity.lifecycleScope.launch(Dispatchers.IO) {
+ database
+ .adventureDao()
+ .deleteAdventure(characterId)
+
+ val generatedItem = generateItem(characterId)
+
+ onResult(generatedItem)
+ }
+ }
+
+ override fun cancelAdventure(characterId: Long, onResult: () -> Unit) {
+ componentActivity.lifecycleScope.launch(Dispatchers.IO) {
+ database
+ .adventureDao()
+ .deleteAdventure(characterId)
+
+ componentActivity
+ .runOnUiThread {
+ Toast.makeText(
+ componentActivity,
+ "Adventure canceled",
+ Toast.LENGTH_SHORT
+ ).show()
+ onResult()
+ }
+
+ }
+ }
+
+ private suspend fun generateItem(characterId: Long): ItemDtos.PurchasedItem {
+ val character = database
+ .userCharacterDao()
+ .getCharacter(characterId)
+
+ val randomItem = database
+ .itemDao()
+ .getAllItems()
+ .random()
+
+ val random = ((Random.nextFloat() * character.stage) + 3).roundToInt()
+
+ database
+ .itemDao()
+ .purchaseItem(
+ itemId = randomItem.id,
+ itemAmount = random
+ )
+
+ return ItemDtos.PurchasedItem(
+ itemId = randomItem.id,
+ itemAmount = random,
+ itemName = randomItem.name,
+ itemIcon = randomItem.itemIcon,
+ itemLength = randomItem.itemLength,
+ itemDescription = randomItem.description
+ )
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/CancelAdventureDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/adventureScreen/CancelAdventureDialog.kt +73 -0
@@ 0,0 1,73 @@
+package com.github.nacabaro.vbhelper.screens.adventureScreen
+
+import androidx.compose.foundation.Image
+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.foundation.layout.size
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getBitmap
+
+@Composable
+fun CancelAdventureDialog(
+ characterSprite: BitmapData,
+ onDismissRequest: () -> Unit,
+ onClickConfirm: () -> Unit
+) {
+ val bitmap = remember (characterSprite) { characterSprite.getBitmap() }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+ val density: Float = LocalContext.current.resources.displayMetrics.density
+ val dpSize = (characterSprite.width * 4 / density).dp
+
+ Dialog(
+ onDismissRequest = onDismissRequest
+ ) {
+ Card {
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Row {
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = null,
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .size(dpSize)
+ )
+ Text(
+ text = "Are you sure you want to cancel this character's adventure?"
+ )
+ }
+ Row(
+ modifier = Modifier
+ .padding(8.dp)
+ ) {
+ Button(
+ onClick = onClickConfirm
+ ) {
+ Text(text = "Confirm")
+ }
+ Spacer(modifier = Modifier.padding(4.dp))
+ Button(
+ onClick = onDismissRequest
+ ) {
+ Text(text = "Cancel")
+ }
+ }
+ }
+ }
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEBEmHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEBEmHomeScreen.kt +1 -1
@@ 15,7 15,7 @@ import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.ItemDisplay
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
-import com.github.nacabaro.vbhelper.components.getIconResource
+import com.github.nacabaro.vbhelper.screens.itemsScreen.getIconResource
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
M app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEDiMHomeScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/BEDiMHomeScreen.kt +1 -1
@@ 16,7 16,7 @@ import com.github.nacabaro.vbhelper.R
import com.github.nacabaro.vbhelper.components.CharacterEntry
import com.github.nacabaro.vbhelper.components.ItemDisplay
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
-import com.github.nacabaro.vbhelper.components.getIconResource
+import com.github.nacabaro.vbhelper.screens.itemsScreen.getIconResource
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
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 +37 -1
@@ 4,15 4,22 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
@@ 27,7 34,8 @@ import kotlinx.coroutines.withContext
@Composable
fun HomeScreen(
- navController: NavController
+ navController: NavController,
+ homeScreenController: HomeScreenControllerImpl
) {
val application = LocalContext.current.applicationContext as VBHelper
val storageRepository = StorageRepository(application.container.db)
@@ 35,6 43,7 @@ fun HomeScreen(
val transformationHistory = remember { mutableStateOf<List<CharacterDtos.TransformationHistory>?>(null) }
val beData = remember { mutableStateOf<BECharacterData?>(null) }
val vbData = remember { mutableStateOf<VBCharacterData?>(null) }
+ var adventureMissionsFinished by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(storageRepository, activeMon) {
withContext(Dispatchers.IO) {
@@ 46,6 55,13 @@ fun HomeScreen(
}
}
+ LaunchedEffect(true) {
+ homeScreenController
+ .didAdventureMissionsFinish {
+ adventureMissionsFinished = it
+ }
+ }
+
Scaffold (
topBar = {
TopBanner(
@@ 94,6 110,26 @@ fun HomeScreen(
}
}
}
+
+ if (adventureMissionsFinished) {
+ Dialog(
+ onDismissRequest = { adventureMissionsFinished = false },
+ ) {
+ Card {
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Text(text = "One of your characters has finished their adventure mission!")
+ Button(onClick = {
+ adventureMissionsFinished = false
+ }) {
+ Text(text = "Dismiss")
+ }
+ }
+ }
+ }
+ }
}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenController.kt +5 -0
@@ 0,0 1,5 @@
+package com.github.nacabaro.vbhelper.screens.homeScreens
+
+interface HomeScreenController {
+ fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit)
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/homeScreens/HomeScreenControllerImpl.kt +29 -0
@@ 0,0 1,29 @@
+package com.github.nacabaro.vbhelper.screens.homeScreens
+
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.lifecycleScope
+import com.github.nacabaro.vbhelper.di.VBHelper
+import kotlinx.coroutines.launch
+import java.time.Instant
+
+class HomeScreenControllerImpl(
+ private val componentActivity: ComponentActivity,
+): HomeScreenController {
+ private val application = componentActivity.applicationContext as VBHelper
+ private val database = application.container.db
+
+ override fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit) {
+ componentActivity.lifecycleScope.launch {
+ val currentTime = Instant.now().epochSecond
+ val adventureCharacters = database
+ .adventureDao()
+ .getAdventureCharacters()
+
+ val finishedAdventureCharacters = adventureCharacters.filter { character ->
+ character.timeLeft <= currentTime
+ }
+
+ onCompletion(finishedAdventureCharacters.isNotEmpty())
+ }
+ }
+}<
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/components/ItemElement.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemElement.kt +1 -2
@@ 1,4 1,4 @@
-package com.github.nacabaro.vbhelper.components
+package com.github.nacabaro.vbhelper.screens.itemsScreen
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ 25,7 25,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.github.nacabaro.vbhelper.R
-import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
@Composable
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 +1 -1
@@ 107,7 107,7 @@ class ItemsScreenControllerImpl (
private fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities {
return database
.itemDao()
- .getUserItem(itemId)
+ .getItem(itemId)
}
private fun consumeItem(itemId: Long) {
M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsStore.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsStore.kt +0 -4
@@ 15,10 15,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
-import com.github.nacabaro.vbhelper.components.ItemDialog
-import com.github.nacabaro.vbhelper.components.ItemElement
-import com.github.nacabaro.vbhelper.components.getIconResource
-import com.github.nacabaro.vbhelper.components.getLengthResource
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.source.ItemsRepository
M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/MyItems.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/MyItems.kt +0 -4
@@ 19,10 19,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
-import com.github.nacabaro.vbhelper.components.ItemDialog
-import com.github.nacabaro.vbhelper.components.ItemElement
-import com.github.nacabaro.vbhelper.components.getIconResource
-import com.github.nacabaro.vbhelper.components.getLengthResource
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.dtos.ItemDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
A app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ObtainedItemDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ObtainedItemDialog.kt +89 -0
@@ 0,0 1,89 @@
+package com.github.nacabaro.vbhelper.screens.itemsScreen
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Card
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import com.github.nacabaro.vbhelper.dtos.ItemDtos
+
+@Composable
+fun ObtainedItemDialog(
+ obtainedItem: ItemDtos.PurchasedItem,
+ onClickDismiss: () -> Unit
+) {
+ Dialog(
+ onDismissRequest = onClickDismiss
+ ) {
+ Card {
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Column (
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Row {
+ Box(modifier = Modifier) {
+ Icon(
+ painter = painterResource(id = getIconResource(obtainedItem.itemIcon)),
+ contentDescription = null,
+ modifier = Modifier
+ .size(96.dp)
+ .align(Alignment.Center)
+ )
+ Icon(
+ painter = painterResource(id = getLengthResource(obtainedItem.itemLength)),
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.outline,
+ modifier = Modifier
+ .size(64.dp)
+ .align(Alignment.BottomEnd)
+ )
+ }
+ Column (
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Text(
+ fontSize = MaterialTheme.typography.titleLarge.fontSize,
+ text = obtainedItem.itemName,
+ modifier = Modifier
+ .fillMaxWidth()
+ )
+ }
+ }
+ Text(
+ textAlign = TextAlign.Center,
+ fontSize = MaterialTheme.typography.bodyMedium.fontSize,
+ fontFamily = MaterialTheme.typography.bodyMedium.fontFamily,
+ text = obtainedItem.itemDescription
+ )
+ Text(
+ textAlign = TextAlign.Center,
+ fontSize = MaterialTheme.typography.bodySmall.fontSize,
+ fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
+ text = "You have obtained ${obtainedItem.itemAmount} of this item",
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ )
+ }
+ }
+ }
+ }
+
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/settingsScreen/SettingsScreenControllerImpl.kt +1 -1
@@ 131,7 131,7 @@ class SettingsScreenControllerImpl(
val characters = card.characterStats.characterEntries
var spriteCounter = when (card is BemCard) {
- true -> 55
+ true -> 54
false -> 10
}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageAdventureTimeDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageAdventureTimeDialog.kt +107 -0
@@ 0,0 1,107 @@
+package com.github.nacabaro.vbhelper.screens.storageScreen
+
+import androidx.compose.foundation.clickable
+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.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import com.github.nacabaro.vbhelper.R
+
+fun getAdventureTime(time: Int): String {
+ return when (time) {
+ 360 -> "6 hours"
+ 720 -> "12 hours"
+ 1440 -> "24 hours"
+ else -> "Unknown"
+ }
+}
+
+@Composable
+fun StorageAdventureTimeDialog(
+ onClickSendToAdventure: (time: Long) -> Unit,
+ onDismissRequest: () -> Unit
+) {
+ val times = arrayOf(360, 720, 1440)
+ var expanded by remember { mutableStateOf(false) }
+ var itemPosition by remember { mutableIntStateOf(-1) }
+
+ Dialog(
+ onDismissRequest = onDismissRequest
+ ) {
+ Card {
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Box(
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ Row (
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier
+ .width(256.dp)
+ .clickable(true) {
+ expanded = true
+ }
+ ) {
+ Text(
+ text = when (itemPosition) {
+ -1 -> "Choose time"
+ else -> getAdventureTime(times[itemPosition])
+ }
+ )
+ Icon(
+ painter = painterResource(R.drawable.baseline_single_arrow_down),
+ contentDescription = "Show more"
+ )
+ }
+ DropdownMenu(
+ expanded = expanded,
+ onDismissRequest = { expanded = false },
+ modifier = Modifier
+ .width(256.dp)
+ ) {
+ times.forEach { time ->
+ DropdownMenuItem(
+ text = { Text(getAdventureTime(time)) },
+ onClick = {
+ itemPosition = times.indexOf(time)
+ expanded = false
+ }
+ )
+ }
+ }
+ }
+ Button(
+ onClick = {
+ if (itemPosition != -1) {
+ onClickSendToAdventure(times[itemPosition].toLong())
+ onDismissRequest()
+ }
+ }
+ ) {
+ Text(text = "Send on adventure")
+ }
+ }
+ }
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageDialog.kt +159 -0
@@ 0,0 1,159 @@
+package com.github.nacabaro.vbhelper.screens.storageScreen
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.Card
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.DialogProperties
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.dtos.CharacterDtos
+import com.github.nacabaro.vbhelper.source.StorageRepository
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getBitmap
+import kotlinx.coroutines.launch
+
+@Composable
+fun StorageDialog(
+ characterId: Long,
+ onDismissRequest: () -> Unit,
+ onSendToBracelet: () -> Unit,
+ onClickSetActive: () -> Unit,
+ onClickSendToAdventure: (time: Long) -> Unit
+) {
+ val coroutineScope = rememberCoroutineScope()
+ val application = LocalContext.current.applicationContext as VBHelper
+ val storageRepository = StorageRepository(application.container.db)
+ val character = remember { mutableStateOf<CharacterDtos.CharacterWithSprites?>(null) }
+ val characterSprite = remember { mutableStateOf<BitmapData?>(null) }
+ val characterName = remember { mutableStateOf<BitmapData?>(null) }
+ var onSendToAdventureClicked by remember { mutableStateOf(false) }
+
+ LaunchedEffect(storageRepository) {
+ coroutineScope.launch {
+ character.value = storageRepository.getSingleCharacter(characterId)
+ characterSprite.value = BitmapData(
+ bitmap = character.value!!.spriteIdle,
+ width = character.value!!.spriteWidth,
+ height = character.value!!.spriteHeight
+ )
+ characterName.value = BitmapData(
+ bitmap = character.value!!.nameSprite,
+ width = character.value!!.nameSpriteWidth,
+ height = character.value!!.nameSpriteHeight
+ )
+ }
+ }
+
+ Dialog(
+ onDismissRequest = onDismissRequest,
+ properties = DialogProperties(
+ dismissOnBackPress = true,
+ dismissOnClickOutside = true
+ )
+ ) {
+ Card(
+ shape = RoundedCornerShape(16.dp)
+ ) {
+ Column (
+ modifier = Modifier
+ .padding(16.dp)
+ ) {
+ if (character.value != null &&
+ characterSprite.value != null &&
+ characterName.value != null
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ val bitmap = remember (characterSprite.value!!) { characterSprite.value!!.getBitmap() }
+ val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
+ val density: Float = LocalContext.current.resources.displayMetrics.density
+ val dpSize = (characterSprite.value!!.width * 4 / density).dp
+ Image(
+ bitmap = imageBitmap,
+ contentDescription = "Character image",
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .size(dpSize)
+ )
+ val nameBitmap = remember (characterName.value!!) { characterName.value!!.getBitmap() }
+ val nameImageBitmap = remember(nameBitmap) { nameBitmap.asImageBitmap() }
+ val nameDpSize = (characterName.value!!.width * 4 / density).dp
+ Image(
+ bitmap = nameImageBitmap,
+ contentDescription = "Character image",
+ filterQuality = FilterQuality.None,
+ modifier = Modifier
+ .size(nameDpSize)
+ )
+ }
+ }
+ Row(
+ horizontalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Button(
+ onClick = onSendToBracelet,
+ ) {
+ Text(text = "Send to bracelet")
+ }
+ Spacer(
+ modifier = Modifier
+ .padding(4.dp)
+ )
+ Button(
+ onClick = onClickSetActive,
+ ) {
+ Text(text = "Set active")
+ }
+ }
+ Button(
+ onClick = {
+ onSendToAdventureClicked = true
+ },
+ ) {
+ Text(text = "Send to adventure")
+ }
+ Button(
+ modifier = Modifier
+ .fillMaxWidth(),
+ onClick = onDismissRequest
+ ) {
+ Text(text = "Close")
+ }
+ }
+ }
+ }
+
+ if (onSendToAdventureClicked) {
+ StorageAdventureTimeDialog(
+ onClickSendToAdventure = { time ->
+ onClickSendToAdventure(time)
+ },
+ onDismissRequest = { onSendToAdventureClicked = false }
+ )
+ }
+}<
\ No newline at end of file
R app/src/main/java/com/github/nacabaro/vbhelper/screens/StorageScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreen.kt +56 -105
@@ 1,20 1,16 @@
-package com.github.nacabaro.vbhelper.screens
+package com.github.nacabaro.vbhelper.screens.storageScreen
+import android.widget.Toast
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
-import androidx.compose.material3.Card
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ 28,35 24,31 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.Dialog
-import androidx.compose.ui.window.DialogProperties
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.device_data.UserCharacter
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
+import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
@Composable
fun StorageScreen(
- navController: NavController
+ navController: NavController,
+ storageScreenController: StorageScreenControllerImpl,
+ adventureScreenController: AdventureScreenControllerImpl
) {
val coroutineScope = rememberCoroutineScope()
val application = LocalContext.current.applicationContext as VBHelper
val storageRepository = StorageRepository(application.container.db)
val monList = remember { mutableStateOf<List<CharacterDtos.CharacterWithSprites>>(emptyList()) }
-
var selectedCharacter by remember { mutableStateOf<Long?>(null) }
- LaunchedEffect(storageRepository) {
+ LaunchedEffect(storageRepository, selectedCharacter) {
coroutineScope.launch {
val characterList = storageRepository.getAllCharacters()
monList.value = characterList
@@ 64,7 56,14 @@ fun StorageScreen(
}
Scaffold (
- topBar = { TopBanner(text = "My characters") }
+ topBar = {
+ TopBanner(
+ text = "My characters",
+ onAdventureClick = {
+ navController.navigate(NavigationItems.Adventure.route)
+ }
+ )
+ }
) { contentPadding ->
if (monList.value.isEmpty()) {
Column (
@@ 80,25 79,36 @@ fun StorageScreen(
modifier = Modifier
)
}
- }
-
- LazyVerticalGrid(
- columns = GridCells.Fixed(3),
- modifier = Modifier
- .scrollable(state = rememberScrollState(), orientation = Orientation.Vertical)
- .padding(top = contentPadding.calculateTopPadding())
- ) {
- items(monList.value) { index ->
- CharacterEntry(
- icon = BitmapData(
- bitmap = index.spriteIdle,
- width = index.spriteWidth,
- height = index.spriteHeight
- ),
- onClick = {
- selectedCharacter = index.id
- }
- )
+ } else {
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(3),
+ modifier = Modifier
+ .scrollable(state = rememberScrollState(), orientation = Orientation.Vertical)
+ .padding(top = contentPadding.calculateTopPadding())
+ ) {
+ items(monList.value) { index ->
+ CharacterEntry(
+ icon = BitmapData(
+ bitmap = index.spriteIdle,
+ width = index.spriteWidth,
+ height = index.spriteHeight
+ ),
+ onClick = {
+ if (!index.isInAdventure) {
+ selectedCharacter = index.id
+ } else {
+ Toast.makeText(
+ application,
+ "This character is in an adventure",
+ Toast.LENGTH_SHORT
+ ).show()
+ navController.navigate(
+ NavigationItems.Adventure.route
+ )
+ }
+ },
+ )
+ }
}
}
@@ 107,13 117,11 @@ fun StorageScreen(
characterId = selectedCharacter!!,
onDismissRequest = { selectedCharacter = null },
onClickSetActive = {
- coroutineScope.launch {
- withContext(Dispatchers.IO) {
- storageRepository.setActiveCharacter(selectedCharacter!!)
+ storageScreenController
+ .setActive(selectedCharacter!!) {
selectedCharacter = null
+ navController.navigate(NavigationItems.Home.route)
}
- navController.navigate(NavigationItems.Home.route)
- }
},
onSendToBracelet = {
navController.navigate(
@@ 122,73 130,16 @@ fun StorageScreen(
selectedCharacter.toString()
)
)
+ },
+ onClickSendToAdventure = { time ->
+ adventureScreenController
+ .sendCharacterToAdventure(
+ characterId = selectedCharacter!!,
+ timeInMinutes = time
+ )
+ selectedCharacter = null
}
)
}
}
}
-
-@Composable
-fun StorageDialog(
- characterId: Long,
- onDismissRequest: () -> Unit,
- onSendToBracelet: () -> Unit,
- onClickSetActive: () -> Unit
-) {
- val coroutineScope = rememberCoroutineScope()
- val application = LocalContext.current.applicationContext as VBHelper
- val storageRepository = StorageRepository(application.container.db)
- val character = remember { mutableStateOf<UserCharacter?>(null) }
-
- LaunchedEffect(storageRepository) {
- coroutineScope.launch {
- character.value = storageRepository.getSingleCharacter(characterId)
- }
- }
-
- Dialog(
- onDismissRequest = onDismissRequest,
- properties = DialogProperties(
- dismissOnBackPress = true,
- dismissOnClickOutside = true
- )
- ) {
- Card(
- shape = RoundedCornerShape(16.dp)
- ) {
- Column (
- modifier = Modifier
- .padding(16.dp)
- ) {
- if (character.value != null) {
- Text(
- text = character.value?.toString() ?: "Loading...",
- textAlign = TextAlign.Center,
- modifier = Modifier
- .padding(8.dp)
- )
- }
- Row (
- modifier = Modifier
- .verticalScroll(rememberScrollState())
- ) {
- Button(
- onClick = onSendToBracelet
- ) {
- Text(text = "Send to bracelet")
- }
- Button(
- onClick = onClickSetActive
- ) {
- Text(text = "Set active")
- }
- Button(
- onClick = onDismissRequest
- ) {
- Text(text = "Close")
- }
- }
- }
- }
- }
-}>
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenController.kt +5 -0
@@ 0,0 1,5 @@
+package com.github.nacabaro.vbhelper.screens.storageScreen
+
+interface StorageScreenController {
+ fun setActive(characterId: Long, onCompletion: () -> Unit)
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenControllerImpl.kt +28 -0
@@ 0,0 1,28 @@
+package com.github.nacabaro.vbhelper.screens.storageScreen
+
+import android.widget.Toast
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.lifecycleScope
+import com.github.nacabaro.vbhelper.di.VBHelper
+import kotlinx.coroutines.launch
+
+class StorageScreenControllerImpl(
+ private val componentActivity: ComponentActivity
+): StorageScreenController {
+ private val application = componentActivity.applicationContext as VBHelper
+ private val database = application.container.db
+
+ override fun setActive(characterId: Long, onCompletion: () -> Unit) {
+ componentActivity.lifecycleScope.launch {
+ database.userCharacterDao().setActiveCharacter(characterId)
+ componentActivity.runOnUiThread {
+ Toast.makeText(
+ componentActivity,
+ "Active character updated!",
+ Toast.LENGTH_SHORT
+ ).show()
+ onCompletion()
+ }
+ }
+ }
+}<
\ 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 +4 -7
@@ 2,8 2,6 @@ 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.TransformationHistory
-import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
class StorageRepository (
@@ 13,8 11,8 @@ class StorageRepository (
return db.userCharacterDao().getAllCharacters()
}
- suspend fun getSingleCharacter(id: Long): UserCharacter {
- return db.userCharacterDao().getCharacter(id)
+ suspend fun getSingleCharacter(id: Long): CharacterDtos.CharacterWithSprites {
+ return db.userCharacterDao().getCharacterWithSprites(id)
}
suspend fun getCharacterBeData(id: Long): BECharacterData {
@@ 37,8 35,7 @@ class StorageRepository (
return db.userCharacterDao().deleteCharacterById(id)
}
- fun setActiveCharacter(id: Long) {
- db.userCharacterDao().clearActiveCharacter()
- return db.userCharacterDao().setActiveCharacter(id)
+ suspend fun getAdventureCharacters(): List<CharacterDtos.AdventureCharacterWithSprites> {
+ return db.adventureDao().getAdventureCharacters()
}
}=
\ No newline at end of file
A app/src/main/res/drawable/baseline_fort_24.xml => app/src/main/res/drawable/baseline_fort_24.xml +9 -0
@@ 0,0 1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:pathData="M40,840v-160l80,-80v-240l-80,-80v-160h80v80h80v-80h80v80h80v-80h80v160l-80,80v40h240v-40l-80,-80v-160h80v80h80v-80h80v80h80v-80h80v160l-80,80v240l80,80v160L560,840v-120q0,-33 -23.5,-56.5T480,640q-33,0 -56.5,23.5T400,720v120L40,840ZM120,760h200v-40q0,-66 47,-113t113,-47q66,0 113,47t47,113v40h200v-47l-80,-80v-306l47,-47L633,280l47,47v153L280,480v-153l47,-47L153,280l47,47v306l-80,80v47ZM480,520Z"
+ android:fillColor="#000000"/>
+</vector>