From 895b704c8d4297388aacc3e2028c3b2e923c914a Mon Sep 17 00:00:00 2001 From: Taveon Nelson <74945303+457R0@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:57:38 -0500 Subject: [PATCH] Make VBH-VW transfer DB owner via provider and shared transfer DAO --- app/src/main/AndroidManifest.xml | 10 +++ .../common/data/SharedDatabaseFactory.kt | 22 ++++++ .../common/data/SharedTransferDatabase.kt | 16 +++++ .../common/data/SharedTransferSeenDao.kt | 47 +++++++++++++ .../common/data/SharedTransferSeenEntity.kt | 24 +++++++ .../nacabaro/vbhelper/daos/TransferSeenDao.kt | 7 ++ .../nacabaro/vbhelper/database/AppDatabase.kt | 37 +++++++++- .../nacabaro/vbhelper/di/AppContainer.kt | 2 + .../vbhelper/di/DefaultAppContainer.kt | 11 ++- .../domain/transfer/TransferSeenEntity.kt | 7 ++ .../scanScreen/ScanScreenControllerImpl.kt | 66 ++++++++++++++++-- .../scanScreen/converters/FromNfcConverter.kt | 18 +++-- .../source/VitalWearCharacterImporter.kt | 25 ++++++- .../transfer/SharedTransferSeenProvider.kt | 67 +++++++++++++++++++ 14 files changed, 344 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/github/cfogrady/vitalwear/common/data/SharedDatabaseFactory.kt create mode 100644 app/src/main/java/com/github/cfogrady/vitalwear/common/data/SharedTransferDatabase.kt create mode 100644 app/src/main/java/com/github/cfogrady/vitalwear/common/data/SharedTransferSeenDao.kt create mode 100644 app/src/main/java/com/github/cfogrady/vitalwear/common/data/SharedTransferSeenEntity.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/daos/TransferSeenDao.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/domain/transfer/TransferSeenEntity.kt create mode 100644 app/src/main/java/com/github/nacabaro/vbhelper/transfer/SharedTransferSeenProvider.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 652d31d..3f49294 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,10 @@ + + @@ -31,6 +35,12 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> + val application = componentActivity.applicationContext as VBHelper - val importer = VitalWearCharacterImporter(application.container.db) + val importer = VitalWearCharacterImporter(application.container.db, application.container.transferSeenDao) try { var importResult: VitalWearCharacterImporter.ImportResult? = null val moved = VitalWearHceReaderClient(isoDep).moveCharacterFromWatch { character -> @@ -176,7 +230,7 @@ class ScanScreenControllerImpl( runCatching { var importResult: VitalWearCharacterImporter.ImportResult? = null val moved = hceClient.moveCharacterFromWatch { character -> - val result = VitalWearCharacterImporter(application.container.db).importCharacter(character) + val result = VitalWearCharacterImporter(application.container.db, application.container.transferSeenDao).importCharacter(character) importResult = result result.success } @@ -236,7 +290,9 @@ class ScanScreenControllerImpl( lastTagId = null lastTagHandledAtMs = 0L } - disableReaderModeSafely() + // Re-arm the suppressor so the TagViewer doesn't appear while the user is still + // on the scan screen but hasn't pressed a transfer button yet. + enableNfcSuppressor() } override fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) { @@ -370,7 +426,9 @@ class ScanScreenControllerImpl( Log.w("NFC", "Failed to ignore handled tag", it) } - disableReaderModeSafely() + // Restore the passive suppressor so devices can remain close without Android + // launching the TagViewer between transfers or while waiting for the next button press. + enableNfcSuppressor() isHandlingTag.set(false) } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt index dcc85a3..2cde698 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt @@ -19,7 +19,8 @@ class FromNfcConverter ( ) { private val application = componentActivity.applicationContext as VBHelper private val database = application.container.db - + private val transferSeenDao = application.container.transferSeenDao + fun addCharacterUsingCard( nfcCharacter: NfcCharacter, @@ -118,6 +119,9 @@ class FromNfcConverter ( .userCharacterDao() .insertCharacterData(characterData) + val seenTimestamp = System.currentTimeMillis() + markSeen(cardData, nfcCharacter.charIndex.toInt(), seenTimestamp) + if (nfcCharacter is BENfcCharacter) { addBeCharacterToDatabase( characterId = characterId, @@ -292,12 +296,14 @@ class FromNfcConverter ( database .dexDao() - .insertCharacter( - item.toCharIndex.toInt(), - dimData.id, - date - ) + .insertCharacter(item.toCharIndex.toInt(), dimData.id, date) + transferSeenDao.markSeen(dimData.name, item.toCharIndex.toInt(), date) } } } + + private fun markSeen(cardData: Card, slotId: Int, timestamp: Long) { + database.dexDao().insertCharacter(slotId, cardData.id, timestamp) + transferSeenDao.markSeen(cardData.name, slotId, timestamp) + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/source/VitalWearCharacterImporter.kt b/app/src/main/java/com/github/nacabaro/vbhelper/source/VitalWearCharacterImporter.kt index b6cfb25..07bba8d 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/source/VitalWearCharacterImporter.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/source/VitalWearCharacterImporter.kt @@ -1,6 +1,7 @@ package com.github.nacabaro.vbhelper.source import com.github.cfogrady.vbnfc.data.NfcCharacter +import com.github.cfogrady.vitalwear.common.data.SharedTransferSeenDao import com.github.cfogrady.vitalwear.protos.Character import com.github.nacabaro.vbhelper.database.AppDatabase import com.github.nacabaro.vbhelper.domain.card.Card @@ -13,7 +14,8 @@ import kotlinx.coroutines.runBlocking import kotlin.math.max class VitalWearCharacterImporter( - private val database: AppDatabase + private val database: AppDatabase, + private val transferSeenDao: SharedTransferSeenDao, ) { data class ImportResult( val success: Boolean, @@ -113,8 +115,9 @@ class VitalWearCharacterImporter( } val now = System.currentTimeMillis() - database.dexDao().insertCharacter(slotId, importedCard.id, now) + markSeen(importedCard.name, slotId, importedCard.id, now) + var insertedTransformationCount = 0 for (transformation in character.transformationHistoryList) { val transformationCard = resolveRelatedCard( incomingCardName = transformation.cardName, @@ -129,10 +132,21 @@ class VitalWearCharacterImporter( transformationCard.id, now ) - database.dexDao().insertCharacter(transformation.slotId, transformationCard.id, now) + insertedTransformationCount++ + markSeen(transformationCard.name, transformation.slotId, transformationCard.id, now) } } + if (insertedTransformationCount == 0) { + // Keep HomeScreen renderable for freshly imported characters with empty history. + database.userCharacterDao().insertTransformation( + userCharacterId, + slotId, + importedCard.id, + now + ) + } + for ((cardName, maxAdventureCompleted) in character.maxAdventureCompletedByCardMap) { val adventureCard = resolveRelatedCard( incomingCardName = cardName, @@ -210,6 +224,11 @@ class VitalWearCharacterImporter( private fun resolveDefaultAbilityRarity(): NfcCharacter.AbilityRarity { return enumValues().first() } + + private fun markSeen(cardName: String, slotId: Int, cardId: Long, timestamp: Long) { + database.dexDao().insertCharacter(slotId, cardId, timestamp) + transferSeenDao.markSeen(cardName, slotId, timestamp) + } } internal fun selectImportedCard( diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/transfer/SharedTransferSeenProvider.kt b/app/src/main/java/com/github/nacabaro/vbhelper/transfer/SharedTransferSeenProvider.kt new file mode 100644 index 0000000..8734c22 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/transfer/SharedTransferSeenProvider.kt @@ -0,0 +1,67 @@ +package com.github.nacabaro.vbhelper.transfer + +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.net.Uri +import android.os.Bundle +import com.github.cfogrady.vitalwear.common.data.SharedDatabaseFactory + +class SharedTransferSeenProvider : ContentProvider() { + companion object { + const val AUTHORITY = "com.github.nacabaro.vbhelper.transferseen" + val URI: Uri = Uri.parse("content://$AUTHORITY") + + const val METHOD_MARK_SEEN = "markSeen" + const val EXTRA_CARD_NAME = "cardName" + const val EXTRA_SLOT_ID = "slotId" + const val EXTRA_SEEN_AT_EPOCH_MILLIS = "seenAtEpochMillis" + const val RESULT_OK = "ok" + } + + override fun onCreate(): Boolean = true + + override fun call(method: String, arg: String?, extras: Bundle?): Bundle { + if (method != METHOD_MARK_SEEN) { + return Bundle().apply { putBoolean(RESULT_OK, false) } + } + + val context = context ?: return Bundle().apply { putBoolean(RESULT_OK, false) } + val cardName = extras?.getString(EXTRA_CARD_NAME).orEmpty() + val slotId = extras?.getInt(EXTRA_SLOT_ID, -1) ?: -1 + val seenAt = extras?.getLong(EXTRA_SEEN_AT_EPOCH_MILLIS, 0L) ?: 0L + + if (cardName.isBlank() || slotId < 0 || seenAt <= 0L) { + return Bundle().apply { putBoolean(RESULT_OK, false) } + } + + return runCatching { + SharedDatabaseFactory.getDatabase(context).transferSeenDao().markSeen(cardName, slotId, seenAt) + Bundle().apply { putBoolean(RESULT_OK, true) } + }.getOrElse { + Bundle().apply { putBoolean(RESULT_OK, false) } + } + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? = null + + override fun getType(uri: Uri): String? = null + + override fun insert(uri: Uri, values: ContentValues?): Uri? = null + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0 + + override fun update( + uri: Uri, + values: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int = 0 +} +