diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9959b40..67ad8c5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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,12 +9,12 @@ 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" @@ -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 { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 39fa631..8af1134 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + @@ -34,7 +35,6 @@ @@ -51,8 +51,10 @@ - - + + + + diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt index 7167b97..2c3635b 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/AdventureDao.kt @@ -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) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardFusionsDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardFusionsDao.kt index 86d6a9a..6ce12e9 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardFusionsDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/CardFusionsDao.kt @@ -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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt index 680c162..4bab3e3 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt @@ -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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt b/app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt index ee83e66..035d20d 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/database/AppDatabase.kt @@ -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, diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Background.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Background.kt index 23766d4..edc9e60 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Background.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Background.kt @@ -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 -) \ No newline at end of file +) { + 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 + } +} diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Card.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Card.kt index 87a2ba1..84fbf89 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Card.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/Card.kt @@ -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 + } +} diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardAdventure.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardAdventure.kt index b8f4f56..c1083c1 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardAdventure.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardAdventure.kt @@ -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( @@ -29,4 +34,4 @@ data class CardAdventure( val bossAp: Int, val bossDp: Int, val bossBp: Int? -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardCharacter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardCharacter.kt index 050cc9a..3856912 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardCharacter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardCharacter.kt @@ -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 -) \ No newline at end of file +) { + 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 + } +} diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardFusions.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardFusions.kt index 1769eda..473e32f 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardFusions.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/CardFusions.kt @@ -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( @@ -26,4 +31,4 @@ data class CardFusions( val fromCharaId: Long, val attribute: NfcCharacter.Attribute, val toCharaId: Long -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/PossibleTransformations.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/PossibleTransformations.kt index 2dc2e8b..895997e 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/PossibleTransformations.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/card/PossibleTransformations.kt @@ -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 ( @@ -30,4 +35,4 @@ data class PossibleTransformations ( val changeTimerHours: Int, val requiredAdventureLevelCompleted: Int, val toCharaId: Long? -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/characters/Sprite.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/characters/Sprite.kt index 1cb0d00..8c28c50 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/characters/Sprite.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/characters/Sprite.kt @@ -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 + } +} diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/SpecialMissions.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/SpecialMissions.kt index 13b092d..e41beb2 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/SpecialMissions.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/SpecialMissions.kt @@ -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, @@ -25,4 +27,4 @@ data class SpecialMissions ( val timeElapsedInMinutes: Int, val timeLimitInMinutes: Int, val missionType: SpecialMission.Type -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt index 0a560cc..d5427f0 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/TransformationHistory.kt @@ -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 ( diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt index e34b57d..6fa08b1 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/UserCharacter.kt @@ -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 @@ -37,4 +39,4 @@ data class UserCharacter ( var heartRateCurrent: Int, var characterType: DeviceType, var isActive: Boolean -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/VitalsHistory.kt b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/VitalsHistory.kt index 313e7c1..ac9b5cc 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/VitalsHistory.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/domain/device_data/VitalsHistory.kt @@ -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, @@ -21,4 +23,4 @@ data class VitalsHistory ( val month: Int, val day: Int, val vitalPoints: Int -) \ No newline at end of file +) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt index 78c5d27..9d2868c 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CardDtos.kt @@ -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 + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt index 0131e6f..ae32d25 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/dtos/CharacterDtos.kt @@ -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 + } + } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt index dad71ac..e9117d6 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt @@ -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) @@ -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 diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreen.kt index 63ca4c5..3cf748d 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ItemsScreen.kt @@ -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 ) { diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/utils/BitmapData.kt b/app/src/main/java/com/github/nacabaro/vbhelper/utils/BitmapData.kt index eae66e2..e3d3db2 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/utils/BitmapData.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/utils/BitmapData.kt @@ -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, diff --git a/app/src/main/java/com/github/nacabhelper/screens/BattlesScreen.kt b/app/src/main/java/com/github/nacabhelper/screens/BattlesScreen.kt deleted file mode 100644 index 0519ecb..0000000 --- a/app/src/main/java/com/github/nacabhelper/screens/BattlesScreen.kt +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a3f894d..d0404cd 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -56,7 +56,6 @@ キャラクター画像 デバイスへ転送 VitalWearへ転送 - VitalWearへ転送 選択 アドベンチャーへ出発 NFC機能が見つかりません。 @@ -111,7 +110,7 @@ %1$s カードが必要です。 転送 カードの読み込みが完了しました。 - " デバイスの準備をしてから確認を押して下さい。" + デバイスの準備をしてから確認を押して下さい。 確認 トロフィー 購入しました。 @@ -147,7 +146,6 @@ バトル %1$d 回 勝利 %1$d 回 カードのインポート - カードのインポート デバイスに接続 カードのインポートに成功しました。 デバイスが見つかりません。 @@ -160,4 +158,4 @@ 注意:ログの転送には時間がかかる場合があります。 ログの送信 現在、転送は無効になっています。 - \ No newline at end of file + diff --git a/gradle.properties b/gradle.properties index 4540b75..c68d2e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aebc19f..8e29ab3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ebefeb4..50b680d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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