mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-07-30 00:31:54 +00:00
Compare commits
4 Commits
7a8815694d
...
81bfec5ac5
| Author | SHA1 | Date | |
|---|---|---|---|
| 81bfec5ac5 | |||
| 8ec98b9d39 | |||
|
|
e549fb4469 | ||
|
|
8d62437aae |
@ -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,21 +17,21 @@
|
|||||||
<string name="nav_adventure">アドベンチャー</string>
|
<string name="nav_adventure">アドベンチャー</string>
|
||||||
<string name="nav_credits">クレジット</string>
|
<string name="nav_credits">クレジット</string>
|
||||||
<string name="adventure_title">アドベンチャー</string>
|
<string name="adventure_title">アドベンチャー</string>
|
||||||
<string name="adventure_empty_state">何もありません。</string>
|
<string name="adventure_empty_state">No Data</string>
|
||||||
<string name="home_title">VB Helper</string>
|
<string name="home_title">VB Helper</string>
|
||||||
<string name="scan_secrets_not_imported">" APKの読み込みがされていません。設定から読み込をして下さい。 "</string>
|
<string name="scan_secrets_not_imported">"APKの読み込みがされていません。設定から読み込をして下さい。 "</string>
|
||||||
<string name="scan_title">デバイスをスキャン</string>
|
<string name="scan_title">デバイスをスキャン</string>
|
||||||
<string name="scan_sent_dim_success">DIMの転送に成功しました。</string>
|
<string name="scan_sent_dim_success">DIMの転送に成功しました。</string>
|
||||||
<string name="scan_nfc_must_be_enabled">NFC機能を有効にして下さい。</string>
|
<string name="scan_nfc_must_be_enabled">NFC機能を有効にして下さい。</string>
|
||||||
<string name="settings_title">設定</string>
|
<string name="settings_title">設定</string>
|
||||||
<string name="scan_missing_secrets">必要なデータが不足しています。設定を開き、Vital ArenaのAPKを読み込んでください。</string>
|
<string name="scan_missing_secrets">Vital ArenaのAPKを読み込みして下さい。</string>
|
||||||
<string name="scan_sent_character_success">転送が成功しました。</string>
|
<string name="scan_sent_character_success">転送が成功しました。</string>
|
||||||
<string name="scan_error_generic">エラー</string>
|
<string name="scan_error_generic">エラー</string>
|
||||||
<string name="settings_about_desc">このアプリについて</string>
|
<string name="settings_about_desc">このアプリについて</string>
|
||||||
<string name="settings_export_data_title">データベースの書き出し</string>
|
<string name="settings_export_data_title">データベースのエクスポート</string>
|
||||||
<string name="settings_export_data_desc">" データベースを書き出します。"</string>
|
<string name="settings_export_data_desc">データベースの書き出しをします。</string>
|
||||||
<string name="settings_import_data_title">データベースの読み込み</string>
|
<string name="settings_import_data_title">データベースのインポート</string>
|
||||||
<string name="settings_import_data_desc">" データベースを読み込みます。"</string>
|
<string name="settings_import_data_desc">データベースの読み込みをします。</string>
|
||||||
<string name="credits_title">クレジット</string>
|
<string name="credits_title">クレジット</string>
|
||||||
<string name="battles_coming_soon">Coming soon</string>
|
<string name="battles_coming_soon">Coming soon</string>
|
||||||
<string name="cards_my_cards_title">カードリスト</string>
|
<string name="cards_my_cards_title">カードリスト</string>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<string name="scan_vb_to_app">デバイスからアプリへ</string>
|
<string name="scan_vb_to_app">デバイスからアプリへ</string>
|
||||||
<string name="scan_app_to_vb">アプリからデバイスへ</string>
|
<string name="scan_app_to_vb">アプリからデバイスへ</string>
|
||||||
<string name="read_character_title">キャラクターを読み込みます。</string>
|
<string name="read_character_title">キャラクターを読み込みます。</string>
|
||||||
<string name="read_character_prepare_device">バイタルブレスを準備してください。</string>
|
<string name="read_character_prepare_device">デバイスを準備してください。</string>
|
||||||
<string name="read_character_go_to_connect">準備が出来たら転送を押してください。</string>
|
<string name="read_character_go_to_connect">準備が出来たら転送を押してください。</string>
|
||||||
<string name="read_character_confirm">転送</string>
|
<string name="read_character_confirm">転送</string>
|
||||||
<string name="card_adventure_missions_title">アドベンチャーミッション</string>
|
<string name="card_adventure_missions_title">アドベンチャーミッション</string>
|
||||||
@ -54,31 +54,33 @@
|
|||||||
<string name="storage_delete_character">削除</string>
|
<string name="storage_delete_character">削除</string>
|
||||||
<string name="storage_close">閉じる</string>
|
<string name="storage_close">閉じる</string>
|
||||||
<string name="storage_character_image_description">キャラクター画像</string>
|
<string name="storage_character_image_description">キャラクター画像</string>
|
||||||
<string name="storage_send_to_watch">転送</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_set_active">選択</string>
|
||||||
<string name="storage_send_on_adventure">アドベンチャーへ出発</string>
|
<string name="storage_send_on_adventure">アドベンチャーへ出発</string>
|
||||||
<string name="scan_no_nfc_on_device">NFC機能が見つかりません。</string>
|
<string name="scan_no_nfc_on_device">NFC機能が見つかりません。</string>
|
||||||
<string name="scan_tag_not_vb">検出されたタグはバイタルブレスでは使用出来ません。</string>
|
<string name="scan_tag_not_vb">検出されたタグはバイタルブレスでは使用出来ません。</string>
|
||||||
<string name="settings_section_nfc">NFC</string>
|
<string name="settings_section_nfc">NFC通信</string>
|
||||||
<string name="settings_section_dim_bem">DiM / BEm</string>
|
<string name="settings_section_dim_bem">DiM / BEm管理</string>
|
||||||
<string name="settings_section_data">データ管理</string>
|
<string name="settings_section_data">データ管理</string>
|
||||||
<string name="settings_import_apk_title">アプリの読み込み</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">Vital Arena 2.1.0のAPKファイルを読み込みします。</string>
|
||||||
<string name="settings_import_card_title">カードの読み込み</string>
|
<string name="settings_import_card_title">カードのインポート</string>
|
||||||
<string name="settings_section_about">概要 / クレジット</string>
|
<string name="settings_section_about">概要 / クレジット</string>
|
||||||
<string name="dex_chara_fusions_button">ジョグレス</string>
|
<string name="dex_chara_fusions_button">ジョグレス</string>
|
||||||
<string name="dex_chara_close_button">閉じる</string>
|
<string name="dex_chara_close_button">閉じる</string>
|
||||||
<string name="settings_import_card_desc">" Dim / BEm カードファイルを読み込みます。"</string>
|
<string name="settings_import_card_desc">Dim / BEm のデータファイルを読み込みします。</string>
|
||||||
<string name="settings_credits_title">クレジット</string>
|
<string name="settings_credits_title">クレジット</string>
|
||||||
<string name="settings_credits_desc">開発者について</string>
|
<string name="settings_credits_desc">開発者について</string>
|
||||||
<string name="settings_about_title">概要</string>
|
<string name="settings_about_title">概要</string>
|
||||||
<string name="beta_warning_message_main">" このアプリは現在アルファ版です。今後のアップデートにより保存されているデータの全てが削除される可能性がある為、大切なデータの保存はしないようにお願い致します。ご不便をおかけして申し訳ございません。 "</string>
|
<string name="beta_warning_message_main">このアプリは現在開発中です。\n今後のアップデートにより、保存されているデータ全ての削除が必要になる場合があります。\nその為、大切なデータの保存には使用しないようお願い致します。\nご不便をおかけして申し訳ございません。</string>
|
||||||
<string name="beta_warning_message_compatibility">" このアプリはオリジナルのVBおよびVHで動作するようになりました。 "</string>
|
<string name="beta_warning_message_compatibility">"このアプリはオリジナルのVBおよびVHで動作するようになりました。 "</string>
|
||||||
<string name="beta_warning_message_thanks">" ご理解とご協力に感謝いたします。\n 開発チーム一同"</string>
|
<string name="beta_warning_message_thanks">ご理解とご協力に感謝致します。\n開発チーム一同</string>
|
||||||
<string name="home_vbdim_vitals">バイタル</string>
|
<string name="home_vbdim_vitals">バイタル</string>
|
||||||
<string name="home_adventure_mission_finished">" 1人のキャラクターがアドベンチャーミッションを完了しました。 "</string>
|
<string name="home_adventure_mission_finished">"1人のキャラクターがアドベンチャーミッションを完了しました。 "</string>
|
||||||
<string name="scan_secrets_not_initialized">" 初期化が出来ませんでした。もう一度試して下さい。 "</string>
|
<string name="scan_secrets_not_initialized">"初期化が出来ませんでした。もう一度試して下さい。 "</string>
|
||||||
<string name="home_special_mission_delete_main">現在の進捗状況が失われますが、本当にこのスペシャルミッションを削除しますか?</string>
|
<string name="home_special_mission_delete_main">現在の進捗状況が失われます。本当にこのミッションを削除しますか?</string>
|
||||||
<string name="home_special_mission_delete_dismiss">閉じる</string>
|
<string name="home_special_mission_delete_dismiss">閉じる</string>
|
||||||
<string name="home_special_mission_delete_remove">削除</string>
|
<string name="home_special_mission_delete_remove">削除</string>
|
||||||
<string name="item_dialog_use">アイテム使用</string>
|
<string name="item_dialog_use">アイテム使用</string>
|
||||||
@ -90,25 +92,26 @@
|
|||||||
<string name="obtained_item_you_also_got_credits">%1$d クレジットを獲得しました。</string>
|
<string name="obtained_item_you_also_got_credits">%1$d クレジットを獲得しました。</string>
|
||||||
<string name="obtained_item_dismiss">閉じる</string>
|
<string name="obtained_item_dismiss">閉じる</string>
|
||||||
<string name="nav_dex">図鑑</string>
|
<string name="nav_dex">図鑑</string>
|
||||||
<string name="action_place_near_reader">バイタルブレス本体を近くに置いて下さい。</string>
|
<string name="credits_RedEyez_description">献身的なデバッグ作業を行って頂きました。</string>
|
||||||
|
<string name="action_place_near_reader">デバイスを近づけて下さい。</string>
|
||||||
<string name="action_cancel">キャンセル</string>
|
<string name="action_cancel">キャンセル</string>
|
||||||
<string name="card_view_discovered_characters">解放済みキャラクター</string>
|
<string name="card_view_discovered_characters">解放済みキャラクター</string>
|
||||||
<string name="dex_chara_icon_description">キャラクターアイコン</string>
|
<string name="dex_chara_icon_description">キャラクターアイコン</string>
|
||||||
<string name="dex_chara_name_icon_description">名前</string>
|
<string name="dex_chara_name_icon_description">名前</string>
|
||||||
<string name="credits_section_reverse_engineering">リバースエンジニアリング</string>
|
<string name="credits_section_reverse_engineering">プログラム解析</string>
|
||||||
<string name="credits_section_app_development">アプリケーション開発</string>
|
<string name="credits_section_app_development">アプリケーション開発</string>
|
||||||
<string name="credits_cyanic_description">" ファームウェアの解析を行い、開発をサポートしてくれました。"</string>
|
<string name="credits_cyanic_description">ファームウェアの解析を行い、開発をサポートしてくれました。</string>
|
||||||
<string name="credits_cfogrady_description">" vb-lib-nfc開発およびアプリの開発に協力して頂きました。"</string>
|
<string name="credits_cfogrady_description">vb-lib-nfc開発および本アプリの開発に協力して頂きました。</string>
|
||||||
<string name="credits_nacabaro_description">" アプリの開発をしました。"</string>
|
<string name="credits_nacabaro_description">本アプリの開発をしました。</string>
|
||||||
<string name="credits_lightheel_description">" アプリのサーバー含む対戦機能を開発して頂きました。現在も開発を継続して頂いています。"</string>
|
<string name="credits_lightheel_description">本アプリのサーバー含む対戦機能を開発して頂きました。現在も開発を継続して頂いています。</string>
|
||||||
<string name="credits_shvstrz_description">" アプリのアイコンデザインをして頂きました。"</string>
|
<string name="credits_shvstrz_description">本アプリのアイコンデザインをして頂きました。</string>
|
||||||
<string name="write_card_title">カード情報書き込み中</string>
|
<string name="write_card_title">カード情報書き込み中</string>
|
||||||
<string name="write_card_icon_description">カードアイコン</string>
|
<string name="write_card_icon_description">カードアイコン</string>
|
||||||
<string name="write_card_device_ready">デバイスの準備をして下さい。</string>
|
<string name="write_card_device_ready">デバイスの準備をして下さい。</string>
|
||||||
<string name="write_card_required_card">%1$s カードが必要です。</string>
|
<string name="write_card_required_card">%1$s カードが必要です。</string>
|
||||||
<string name="write_card_confirm">転送</string>
|
<string name="write_card_confirm">転送</string>
|
||||||
<string name="write_character_success">" カードの読み込みが完了しました。"</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="write_character_confirm">確認</string>
|
||||||
<string name="home_vbdim_trophies">トロフィー</string>
|
<string name="home_vbdim_trophies">トロフィー</string>
|
||||||
<string name="items_purchase_success">購入しました。</string>
|
<string name="items_purchase_success">購入しました。</string>
|
||||||
@ -119,10 +122,10 @@
|
|||||||
<string name="dex_chara_stats">HP: %1$d, BP: %2$d, AP: %3$d</string>
|
<string name="dex_chara_stats">HP: %1$d, BP: %2$d, AP: %3$d</string>
|
||||||
<string name="dex_chara_stage_attribute_unknown">Stg: -, Atr: -</string>
|
<string name="dex_chara_stage_attribute_unknown">Stg: -, Atr: -</string>
|
||||||
<string name="dex_chara_stats_unknown">HP: -, BP: -, AP: -</string>
|
<string name="dex_chara_stats_unknown">HP: -, BP: -, AP: -</string>
|
||||||
<string name="dex_chara_requirements">" Tr: %1$d; Bt: %2$d; Vr: %3$d; Wr: %4$d%%; Ct: %5$dh "</string>
|
<string name="dex_chara_requirements">\n Tr: %1$d; Bt: %2$d; Vr: %3$d; Wr: %4$d%%; Ct: %5$dh</string>
|
||||||
<string name="dex_chara_adventure_level">AdvLvl %1$d</string>
|
<string name="dex_chara_adventure_level">AdvLvl %1$d</string>
|
||||||
<string name="storage_my_characters_title">キャラクターリスト</string>
|
<string name="storage_my_characters_title">キャラクターリスト</string>
|
||||||
<string name="storage_nothing_to_see_here">表示するデータはありません。</string>
|
<string name="storage_nothing_to_see_here">No Data</string>
|
||||||
<string name="storage_in_adventure_toast">このキャラクターは冒険中です。</string>
|
<string name="storage_in_adventure_toast">このキャラクターは冒険中です。</string>
|
||||||
<string name="home_vbdim_next_timer">次のタイマー</string>
|
<string name="home_vbdim_next_timer">次のタイマー</string>
|
||||||
<string name="home_vbdim_total_battle_win">総勝率 %</string>
|
<string name="home_vbdim_total_battle_win">総勝率 %</string>
|
||||||
@ -143,4 +146,18 @@
|
|||||||
<string name="special_mission_steps_progress">歩数 %1$d 歩</string>
|
<string name="special_mission_steps_progress">歩数 %1$d 歩</string>
|
||||||
<string name="special_mission_battles_progress">バトル %1$d 回</string>
|
<string name="special_mission_battles_progress">バトル %1$d 回</string>
|
||||||
<string name="special_mission_wins_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>
|
||||||
|
<string name="companion_validation_insert_card">デバイスへカードを差し込んで下さい。</string>
|
||||||
|
<string name="companion_validation_success">データチェックが完了しました。</string>
|
||||||
|
<string name="companion_loading_select_firmware">ファームウェアファイルを選択</string>
|
||||||
|
<string name="companion_firmware_sent_success">ファームウェアの送信が完了しました。</string>
|
||||||
|
<string name="companion_logs_receive_failed">ログの受信に失敗しました。</string>
|
||||||
|
<string name="companion_logs_failed_request">ログの要求に失敗しました。</string>
|
||||||
|
<string name="companion_logs_warning">注意:ログの転送には時間がかかる場合があります。</string>
|
||||||
|
<string name="settings_companion_send_watch_logs_title">ログの送信</string>
|
||||||
|
<string name="companion_transfer_disabled_message">現在、転送は無効になっています。</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -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