Compare commits

..
26 changed files with 300 additions and 283 deletions
+3
View File
@@ -91,4 +91,7 @@ dependencies {
implementation("com.google.android.material:material:1.2.0") implementation("com.google.android.material:material:1.2.0")
implementation(libs.protobuf.javalite) implementation(libs.protobuf.javalite)
implementation("androidx.compose.material:material") implementation("androidx.compose.material:material")
implementation("androidx.glance:glance:1.1.1")
implementation("androidx.glance:glance-appwidget:1.1.1")
implementation("androidx.work:work-runtime-ktx:2.9.0")
} }
+9
View File
@@ -27,6 +27,15 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:name=".widget.CharacterDisplayWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
</application> </application>
</manifest> </manifest>
@@ -14,7 +14,6 @@ import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImp
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
@@ -46,7 +45,6 @@ class MainActivity : ComponentActivity() {
val adventureScreenController = AdventureScreenControllerImpl(this) val adventureScreenController = AdventureScreenControllerImpl(this)
val storageScreenController = StorageScreenControllerImpl(this) val storageScreenController = StorageScreenControllerImpl(this)
val homeScreenController = HomeScreenControllerImpl(this) val homeScreenController = HomeScreenControllerImpl(this)
val spriteViewerController = SpriteViewerControllerImpl(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -60,8 +58,7 @@ class MainActivity : ComponentActivity() {
itemsScreenController = itemsScreenController, itemsScreenController = itemsScreenController,
adventureScreenController = adventureScreenController, adventureScreenController = adventureScreenController,
homeScreenController = homeScreenController, homeScreenController = homeScreenController,
storageScreenController = storageScreenController, storageScreenController = storageScreenController
spriteViewerController = spriteViewerController
) )
} }
} }
@@ -93,7 +90,7 @@ class MainActivity : ComponentActivity() {
adventureScreenController: AdventureScreenControllerImpl, adventureScreenController: AdventureScreenControllerImpl,
storageScreenController: StorageScreenControllerImpl, storageScreenController: StorageScreenControllerImpl,
homeScreenController: HomeScreenControllerImpl, homeScreenController: HomeScreenControllerImpl,
spriteViewerController: SpriteViewerControllerImpl
) { ) {
AppNavigation( AppNavigation(
applicationNavigationHandlers = AppNavigationHandlers( applicationNavigationHandlers = AppNavigationHandlers(
@@ -102,8 +99,7 @@ class MainActivity : ComponentActivity() {
itemsScreenController, itemsScreenController,
adventureScreenController, adventureScreenController,
storageScreenController, storageScreenController,
homeScreenController, homeScreenController
spriteViewerController
) )
) )
} }
@@ -23,15 +23,14 @@ interface AdventureDao {
uc.*, uc.*,
c.stage, c.stage,
c.attribute, c.attribute,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.width AS spriteWidth, c.spritesWidth AS spriteWidth,
s.height AS spriteHeight, c.spritesHeight AS spriteHeight,
d.isBEm as isBemCard, d.isBEm as isBemCard,
a.finishesAdventure AS finishesAdventure, a.finishesAdventure AS finishesAdventure,
a.originalDuration AS originalTimeInMinutes a.originalDuration AS originalTimeInMinutes
FROM UserCharacter uc FROM UserCharacter uc
JOIN Character c ON uc.charId = c.id JOIN Character c ON uc.charId = c.id
JOIN Sprite s ON s.id = c.spriteId
JOIN Card d ON c.dimId = d.id JOIN Card d ON c.dimId = d.id
JOIN Adventure a ON uc.id = a.characterId JOIN Adventure a ON uc.id = a.characterId
""") """)
@@ -4,7 +4,7 @@ import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.characters.Character import com.github.nacabaro.vbhelper.domain.characters.Character
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.dtos.CharacterDtos import com.github.nacabaro.vbhelper.dtos.CharacterDtos
@Dao @Dao
@@ -22,10 +22,10 @@ interface CharacterDao {
fun getCharacterByMonIndex(monIndex: Int, dimId: Long): Character fun getCharacterByMonIndex(monIndex: Int, dimId: Long): Character
@Insert @Insert
suspend fun insertSprite(vararg sprite: Sprite) suspend fun insertSprite(vararg sprite: Sprites)
@Query("SELECT * FROM Sprite") @Query("SELECT * FROM Sprites")
suspend fun getAllSprites(): List<Sprite> suspend fun getAllSprites(): List<Sprites>
@Query( @Query(
""" """
@@ -19,12 +19,11 @@ interface DexDao {
@Query(""" @Query("""
SELECT SELECT
c.id AS id, c.id AS id,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.width AS spriteWidth, c.spritesWidth AS spriteWidth,
s.height AS spriteHeight, c.spritesHeight AS spriteHeight,
d.discoveredOn AS discoveredOn d.discoveredOn AS discoveredOn
FROM Character c FROM character c
JOIN Sprite s ON c.spriteId = s.id
LEFT JOIN dex d ON c.id = d.id LEFT JOIN dex d ON c.id = d.id
WHERE c.dimId = :cardId WHERE c.dimId = :cardId
""") """)
@@ -1,16 +0,0 @@
package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.characters.Sprite
@Dao
interface SpriteDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertSprite(sprite: Sprite): Long
@Query("SELECT * FROM Sprite")
suspend fun getAllSprites(): List<Sprite>
}
@@ -31,14 +31,13 @@ interface UserCharacterDao {
@Query(""" @Query("""
SELECT SELECT
c.id AS id, c.id AS id,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.width AS spriteWidth, c.spritesWidth AS spriteWidth,
s.height AS spriteHeight, c.spritesHeight AS spriteHeight,
c.monIndex AS monIndex, c.monIndex AS monIndex,
t.transformationDate AS transformationDate t.transformationDate AS transformationDate
FROM TransformationHistory t FROM TransformationHistory t
JOIN Character c ON c.id = t.stageId JOIN Character c ON c.id = t.stageId
JOIN Sprite s ON s.id = c.spriteId
WHERE monId = :monId WHERE monId = :monId
""") """)
fun getTransformationHistory(monId: Long): List<CharacterDtos.TransformationHistory>? fun getTransformationHistory(monId: Long): List<CharacterDtos.TransformationHistory>?
@@ -49,10 +48,9 @@ interface UserCharacterDao {
uc.*, uc.*,
c.stage, c.stage,
c.attribute, c.attribute,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.spriteIdle2 AS spriteIdle2, c.spritesWidth AS spriteWidth,
s.width AS spriteWidth, c.spritesHeight AS spriteHeight,
s.height AS spriteHeight,
c.name as nameSprite, c.name as nameSprite,
c.nameWidth as nameSpriteWidth, c.nameWidth as nameSpriteWidth,
c.nameHeight as nameSpriteHeight, c.nameHeight as nameSpriteHeight,
@@ -60,8 +58,7 @@ interface UserCharacterDao {
a.characterId = uc.id as isInAdventure a.characterId = uc.id as isInAdventure
FROM UserCharacter uc FROM UserCharacter uc
JOIN Character c ON uc.charId = c.id JOIN Character c ON uc.charId = c.id
JOIN Card d ON d.id = c.dimId JOIN Card d ON c.dimId = d.id
JOIN Sprite s ON s.id = c.spriteId
LEFT JOIN Adventure a ON a.characterId = uc.id LEFT JOIN Adventure a ON a.characterId = uc.id
""" """
) )
@@ -73,10 +70,9 @@ interface UserCharacterDao {
uc.*, uc.*,
c.stage, c.stage,
c.attribute, c.attribute,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.spriteIdle2 AS spriteIdle2, c.spritesWidth AS spriteWidth,
s.width AS spriteWidth, c.spritesHeight AS spriteHeight,
s.height AS spriteHeight,
c.name as nameSprite, c.name as nameSprite,
c.nameWidth as nameSpriteWidth, c.nameWidth as nameSpriteWidth,
c.nameHeight as nameSpriteHeight, c.nameHeight as nameSpriteHeight,
@@ -85,7 +81,6 @@ interface UserCharacterDao {
FROM UserCharacter uc FROM UserCharacter uc
JOIN Character c ON uc.charId = c.id JOIN Character c ON uc.charId = c.id
JOIN Card d ON c.dimId = d.id JOIN Card d ON c.dimId = d.id
JOIN Sprite s ON s.id = c.spriteId
LEFT JOIN Adventure a ON a.characterId = uc.id LEFT JOIN Adventure a ON a.characterId = uc.id
WHERE uc.id = :id WHERE uc.id = :id
""") """)
@@ -103,10 +98,9 @@ interface UserCharacterDao {
uc.*, uc.*,
c.stage, c.stage,
c.attribute, c.attribute,
s.spriteIdle1 AS spriteIdle, c.sprite1 AS spriteIdle,
s.spriteIdle2 AS spriteIdle2, c.spritesWidth AS spriteWidth,
s.width AS spriteWidth, c.spritesHeight AS spriteHeight,
s.height AS spriteHeight,
c.name as nameSprite, c.name as nameSprite,
c.nameWidth as nameSpriteWidth, c.nameWidth as nameSpriteWidth,
c.nameHeight as nameSpriteHeight, c.nameHeight as nameSpriteHeight,
@@ -115,7 +109,6 @@ interface UserCharacterDao {
FROM UserCharacter uc FROM UserCharacter uc
JOIN Character c ON uc.charId = c.id JOIN Character c ON uc.charId = c.id
JOIN Card d ON c.dimId = d.id JOIN Card d ON c.dimId = d.id
JOIN Sprite s ON s.id = c.spriteId
LEFT JOIN Adventure a ON a.characterId = uc.id LEFT JOIN Adventure a ON a.characterId = uc.id
WHERE uc.isActive = 1 WHERE uc.isActive = 1
LIMIT 1 LIMIT 1
@@ -7,11 +7,10 @@ import com.github.nacabaro.vbhelper.daos.CharacterDao
import com.github.nacabaro.vbhelper.daos.DexDao import com.github.nacabaro.vbhelper.daos.DexDao
import com.github.nacabaro.vbhelper.daos.DiMDao import com.github.nacabaro.vbhelper.daos.DiMDao
import com.github.nacabaro.vbhelper.daos.ItemDao import com.github.nacabaro.vbhelper.daos.ItemDao
import com.github.nacabaro.vbhelper.daos.SpriteDao
import com.github.nacabaro.vbhelper.daos.UserCharacterDao import com.github.nacabaro.vbhelper.daos.UserCharacterDao
import com.github.nacabaro.vbhelper.domain.characters.Character import com.github.nacabaro.vbhelper.domain.characters.Character
import com.github.nacabaro.vbhelper.domain.characters.Card import com.github.nacabaro.vbhelper.domain.characters.Card
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.domain.characters.Adventure import com.github.nacabaro.vbhelper.domain.characters.Adventure
import com.github.nacabaro.vbhelper.domain.characters.Dex 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.BECharacterData
@@ -24,7 +23,7 @@ import com.github.nacabaro.vbhelper.domain.items.Items
entities = [ entities = [
Card::class, Card::class,
Character::class, Character::class,
Sprite::class, Sprites::class,
UserCharacter::class, UserCharacter::class,
BECharacterData::class, BECharacterData::class,
TransformationHistory::class, TransformationHistory::class,
@@ -40,5 +39,4 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun dexDao(): DexDao abstract fun dexDao(): DexDao
abstract fun itemDao(): ItemDao abstract fun itemDao(): ItemDao
abstract fun adventureDao(): AdventureDao abstract fun adventureDao(): AdventureDao
abstract fun spriteDao(): SpriteDao
} }
@@ -0,0 +1,12 @@
package com.github.nacabaro.vbhelper.domain
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Sprites(
@PrimaryKey(autoGenerate = true) val id : Int,
val sprite: ByteArray,
val width: Int,
val height: Int
)
@@ -12,16 +12,9 @@ import com.github.cfogrady.vbnfc.data.NfcCharacter
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["dimId"], childColumns = ["dimId"],
onDelete = ForeignKey.CASCADE onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = Sprite::class,
parentColumns = ["id"],
childColumns = ["spriteId"],
onDelete = ForeignKey.CASCADE
) )
] ]
) )
/* /*
* Character represents a character on a DIM card. There should only be one of these per dimId * Character represents a character on a DIM card. There should only be one of these per dimId
* and monIndex. * and monIndex.
@@ -30,7 +23,6 @@ import com.github.cfogrady.vbnfc.data.NfcCharacter
data class Character ( data class Character (
@PrimaryKey(autoGenerate = true) val id: Long = 0, @PrimaryKey(autoGenerate = true) val id: Long = 0,
val dimId: Long, val dimId: Long,
val spriteId: Long,
val monIndex: Int, val monIndex: Int,
val name: ByteArray, val name: ByteArray,
val stage: Int, // These should be replaced with enums val stage: Int, // These should be replaced with enums
@@ -38,6 +30,10 @@ data class Character (
val baseHp: Int, val baseHp: Int,
val baseBp: Int, val baseBp: Int,
val baseAp: Int, val baseAp: Int,
val sprite1: ByteArray,
val sprite2: ByteArray,
val nameWidth: Int, val nameWidth: Int,
val nameHeight: Int val nameHeight: Int,
val spritesWidth: Int,
val spritesHeight: Int
) )
@@ -1,23 +0,0 @@
package com.github.nacabaro.vbhelper.domain.characters
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Sprite(
@PrimaryKey(autoGenerate = true) val id : Int = 0,
val spriteIdle1: ByteArray,
val spriteIdle2: ByteArray,
val spriteWalk1: ByteArray,
val spriteWalk2: ByteArray,
val spriteRun1: ByteArray,
val spriteRun2: ByteArray,
val spriteTrain1: ByteArray,
val spriteTrain2: ByteArray,
val spriteHappy: ByteArray,
val spriteSleep: ByteArray,
val spriteAttack: ByteArray,
val spriteDodge: ByteArray,
val width: Int,
val height: Int
)
@@ -25,7 +25,6 @@ object CharacterDtos {
var heartRateCurrent: Int, var heartRateCurrent: Int,
var characterType: DeviceType, var characterType: DeviceType,
val spriteIdle: ByteArray, val spriteIdle: ByteArray,
val spriteIdle2: ByteArray,
val spriteWidth: Int, val spriteWidth: Int,
val spriteHeight: Int, val spriteHeight: Int,
val nameSprite: ByteArray, val nameSprite: ByteArray,
@@ -1,8 +1,5 @@
package com.github.nacabaro.vbhelper.navigation package com.github.nacabaro.vbhelper.navigation
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.foundation.layout.padding
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -18,7 +15,7 @@ import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreen import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreen
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewer import com.github.nacabaro.vbhelper.screens.SpriteViewer
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreen import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreen
import com.github.nacabaro.vbhelper.screens.itemsScreen.ChooseCharacterScreen import com.github.nacabaro.vbhelper.screens.itemsScreen.ChooseCharacterScreen
@@ -27,7 +24,6 @@ import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControl
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreen import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreen
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
import com.github.nacabaro.vbhelper.screens.settingsScreen.CreditsScreen import com.github.nacabaro.vbhelper.screens.settingsScreen.CreditsScreen
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
data class AppNavigationHandlers( data class AppNavigationHandlers(
@@ -36,8 +32,7 @@ data class AppNavigationHandlers(
val itemsScreenController: ItemsScreenControllerImpl, val itemsScreenController: ItemsScreenControllerImpl,
val adventureScreenController: AdventureScreenControllerImpl, val adventureScreenController: AdventureScreenControllerImpl,
val storageScreenController: StorageScreenControllerImpl, val storageScreenController: StorageScreenControllerImpl,
val homeScreenController: HomeScreenControllerImpl, val homeScreenController: HomeScreenControllerImpl
val spriteViewerController: SpriteViewerControllerImpl
) )
@Composable @Composable
@@ -54,19 +49,8 @@ fun AppNavigation(
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = NavigationItems.Home.route, startDestination = NavigationItems.Home.route,
enterTransition = {
fadeIn(
animationSpec = tween(200)
)
},
exitTransition = {
fadeOut(
animationSpec = tween(200)
)
},
modifier = Modifier modifier = Modifier
.padding(contentPadding) .padding(contentPadding)
) { ) {
composable(NavigationItems.Battles.route) { composable(NavigationItems.Battles.route) {
BattlesScreen() BattlesScreen()
@@ -107,8 +91,7 @@ fun AppNavigation(
} }
composable(NavigationItems.Viewer.route) { composable(NavigationItems.Viewer.route) {
SpriteViewer( SpriteViewer(
navController = navController, navController = navController
spriteViewerController = applicationNavigationHandlers.spriteViewerController
) )
} }
composable(NavigationItems.CardView.route) { composable(NavigationItems.CardView.route) {
@@ -1,33 +1,9 @@
package com.github.nacabaro.vbhelper.screens package com.github.nacabaro.vbhelper.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.github.nacabaro.vbhelper.components.TopBanner
@Composable @Composable
fun BattlesScreen() { fun BattlesScreen() {
Scaffold ( Text("Battles Screen")
topBar = {
TopBanner(
text = "Online battles"
)
}
) { contentPadding ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.padding(top = contentPadding.calculateTopPadding())
.fillMaxSize()
) {
Text("Coming soon")
}
}
} }
@@ -1,38 +1,55 @@
package com.github.nacabaro.vbhelper.screens.spriteViewer package com.github.nacabaro.vbhelper.screens
import android.graphics.Bitmap import android.graphics.Bitmap
import android.util.Log import android.util.Log
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.source.SpriteRepo
import kotlinx.coroutines.launch
import java.nio.ByteBuffer
@Composable @Composable
fun SpriteViewer( fun SpriteViewer(
navController: NavController, navController: NavController
spriteViewerController: SpriteViewerController
) { ) {
val spriteList = remember { mutableStateListOf<Bitmap>() } val coroutineScope = rememberCoroutineScope()
val application = LocalContext.current.applicationContext as VBHelper
val db = application.container.db
val spriteRepo = SpriteRepo(db)
val spriteList = remember { mutableStateListOf<Sprites>() }
Log.d("SpriteViewer", "spriteList: $spriteList") Log.d("SpriteViewer", "spriteList: $spriteList")
LaunchedEffect(spriteViewerController) { LaunchedEffect(spriteRepo) {
val sprites = spriteViewerController.getAllSprites() coroutineScope.launch {
val bitmapData = spriteViewerController.convertToBitmap(sprites) spriteList.clear()
spriteList.addAll(bitmapData) spriteList.addAll(spriteRepo.getAllSprites())
}
} }
Scaffold ( Scaffold (
@@ -52,7 +69,13 @@ fun SpriteViewer(
.padding(top = contentPadding.calculateTopPadding()) .padding(top = contentPadding.calculateTopPadding())
) { ) {
items(spriteList) { sprite -> items(spriteList) { sprite ->
val imageBitmap = remember(sprite) { sprite.asImageBitmap() } val bitmap = remember (sprite.sprite) {
Log.d("SpriteViewer", "sprite: $sprite")
Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.sprite))
}
}
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
Image( Image(
bitmap = imageBitmap, bitmap = imageBitmap,
contentDescription = "Sprite", contentDescription = "Sprite",
@@ -184,8 +184,7 @@ fun ScanScreen(
} }
} }
} }
}, }
navController = navController
) )
} }
} }
@@ -194,17 +193,9 @@ fun ScanScreen(
fun ChooseConnectOption( fun ChooseConnectOption(
onClickRead: (() -> Unit)? = null, onClickRead: (() -> Unit)? = null,
onClickWrite: (() -> Unit)? = null, onClickWrite: (() -> Unit)? = null,
navController: NavController
) { ) {
Scaffold( Scaffold(
topBar = { topBar = { TopBanner(text = "Scan a Vital Bracelet") }
TopBanner(
text = "Scan a Vital Bracelet",
onBackClick = {
navController.popBackStack()
}
)
}
) { contentPadding -> ) { contentPadding ->
Column( Column(
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
@@ -10,12 +10,11 @@ import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import com.github.cfogrady.vb.dim.card.BemCard import com.github.cfogrady.vb.dim.card.BemCard
import com.github.cfogrady.vb.dim.card.DimCard
import com.github.cfogrady.vb.dim.card.DimReader import com.github.cfogrady.vb.dim.card.DimReader
import com.github.cfogrady.vbnfc.data.NfcCharacter import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.database.AppDatabase import com.github.nacabaro.vbhelper.database.AppDatabase
import com.github.nacabaro.vbhelper.di.VBHelper import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.characters.Sprite import com.github.nacabaro.vbhelper.domain.Sprites
import com.github.nacabaro.vbhelper.domain.characters.Card import com.github.nacabaro.vbhelper.domain.characters.Card
import com.github.nacabaro.vbhelper.domain.characters.Character import com.github.nacabaro.vbhelper.domain.characters.Character
import com.github.nacabaro.vbhelper.source.ApkSecretsImporter import com.github.nacabaro.vbhelper.source.ApkSecretsImporter
@@ -140,53 +139,9 @@ class SettingsScreenControllerImpl(
val domainCharacters = mutableListOf<Character>() val domainCharacters = mutableListOf<Character>()
for (index in 0 until characters.size) { for (index in 0 until characters.size) {
var domainSprite: Sprite? = null;
if (index < 2 && card is DimCard) {
domainSprite = Sprite(
width = card.spriteData.sprites[spriteCounter + 1].spriteDimensions.width,
height = card.spriteData.sprites[spriteCounter + 1].spriteDimensions.height,
spriteIdle1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
spriteIdle2 = card.spriteData.sprites[spriteCounter + 2].pixelData,
spriteWalk1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
spriteWalk2 = card.spriteData.sprites[spriteCounter + 3].pixelData,
spriteRun1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
spriteRun2 = card.spriteData.sprites[spriteCounter + 3].pixelData,
spriteTrain1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
spriteTrain2 = card.spriteData.sprites[spriteCounter + 3].pixelData,
spriteHappy = card.spriteData.sprites[spriteCounter + 4].pixelData,
spriteSleep = card.spriteData.sprites[spriteCounter + 5].pixelData,
spriteAttack = card.spriteData.sprites[spriteCounter + 2].pixelData,
spriteDodge = card.spriteData.sprites[spriteCounter + 3].pixelData
)
} else {
domainSprite = Sprite(
width = card.spriteData.sprites[spriteCounter + 1].spriteDimensions.width,
height = card.spriteData.sprites[spriteCounter + 1].spriteDimensions.height,
spriteIdle1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
spriteIdle2 = card.spriteData.sprites[spriteCounter + 2].pixelData,
spriteWalk1 = card.spriteData.sprites[spriteCounter + 3].pixelData,
spriteWalk2 = card.spriteData.sprites[spriteCounter + 4].pixelData,
spriteRun1 = card.spriteData.sprites[spriteCounter + 5].pixelData,
spriteRun2 = card.spriteData.sprites[spriteCounter + 6].pixelData,
spriteTrain1 = card.spriteData.sprites[spriteCounter + 7].pixelData,
spriteTrain2 = card.spriteData.sprites[spriteCounter + 8].pixelData,
spriteHappy = card.spriteData.sprites[spriteCounter + 9].pixelData,
spriteSleep = card.spriteData.sprites[spriteCounter + 10].pixelData,
spriteAttack = card.spriteData.sprites[spriteCounter + 11].pixelData,
spriteDodge = card.spriteData.sprites[spriteCounter + 12].pixelData
)
}
val spriteId = database
.spriteDao()
.insertSprite(domainSprite)
domainCharacters.add( domainCharacters.add(
Character( Character(
dimId = dimId, dimId = dimId,
spriteId = spriteId,
monIndex = index, monIndex = index,
name = card.spriteData.sprites[spriteCounter].pixelData, name = card.spriteData.sprites[spriteCounter].pixelData,
stage = characters[index].stage, stage = characters[index].stage,
@@ -194,8 +149,12 @@ class SettingsScreenControllerImpl(
baseHp = characters[index].hp, baseHp = characters[index].hp,
baseBp = characters[index].dp, baseBp = characters[index].dp,
baseAp = characters[index].ap, baseAp = characters[index].ap,
nameWidth = card.spriteData.sprites[spriteCounter].spriteDimensions.width, sprite1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
nameHeight = card.spriteData.sprites[spriteCounter].spriteDimensions.height, sprite2 = card.spriteData.sprites[spriteCounter + 2].pixelData,
nameWidth = card.spriteData.sprites[spriteCounter].width,
nameHeight = card.spriteData.sprites[spriteCounter].height,
spritesWidth = card.spriteData.sprites[spriteCounter + 1].width,
spritesHeight = card.spriteData.sprites[spriteCounter + 1].height
) )
) )
@@ -213,6 +172,18 @@ class SettingsScreenControllerImpl(
database database
.characterDao() .characterDao()
.insertCharacter(*domainCharacters.toTypedArray()) .insertCharacter(*domainCharacters.toTypedArray())
val sprites = card.spriteData.sprites.map { sprite ->
Sprites(
id = 0,
sprite = sprite.pixelData,
width = sprite.width,
height = sprite.height
)
}
database
.characterDao()
.insertSprite(*sprites.toTypedArray())
} }
inputStream?.close() inputStream?.close()
@@ -1,9 +0,0 @@
package com.github.nacabaro.vbhelper.screens.spriteViewer
import android.graphics.Bitmap
import com.github.nacabaro.vbhelper.domain.characters.Sprite
interface SpriteViewerController {
suspend fun getAllSprites(): List<Sprite>
fun convertToBitmap(sprites: List<Sprite>): List<Bitmap>
}
@@ -1,68 +0,0 @@
package com.github.nacabaro.vbhelper.screens.spriteViewer
import android.graphics.Bitmap
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.asImageBitmap
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.domain.characters.Sprite
import java.nio.ByteBuffer
class SpriteViewerControllerImpl(
private val context: ComponentActivity
) : SpriteViewerController {
override suspend fun getAllSprites(): List<Sprite> {
val applicationContext = context.applicationContext as VBHelper
val db = applicationContext.container.db
val sprites = db.spriteDao().getAllSprites()
return sprites
}
// I don't like this, chief
override fun convertToBitmap(sprites: List<Sprite>): List<Bitmap> {
val bitmapList = mutableListOf<Bitmap>()
for (sprite in sprites) {
Log.d("SpriteViewer", "sprite: $sprite")
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteIdle1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteIdle2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteWalk1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteWalk2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteRun1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteRun2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteTrain1))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteTrain2))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteHappy))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteSleep))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteAttack))
})
bitmapList.add(Bitmap.createBitmap(sprite.width, sprite.height, Bitmap.Config.RGB_565).apply {
copyPixelsFromBuffer(ByteBuffer.wrap(sprite.spriteDodge))
})
}
return bitmapList
}
}
@@ -0,0 +1,12 @@
package com.github.nacabaro.vbhelper.source
import com.github.nacabaro.vbhelper.database.AppDatabase
import com.github.nacabaro.vbhelper.domain.Sprites
class SpriteRepo (
private val db: AppDatabase
) {
suspend fun getAllSprites(): List<Sprites> {
return db.characterDao().getAllSprites()
}
}
@@ -0,0 +1,117 @@
package com.github.nacabaro.vbhelper.widget
import android.content.Context
import android.graphics.Bitmap
import androidx.compose.material3.MaterialTheme
import androidx.glance.GlanceTheme
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.glance.background
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.layout.Alignment
import androidx.glance.layout.Column
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.size
import androidx.glance.state.PreferencesGlanceStateDefinition
import androidx.glance.text.Text
import androidx.glance.unit.ColorProvider
import com.github.nacabaro.vbhelper.di.VBHelper
import com.github.nacabaro.vbhelper.utils.BitmapData
import com.github.nacabaro.vbhelper.utils.getBitmap
/*
RANT: Why did they have to create the components from Jetpack Compose
with a different API for Glance? Now there are things I use in Jetpack Compose
like the filterQuality, which isn't here.
*/
val CURRENT_IMAGE_KEY = booleanPreferencesKey("current_image")
class CharacterDisplayWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
val application = context.applicationContext as VBHelper
val storageRepository = application.container.db
val currentCharacter = storageRepository
.userCharacterDao()
.getActiveCharacter()
val multiplier = 4
provideContent {
var bitmapIdle1 by remember { mutableStateOf<Bitmap?>(null) }
var bitmapIdle2 by remember { mutableStateOf<Bitmap?>(null) }
var dpSize by remember { mutableStateOf(0.dp) }
if (currentCharacter != null) {
val currentCharacterBitmapIdle1 = BitmapData(
currentCharacter.spriteIdle,
currentCharacter.spriteWidth,
currentCharacter.spriteHeight
)
val currentCharacterBitmapIdle2 = BitmapData(
currentCharacter.spriteIdle2,
currentCharacter.spriteWidth,
currentCharacter.spriteHeight
)
bitmapIdle1 = currentCharacterBitmapIdle1.getBitmap()
bitmapIdle2 = currentCharacterBitmapIdle2.getBitmap()
val density: Float = application.resources.displayMetrics.density
dpSize = (currentCharacterBitmapIdle1.width * multiplier / density).dp
}
WidgetContent(
imageBitmapFrame1 = bitmapIdle1,
imageBitmapFrame2 = bitmapIdle2,
dpSize = dpSize
)
}
}
@Composable
private fun WidgetContent(
imageBitmapFrame1: Bitmap?,
imageBitmapFrame2: Bitmap?,
dpSize: Dp
) {
GlanceTheme {
Column (
horizontalAlignment = Alignment.Horizontal.CenterHorizontally,
verticalAlignment = Alignment.Vertical.CenterVertically,
modifier = GlanceModifier
.fillMaxSize()
.background(ColorProvider(MaterialTheme.colorScheme.background))
) {
if (imageBitmapFrame1 != null) {
Image(
provider = ImageProvider(
bitmap = imageBitmapFrame1
),
contentDescription = "Character",
modifier = GlanceModifier
.size(dpSize)
)
} else {
Text(
text = "No character selected"
)
}
}
}
}
}
@@ -0,0 +1,3 @@
package com.github.nacabaro.vbhelper.widget
import androidx.glance.state.PreferencesGlanceStateDefinition
@@ -0,0 +1,8 @@
package com.github.nacabaro.vbhelper.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class CharacterDisplayWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = CharacterDisplayWidget()
}
@@ -0,0 +1,35 @@
package com.github.nacabaro.vbhelper.widget
import android.content.Context
import androidx.glance.appwidget.GlanceAppWidgetManager
import androidx.glance.appwidget.state.updateAppWidgetState
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
class CharacterDisplayWidgetWorker(
appContext: Context,
workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
// Get all widget IDs for your ImageSwapWidget
val glanceIds = GlanceAppWidgetManager(applicationContext)
.getGlanceIds(CharacterDisplayWidget::class.java)
glanceIds.forEach { glanceId ->
// Update the widget's state (toggle the boolean)
updateAppWidgetState(
context = applicationContext,
glanceId = glanceId
) { prefs ->
val currentImageIsImage1 = prefs[CURRENT_IMAGE_KEY] ?: true
prefs[CURRENT_IMAGE_KEY] = !currentImageIsImage1 // Toggle the boolean
}
// Trigger the widget to redraw itself with the new state
CharacterDisplayWidget().update(applicationContext, glanceId)
}
// Indicate that the work was successful
return Result.success()
}
}
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="40dp"
android:minHeight="20dp"
android:minResizeWidth="20dp"
android:previewImage="@drawable/baseline_image_24"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="300000"
android:widgetCategory="home_screen" />