mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-07-30 00:31:54 +00:00
Merge pull request #55 from b13st/fix/vitalwear-hce-transfer
Fix VitalWear HCE transfer in both directions
This commit is contained in:
commit
81bfec5ac5
@ -49,7 +49,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
application.container.dataStoreSecretsRepository.secretsFlow,
|
application.container.dataStoreSecretsRepository.secretsFlow,
|
||||||
this,
|
this,
|
||||||
this::registerActivityLifecycleListener,
|
this::registerActivityLifecycleListener,
|
||||||
this::unregisterActivityLifecycleListener
|
this::unregisterActivityLifecycleListener,
|
||||||
|
application.container.db,
|
||||||
)
|
)
|
||||||
val settingsScreenController = SettingsScreenControllerImpl(this)
|
val settingsScreenController = SettingsScreenControllerImpl(this)
|
||||||
val itemsScreenController = ItemsScreenControllerImpl(this)
|
val itemsScreenController = ItemsScreenControllerImpl(this)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.github.nacabaro.vbhelper.screens.scanScreen
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.nfc.NfcAdapter
|
import android.nfc.NfcAdapter
|
||||||
import android.nfc.Tag
|
import android.nfc.Tag
|
||||||
|
import android.nfc.tech.IsoDep
|
||||||
import android.nfc.tech.NfcA
|
import android.nfc.tech.NfcA
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
@ -15,12 +16,16 @@ import com.github.cfogrady.vbnfc.be.BENfcCharacter
|
|||||||
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
|
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
|
||||||
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
||||||
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
import com.github.nacabaro.vbhelper.domain.card.Card
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.FromNfcConverter
|
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.FromNfcConverter
|
||||||
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.ToNfcConverter
|
import com.github.nacabaro.vbhelper.screens.scanScreen.converters.ToNfcConverter
|
||||||
|
import com.github.nacabaro.vbhelper.source.VitalWearCharacterExporter
|
||||||
|
import com.github.nacabaro.vbhelper.source.VitalWearCharacterImporter
|
||||||
import com.github.nacabaro.vbhelper.source.getCryptographicTransformerMap
|
import com.github.nacabaro.vbhelper.source.getCryptographicTransformerMap
|
||||||
import com.github.nacabaro.vbhelper.source.isMissingSecrets
|
import com.github.nacabaro.vbhelper.source.isMissingSecrets
|
||||||
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
||||||
|
import com.github.nacabaro.vbhelper.transfer.hce.VitalWearHceReaderClient
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
@ -32,8 +37,10 @@ class ScanScreenControllerImpl(
|
|||||||
private val componentActivity: ComponentActivity,
|
private val componentActivity: ComponentActivity,
|
||||||
private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit,
|
private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit,
|
||||||
private val unregisterActivityLifecycleListener: (String)->Unit,
|
private val unregisterActivityLifecycleListener: (String)->Unit,
|
||||||
|
private val database: AppDatabase,
|
||||||
): ScanScreenController {
|
): ScanScreenController {
|
||||||
private var lastScannedCharacter: NfcCharacter? = null
|
private var lastScannedCharacter: NfcCharacter? = null
|
||||||
|
private var pendingExportCharacterId: Long? = null
|
||||||
private val nfcAdapter: NfcAdapter
|
private val nfcAdapter: NfcAdapter
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -46,24 +53,46 @@ class ScanScreenControllerImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {
|
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {
|
||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(
|
||||||
try {
|
secrets,
|
||||||
val character = tagCommunicator.receiveCharacter()
|
handlerFunc = { tagCommunicator ->
|
||||||
val resultMessage = characterFromNfc(character) { cards, nfcCharacter ->
|
try {
|
||||||
lastScannedCharacter = nfcCharacter
|
val character = tagCommunicator.receiveCharacter()
|
||||||
onMultipleCards(cards)
|
val resultMessage = characterFromNfc(character) { cards, nfcCharacter ->
|
||||||
|
lastScannedCharacter = nfcCharacter
|
||||||
|
onMultipleCards(cards)
|
||||||
|
}
|
||||||
|
onComplete.invoke()
|
||||||
|
resultMessage
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("NFC_READ", "Error reading character from NFC", e)
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_error_generic) + ": " + (e.message ?: e.javaClass.simpleName), Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
onComplete.invoke()
|
||||||
|
componentActivity.getString(R.string.scan_error_generic)
|
||||||
}
|
}
|
||||||
onComplete.invoke()
|
},
|
||||||
resultMessage
|
hceHandler = { isoDep ->
|
||||||
} catch (e: Exception) {
|
try {
|
||||||
Log.e("NFC_READ", "Error reading character from NFC", e)
|
val client = VitalWearHceReaderClient(isoDep)
|
||||||
componentActivity.runOnUiThread {
|
val character = client.receiveCharacterFromWatch()
|
||||||
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_error_generic) + ": " + (e.message ?: e.javaClass.simpleName), Toast.LENGTH_LONG).show()
|
val importer = VitalWearCharacterImporter(database)
|
||||||
|
val result = importer.importCharacter(character)
|
||||||
|
Log.i("NFC_READ", "VitalWear HCE import: ${result.message}")
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, result.message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("NFC_READ", "Error reading character from VitalWear HCE", e)
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_error_generic) + ": " + (e.message ?: e.javaClass.simpleName), Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
onComplete()
|
||||||
}
|
}
|
||||||
onComplete.invoke()
|
|
||||||
componentActivity.getString(R.string.scan_error_generic)
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelRead() {
|
override fun cancelRead() {
|
||||||
@ -83,35 +112,53 @@ class ScanScreenControllerImpl(
|
|||||||
unregisterActivityLifecycleListener.invoke(key)
|
unregisterActivityLifecycleListener.invoke(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
private fun handleTag(
|
||||||
private fun handleTag(secrets: Secrets, handlerFunc: (TagCommunicator)->String) {
|
secrets: Secrets,
|
||||||
|
handlerFunc: (TagCommunicator) -> String,
|
||||||
|
hceHandler: ((IsoDep) -> Unit)? = null,
|
||||||
|
) {
|
||||||
if (!nfcAdapter.isEnabled) {
|
if (!nfcAdapter.isEnabled) {
|
||||||
showWirelessSettings()
|
showWirelessSettings()
|
||||||
} else {
|
} else {
|
||||||
val options = Bundle()
|
val options = Bundle()
|
||||||
// Work around for some broken Nfc firmware implementations that poll the card too fast
|
// Work around for some broken Nfc firmware implementations that poll the card too fast
|
||||||
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250)
|
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250)
|
||||||
nfcAdapter.enableReaderMode(componentActivity, buildOnReadTag(secrets, handlerFunc), NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
nfcAdapter.enableReaderMode(
|
||||||
|
componentActivity,
|
||||||
|
buildOnReadTag(secrets, handlerFunc, hceHandler),
|
||||||
|
NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
private fun buildOnReadTag(
|
||||||
private fun buildOnReadTag(secrets: Secrets, handlerFunc: (TagCommunicator)->String): (Tag)->Unit {
|
secrets: Secrets,
|
||||||
return { tag->
|
handlerFunc: (TagCommunicator) -> String,
|
||||||
val nfcData = NfcA.get(tag)
|
hceHandler: ((IsoDep) -> Unit)? = null,
|
||||||
if (nfcData == null) {
|
): (Tag) -> Unit {
|
||||||
componentActivity.runOnUiThread {
|
return { tag ->
|
||||||
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_tag_not_vb), Toast.LENGTH_SHORT).show()
|
val isoDep = IsoDep.get(tag)
|
||||||
}
|
if (isoDep != null && hceHandler != null) {
|
||||||
}
|
// VitalWear watch via HCE / ISO-DEP
|
||||||
nfcData.connect()
|
isoDep.connect()
|
||||||
nfcData.use {
|
isoDep.use { hceHandler(isoDep) }
|
||||||
val tagCommunicator = TagCommunicator.getInstance(nfcData, secrets.getCryptographicTransformerMap())
|
} else {
|
||||||
val successText = handlerFunc(tagCommunicator)
|
// Physical Vital Bracelet via raw NFC-A
|
||||||
componentActivity.runOnUiThread {
|
val nfcData = NfcA.get(tag)
|
||||||
Toast.makeText(componentActivity, successText, Toast.LENGTH_SHORT).show()
|
if (nfcData == null) {
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_tag_not_vb), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nfcData.connect()
|
||||||
|
nfcData.use {
|
||||||
|
val tagCommunicator = TagCommunicator.getInstance(nfcData, secrets.getCryptographicTransformerMap())
|
||||||
|
val successText = handlerFunc(tagCommunicator)
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, successText, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,24 +179,29 @@ class ScanScreenControllerImpl(
|
|||||||
nfcCharacter: NfcCharacter,
|
nfcCharacter: NfcCharacter,
|
||||||
onComplete: () -> Unit
|
onComplete: () -> Unit
|
||||||
) {
|
) {
|
||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(
|
||||||
try {
|
secrets,
|
||||||
if (nfcCharacter is VBNfcCharacter) {
|
handlerFunc = { tagCommunicator ->
|
||||||
Log.d("SendCharacter", "VBNfcCharacter")
|
try {
|
||||||
val castNfcCharacter: VBNfcCharacter = nfcCharacter
|
if (nfcCharacter is VBNfcCharacter) {
|
||||||
tagCommunicator.sendCharacter(castNfcCharacter)
|
Log.d("SendCharacter", "VBNfcCharacter")
|
||||||
} else if (nfcCharacter is BENfcCharacter) {
|
tagCommunicator.sendCharacter(nfcCharacter)
|
||||||
Log.d("SendCharacter", "BENfcCharacter")
|
} else if (nfcCharacter is BENfcCharacter) {
|
||||||
val castNfcCharacter: BENfcCharacter = nfcCharacter
|
Log.d("SendCharacter", "BENfcCharacter")
|
||||||
tagCommunicator.sendCharacter(castNfcCharacter)
|
tagCommunicator.sendCharacter(nfcCharacter)
|
||||||
|
}
|
||||||
|
onComplete.invoke()
|
||||||
|
componentActivity.getString(R.string.scan_sent_character_success)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e("TAG", e.stackTraceToString())
|
||||||
|
componentActivity.getString(R.string.scan_error_generic)
|
||||||
}
|
}
|
||||||
onComplete.invoke()
|
},
|
||||||
componentActivity.getString(R.string.scan_sent_character_success)
|
hceHandler = { _ ->
|
||||||
} catch (e: Throwable) {
|
// Character was already sent in onClickCheckCard's HCE handler.
|
||||||
Log.e("TAG", e.stackTraceToString())
|
onComplete()
|
||||||
componentActivity.getString(R.string.scan_error_generic)
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClickCheckCard(
|
override fun onClickCheckCard(
|
||||||
@ -157,11 +209,42 @@ class ScanScreenControllerImpl(
|
|||||||
nfcCharacter: NfcCharacter,
|
nfcCharacter: NfcCharacter,
|
||||||
onComplete: () -> Unit
|
onComplete: () -> Unit
|
||||||
) {
|
) {
|
||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(
|
||||||
tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId)
|
secrets,
|
||||||
onComplete.invoke()
|
handlerFunc = { tagCommunicator ->
|
||||||
componentActivity.getString(R.string.scan_sent_dim_success)
|
tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId)
|
||||||
}
|
onComplete.invoke()
|
||||||
|
componentActivity.getString(R.string.scan_sent_dim_success)
|
||||||
|
},
|
||||||
|
hceHandler = { isoDep ->
|
||||||
|
// VitalWear watch: send the character proto directly via HCE.
|
||||||
|
val characterId = pendingExportCharacterId
|
||||||
|
if (characterId == null) {
|
||||||
|
Log.e("NFC_WRITE", "No pending character to send to VitalWear")
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_error_generic), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
onComplete()
|
||||||
|
return@handleTag
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val proto = VitalWearCharacterExporter(componentActivity, database).buildCharacterProto(characterId)
|
||||||
|
val client = VitalWearHceReaderClient(isoDep)
|
||||||
|
client.sendCharacterToWatch(proto)
|
||||||
|
Log.i("NFC_WRITE", "Character sent to VitalWear via HCE")
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_sent_character_success), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("NFC_WRITE", "Error sending character to VitalWear HCE", e)
|
||||||
|
componentActivity.runOnUiThread {
|
||||||
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_error_generic) + ": " + (e.message ?: e.javaClass.simpleName), Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
||||||
@ -181,10 +264,8 @@ class ScanScreenControllerImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun characterToNfc(characterId: Long): NfcCharacter {
|
override suspend fun characterToNfc(characterId: Long): NfcCharacter {
|
||||||
val nfcGenerator = ToNfcConverter(
|
pendingExportCharacterId = characterId
|
||||||
componentActivity = componentActivity
|
val nfcGenerator = ToNfcConverter(componentActivity = componentActivity)
|
||||||
)
|
|
||||||
|
|
||||||
val character = nfcGenerator.characterToNfc(characterId)
|
val character = nfcGenerator.characterToNfc(characterId)
|
||||||
Log.d("CharacterType", character.toString())
|
Log.d("CharacterType", character.toString())
|
||||||
return character
|
return character
|
||||||
|
|||||||
@ -15,52 +15,56 @@ class VitalWearCharacterExporter(
|
|||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val database: AppDatabase
|
private val database: AppDatabase
|
||||||
) {
|
) {
|
||||||
|
fun buildCharacterProto(characterId: Long): Character = runBlocking {
|
||||||
|
val characterWithSprites = database.userCharacterDao().getCharacterWithSprites(characterId)
|
||||||
|
val userCharacter = database.userCharacterDao().getCharacter(characterId)
|
||||||
|
val card = database.cardDao().getCardByCharacterIdSync(characterId)
|
||||||
|
?: error("Card not found for character $characterId")
|
||||||
|
val cardProgress = database.cardProgressDao().getCardProgressSync(card.id) ?: 0
|
||||||
|
Character.newBuilder()
|
||||||
|
.setCardId(card.cardId)
|
||||||
|
.setCardName(card.name)
|
||||||
|
.setCharacterStats(
|
||||||
|
Character.CharacterStats.newBuilder()
|
||||||
|
.setSlotId(database.userCharacterDao().getCharacterInfo(characterId).charaIndex)
|
||||||
|
.setVitals(characterWithSprites.vitalPoints)
|
||||||
|
.setTrainingTimeRemainingInSeconds(resolveTrainingSeconds(characterId, userCharacter.characterType))
|
||||||
|
.setTimeUntilNextTransformation(characterWithSprites.transformationCountdown.toLong() * 60L)
|
||||||
|
.setTrainedBp(resolveTrainedBp(characterId, userCharacter.characterType))
|
||||||
|
.setTrainedHp(resolveTrainedHp(characterId, userCharacter.characterType))
|
||||||
|
.setTrainedAp(resolveTrainedAp(characterId, userCharacter.characterType))
|
||||||
|
.setTrainedPp(characterWithSprites.trophies)
|
||||||
|
.setInjured(characterWithSprites.injuryStatus.name.lowercase().contains("inj"))
|
||||||
|
.setAccumulatedDailyInjuries(0)
|
||||||
|
.setTotalBattles(characterWithSprites.totalBattlesWon + characterWithSprites.totalBattlesLost)
|
||||||
|
.setCurrentPhaseBattles(characterWithSprites.currentPhaseBattlesWon + characterWithSprites.currentPhaseBattlesLost)
|
||||||
|
.setTotalWins(characterWithSprites.totalBattlesWon)
|
||||||
|
.setCurrentPhaseWins(characterWithSprites.currentPhaseBattlesWon)
|
||||||
|
.setMood(characterWithSprites.mood)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.setSettings(
|
||||||
|
Character.Settings.newBuilder()
|
||||||
|
.setTrainingInBackground(false)
|
||||||
|
.setAllowedBattles(Character.Settings.AllowedBattles.CARD_ONLY)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.putMaxAdventureCompletedByCard(card.name, (cardProgress - 1).coerceAtLeast(0))
|
||||||
|
.addAllTransformationHistory(
|
||||||
|
database.userCharacterDao().getTransformationHistoryForExport(characterId).map {
|
||||||
|
Character.TransformationEvent.newBuilder()
|
||||||
|
.setCardName(it.cardName)
|
||||||
|
.setPhase(0)
|
||||||
|
.setSlotId(it.monIndex)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
fun buildShareIntent(characterId: Long): Intent {
|
fun buildShareIntent(characterId: Long): Intent {
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
val characterWithSprites = database.userCharacterDao().getCharacterWithSprites(characterId)
|
val proto = buildCharacterProto(characterId)
|
||||||
val userCharacter = database.userCharacterDao().getCharacter(characterId)
|
|
||||||
val card = database.cardDao().getCardByCharacterIdSync(characterId)
|
|
||||||
?: error("Card not found for character $characterId")
|
|
||||||
val cardProgress = database.cardProgressDao().getCardProgressSync(card.id) ?: 0
|
|
||||||
val proto = Character.newBuilder()
|
|
||||||
.setCardId(card.cardId)
|
|
||||||
.setCardName(card.name)
|
|
||||||
.setCharacterStats(
|
|
||||||
Character.CharacterStats.newBuilder()
|
|
||||||
.setSlotId(database.userCharacterDao().getCharacterInfo(characterId).charaIndex)
|
|
||||||
.setVitals(characterWithSprites.vitalPoints)
|
|
||||||
.setTrainingTimeRemainingInSeconds(resolveTrainingSeconds(characterId, userCharacter.characterType))
|
|
||||||
.setTimeUntilNextTransformation(characterWithSprites.transformationCountdown.toLong() * 60L)
|
|
||||||
.setTrainedBp(resolveTrainedBp(characterId, userCharacter.characterType))
|
|
||||||
.setTrainedHp(resolveTrainedHp(characterId, userCharacter.characterType))
|
|
||||||
.setTrainedAp(resolveTrainedAp(characterId, userCharacter.characterType))
|
|
||||||
.setTrainedPp(characterWithSprites.trophies)
|
|
||||||
.setInjured(characterWithSprites.injuryStatus.name.lowercase().contains("inj"))
|
|
||||||
.setAccumulatedDailyInjuries(0)
|
|
||||||
.setTotalBattles(characterWithSprites.totalBattlesWon + characterWithSprites.totalBattlesLost)
|
|
||||||
.setCurrentPhaseBattles(characterWithSprites.currentPhaseBattlesWon + characterWithSprites.currentPhaseBattlesLost)
|
|
||||||
.setTotalWins(characterWithSprites.totalBattlesWon)
|
|
||||||
.setCurrentPhaseWins(characterWithSprites.currentPhaseBattlesWon)
|
|
||||||
.setMood(characterWithSprites.mood)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.setSettings(
|
|
||||||
Character.Settings.newBuilder()
|
|
||||||
.setTrainingInBackground(false)
|
|
||||||
.setAllowedBattles(Character.Settings.AllowedBattles.CARD_ONLY)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.putMaxAdventureCompletedByCard(card.name, (cardProgress - 1).coerceAtLeast(0))
|
|
||||||
.addAllTransformationHistory(
|
|
||||||
database.userCharacterDao().getTransformationHistoryForExport(characterId).map {
|
|
||||||
Character.TransformationEvent.newBuilder()
|
|
||||||
.setCardName(it.cardName)
|
|
||||||
.setPhase(0)
|
|
||||||
.setSlotId(it.monIndex)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val exportDir = File(context.cacheDir, "exports").apply { mkdirs() }
|
val exportDir = File(context.cacheDir, "exports").apply { mkdirs() }
|
||||||
val exportFile = File(exportDir, "vbhelper_character_$characterId.vitalwear")
|
val exportFile = File(exportDir, "vbhelper_character_$characterId.vitalwear")
|
||||||
|
|||||||
@ -17,6 +17,7 @@ dependencyResolutionManagement {
|
|||||||
mavenLocal()
|
mavenLocal()
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user