Compare commits

...
7 Commits
Author SHA1 Message Date
nacabaroandGitHub 99d309adc1 Merge pull request #60 from b13st/fix/hce-send-crash
Fix double character deletion causing crash on HCE transfer to VitalWear
2026-07-01 17:24:49 +02:00
nacabaroandGitHub 2760af5d2b Merge pull request #59 from b13st/chore/visual-improvements
improving various visuals
2026-07-01 17:23:34 +02:00
b13st 931f730406 Fix double character deletion causing crash on HCE transfer to VitalWear
Character was deleted from the local DB both right after sendCharacterToWatch
and again in WritingScreen's completion callback. The second deletion failed
because the character no longer existed, causing the reported random crash
when sending back to the watch. Deletion is now handled only once, in
WritingScreen.
2026-07-01 15:04:26 +02:00
b13st 4eaf6cdf1b Fix double character deletion causing crash on HCE transfer to VitalWear
Character was deleted from the local DB both right after sendCharacterToWatch
and again in WritingScreen's completion callback. The second deletion failed
because the character no longer existed, causing the reported random crash
when sending back to the watch. Deletion is now handled only once, in
WritingScreen.
2026-07-01 15:00:56 +02:00
b13st 416b30f7a8 improving various visuals 2026-07-01 13:51:34 +02:00
nacabaro df713855f5 I forgot to update the version number. 2026-06-29 21:26:11 +02:00
nacabaro e5ccff16d0 Pulidora industrial
- Removed all the warnings during building
- Upgraded all the libraries
- Upgraded grandle and the SDK version
- Fix japanese strings
- Added vibration permission
2026-06-29 16:15:12 +00:00
33 changed files with 652 additions and 115 deletions
+3 -7
View File
@@ -2,7 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.vksp)
alias(libs.plugins.vprotobuf)
@@ -10,14 +9,14 @@ plugins {
android {
namespace = "com.github.nacabaro.vbhelper"
compileSdk = 36
compileSdk = 37
defaultConfig {
applicationId = "com.github.nacabaro.vbhelper"
minSdk = 28
targetSdk = 36
targetSdk = 37
versionCode = 1
versionName = "Alpha 0.6.4"
versionName = "Alpha 0.6.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -56,9 +55,6 @@ protobuf {
artifact = "com.google.protobuf:protoc:4.27.0"
}
// Generates the java Protobuf-lite code for the Protobufs in this project. See
// https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
// for more information.
generateProtoTasks {
all().forEach { task ->
task.builtins {
+5 -3
View File
@@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
@@ -34,7 +35,6 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.VBHelper">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -51,8 +51,10 @@
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="localhost" android:port="8080" android:pathPrefix="/authenticate" />
<data android:scheme="http" android:host="127.0.0.1" android:port="8080" android:pathPrefix="/authenticate" />
<data android:scheme="http" />
<data android:host="localhost" android:port="8080" />
<data android:host="127.0.0.1" android:port="8080" />
<data android:pathPrefix="/authenticate" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
@@ -2,11 +2,13 @@ package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import kotlinx.coroutines.flow.Flow
@Dao
@RewriteQueriesToDropUnusedColumns
interface AdventureDao {
@Query("""
INSERT INTO Adventure (characterId, originalDuration, finishesAdventure)
@@ -2,11 +2,13 @@ package com.github.nacabaro.vbhelper.daos
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns
import com.github.cfogrady.vbnfc.data.NfcCharacter
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import kotlinx.coroutines.flow.Flow
@Dao
@RewriteQueriesToDropUnusedColumns
interface CardFusionsDao {
@Query("""
INSERT INTO
@@ -5,6 +5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Upsert
import androidx.room.RewriteQueriesToDropUnusedColumns
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
@@ -16,6 +17,7 @@ import com.github.nacabaro.vbhelper.dtos.CharacterDtos
import kotlinx.coroutines.flow.Flow
@Dao
@RewriteQueriesToDropUnusedColumns
interface UserCharacterDao {
@Insert
fun insertCharacterData(characterData: UserCharacter): Long
@@ -40,7 +40,8 @@ import com.github.nacabaro.vbhelper.domain.device_data.CharacterTransferPolicy
import com.github.nacabaro.vbhelper.domain.items.Items
@Database(
version = 2,
version = 3,
exportSchema = false,
entities = [
Card::class,
CardProgress::class,
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@@ -12,7 +13,8 @@ import androidx.room.PrimaryKey
childColumns = ["cardId"],
onDelete = ForeignKey.CASCADE
)
]
],
indices = [Index(value = ["cardId"])]
)
data class Background (
@PrimaryKey(autoGenerate = true) val id: Long,
@@ -20,4 +22,28 @@ data class Background (
val background: ByteArray,
val backgroundWidth: Int,
val backgroundHeight: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Background
if (id != other.id) return false
if (cardId != other.cardId) return false
if (!background.contentEquals(other.background)) return false
if (backgroundWidth != other.backgroundWidth) return false
if (backgroundHeight != other.backgroundHeight) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + cardId.hashCode()
result = 31 * result + background.contentHashCode()
result = 31 * result + backgroundWidth
result = 31 * result + backgroundHeight
return result
}
}
@@ -14,4 +14,34 @@ data class Card(
val name: String,
val stageCount: Int,
val isBEm: Boolean
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Card
if (id != other.id) return false
if (cardId != other.cardId) return false
if (!logo.contentEquals(other.logo)) return false
if (logoWidth != other.logoWidth) return false
if (logoHeight != other.logoHeight) return false
if (name != other.name) return false
if (stageCount != other.stageCount) return false
if (isBEm != other.isBEm) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + cardId
result = 31 * result + logo.contentHashCode()
result = 31 * result + logoWidth
result = 31 * result + logoHeight
result = 31 * result + name.hashCode()
result = 31 * result + stageCount
result = 31 * result + isBEm.hashCode()
return result
}
}
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@@ -18,6 +19,10 @@ import androidx.room.PrimaryKey
childColumns = ["cardId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index(value = ["characterId"]),
Index(value = ["cardId"])
]
)
data class CardAdventure(
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.cfogrady.vbnfc.data.NfcCharacter
@@ -20,6 +21,10 @@ import com.github.nacabaro.vbhelper.domain.characters.Sprite
childColumns = ["spriteId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index(value = ["cardId"]),
Index(value = ["spriteId"])
]
)
@@ -41,4 +46,42 @@ data class CardCharacter (
val nameSprite: ByteArray,
val nameWidth: Int,
val nameHeight: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardCharacter
if (id != other.id) return false
if (cardId != other.cardId) return false
if (spriteId != other.spriteId) return false
if (charaIndex != other.charaIndex) return false
if (stage != other.stage) return false
if (attribute != other.attribute) return false
if (baseHp != other.baseHp) return false
if (baseBp != other.baseBp) return false
if (baseAp != other.baseAp) return false
if (!nameSprite.contentEquals(other.nameSprite)) return false
if (nameWidth != other.nameWidth) return false
if (nameHeight != other.nameHeight) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + cardId.hashCode()
result = 31 * result + spriteId.hashCode()
result = 31 * result + charaIndex
result = 31 * result + stage
result = 31 * result + attribute.hashCode()
result = 31 * result + baseHp
result = 31 * result + baseBp
result = 31 * result + baseAp
result = 31 * result + nameSprite.contentHashCode()
result = 31 * result + nameWidth
result = 31 * result + nameHeight
return result
}
}
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.cfogrady.vbnfc.data.NfcCharacter
@@ -19,6 +20,10 @@ import com.github.cfogrady.vbnfc.data.NfcCharacter
childColumns = ["toCharaId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index(value = ["fromCharaId"]),
Index(value = ["toCharaId"])
]
)
data class CardFusions(
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.card
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@@ -18,6 +19,10 @@ import androidx.room.PrimaryKey
childColumns = ["toCharaId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index(value = ["charaId"]),
Index(value = ["toCharaId"])
]
)
data class PossibleTransformations (
@@ -20,4 +20,48 @@ data class Sprite(
val spriteDodge: ByteArray,
val width: Int,
val height: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Sprite
if (id != other.id) return false
if (!spriteIdle1.contentEquals(other.spriteIdle1)) return false
if (!spriteIdle2.contentEquals(other.spriteIdle2)) return false
if (!spriteWalk1.contentEquals(other.spriteWalk1)) return false
if (!spriteWalk2.contentEquals(other.spriteWalk2)) return false
if (!spriteRun1.contentEquals(other.spriteRun1)) return false
if (!spriteRun2.contentEquals(other.spriteRun2)) return false
if (!spriteTrain1.contentEquals(other.spriteTrain1)) return false
if (!spriteTrain2.contentEquals(other.spriteTrain2)) return false
if (!spriteHappy.contentEquals(other.spriteHappy)) return false
if (!spriteSleep.contentEquals(other.spriteSleep)) return false
if (!spriteAttack.contentEquals(other.spriteAttack)) return false
if (!spriteDodge.contentEquals(other.spriteDodge)) return false
if (width != other.width) return false
if (height != other.height) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + spriteIdle1.contentHashCode()
result = 31 * result + spriteIdle2.contentHashCode()
result = 31 * result + spriteWalk1.contentHashCode()
result = 31 * result + spriteWalk2.contentHashCode()
result = 31 * result + spriteRun1.contentHashCode()
result = 31 * result + spriteRun2.contentHashCode()
result = 31 * result + spriteTrain1.contentHashCode()
result = 31 * result + spriteTrain2.contentHashCode()
result = 31 * result + spriteHappy.contentHashCode()
result = 31 * result + spriteSleep.contentHashCode()
result = 31 * result + spriteAttack.contentHashCode()
result = 31 * result + spriteDodge.contentHashCode()
result = 31 * result + width
result = 31 * result + height
return result
}
}
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.device_data
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.cfogrady.vbnfc.vb.SpecialMission
@@ -13,7 +14,8 @@ import com.github.cfogrady.vbnfc.vb.SpecialMission
childColumns = ["characterId"],
onDelete = ForeignKey.CASCADE
)
]
],
indices = [Index(value = ["characterId"])]
)
data class SpecialMissions (
@PrimaryKey(autoGenerate = true) var id: Long = 0,
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.device_data
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
@@ -19,6 +20,10 @@ import com.github.nacabaro.vbhelper.domain.card.CardCharacter
childColumns = ["stageId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [
Index(value = ["monId"]),
Index(value = ["stageId"])
]
)
data class TransformationHistory (
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.device_data
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.github.cfogrady.vbnfc.data.NfcCharacter
@@ -15,7 +16,8 @@ import com.github.nacabaro.vbhelper.domain.card.CardCharacter
childColumns = ["charId"],
onDelete = ForeignKey.CASCADE
)
]
],
indices = [Index(value = ["charId"])]
)
/**
* UserCharacter represents and instance of a character. The charId should map to a Character
@@ -1,6 +1,7 @@
package com.github.nacabaro.vbhelper.domain.device_data
import androidx.room.Entity
import androidx.room.Index
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@@ -12,7 +13,8 @@ import androidx.room.PrimaryKey
childColumns = ["charId"],
onDelete = ForeignKey.CASCADE
)
]
],
indices = [Index(value = ["charId"])]
)
data class VitalsHistory (
@PrimaryKey(autoGenerate = true) val id: Long = 0,
@@ -9,7 +9,35 @@ object CardDtos {
val logoHeight: Int,
val totalCharacters: Int,
val obtainedCharacters: Int,
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardProgress
if (cardId != other.cardId) return false
if (cardName != other.cardName) return false
if (!cardLogo.contentEquals(other.cardLogo)) return false
if (logoWidth != other.logoWidth) return false
if (logoHeight != other.logoHeight) return false
if (totalCharacters != other.totalCharacters) return false
if (obtainedCharacters != other.obtainedCharacters) return false
return true
}
override fun hashCode(): Int {
var result = cardId.hashCode()
result = 31 * result + cardName.hashCode()
result = 31 * result + cardLogo.contentHashCode()
result = 31 * result + logoWidth
result = 31 * result + logoHeight
result = 31 * result + totalCharacters
result = 31 * result + obtainedCharacters
return result
}
}
data class CardAdventureWithSprites (
val characterName: ByteArray,
@@ -23,11 +51,67 @@ object CardDtos {
val characterDp: Int,
val characterHp: Int,
val steps: Int,
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardAdventureWithSprites
if (!characterName.contentEquals(other.characterName)) return false
if (characterNameWidth != other.characterNameWidth) return false
if (characterNameHeight != other.characterNameHeight) return false
if (!characterIdleSprite.contentEquals(other.characterIdleSprite)) return false
if (characterIdleSpriteWidth != other.characterIdleSpriteWidth) return false
if (characterIdleSpriteHeight != other.characterIdleSpriteHeight) return false
if (characterAp != other.characterAp) return false
if (characterBp != other.characterBp) return false
if (characterDp != other.characterDp) return false
if (characterHp != other.characterHp) return false
if (steps != other.steps) return false
return true
}
override fun hashCode(): Int {
var result = characterName.contentHashCode()
result = 31 * result + characterNameWidth
result = 31 * result + characterNameHeight
result = 31 * result + characterIdleSprite.contentHashCode()
result = 31 * result + characterIdleSpriteWidth
result = 31 * result + characterIdleSpriteHeight
result = 31 * result + characterAp
result = 31 * result + (characterBp ?: 0)
result = 31 * result + characterDp
result = 31 * result + characterHp
result = 31 * result + steps
return result
}
}
data class CardIcon (
val cardIcon: ByteArray,
val cardIconWidth: Int,
val cardIconHeight: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardIcon
if (!cardIcon.contentEquals(other.cardIcon)) return false
if (cardIconWidth != other.cardIconWidth) return false
if (cardIconHeight != other.cardIconHeight) return false
return true
}
override fun hashCode(): Int {
var result = cardIcon.contentHashCode()
result = 31 * result + cardIconWidth
result = 31 * result + cardIconHeight
return result
}
}
}
@@ -33,7 +33,75 @@ object CharacterDtos {
val isBemCard: Boolean,
val isInAdventure: Boolean,
val active: Boolean
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CharacterWithSprites
if (id != other.id) return false
if (charId != other.charId) return false
if (stage != other.stage) return false
if (attribute != other.attribute) return false
if (ageInDays != other.ageInDays) return false
if (mood != other.mood) return false
if (vitalPoints != other.vitalPoints) return false
if (transformationCountdown != other.transformationCountdown) return false
if (injuryStatus != other.injuryStatus) return false
if (trophies != other.trophies) return false
if (currentPhaseBattlesWon != other.currentPhaseBattlesWon) return false
if (currentPhaseBattlesLost != other.currentPhaseBattlesLost) return false
if (totalBattlesWon != other.totalBattlesWon) return false
if (totalBattlesLost != other.totalBattlesLost) return false
if (activityLevel != other.activityLevel) return false
if (heartRateCurrent != other.heartRateCurrent) return false
if (characterType != other.characterType) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (!spriteIdle2.contentEquals(other.spriteIdle2)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (!nameSprite.contentEquals(other.nameSprite)) return false
if (nameSpriteWidth != other.nameSpriteWidth) return false
if (nameSpriteHeight != other.nameSpriteHeight) return false
if (isBemCard != other.isBemCard) return false
if (isInAdventure != other.isInAdventure) return false
if (active != other.active) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + charId.hashCode()
result = 31 * result + stage
result = 31 * result + attribute.hashCode()
result = 31 * result + ageInDays
result = 31 * result + mood
result = 31 * result + vitalPoints
result = 31 * result + transformationCountdown
result = 31 * result + injuryStatus.hashCode()
result = 31 * result + trophies
result = 31 * result + currentPhaseBattlesWon
result = 31 * result + currentPhaseBattlesLost
result = 31 * result + totalBattlesWon
result = 31 * result + totalBattlesLost
result = 31 * result + activityLevel
result = 31 * result + heartRateCurrent
result = 31 * result + characterType.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteIdle2.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + nameSprite.contentHashCode()
result = 31 * result + nameSpriteWidth
result = 31 * result + nameSpriteHeight
result = 31 * result + isBemCard.hashCode()
result = 31 * result + isInAdventure.hashCode()
result = 31 * result + active.hashCode()
return result
}
}
data class CardCharacterInfo(
val cardId: Long,
@@ -50,7 +118,33 @@ object CharacterDtos {
val spriteHeight: Int,
val monIndex: Int,
val transformationDate: Long
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as TransformationHistory
if (id != other.id) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (monIndex != other.monIndex) return false
if (transformationDate != other.transformationDate) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + monIndex
result = 31 * result + transformationDate.hashCode()
return result
}
}
data class TransformationHistoryExport(
val stageId: Long,
@@ -73,14 +167,76 @@ object CharacterDtos {
val baseAp: Int,
val stage: Int,
val attribute: NfcCharacter.Attribute,
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardCharaProgress
if (id != other.id) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (!nameSprite.contentEquals(other.nameSprite)) return false
if (nameSpriteWidth != other.nameSpriteWidth) return false
if (nameSpriteHeight != other.nameSpriteHeight) return false
if (discoveredOn != other.discoveredOn) return false
if (baseHp != other.baseHp) return false
if (baseBp != other.baseBp) return false
if (baseAp != other.baseAp) return false
if (stage != other.stage) return false
if (attribute != other.attribute) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + nameSprite.contentHashCode()
result = 31 * result + nameSpriteWidth
result = 31 * result + nameSpriteHeight
result = 31 * result + (discoveredOn?.hashCode() ?: 0)
result = 31 * result + baseHp
result = 31 * result + baseBp
result = 31 * result + baseAp
result = 31 * result + stage
result = 31 * result + attribute.hashCode()
return result
}
}
data class CardProgress(
val id: Long,
val spriteIdle: ByteArray,
val spriteWidth: Int,
val spriteHeight: Int,
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CardProgress
if (id != other.id) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
return result
}
}
data class AdventureCharacterWithSprites(
var id: Long = 0,
@@ -106,7 +262,67 @@ object CharacterDtos {
val isBemCard: Boolean,
val finishesAdventure: Long,
val originalTimeInMinutes: Long
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as AdventureCharacterWithSprites
if (id != other.id) return false
if (charId != other.charId) return false
if (stage != other.stage) return false
if (attribute != other.attribute) return false
if (ageInDays != other.ageInDays) return false
if (mood != other.mood) return false
if (vitalPoints != other.vitalPoints) return false
if (transformationCountdown != other.transformationCountdown) return false
if (injuryStatus != other.injuryStatus) return false
if (trophies != other.trophies) return false
if (currentPhaseBattlesWon != other.currentPhaseBattlesWon) return false
if (currentPhaseBattlesLost != other.currentPhaseBattlesLost) return false
if (totalBattlesWon != other.totalBattlesWon) return false
if (totalBattlesLost != other.totalBattlesLost) return false
if (activityLevel != other.activityLevel) return false
if (heartRateCurrent != other.heartRateCurrent) return false
if (characterType != other.characterType) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (isBemCard != other.isBemCard) return false
if (finishesAdventure != other.finishesAdventure) return false
if (originalTimeInMinutes != other.originalTimeInMinutes) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + charId.hashCode()
result = 31 * result + stage
result = 31 * result + attribute.hashCode()
result = 31 * result + ageInDays
result = 31 * result + mood
result = 31 * result + vitalPoints
result = 31 * result + transformationCountdown
result = 31 * result + injuryStatus.hashCode()
result = 31 * result + trophies
result = 31 * result + currentPhaseBattlesWon
result = 31 * result + currentPhaseBattlesLost
result = 31 * result + totalBattlesWon
result = 31 * result + totalBattlesLost
result = 31 * result + activityLevel
result = 31 * result + heartRateCurrent
result = 31 * result + characterType.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + isBemCard.hashCode()
result = 31 * result + finishesAdventure.hashCode()
result = 31 * result + originalTimeInMinutes.hashCode()
return result
}
}
data class EvolutionRequirementsWithSpritesAndObtained(
val charaId: Long,
@@ -121,7 +337,45 @@ object CharacterDtos {
val requiredWinRate: Int,
val changeTimerHours: Int,
val requiredAdventureLevelCompleted: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as EvolutionRequirementsWithSpritesAndObtained
if (charaId != other.charaId) return false
if (fromCharaId != other.fromCharaId) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (discoveredOn != other.discoveredOn) return false
if (requiredTrophies != other.requiredTrophies) return false
if (requiredVitals != other.requiredVitals) return false
if (requiredBattles != other.requiredBattles) return false
if (requiredWinRate != other.requiredWinRate) return false
if (changeTimerHours != other.changeTimerHours) return false
if (requiredAdventureLevelCompleted != other.requiredAdventureLevelCompleted) return false
return true
}
override fun hashCode(): Int {
var result = charaId.hashCode()
result = 31 * result + fromCharaId.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + (discoveredOn?.hashCode() ?: 0)
result = 31 * result + requiredTrophies
result = 31 * result + requiredVitals
result = 31 * result + requiredBattles
result = 31 * result + requiredWinRate
result = 31 * result + changeTimerHours
result = 31 * result + requiredAdventureLevelCompleted
return result
}
}
data class FusionsWithSpritesAndObtained(
val charaId: Long,
@@ -131,5 +385,33 @@ object CharacterDtos {
val spriteHeight: Int,
val discoveredOn: Long?,
val fusionAttribute: NfcCharacter.Attribute
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as FusionsWithSpritesAndObtained
if (charaId != other.charaId) return false
if (fromCharaId != other.fromCharaId) return false
if (!spriteIdle.contentEquals(other.spriteIdle)) return false
if (spriteWidth != other.spriteWidth) return false
if (spriteHeight != other.spriteHeight) return false
if (discoveredOn != other.discoveredOn) return false
if (fusionAttribute != other.fusionAttribute) return false
return true
}
override fun hashCode(): Int {
var result = charaId.hashCode()
result = 31 * result + fromCharaId.hashCode()
result = 31 * result + spriteIdle.contentHashCode()
result = 31 * result + spriteWidth
result = 31 * result + spriteHeight
result = 31 * result + (discoveredOn?.hashCode() ?: 0)
result = 31 * result + fusionAttribute.hashCode()
return result
}
}
}
@@ -1,10 +1,15 @@
package com.github.nacabaro.vbhelper.screens
/**
* This is me, nacabaro.
* File related to battles.
* TODO: Refactor this, 2400+ lines feels like a lot.
*/
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.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
@@ -28,10 +33,6 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.material3.LinearProgressIndicator
//import androidx.compose.material3.ExposedDropdownMenuBox
//import androidx.compose.material3.ExposedDropdownMenuDefaults
//import androidx.compose.material3.OutlinedTextField
//import androidx.compose.material3.DropdownMenuItem
import androidx.compose.foundation.layout.Box
import androidx.compose.ui.platform.LocalContext
import androidx.compose.runtime.LaunchedEffect
@@ -51,8 +52,6 @@ import android.content.Intent
import android.net.Uri
import android.media.MediaPlayer
import android.os.Environment
//import androidx.compose.animation.core.animateFloatAsState
//import androidx.compose.animation.core.tween
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import androidx.compose.runtime.rememberCoroutineScope
@@ -72,13 +71,8 @@ import com.github.nacabaro.vbhelper.battle.AnimatedSpriteImage
import com.github.nacabaro.vbhelper.battle.HitEffectOverlay
import com.github.nacabaro.vbhelper.battle.BattleAuthContainer
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.collect
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
//import kotlin.math.sin
//import kotlin.math.PI
//import androidx.compose.animation.core.animateDpAsState
//import androidx.compose.animation.core.animateIntAsState
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Shadow
@@ -86,24 +80,20 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.foundation.Image
import androidx.compose.ui.graphics.asImageBitmap
import android.graphics.BitmapFactory
//import android.os.Environment
import java.io.File
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.foundation.layout.width
import com.github.nacabaro.vbhelper.di.VBHelper
import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.material3.AlertDialog
@Composable
/*@Composable
fun isLandscapeMode(): Boolean {
val configuration = LocalConfiguration.current
return configuration.screenWidthDp > configuration.screenHeightDp
}
}*/
@Composable
fun getLandscapeModifier(): Modifier {
@@ -1735,7 +1725,7 @@ fun BattlesScreen() {
val currentCharacter = activeUserCharacter
if (currentCharacter != null && canBattle && playerBattleType != null) {
try {
RetrofitHelper().getOpponents(context, playerBattleType!!) { opponents ->
RetrofitHelper().getOpponents(context, playerBattleType) { opponents ->
try {
// Create a new list to trigger UI recomposition
opponentsList = ArrayList(opponents.opponentsList)
@@ -2134,8 +2124,8 @@ fun BattlesScreen() {
// Create APIBattleCharacter from database character
val playerCharacter = APIBattleCharacter(
name = "Player Digimon", // We could get this from the database if needed
namekey = "player_digimon", // Name key for the character
name = "Player Character", // We could get this from the database if needed
namekey = "player_digimon", // Name key for the character (functional lookup key, not shown)
charaId = formattedCardId, // Use the formatted card ID for sprite loading
stage = characterData.stage,
attribute = characterData.attribute.ordinal, // Convert enum to int
@@ -2242,10 +2232,10 @@ fun BattlesScreen() {
) {
// Show active character info
activeUserCharacter?.let { character ->
Text("Active Digimon:")
Text("Active character:")
Text("Stage: ${character.stage}")
activeCardId?.let { cardId ->
Text("Digimon ID: $cardId", fontSize = 14.sp, color = Color.Blue, fontWeight = FontWeight.Bold)
Text("Character ID: $cardId", fontSize = 14.sp, color = Color.Blue, fontWeight = FontWeight.Bold)
}
Spacer(modifier = Modifier.height(16.dp))
@@ -2346,7 +2336,7 @@ fun BattlesScreen() {
textAlign = TextAlign.Center)
}
} else {
Text("Your Digimon must be at least Stage 2 to battle",
Text("Your character must be at least Stage 2 to battle",
fontSize = 16.sp,
color = Color.Red,
textAlign = TextAlign.Center)
@@ -2415,7 +2405,7 @@ fun BattlesScreen() {
// Also check winner field if it's not empty
val playerWonFromWinner = activeCardId?.let { cardId ->
val winner = apiResult.winner ?: ""
val winner = apiResult.winner
if (winner.isNotEmpty()) {
if (winner.contains("|")) {
// Pipe-separated format: first part is the winner
@@ -2442,7 +2432,7 @@ fun BattlesScreen() {
println("BATTLESCREEN: Battle result (first call) - winner: '${apiResult.winner}', playerHP: ${apiResult.playerHP}, opponentHP: ${apiResult.opponentHP}, playerWonFromHP: $playerWonFromHP, playerWonFromWinner: $playerWonFromWinner, final playerWon: $playerWon")
// Store winner name for display (will be updated in cleanup call if available)
winnerName = apiResult.winner ?: if (playerWon) "You" else "Opponent"
winnerName = apiResult.winner
isWinnerLoaded = true
// Then send the cleanup call - this will have the actual winner name
@@ -2465,7 +2455,7 @@ fun BattlesScreen() {
// Primary method: Check HP values (opponentHP <= 0 means opponent lost = player won)
// Secondary method: Check winner name (if winner doesn't match opponent, player won)
val opponentName = selectedOpponent?.name ?: ""
val winner = cleanupResult.winner ?: ""
val winner = cleanupResult.winner
// Primary: HP-based determination (most reliable)
// If opponentHP <= 0, opponent is dead = player won
@@ -4,9 +4,9 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -34,7 +34,7 @@ fun ItemsScreen(
topBar = {
Column {
TopBanner(text = stringResource(R.string.items_title))
TabRow(
PrimaryTabRow(
selectedTabIndex = selectedTabItem,
modifier = Modifier
) {
@@ -43,7 +43,7 @@ fun ChooseConnectOption(
.padding(contentPadding)
) {
Text(
text = "Bandai Toys = Vital Bracelet, Vital Hero, BE Bracelet",
text = "VB, VH, VBBE",
fontSize = 14.sp,
modifier = Modifier.padding(bottom = 24.dp)
)
@@ -231,9 +231,7 @@ class ScanScreenControllerImpl(
val proto = VitalWearCharacterExporter(componentActivity, database).buildCharacterProto(characterId)
val client = VitalWearHceReaderClient(isoDep)
client.sendCharacterToWatch(proto)
database.userCharacterDao().deleteCharacterById(characterId)
pendingExportCharacterId = null
Log.i("NFC_WRITE", "Character sent to VitalWear and deleted from app (id=$characterId)")
Log.i("NFC_WRITE", "Character sent to VitalWear (id=$characterId), deletion deferred to WritingScreen")
componentActivity.runOnUiThread {
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_sent_character_success), Toast.LENGTH_SHORT).show()
}
@@ -104,7 +104,7 @@ fun TransferAnimationScreen(
) {
Image(
bitmap = preview.imageBitmap,
contentDescription = "Transferred Digimon sprite",
contentDescription = "Transferred character sprite",
modifier = Modifier
.size(preview.dpWidth, preview.dpHeight)
.padding(8.dp),
@@ -136,7 +136,7 @@ class SettingsScreenControllerImpl(
secrets = secretsImporter.importSecrets(it)
} catch (e: Exception) {
context.runOnUiThread {
Toast.makeText(context, "Secrets import failed. Please only select the official Vital Arena App 2.1.0 APK.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "Secrets import failed. Please only select the official app APK.", Toast.LENGTH_SHORT).show()
}
return@launch
}
@@ -13,7 +13,27 @@ data class BitmapData (
val bitmap: ByteArray,
val width: Int,
val height: Int
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BitmapData
if (!bitmap.contentEquals(other.bitmap)) return false
if (width != other.width) return false
if (height != other.height) return false
return true
}
override fun hashCode(): Int {
var result = bitmap.contentHashCode()
result = 31 * result + width
result = 31 * result + height
return result
}
}
data class ImageBitmapData(
val imageBitmap: ImageBitmap,
+3 -5
View File
@@ -24,7 +24,7 @@
<string name="scan_sent_dim_success">DIMの転送に成功しました。</string>
<string name="scan_nfc_must_be_enabled">NFC機能を有効にして下さい。</string>
<string name="settings_title">設定</string>
<string name="scan_missing_secrets">Vital ArenaのAPKを読み込みして下さい。</string>
<string name="scan_missing_secrets">公式アプリのAPKを読み込みして下さい。</string>
<string name="scan_sent_character_success">転送が成功しました。</string>
<string name="scan_error_generic">エラー</string>
<string name="settings_about_desc">このアプリについて</string>
@@ -56,7 +56,6 @@
<string name="storage_character_image_description">キャラクター画像</string>
<string name="storage_send_to_watch">デバイスへ転送</string>
<string name="storage_send_to_vitalwear">VitalWearへ転送</string>
<string name="storage_send_to_vitalwear">VitalWearへ転送</string>
<string name="storage_set_active">選択</string>
<string name="storage_send_on_adventure">アドベンチャーへ出発</string>
<string name="scan_no_nfc_on_device">NFC機能が見つかりません。</string>
@@ -65,7 +64,7 @@
<string name="settings_section_dim_bem">DiM / BEm管理</string>
<string name="settings_section_data">データ管理</string>
<string name="settings_import_apk_title">アプリのインポート</string>
<string name="settings_import_apk_desc">Vital Arena 2.1.0のAPKファイルを読み込みします。</string>
<string name="settings_import_apk_desc">公式アプリのAPKファイルを読み込みします。</string>
<string name="settings_import_card_title">カードのインポート</string>
<string name="settings_section_about">概要 / クレジット</string>
<string name="dex_chara_fusions_button">ジョグレス</string>
@@ -111,7 +110,7 @@
<string name="write_card_required_card">%1$s カードが必要です。</string>
<string name="write_card_confirm">転送</string>
<string name="write_character_success">カードの読み込みが完了しました。</string>
<string name="write_character_wait_ready">" デバイスの準備をしてから確認を押して下さい。"</string>
<string name="write_character_wait_ready">デバイスの準備をしてから確認を押して下さい。</string>
<string name="write_character_confirm">確認</string>
<string name="home_vbdim_trophies">トロフィー</string>
<string name="items_purchase_success">購入しました。</string>
@@ -147,7 +146,6 @@
<string name="special_mission_battles_progress">バトル %1$d 回</string>
<string name="special_mission_wins_progress">勝利 %1$d 回</string>
<string name="settings_companion_import_card_image_title">カードのインポート</string>
<string name="settings_companion_import_card_image_title">カードのインポート</string>
<string name="companion_validation_connect_vb">デバイスに接続</string>
<string name="companion_card_import_success">カードのインポートに成功しました。</string>
<string name="companion_firmware_no_watch">デバイスが見つかりません。</string>
+7 -7
View File
@@ -43,13 +43,13 @@
Os segredos ainda não foram importados. Vá em Configurações e importe o APK.
</string>
<string name="scan_title">Escanear um Vital Bracelet</string>
<string name="scan_vb_to_app">Vital Bracelet para o app</string>
<string name="scan_app_to_vb">App para o Vital Bracelet</string>
<string name="scan_title">Escanear um VB</string>
<string name="scan_vb_to_app">VB para o app</string>
<string name="scan_app_to_vb">App para o VB</string>
<string name="scan_no_nfc_on_device">O dispositivo não possui NFC!</string>
<string name="scan_tag_not_vb">A tag detectada não é do Vital Bracelet.</string>
<string name="scan_missing_secrets">" Segredos ausentes. Vá em Configurações e importe o APK do Vital Arena. "</string>
<string name="scan_tag_not_vb">A tag detectada não é do VB.</string>
<string name="scan_missing_secrets">" Segredos ausentes. Vá em Configurações e importe o APK do app oficial. "</string>
<string name="scan_sent_character_success">Personagem enviado com sucesso!</string>
<string name="scan_error_generic">Ops!</string>
<string name="scan_sent_dim_success">DIM enviado com sucesso!</string>
@@ -64,7 +64,7 @@
<string name="settings_import_apk_title">Importar APK</string>
<string name="settings_import_apk_desc">
Importar segredos do APK do Vital Arena 2.1.0
Importar segredos do APK do app oficial
</string>
<string name="settings_import_card_title">Importar card</string>
@@ -106,7 +106,7 @@
Responsável pelo design do ícone do aplicativo em SVG.
</string>
<string name="action_place_near_reader">Aproxime o seu Vital Bracelet do leitor...</string>
<string name="action_place_near_reader">Aproxime o seu VB do leitor...</string>
<string name="action_cancel">Cancelar</string>
<string name="read_character_title">Ler personagem</string>
+6 -6
View File
@@ -43,13 +43,13 @@
Secrets not yet imported. Go to Settings and Import APK.
</string>
<string name="scan_title">Scan a Vital Bracelet</string>
<string name="scan_title">Scan a VB</string>
<string name="scan_vb_to_app">Watch to VBH</string>
<string name="scan_app_to_vb">VBH to Watch</string>
<string name="scan_no_nfc_on_device">No NFC on device!</string>
<string name="scan_tag_not_vb">Tag detected is not VB</string>
<string name="scan_missing_secrets">" Missing Secrets. Go to settings and import Vital Arena APK. "</string>
<string name="scan_missing_secrets">" Missing Secrets. Go to settings and import the official app APK. "</string>
<string name="scan_sent_character_success">Sent character successfully!</string>
<string name="scan_error_generic">Whoops</string>
<string name="scan_sent_dim_success">Sent DIM successfully!</string>
@@ -65,7 +65,7 @@
<string name="settings_import_apk_title">Import APK</string>
<string name="settings_import_apk_desc">
Import Secrets From Vital Arena APK
Import Secrets From the official app APK
</string>
<string name="settings_import_card_title">Import card</string>
@@ -109,7 +109,7 @@
<string name="credits_RedEyez_description">
Devout Debugger.
</string>
<string name="action_place_near_reader">Place your Vital Bracelet near the reader...</string>
<string name="action_place_near_reader">Place your VB near the reader...</string>
<string name="action_cancel">Cancel</string>
<string name="read_character_title">Read character</string>
@@ -220,10 +220,10 @@
<string name="home_special_mission_delete_remove">Remove</string>
<string name="settings_companion_import_card_image_title">Import Card Image</string>
<string name="companion_validation_connect_vb">Connect Vital Bracelet</string>
<string name="companion_validation_connect_vb">Connect VB</string>
<string name="companion_card_import_success">Card imported successfully!</string>
<string name="companion_firmware_no_watch">No watch found!</string>
<string name="companion_validation_insert_card">Insert card into Vital Bracelet</string>
<string name="companion_validation_insert_card">Insert card into VB</string>
<string name="companion_validation_success">Validation successful!</string>
<string name="companion_loading_select_firmware">Select firmware file</string>
<string name="companion_firmware_sent_success">Firmware sent successfully!</string>
-7
View File
@@ -21,13 +21,6 @@ kotlin.code.style=official
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.defaults.buildfeatures.resvalues=true
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
android.enableAppCompileTimeRClass=false
android.usesSdkInManifest.disallowed=false
android.uniquePackageNames=false
android.dependency.useConstraints=true
android.r8.strictFullModeForKeepRules=false
android.r8.optimizedResourceShrinking=false
android.builtInKotlin=false
android.newDsl=false
+15 -16
View File
@@ -1,19 +1,19 @@
[versions]
agp = "9.2.1"
datastore = "1.2.0"
datastorePreferences = "1.2.0"
kotlin = "2.3.0"
coreKtx = "1.17.0"
datastore = "1.2.1"
datastorePreferences = "1.2.1"
kotlin = "2.4.0"
coreKtx = "1.19.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.10.0"
activityCompose = "1.12.2"
composeBom = "2026.01.00"
material = "1.13.0"
navigationCompose = "2.9.6"
protobufGradlePlugin = "0.9.6"
protobufJavalite = "4.33.4"
lifecycleRuntimeKtx = "2.11.0"
activityCompose = "1.13.0"
composeBom = "2026.06.00"
material = "1.14.0"
navigationCompose = "2.9.8"
protobufGradlePlugin = "0.10.0"
protobufJavalite = "4.35.1"
roomRuntime = "2.8.4"
vbNfcReader = "0.2.0-SNAPSHOT"
dimReader = "2.1.0"
@@ -21,10 +21,10 @@ playServicesWearable = "20.0.1"
kotlinxCoroutinesPlayServices = "1.11.0"
timber = "5.0.1"
tinylog = "2.7.0"
retrofit = "2.9.0"
gson = "2.10.1"
okhttp = "4.11.0"
ksp = "2.3.2"
retrofit = "3.0.0"
gson = "2.14.0"
okhttp = "5.4.0"
ksp = "2.3.9"
[libraries]
androidx-compose-material = { module = "androidx.compose.material:material" }
@@ -50,7 +50,6 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
material = { module = "com.google.android.material:material", version.ref = "material" }
protobuf-gradle-plugin = { module = "com.google.protobuf:protobuf-gradle-plugin", version.ref = "protobufGradlePlugin" }
protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" }
vb-nfc-reader = { module = "com.github.cfogrady:vb-nfc-reader", version.ref = "vbNfcReader" }
dim-reader = { module = "com.github.cfogrady:vb-dim-reader", version.ref = "dimReader" }
+1 -1
View File
@@ -1,6 +1,6 @@
#Tue Dec 24 10:55:57 UTC 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists