mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-10-01 15:41:36 +00:00
Compare commits
84
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8815907563 | ||
|
|
6cce33c5f6 | ||
|
|
16fbfae0c2 | ||
|
|
0d174f1550 | ||
|
|
489e27b038 | ||
|
|
6be167bbed | ||
|
|
61dfc2ce0d | ||
|
|
dce186737d | ||
|
|
cf272e8030 | ||
|
|
ffa6958a89 | ||
|
|
1d9879fb50 | ||
|
|
3fa072ce1e | ||
|
|
69245be8dd | ||
|
|
73c393df64 | ||
|
|
0b3ce486cb | ||
|
|
7160eb792a | ||
|
|
cb9fe8e716 | ||
|
|
540766eefb | ||
|
|
af2c852bac | ||
|
|
8dc5bbbdde | ||
|
|
aac05a3b1c | ||
|
|
b827fdccbe | ||
|
|
2586190e5c | ||
|
|
1a6753d2aa | ||
|
|
f8ec899335 | ||
|
|
b95edfa2a1 | ||
|
|
1a570170ca | ||
|
|
1566876106 | ||
|
|
019f07d827 | ||
|
|
4474e6689d | ||
|
|
fb09004d13 | ||
|
|
dd1a62d184 | ||
|
|
f96f00e05a | ||
|
|
3c17e93d0f | ||
|
|
f8ce81e932 | ||
|
|
7bb7693876 | ||
|
|
2b33042fe0 | ||
|
|
4d8dcde26e | ||
|
|
0b1eed7da9 | ||
|
|
36c3e25fd3 | ||
|
|
ac05dfc541 | ||
|
|
220a61a553 | ||
|
|
d847f600f1 | ||
|
|
f7a4039d66 | ||
|
|
1eed6a4c17 | ||
|
|
1a09e40d1d | ||
|
|
13051145b7 | ||
|
|
1a150ce7ce | ||
|
|
39ba48d867 | ||
|
|
3f324ca141 | ||
|
|
1e28a8c249 | ||
|
|
d46769b0cb | ||
|
|
fce05870c5 | ||
|
|
9f5f806786 | ||
|
|
d749af0a9c | ||
|
|
076f6bfacf | ||
|
|
a4f3b701e5 | ||
|
|
da134247b1 | ||
|
|
f7b3b7256a | ||
|
|
e36a700d9f | ||
|
|
fb6b6d2825 | ||
|
|
e17f6c23e4 | ||
|
|
409474b5d1 | ||
|
|
547318864b | ||
|
|
5e92895656 | ||
|
|
25500e9cb4 | ||
|
|
1a38cefb92 | ||
|
|
a974bd366e | ||
|
|
bb5f66d167 | ||
|
|
09394871e5 | ||
|
|
972a640394 | ||
|
|
35a7c9d959 | ||
|
|
b4a73031e7 | ||
|
|
3e41f82273 | ||
|
|
f3740d4816 | ||
|
|
305b776b52 | ||
|
|
c0a67e382b | ||
|
|
bc7a05ccd3 | ||
|
|
660dbaca19 | ||
|
|
b89dfb0df3 | ||
|
|
23e233227a | ||
|
|
542072c238 | ||
|
|
42dd87f0c4 | ||
|
|
635be60cdb |
@@ -1,38 +1,69 @@
|
|||||||
# VBHelper
|
# VBHelper
|
||||||
|
|
||||||
## Developer Setup
|
Application to interact with the Vital series, VB, VH, VBC and VBBE.
|
||||||
|
|
||||||
1. Clone vb-nfc-reader (https://github.com/cfogrady/lib-vb-nfc)
|
## Current state of the project
|
||||||
2. Run vb-nfc-reader/publishToMavenLocal gradle task in the lib-vb-nfc project.
|
|
||||||
3. Clone vb-dim-reader (https://github.com/cfogrady/vb-dim-reader)
|
Right now the project is still under development, and until further notice, any database updates will result in having to erase application data.
|
||||||
4. Run publishToMavenLocal gradle task in the vb-dim-reader project.
|
|
||||||
5. Create res/values/keys.xml within the app module.
|
This document will be updated once the application does not need any more database resets.
|
||||||
6. Populate with:
|
|
||||||
```
|
## Features
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
As of now, the project allows you to read characters, view characters stats, and send them back to your watch.
|
||||||
<string name="password1">beHmacKey1</string>
|
|
||||||
<string name="password2">beHmacKey2</string>
|
You can also apply items to the characters read, such as special missions, or change timers, and store characters in the storage section.
|
||||||
<string name="decryptionKey">aesKey</string>
|
|
||||||
<integer-array name="substitutionArray">
|
You also earn new items every time an item such as a special mission (VB only) or a character completes an in-app adventure mission.
|
||||||
<item>0</item>
|
|
||||||
<item>1</item>
|
App also comes with a dex that will update every time a new character is added, and allows you to see evolution requirements and current adventure stage in the watch.
|
||||||
<item>2</item>
|
|
||||||
<item>3</item>
|
## How to set up
|
||||||
<item>4</item>
|
|
||||||
<item>5</item>
|
1. Download the latest version for VB Arena APK from a trustworthy source. If your download is a standalone APK, continue to step 2. Otherwise, if your download is an XAPK, do the following:
|
||||||
<item>6</item>
|
|
||||||
<item>7</item>
|
1. Using your phone file manager, rename the XAPK file to ZIP, and extract its contents. You can also do this with any other device, such as Windows, macOS and Linux.
|
||||||
<item>8</item>
|
|
||||||
<item>9</item>
|
2. Once the files are extracted, look for an APK called `com.bandai.vitalbraceletarena.apk`. Copy it somewhere else, you will need it.
|
||||||
<item>10</item>
|
|
||||||
<item>11</item>
|
2. Install an APK release for VB Arena. You will find the releases [here](http://github.com/nacabaro/vbhelper/releases). Download the latest release and install its APK.
|
||||||
<item>12</item>
|
|
||||||
<item>13</item>
|
Note, in the current stage of the project, you will have to delete the old application from your device. If the app keeps crashing after installing, clear application data and storage.
|
||||||
<item>14</item>
|
|
||||||
<item>15</item>
|
3. Import secrets in the app. These secrets will allow the app to talk to the watch. On the main screen, click on the gear icon, then `Import secrets`.
|
||||||
</integer-array>
|
|
||||||
</resources>
|
You will be prompted to choose a file. Choose the APK file that was previously obtained.
|
||||||
```
|
|
||||||
7. Replace the values in the keys.xml file with those extracted from the original app.
|
4. Import cards. Due to copyright laws, we cannot offer the characters and sprites themselves in the application. In order to import the cards do the following.
|
||||||
8. Run
|
|
||||||
|
1. Using your own DiM/BEm cards, dump the cards to your device. You can get an in-depth tutorial in [here](http://mrblinky.net/digimon/vb/dimcardtool/dimcardtool.html). You can download the dump tool from [here](http://mrblinky.net/digimon/vb/dimcardtool/)
|
||||||
|
|
||||||
|
2. Once installed the tool and drivers, open the tool, connect your DiM/BEm reader hardware to yout computer and click on Read card.
|
||||||
|
|
||||||
|
3. Transfer the resulting file to your mobile device. You can put them anywhere, as long as they are accessible. My recommendation is to put them under a folder called `Cards` in your `Internal storage` or `SD Card`
|
||||||
|
|
||||||
|
4. In the app, click on import card. Next choose the BIN file corresponding to the card you want to import.
|
||||||
|
|
||||||
|
**Note: if you do not import the card, whenever you attempt to read a character from th watch, the character you read will get deleted.**
|
||||||
|
|
||||||
|
5. App will now be ready to be used.
|
||||||
|
|
||||||
|
## Planned features
|
||||||
|
|
||||||
|
- Online battles, undegoing development by `lightheel`.
|
||||||
|
|
||||||
|
- VitalWear compatibility, undergoing development by `cfogrady`.
|
||||||
|
|
||||||
|
- Support for multiple languages, not yet started.
|
||||||
|
|
||||||
|
- Database backup/restore.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- `cyanic` for helping us understand more about the VB connection protocol.
|
||||||
|
|
||||||
|
- `cfogrady` for making both [`VB-DIM-Reader`](https://github.com/cfogrady/VB-DIM-Reader) and [`lib-vb-nfc`](https://github.com/cfogrady/lib-vb-nfc)
|
||||||
|
|
||||||
|
- `lightheel` for working on the online component in the application, both server and battle client.
|
||||||
|
|
||||||
|
- `shvstrz` for the app icon.
|
||||||
@@ -15,7 +15,7 @@ android {
|
|||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "Alpha 0.6.2"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@@ -91,4 +91,5 @@ dependencies {
|
|||||||
implementation("com.google.android.material:material:1.2.0")
|
implementation("com.google.android.material:material:1.2.0")
|
||||||
implementation(libs.protobuf.javalite)
|
implementation(libs.protobuf.javalite)
|
||||||
implementation("androidx.compose.material:material")
|
implementation("androidx.compose.material:material")
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.1.7")
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -1,45 +1,26 @@
|
|||||||
package com.github.nacabaro.vbhelper
|
package com.github.nacabaro.vbhelper
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.github.cfogrady.vb.dim.card.BemCard
|
|
||||||
import com.github.cfogrady.vb.dim.card.DimReader
|
|
||||||
import com.github.nacabaro.vbhelper.navigation.AppNavigation
|
import com.github.nacabaro.vbhelper.navigation.AppNavigation
|
||||||
import com.github.cfogrady.vbnfc.be.BENfcCharacter
|
|
||||||
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
|
||||||
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
|
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Card
|
|
||||||
import com.github.nacabaro.vbhelper.domain.Sprites
|
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Dex
|
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
|
||||||
import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers
|
import com.github.nacabaro.vbhelper.navigation.AppNavigationHandlers
|
||||||
|
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
|
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.screens.SettingsScreenController
|
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.source.ApkSecretsImporter
|
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.CardScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
|
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
|
||||||
import com.github.nacabaro.vbhelper.utils.DeviceType
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.GregorianCalendar
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
private var nfcCharacter = MutableStateFlow<NfcCharacter?>(null)
|
|
||||||
|
|
||||||
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
|
||||||
|
|
||||||
private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>()
|
private val onActivityLifecycleListeners = HashMap<String, ActivityLifecycleListener>()
|
||||||
|
|
||||||
private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) {
|
private fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener) {
|
||||||
@@ -54,26 +35,40 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
registerFileActivityResult()
|
|
||||||
|
|
||||||
val application = applicationContext as VBHelper
|
val application = applicationContext as VBHelper
|
||||||
val settingsScreenController = SettingsScreenController.Factory(this, ApkSecretsImporter(), application.container.dataStoreSecretsRepository)
|
|
||||||
.buildSettingScreenHandlers()
|
|
||||||
val scanScreenController = ScanScreenControllerImpl(
|
val scanScreenController = ScanScreenControllerImpl(
|
||||||
application.container.dataStoreSecretsRepository.secretsFlow,
|
application.container.dataStoreSecretsRepository.secretsFlow,
|
||||||
this::handleReceivedNfcCharacter,
|
|
||||||
this,
|
this,
|
||||||
this::registerActivityLifecycleListener,
|
this::registerActivityLifecycleListener,
|
||||||
this::unregisterActivityLifecycleListener)
|
this::unregisterActivityLifecycleListener
|
||||||
|
)
|
||||||
|
val settingsScreenController = SettingsScreenControllerImpl(this)
|
||||||
|
val itemsScreenController = ItemsScreenControllerImpl(this)
|
||||||
|
val adventureScreenController = AdventureScreenControllerImpl(this)
|
||||||
|
val storageScreenController = StorageScreenControllerImpl(this)
|
||||||
|
val homeScreenController = HomeScreenControllerImpl(this)
|
||||||
|
val spriteViewerController = SpriteViewerControllerImpl(this)
|
||||||
|
val cardScreenController = CardScreenControllerImpl(this)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
VBHelperTheme {
|
VBHelperTheme {
|
||||||
MainApplication(settingsScreenController, scanScreenController)
|
MainApplication(
|
||||||
|
scanScreenController = scanScreenController,
|
||||||
|
settingsScreenController = settingsScreenController,
|
||||||
|
itemsScreenController = itemsScreenController,
|
||||||
|
adventureScreenController = adventureScreenController,
|
||||||
|
homeScreenController = homeScreenController,
|
||||||
|
storageScreenController = storageScreenController,
|
||||||
|
spriteViewerController = spriteViewerController,
|
||||||
|
cardScreenController = cardScreenController
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("MainActivity", "Activity onCreated")
|
Log.i("MainActivity", "Activity onCreated")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,232 +88,28 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerFileActivityResult() {
|
|
||||||
activityResultLauncher = registerForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val application = applicationContext as VBHelper
|
|
||||||
val storageRepository = application.container.db
|
|
||||||
|
|
||||||
if (it.resultCode != RESULT_OK) {
|
|
||||||
Toast.makeText(applicationContext, "Import operation cancelled.", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
val contentResolver = applicationContext.contentResolver
|
|
||||||
val inputStream = contentResolver.openInputStream(it.data!!.data!!)
|
|
||||||
inputStream.use { fileReader ->
|
|
||||||
val dimReader = DimReader()
|
|
||||||
val card = dimReader.readCard(fileReader, false)
|
|
||||||
|
|
||||||
Log.i("MainActivity", "Card name: ${card is BemCard}")
|
|
||||||
|
|
||||||
val cardModel = Card(
|
|
||||||
dimId = card.header.dimId,
|
|
||||||
logo = card.spriteData.sprites[0].pixelData,
|
|
||||||
name = card.spriteData.text, // TODO Make user write card name
|
|
||||||
stageCount = card.adventureLevels.levels.size,
|
|
||||||
logoHeight = card.spriteData.sprites[0].height,
|
|
||||||
logoWidth = card.spriteData.sprites[0].width,
|
|
||||||
isBEm = card is BemCard
|
|
||||||
)
|
|
||||||
|
|
||||||
val dimId = storageRepository
|
|
||||||
.dimDao()
|
|
||||||
.insertNewDim(cardModel)
|
|
||||||
|
|
||||||
val characters = card.characterStats.characterEntries
|
|
||||||
|
|
||||||
var spriteCounter = when (card is BemCard) {
|
|
||||||
true -> 55
|
|
||||||
false -> 10
|
|
||||||
}
|
|
||||||
|
|
||||||
val domainCharacters = mutableListOf<Character>()
|
|
||||||
|
|
||||||
for (index in 0 until characters.size) {
|
|
||||||
domainCharacters.add(
|
|
||||||
Character(
|
|
||||||
dimId = dimId,
|
|
||||||
monIndex = index,
|
|
||||||
name = card.spriteData.sprites[spriteCounter].pixelData,
|
|
||||||
stage = characters[index].stage,
|
|
||||||
attribute = characters[index].attribute,
|
|
||||||
baseHp = characters[index].hp,
|
|
||||||
baseBp = characters[index].dp,
|
|
||||||
baseAp = characters[index].ap,
|
|
||||||
sprite1 = card.spriteData.sprites[spriteCounter + 1].pixelData,
|
|
||||||
sprite2 = card.spriteData.sprites[spriteCounter + 2].pixelData,
|
|
||||||
nameWidth = card.spriteData.sprites[spriteCounter].width,
|
|
||||||
nameHeight = card.spriteData.sprites[spriteCounter].height,
|
|
||||||
spritesWidth = card.spriteData.sprites[spriteCounter + 1].width,
|
|
||||||
spritesHeight = card.spriteData.sprites[spriteCounter + 1].height
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: Improve this
|
|
||||||
if (card is BemCard) {
|
|
||||||
spriteCounter += 14
|
|
||||||
} else {
|
|
||||||
when (index) {
|
|
||||||
0 -> spriteCounter += 6
|
|
||||||
1 -> spriteCounter += 7
|
|
||||||
else -> spriteCounter += 14
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storageRepository
|
|
||||||
.characterDao()
|
|
||||||
.insertCharacter(*domainCharacters.toTypedArray())
|
|
||||||
|
|
||||||
val sprites = card.spriteData.sprites.map { sprite ->
|
|
||||||
Sprites(
|
|
||||||
id = 0,
|
|
||||||
sprite = sprite.pixelData,
|
|
||||||
width = sprite.width,
|
|
||||||
height = sprite.height
|
|
||||||
)
|
|
||||||
}
|
|
||||||
storageRepository
|
|
||||||
.characterDao()
|
|
||||||
.insertSprite(*sprites.toTypedArray())
|
|
||||||
}
|
|
||||||
inputStream?.close()
|
|
||||||
Toast.makeText(applicationContext, "Import successful!", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun MainApplication(settingsScreenController: SettingsScreenController, scanScreenController: ScanScreenControllerImpl) {
|
private fun MainApplication(
|
||||||
|
scanScreenController: ScanScreenControllerImpl,
|
||||||
|
settingsScreenController: SettingsScreenControllerImpl,
|
||||||
|
itemsScreenController: ItemsScreenControllerImpl,
|
||||||
|
adventureScreenController: AdventureScreenControllerImpl,
|
||||||
|
storageScreenController: StorageScreenControllerImpl,
|
||||||
|
homeScreenController: HomeScreenControllerImpl,
|
||||||
|
spriteViewerController: SpriteViewerControllerImpl,
|
||||||
|
cardScreenController: CardScreenControllerImpl
|
||||||
|
) {
|
||||||
AppNavigation(
|
AppNavigation(
|
||||||
applicationNavigationHandlers = AppNavigationHandlers(settingsScreenController, scanScreenController),
|
applicationNavigationHandlers = AppNavigationHandlers(
|
||||||
onClickImportCard = {
|
settingsScreenController,
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
scanScreenController,
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
itemsScreenController,
|
||||||
type = "*/*"
|
adventureScreenController,
|
||||||
}
|
storageScreenController,
|
||||||
activityResultLauncher.launch(intent)
|
homeScreenController,
|
||||||
}
|
spriteViewerController,
|
||||||
)
|
cardScreenController
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleReceivedNfcCharacter(character: NfcCharacter): String {
|
|
||||||
nfcCharacter.value = character
|
|
||||||
|
|
||||||
val importStatus = addCharacterScannedIntoDatabase()
|
|
||||||
|
|
||||||
return importStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
TODO:
|
|
||||||
- Support for regular VB
|
|
||||||
|
|
||||||
The good news is that the theory behind inserting to the database should be working
|
|
||||||
now, it's a matter of implementing the functionality to parse dim/bem cards and use my
|
|
||||||
domain model.
|
|
||||||
*/
|
|
||||||
private fun addCharacterScannedIntoDatabase(): String {
|
|
||||||
val application = applicationContext as VBHelper
|
|
||||||
val storageRepository = application.container.db
|
|
||||||
|
|
||||||
val dimData = storageRepository
|
|
||||||
.dimDao()
|
|
||||||
.getDimById(nfcCharacter.value!!.dimId.toInt())
|
|
||||||
|
|
||||||
if (dimData == null) return "Card not found"
|
|
||||||
|
|
||||||
val cardCharData = storageRepository
|
|
||||||
.characterDao()
|
|
||||||
.getCharacterByMonIndex(nfcCharacter.value!!.charIndex.toInt(), dimData.id)
|
|
||||||
|
|
||||||
val characterData = UserCharacter(
|
|
||||||
charId = cardCharData.id,
|
|
||||||
stage = nfcCharacter.value!!.stage.toInt(),
|
|
||||||
attribute = nfcCharacter.value!!.attribute,
|
|
||||||
ageInDays = nfcCharacter.value!!.ageInDays.toInt(),
|
|
||||||
nextAdventureMissionStage = nfcCharacter.value!!.nextAdventureMissionStage.toInt(),
|
|
||||||
mood = nfcCharacter.value!!.mood.toInt(),
|
|
||||||
vitalPoints = nfcCharacter.value!!.vitalPoints.toInt(),
|
|
||||||
transformationCountdown = nfcCharacter.value!!.transformationCountdownInMinutes.toInt(),
|
|
||||||
injuryStatus = nfcCharacter.value!!.injuryStatus,
|
|
||||||
trophies = nfcCharacter.value!!.trophies.toInt(),
|
|
||||||
currentPhaseBattlesWon = nfcCharacter.value!!.currentPhaseBattlesWon.toInt(),
|
|
||||||
currentPhaseBattlesLost = nfcCharacter.value!!.currentPhaseBattlesLost.toInt(),
|
|
||||||
totalBattlesWon = nfcCharacter.value!!.totalBattlesWon.toInt(),
|
|
||||||
totalBattlesLost = nfcCharacter.value!!.totalBattlesLost.toInt(),
|
|
||||||
activityLevel = nfcCharacter.value!!.activityLevel.toInt(),
|
|
||||||
heartRateCurrent = nfcCharacter.value!!.heartRateCurrent.toInt(),
|
|
||||||
characterType = when (nfcCharacter.value) {
|
|
||||||
is BENfcCharacter -> DeviceType.BEDevice
|
|
||||||
else -> DeviceType.VBDevice
|
|
||||||
},
|
|
||||||
isActive = true
|
|
||||||
)
|
|
||||||
|
|
||||||
storageRepository
|
|
||||||
.userCharacterDao()
|
|
||||||
.clearActiveCharacter()
|
|
||||||
|
|
||||||
val characterId: Long = storageRepository
|
|
||||||
.userCharacterDao()
|
|
||||||
.insertCharacterData(characterData)
|
|
||||||
|
|
||||||
if (nfcCharacter.value is BENfcCharacter) {
|
|
||||||
val beCharacter = nfcCharacter.value as BENfcCharacter
|
|
||||||
val extraCharacterData = BECharacterData(
|
|
||||||
id = characterId,
|
|
||||||
trainingHp = beCharacter.trainingHp.toInt(),
|
|
||||||
trainingAp = beCharacter.trainingAp.toInt(),
|
|
||||||
trainingBp = beCharacter.trainingBp.toInt(),
|
|
||||||
remainingTrainingTimeInMinutes = beCharacter.remainingTrainingTimeInMinutes.toInt(),
|
|
||||||
itemEffectActivityLevelValue = beCharacter.itemEffectActivityLevelValue.toInt(),
|
|
||||||
itemEffectMentalStateValue = beCharacter.itemEffectMentalStateValue.toInt(),
|
|
||||||
itemEffectMentalStateMinutesRemaining = beCharacter.itemEffectMentalStateMinutesRemaining.toInt(),
|
|
||||||
itemEffectActivityLevelMinutesRemaining = beCharacter.itemEffectActivityLevelMinutesRemaining.toInt(),
|
|
||||||
itemEffectVitalPointsChangeValue = beCharacter.itemEffectVitalPointsChangeValue.toInt(),
|
|
||||||
itemEffectVitalPointsChangeMinutesRemaining = beCharacter.itemEffectVitalPointsChangeMinutesRemaining.toInt(),
|
|
||||||
abilityRarity = beCharacter.abilityRarity,
|
|
||||||
abilityType = beCharacter.abilityType.toInt(),
|
|
||||||
abilityBranch = beCharacter.abilityBranch.toInt(),
|
|
||||||
abilityReset = beCharacter.abilityReset.toInt(),
|
|
||||||
rank = beCharacter.abilityReset.toInt(),
|
|
||||||
itemType = beCharacter.itemType.toInt(),
|
|
||||||
itemMultiplier = beCharacter.itemMultiplier.toInt(),
|
|
||||||
itemRemainingTime = beCharacter.itemRemainingTime.toInt(),
|
|
||||||
otp0 = "", //beCharacter.value!!.otp0.toString(),
|
|
||||||
otp1 = "", //beCharacter.value!!.otp1.toString(),
|
|
||||||
minorVersion = beCharacter.characterCreationFirmwareVersion.minorVersion.toInt(),
|
|
||||||
majorVersion = beCharacter.characterCreationFirmwareVersion.majorVersion.toInt(),
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
storageRepository
|
|
||||||
.userCharacterDao()
|
|
||||||
.insertBECharacterData(extraCharacterData)
|
|
||||||
|
|
||||||
val transformationHistoryWatch = beCharacter.transformationHistory
|
|
||||||
transformationHistoryWatch.map { item ->
|
|
||||||
if (item.toCharIndex.toInt() != 255) {
|
|
||||||
val date = GregorianCalendar(item.year.toInt(), item.month.toInt(), item.day.toInt())
|
|
||||||
.time
|
|
||||||
.time
|
|
||||||
|
|
||||||
storageRepository
|
|
||||||
.characterDao()
|
|
||||||
.insertTransformation(characterId, item.toCharIndex.toInt(), dimData.id, date)
|
|
||||||
|
|
||||||
storageRepository
|
|
||||||
.dexDao()
|
|
||||||
.insertCharacter(item.toCharIndex.toInt(), dimData.id, date)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (nfcCharacter.value is VBNfcCharacter) {
|
|
||||||
return "Not implemented yet"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Done reading character!"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
package com.github.nacabaro.vbhelper.components
|
package com.github.nacabaro.vbhelper.components
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardColors
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -18,58 +21,91 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
import com.github.nacabaro.vbhelper.utils.getBitmap
|
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.Dp
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
import com.github.nacabaro.vbhelper.utils.getObscuredBitmap
|
import com.github.nacabaro.vbhelper.utils.getObscuredBitmap
|
||||||
import java.nio.ByteBuffer
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CharacterEntry(
|
fun CharacterEntry(
|
||||||
icon: BitmapData,
|
icon: BitmapData,
|
||||||
obscure: Boolean = false,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
cardIcon: BitmapData? = null,
|
||||||
|
obscure: Boolean = false,
|
||||||
|
disabled: Boolean = false,
|
||||||
shape: Shape = MaterialTheme.shapes.medium,
|
shape: Shape = MaterialTheme.shapes.medium,
|
||||||
multiplier: Int = 3,
|
multiplier: Int = 4,
|
||||||
|
cardColors: CardColors = CardDefaults.cardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest
|
||||||
|
),
|
||||||
onClick: () -> Unit = { }
|
onClick: () -> Unit = { }
|
||||||
) {
|
) {
|
||||||
val bitmap = remember (icon.bitmap) {
|
val bitmap = remember (icon.bitmap) {
|
||||||
if(obscure) icon.getObscuredBitmap() else icon.getBitmap()
|
if(obscure) icon.getObscuredBitmap() else icon.getBitmap()
|
||||||
}
|
}
|
||||||
|
val iconSizeMultiplier = 3
|
||||||
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
||||||
val density: Float = LocalContext.current.resources.displayMetrics.density
|
val density: Float = LocalContext.current.resources.displayMetrics.density
|
||||||
val dpSize = (icon.width * multiplier / density).dp
|
val dpSize = (icon.width * multiplier / density).dp
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
shape = shape,
|
shape = shape,
|
||||||
onClick = onClick,
|
onClick = when (disabled) {
|
||||||
|
true -> { {} }
|
||||||
|
false -> onClick
|
||||||
|
},
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.padding(8.dp)
|
.padding(8.dp),
|
||||||
|
colors = cardColors
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
contentAlignment = Alignment.BottomCenter,
|
contentAlignment = Alignment.BottomCenter,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp)
|
.padding(4.dp)
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
bitmap = imageBitmap,
|
bitmap = imageBitmap,
|
||||||
contentDescription = "Icon",
|
contentDescription = "Icon",
|
||||||
filterQuality = FilterQuality.None,
|
filterQuality = FilterQuality.None,
|
||||||
|
colorFilter = when (obscure) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(dpSize)
|
.size(dpSize)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (cardIcon != null) {
|
||||||
|
val bitmap = remember (icon.bitmap) { cardIcon.getBitmap() }
|
||||||
|
val iconBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
||||||
|
val dpSize = (icon.width * iconSizeMultiplier /density).dp
|
||||||
|
|
||||||
|
Image(
|
||||||
|
bitmap = iconBitmap,
|
||||||
|
contentDescription = "Card icon",
|
||||||
|
filterQuality = FilterQuality.None,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(dpSize)
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,8 +115,6 @@ fun ItemDisplay(
|
|||||||
icon: Int,
|
icon: Int,
|
||||||
textValue: String,
|
textValue: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
iconSize: Dp = 48.dp,
|
|
||||||
textSize: TextUnit = 24.sp,
|
|
||||||
definition: String = "",
|
definition: String = "",
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -101,16 +135,125 @@ fun ItemDisplay(
|
|||||||
painter = painterResource(icon),
|
painter = painterResource(icon),
|
||||||
contentDescription = "Vitals",
|
contentDescription = "Vitals",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.fillMaxSize(0.5f)
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
.size(iconSize)
|
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = textValue,
|
text = textValue,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
fontSize = textSize,
|
|
||||||
fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
|
fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SpecialMissionsEntry(
|
||||||
|
specialMission: SpecialMissions,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClickCard: () -> Unit = { },
|
||||||
|
) {
|
||||||
|
val textValue = when (specialMission.missionType) {
|
||||||
|
SpecialMission.Type.NONE -> stringResource(R.string.special_mission_none)
|
||||||
|
SpecialMission.Type.STEPS -> stringResource(
|
||||||
|
R.string.special_mission_steps,
|
||||||
|
specialMission.goal
|
||||||
|
)
|
||||||
|
SpecialMission.Type.BATTLES -> stringResource(
|
||||||
|
R.string.special_mission_battles,
|
||||||
|
specialMission.goal
|
||||||
|
)
|
||||||
|
SpecialMission.Type.WINS -> stringResource(
|
||||||
|
R.string.special_mission_wins,
|
||||||
|
specialMission.goal
|
||||||
|
)
|
||||||
|
SpecialMission.Type.VITALS -> stringResource(
|
||||||
|
R.string.special_mission_vitals,
|
||||||
|
specialMission.goal
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val progress = if (specialMission.status == SpecialMission.Status.COMPLETED) {
|
||||||
|
specialMission.goal
|
||||||
|
} else {
|
||||||
|
specialMission.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
val completion = when (specialMission.missionType) {
|
||||||
|
SpecialMission.Type.NONE -> ""
|
||||||
|
SpecialMission.Type.STEPS -> stringResource(
|
||||||
|
R.string.special_mission_steps_progress,
|
||||||
|
progress
|
||||||
|
)
|
||||||
|
SpecialMission.Type.BATTLES -> stringResource(
|
||||||
|
R.string.special_mission_battles_progress,
|
||||||
|
progress
|
||||||
|
)
|
||||||
|
SpecialMission.Type.WINS -> stringResource(
|
||||||
|
R.string.special_mission_wins_progress,
|
||||||
|
progress
|
||||||
|
)
|
||||||
|
SpecialMission.Type.VITALS -> stringResource(
|
||||||
|
R.string.special_mission_vitals_progress,
|
||||||
|
progress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val icon = when (specialMission.missionType) {
|
||||||
|
SpecialMission.Type.NONE -> R.drawable.baseline_free_24
|
||||||
|
SpecialMission.Type.STEPS -> R.drawable.baseline_agility_24
|
||||||
|
SpecialMission.Type.BATTLES -> R.drawable.baseline_swords_24
|
||||||
|
SpecialMission.Type.WINS -> R.drawable.baseline_trophy_24
|
||||||
|
SpecialMission.Type.VITALS -> R.drawable.baseline_vitals_24
|
||||||
|
}
|
||||||
|
|
||||||
|
val color = when (specialMission.status)
|
||||||
|
{
|
||||||
|
SpecialMission.Status.IN_PROGRESS -> MaterialTheme.colorScheme.secondary
|
||||||
|
SpecialMission.Status.COMPLETED -> MaterialTheme.colorScheme.primary
|
||||||
|
SpecialMission.Status.FAILED -> MaterialTheme.colorScheme.error
|
||||||
|
else -> MaterialTheme.colorScheme.surfaceContainerHighest
|
||||||
|
}
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = modifier,
|
||||||
|
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
||||||
|
onClick = if (specialMission.status == SpecialMission.Status.COMPLETED || specialMission.status == SpecialMission.Status.FAILED) {
|
||||||
|
onClickCard
|
||||||
|
} else {
|
||||||
|
{ }
|
||||||
|
},
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = color
|
||||||
|
)
|
||||||
|
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(icon),
|
||||||
|
contentDescription = stringResource(R.string.special_mission_icon_content_description),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = textValue,
|
||||||
|
fontFamily = MaterialTheme.typography.titleLarge.fontFamily,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = completion,
|
||||||
|
fontFamily = MaterialTheme.typography.titleSmall.fontFamily,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,9 @@ fun TopBanner(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onGearClick: (() -> Unit)? = null,
|
onGearClick: (() -> Unit)? = null,
|
||||||
onBackClick: (() -> Unit)? = null,
|
onBackClick: (() -> Unit)? = null,
|
||||||
onScanClick: (() -> Unit)? = null
|
onScanClick: (() -> Unit)? = null,
|
||||||
|
onAdventureClick: (() -> Unit)? = null,
|
||||||
|
onModifyClick: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
Box( // Use Box to overlay elements
|
Box( // Use Box to overlay elements
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -36,29 +38,51 @@ fun TopBanner(
|
|||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
fontSize = 24.sp,
|
fontSize = 24.sp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center) // Center the text
|
.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
if (onGearClick != null) {
|
if (onGearClick != null) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onGearClick,
|
onClick = onGearClick,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterEnd) // Place gear icon at the end
|
.align(Alignment.CenterEnd)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.baseline_settings_24), // Use a gear icon
|
painter = painterResource(R.drawable.baseline_settings_24),
|
||||||
contentDescription = "Settings"
|
contentDescription = "Settings"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
} else if (onAdventureClick != null) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onAdventureClick,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.baseline_fort_24),
|
||||||
|
contentDescription = "Adventure"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (onModifyClick != null) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onModifyClick,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.baseline_edit_24),
|
||||||
|
contentDescription = "Adventure"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (onScanClick != null) {
|
if (onScanClick != null) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onScanClick,
|
onClick = onScanClick,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterStart) // Place gear icon at the end
|
.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.baseline_nfc_24), // Use a gear icon
|
painter = painterResource(R.drawable.baseline_nfc_24),
|
||||||
contentDescription = "Scan"
|
contentDescription = "Scan"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -66,10 +90,10 @@ fun TopBanner(
|
|||||||
IconButton(
|
IconButton(
|
||||||
onClick = onBackClick,
|
onClick = onBackClick,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterStart) // Place gear icon at the end
|
.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(R.drawable.baseline_arrow_back_24), // Use a gear icon
|
painter = painterResource(R.drawable.baseline_arrow_back_24),
|
||||||
contentDescription = "Settings"
|
contentDescription = "Settings"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface AdventureDao {
|
||||||
|
@Query("""
|
||||||
|
INSERT INTO Adventure (characterId, originalDuration, finishesAdventure)
|
||||||
|
VALUES (:characterId, :originalDuration, strftime('%s', 'now') + :timeInSeconds)
|
||||||
|
""")
|
||||||
|
fun insertNewAdventure(characterId: Long, originalDuration: Long, timeInSeconds: Long)
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT COUNT(*) FROM Adventure
|
||||||
|
""")
|
||||||
|
fun getAdventureCount(): Int
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
uc.*,
|
||||||
|
c.stage,
|
||||||
|
c.attribute,
|
||||||
|
s.spriteIdle1 AS spriteIdle,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.finishesAdventure AS finishesAdventure,
|
||||||
|
a.originalDuration AS originalTimeInMinutes
|
||||||
|
FROM UserCharacter uc
|
||||||
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
JOIN Card d ON c.cardId = d.id
|
||||||
|
JOIN Adventure a ON uc.id = a.characterId
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getAdventureCharacters(): Flow<List<CharacterDtos.AdventureCharacterWithSprites>>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
DELETE FROM Adventure
|
||||||
|
WHERE characterId = :characterId
|
||||||
|
""")
|
||||||
|
suspend fun deleteAdventure(characterId: Long)
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CardAdventureDao {
|
||||||
|
@Query("""
|
||||||
|
INSERT INTO
|
||||||
|
CardAdventure (cardId, characterId, steps, bossAp, bossHp, bossDp, bossBp)
|
||||||
|
SELECT
|
||||||
|
:cardId,
|
||||||
|
cc.id,
|
||||||
|
:steps,
|
||||||
|
:bossAp,
|
||||||
|
:bossHp,
|
||||||
|
:bossDp,
|
||||||
|
:bossBp
|
||||||
|
FROM
|
||||||
|
CardCharacter cc
|
||||||
|
WHERE
|
||||||
|
cc.charaIndex = :characterId AND
|
||||||
|
cc.cardId = :cardId
|
||||||
|
""")
|
||||||
|
suspend fun insertNewAdventure(
|
||||||
|
cardId: Long,
|
||||||
|
characterId: Int,
|
||||||
|
steps: Int,
|
||||||
|
bossAp: Int,
|
||||||
|
bossHp: Int,
|
||||||
|
bossDp: Int,
|
||||||
|
bossBp: Int?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT
|
||||||
|
cc.nameSprite as characterName,
|
||||||
|
cc.nameWidth as characterNameWidth,
|
||||||
|
cc.nameHeight as characterNameHeight,
|
||||||
|
s.spriteIdle1 as characterIdleSprite,
|
||||||
|
s.width as characterIdleSpriteWidth,
|
||||||
|
s.height as characterIdleSpriteHeight,
|
||||||
|
ca.bossAp as characterAp,
|
||||||
|
ca.bossBp as characterBp,
|
||||||
|
ca.bossDp as characterDp,
|
||||||
|
ca.bossHp as characterHp,
|
||||||
|
ca.steps as steps
|
||||||
|
FROM CardCharacter cc
|
||||||
|
JOIN Sprite s ON cc.spriteId = s.id
|
||||||
|
JOIN CardAdventure ca ON cc.id = ca.characterId
|
||||||
|
WHERE
|
||||||
|
cc.cardId = :cardId
|
||||||
|
""")
|
||||||
|
fun getAdventureForCard(
|
||||||
|
cardId: Long
|
||||||
|
): Flow<List<CardDtos.CardAdventureWithSprites>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CardDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
suspend fun insertNewCard(card: Card): Long
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Card WHERE cardId = :id")
|
||||||
|
fun getCardByCardId(id: Int): List<Card>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Card WHERE id = :id")
|
||||||
|
fun getCardById(id: Long): Card?
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT ca.*
|
||||||
|
FROM Card ca
|
||||||
|
JOIN CardCharacter ch ON ca.id = ch.cardId
|
||||||
|
JOIN UserCharacter uc ON ch.id = uc.charId
|
||||||
|
WHERE uc.id = :id
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getCardByCharacterId(id: Long): Flow<Card>
|
||||||
|
|
||||||
|
@Query("UPDATE Card SET name = :newName WHERE id = :id")
|
||||||
|
suspend fun renameCard(id: Int, newName: String)
|
||||||
|
|
||||||
|
@Query("DELETE FROM Card WHERE id = :id")
|
||||||
|
suspend fun deleteCard(id: Long)
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT
|
||||||
|
c.logo as cardIcon,
|
||||||
|
c.logoWidth as cardIconWidth,
|
||||||
|
c.logoHeight as cardIconHeight
|
||||||
|
FROM Card c
|
||||||
|
JOIN CardCharacter cc ON cc.cardId = c.id
|
||||||
|
WHERE cc.id = :charaId
|
||||||
|
""")
|
||||||
|
fun getCardIconByCharaId(charaId: Long): Flow<CardDtos.CardIcon>
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CardFusionsDao {
|
||||||
|
@Query("""
|
||||||
|
INSERT INTO
|
||||||
|
CardFusions (
|
||||||
|
fromCharaId,
|
||||||
|
attribute,
|
||||||
|
toCharaId
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :fromCharaId),
|
||||||
|
:attribute,
|
||||||
|
(SELECT id FROM CardCharacter WHERE cardId = :cardId AND charaIndex = :toCharaId)
|
||||||
|
""")
|
||||||
|
suspend fun insertNewFusion(
|
||||||
|
cardId: Long,
|
||||||
|
fromCharaId: Int,
|
||||||
|
attribute: NfcCharacter.Attribute,
|
||||||
|
toCharaId: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT
|
||||||
|
cf.toCharaId as charaId,
|
||||||
|
cf.fromCharaId as fromCharaId,
|
||||||
|
s.spriteIdle1 as spriteIdle,
|
||||||
|
cc.attribute as attribute,
|
||||||
|
s.width as spriteWidth,
|
||||||
|
s.height as spriteHeight,
|
||||||
|
d.discoveredOn as discoveredOn,
|
||||||
|
cf.attribute as fusionAttribute
|
||||||
|
FROM CardFusions cf
|
||||||
|
JOIN CardCharacter cc ON cc.id = cf.toCharaId
|
||||||
|
JOIN Sprite s ON s.id = cc.id
|
||||||
|
LEFT JOIN Dex d ON d.id = cc.id
|
||||||
|
WHERE cf.fromCharaId = :charaId
|
||||||
|
ORDER BY cc.charaIndex
|
||||||
|
""")
|
||||||
|
fun getFusionsForCharacter(charaId: Long): Flow<List<CharacterDtos.FusionsWithSpritesAndObtained>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.CardProgress
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CardProgressDao {
|
||||||
|
@Query("""
|
||||||
|
UPDATE CardProgress
|
||||||
|
SET
|
||||||
|
currentStage = :currentStage,
|
||||||
|
unlocked = :unlocked
|
||||||
|
WHERE cardId = :cardId AND
|
||||||
|
currentStage < :currentStage
|
||||||
|
""")
|
||||||
|
fun updateCardProgress(currentStage: Int, cardId: Long, unlocked: Boolean)
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"SELECT currentStage FROM CardProgress WHERE cardId = :cardId"
|
||||||
|
)
|
||||||
|
fun getCardProgress(cardId: Long): Flow<Int>
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertCardProgress(cardProgress: CardProgress)
|
||||||
|
}
|
||||||
@@ -3,49 +3,88 @@ package com.github.nacabaro.vbhelper.daos
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
|
||||||
import com.github.nacabaro.vbhelper.domain.Sprites
|
import com.github.nacabaro.vbhelper.domain.characters.Sprite
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface CharacterDao {
|
interface CharacterDao {
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertCharacter(vararg characterData: Character)
|
suspend fun insertCharacter(vararg characterData: CardCharacter)
|
||||||
|
|
||||||
@Query("SELECT * FROM Character")
|
@Query("SELECT * FROM CardCharacter WHERE charaIndex = :monIndex AND cardId = :dimId LIMIT 1")
|
||||||
suspend fun getAllCharacters(): List<Character>
|
fun getCharacterByMonIndex(monIndex: Int, dimId: Long): CardCharacter
|
||||||
|
|
||||||
@Query("SELECT * FROM Character WHERE dimId = :dimId")
|
|
||||||
suspend fun getCharacterByDimId(dimId: Int): List<Character>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Character WHERE monIndex = :monIndex AND dimId = :dimId LIMIT 1")
|
|
||||||
fun getCharacterByMonIndex(monIndex: Int, dimId: Long): Character
|
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertSprite(vararg sprite: Sprites)
|
suspend fun insertSprite(vararg sprite: Sprite)
|
||||||
|
|
||||||
@Query("SELECT * FROM Sprites")
|
|
||||||
suspend fun getAllSprites(): List<Sprites>
|
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
d.dimId as cardId,
|
d.cardId as cardId,
|
||||||
c.monIndex as charId
|
c.charaIndex as charId,
|
||||||
FROM Character c
|
c.stage as stage,
|
||||||
|
c.attribute as attribute,
|
||||||
|
cp.currentStage as currentStage
|
||||||
|
FROM CardCharacter c
|
||||||
JOIN UserCharacter uc ON c.id = uc.charId
|
JOIN UserCharacter uc ON c.id = uc.charId
|
||||||
JOIN Card d ON c.dimId = d.id
|
JOIN Card d ON c.cardId = d.id
|
||||||
WHERE uc.id = :charId
|
JOIN CardProgress cp ON d.id = cp.cardId
|
||||||
|
WHERE c.id = :charId
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
suspend fun getCharacterInfo(charId: Long): CharacterDtos.DiMInfo
|
suspend fun getCharacterInfo(charId: Long): CharacterDtos.CardCharacterInfo
|
||||||
|
|
||||||
@Query("""
|
@Query(
|
||||||
INSERT INTO TransformationHistory(monId, stageId, transformationDate)
|
"""
|
||||||
VALUES
|
INSERT INTO PossibleTransformations (charaId, requiredVitals, requiredTrophies, requiredBattles, requiredWinRate, changeTimerHours, requiredAdventureLevelCompleted, toCharaId)
|
||||||
(:monId,
|
SELECT
|
||||||
(SELECT id FROM Character WHERE monIndex = :stage AND dimId = :dimId),
|
(SELECT id FROM CardCharacter WHERE charaIndex = :fromChraraIndex AND cardId = :cardId),
|
||||||
:transformationDate)
|
:requiredVitals,
|
||||||
""")
|
:requiredTrophies,
|
||||||
fun insertTransformation(monId: Long, stage: Int, dimId: Long, transformationDate: Long)
|
:requiredBattles,
|
||||||
|
:requiredWinRate,
|
||||||
|
:changeTimerHours,
|
||||||
|
:requiredAdventureLevelCompleted,
|
||||||
|
(SELECT id FROM CardCharacter WHERE charaIndex = :toChraraIndex AND cardId = :cardId)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun insertPossibleTransformation(
|
||||||
|
fromChraraIndex: Int,
|
||||||
|
toChraraIndex: Int,
|
||||||
|
cardId: Long,
|
||||||
|
requiredVitals: Int,
|
||||||
|
requiredTrophies: Int,
|
||||||
|
requiredBattles: Int,
|
||||||
|
changeTimerHours: Int,
|
||||||
|
requiredWinRate: Int,
|
||||||
|
requiredAdventureLevelCompleted: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
pt.charaId as fromCharaId,
|
||||||
|
pt.toCharaId as charaId,
|
||||||
|
s.spriteIdle1 as spriteIdle,
|
||||||
|
s.width as spriteWidth,
|
||||||
|
s.height as spriteHeight,
|
||||||
|
d.discoveredOn as discoveredOn,
|
||||||
|
pt.requiredTrophies as requiredTrophies,
|
||||||
|
pt.requiredVitals as requiredVitals,
|
||||||
|
pt.requiredBattles as requiredBattles,
|
||||||
|
pt.requiredWinRate as requiredWinRate,
|
||||||
|
pt.changeTimerHours as changeTimerHours,
|
||||||
|
pt.requiredAdventureLevelCompleted as requiredAdventureLevelCompleted
|
||||||
|
FROM
|
||||||
|
PossibleTransformations pt
|
||||||
|
JOIN CardCharacter c on pt.toCharaId = c.id
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Dex d ON d.id = pt.toCharaId
|
||||||
|
WHERE
|
||||||
|
pt.charaId = :characterId
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getEvolutionRequirementsForCard(characterId: Long): Flow<List<CharacterDtos.EvolutionRequirementsWithSpritesAndObtained>>
|
||||||
}
|
}
|
||||||
@@ -4,41 +4,57 @@ import androidx.room.Dao
|
|||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface DexDao {
|
interface DexDao {
|
||||||
@Query("""
|
@Query(
|
||||||
|
"""
|
||||||
INSERT OR IGNORE INTO Dex(id, discoveredOn)
|
INSERT OR IGNORE INTO Dex(id, discoveredOn)
|
||||||
VALUES (
|
VALUES (
|
||||||
(SELECT id FROM Character WHERE monIndex = :charIndex AND dimId = :cardId),
|
(SELECT id FROM CardCharacter WHERE charaIndex = :charIndex AND cardId = :cardId),
|
||||||
:discoveredOn
|
:discoveredOn
|
||||||
)
|
)
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
fun insertCharacter(charIndex: Int, cardId: Long, discoveredOn: Long)
|
fun insertCharacter(charIndex: Int, cardId: Long, discoveredOn: Long)
|
||||||
|
|
||||||
@Query("""
|
@Query(
|
||||||
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
c.id AS id,
|
c.id AS id,
|
||||||
c.sprite1 AS spriteIdle,
|
s.spriteIdle1 AS spriteIdle,
|
||||||
c.spritesWidth AS spriteWidth,
|
s.width AS spriteWidth,
|
||||||
c.spritesHeight AS spriteHeight,
|
s.height AS spriteHeight,
|
||||||
d.discoveredOn AS discoveredOn
|
c.nameSprite AS nameSprite,
|
||||||
FROM character c
|
c.nameWidth AS nameSpriteWidth,
|
||||||
|
c.nameHeight AS nameSpriteHeight,
|
||||||
|
d.discoveredOn AS discoveredOn,
|
||||||
|
c.baseHp as baseHp,
|
||||||
|
c.baseBp as baseBp,
|
||||||
|
c.baseAp as baseAp,
|
||||||
|
c.stage as stage,
|
||||||
|
c.attribute as attribute
|
||||||
|
FROM CardCharacter c
|
||||||
|
JOIN Sprite s ON c.spriteId = s.id
|
||||||
LEFT JOIN dex d ON c.id = d.id
|
LEFT JOIN dex d ON c.id = d.id
|
||||||
WHERE c.dimId = :cardId
|
WHERE c.cardId = :cardId
|
||||||
""")
|
"""
|
||||||
suspend fun getSingleCardProgress(cardId: Long): List<CharacterDtos.CardProgress>
|
)
|
||||||
|
fun getSingleCardProgress(cardId: Long): Flow<List<CharacterDtos.CardCharaProgress>>
|
||||||
|
|
||||||
@Query("""
|
@Query(
|
||||||
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
c.id as cardId,
|
c.id as cardId,
|
||||||
c.name as cardName,
|
c.name as cardName,
|
||||||
c.logo as cardLogo,
|
c.logo as cardLogo,
|
||||||
c.logoWidth as logoWidth,
|
c.logoWidth as logoWidth,
|
||||||
c.logoHeight as logoHeight,
|
c.logoHeight as logoHeight,
|
||||||
(SELECT COUNT(*) FROM Character cc WHERE cc.dimId = c.id) AS totalCharacters,
|
(SELECT COUNT(*) FROM CardCharacter cc WHERE cc.cardId = c.id) AS totalCharacters,
|
||||||
(SELECT COUNT(*) FROM Dex d JOIN Character cc ON d.id = cc.id WHERE cc.dimId = c.id AND d.discoveredOn IS NOT NULL) AS obtainedCharacters
|
(SELECT COUNT(*) FROM Dex d JOIN CardCharacter cc ON d.id = cc.id WHERE cc.cardId = c.id AND d.discoveredOn IS NOT NULL) AS obtainedCharacters
|
||||||
FROM Card c
|
FROM Card c
|
||||||
""")
|
"""
|
||||||
suspend fun getCardsWithProgress(): List<CardDtos.CardProgress>
|
)
|
||||||
|
fun getCardsWithProgress(): Flow<List<CardDtos.CardProgress>>
|
||||||
}
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.daos
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Insert
|
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Card
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
interface DiMDao {
|
|
||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
|
||||||
suspend fun insertNewDim(card: Card): Long
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Card")
|
|
||||||
suspend fun getAllDims(): List<Card>
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Card WHERE dimId = :id")
|
|
||||||
fun getDimById(id: Int): Card?
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.daos
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Upsert
|
|
||||||
import com.github.nacabaro.vbhelper.domain.DimProgress
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
interface DiMProgressDao {
|
|
||||||
@Upsert
|
|
||||||
suspend fun updateDimProgress(vararg dimProgress: DimProgress)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface ItemDao {
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT *
|
||||||
|
FROM Items
|
||||||
|
ORDER BY Items.itemIcon ASC
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getAllItems(): Flow<List<ItemDtos.ItemsWithQuantities>>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT *
|
||||||
|
FROM Items
|
||||||
|
WHERE quantity > 0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun getAllUserItems(): Flow<List<ItemDtos.ItemsWithQuantities>>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT *
|
||||||
|
FROM Items
|
||||||
|
WHERE Items.id = :itemId
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
UPDATE Items
|
||||||
|
SET quantity = quantity - 1
|
||||||
|
WHERE id = :itemId
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun useItem(itemId: Long)
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
UPDATE Items
|
||||||
|
SET quantity = quantity + :itemAmount
|
||||||
|
WHERE id = :itemId
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun purchaseItem(itemId: Long, itemAmount: Int)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface SpecialMissionDao {
|
||||||
|
@Query("""
|
||||||
|
UPDATE SpecialMissions SET
|
||||||
|
missionType = "NONE",
|
||||||
|
status = "UNAVAILABLE"
|
||||||
|
WHERE id = :id
|
||||||
|
""")
|
||||||
|
suspend fun clearSpecialMission(id: Long)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.daos
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.github.nacabaro.vbhelper.domain.characters.Sprite
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface SpriteDao {
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
fun insertSprite(sprite: Sprite): Long
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Sprite")
|
||||||
|
suspend fun getAllSprites(): List<Sprite>
|
||||||
|
}
|
||||||
@@ -4,10 +4,16 @@ import androidx.room.Dao
|
|||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import androidx.room.Upsert
|
||||||
|
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.UserCharacter
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
|
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VitalsHistory
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface UserCharacterDao {
|
interface UserCharacterDao {
|
||||||
@@ -17,60 +23,127 @@ interface UserCharacterDao {
|
|||||||
@Insert
|
@Insert
|
||||||
fun insertBECharacterData(characterData: BECharacterData)
|
fun insertBECharacterData(characterData: BECharacterData)
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
fun insertVBCharacterData(characterData: VBCharacterData)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
fun updateCharacter(character: UserCharacter)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
fun updateBECharacterData(characterData: BECharacterData)
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
fun insertTransformationHistory(vararg transformationHistory: TransformationHistory)
|
fun insertTransformationHistory(vararg transformationHistory: TransformationHistory)
|
||||||
|
|
||||||
@Query("""
|
@Upsert
|
||||||
|
fun insertSpecialMissions(vararg specialMissions: SpecialMissions)
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
c.id AS id,
|
c.id AS id,
|
||||||
c.sprite1 AS spriteIdle,
|
s.spriteIdle1 AS spriteIdle,
|
||||||
c.spritesWidth AS spriteWidth,
|
s.width AS spriteWidth,
|
||||||
c.spritesHeight AS spriteHeight,
|
s.height AS spriteHeight,
|
||||||
c.monIndex AS monIndex,
|
c.charaIndex AS monIndex,
|
||||||
t.transformationDate AS transformationDate
|
t.transformationDate AS transformationDate
|
||||||
FROM TransformationHistory t
|
FROM TransformationHistory t
|
||||||
JOIN Character c ON c.id = t.stageId
|
JOIN CardCharacter c ON c.id = t.stageId
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
WHERE monId = :monId
|
WHERE monId = :monId
|
||||||
""")
|
"""
|
||||||
fun getTransformationHistory(monId: Long): List<CharacterDtos.TransformationHistory>?
|
)
|
||||||
|
fun getTransformationHistory(monId: Long): Flow<List<CharacterDtos.TransformationHistory>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
uc.*,
|
uc.*,
|
||||||
c.sprite1 AS spriteIdle,
|
c.stage,
|
||||||
c.spritesWidth AS spriteWidth,
|
c.attribute,
|
||||||
c.spritesHeight AS spriteHeight,
|
s.spriteIdle1 AS spriteIdle,
|
||||||
d.isBEm as isBemCard
|
s.spriteIdle2 AS spriteIdle2,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
c.nameSprite as nameSprite,
|
||||||
|
c.nameWidth as nameSpriteWidth,
|
||||||
|
c.nameHeight as nameSpriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.characterId = uc.id as isInAdventure,
|
||||||
|
uc.isActive as active
|
||||||
FROM UserCharacter uc
|
FROM UserCharacter uc
|
||||||
JOIN Character c ON uc.charId = c.id
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
JOIN Card d ON c.dimId = d.id
|
JOIN Card d ON d.id = c.cardId
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Adventure a ON a.characterId = uc.id
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
suspend fun getAllCharacters(): List<CharacterDtos.CharacterWithSprites>
|
fun getAllCharacters(): Flow<List<CharacterDtos.CharacterWithSprites>>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
uc.*,
|
||||||
|
c.stage,
|
||||||
|
c.attribute,
|
||||||
|
s.spriteIdle1 AS spriteIdle,
|
||||||
|
s.spriteIdle2 AS spriteIdle2,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
c.nameSprite as nameSprite,
|
||||||
|
c.nameWidth as nameSpriteWidth,
|
||||||
|
c.nameHeight as nameSpriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.characterId = uc.id as isInAdventure,
|
||||||
|
uc.isActive as active
|
||||||
|
FROM UserCharacter uc
|
||||||
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
|
JOIN Card d ON c.cardId = d.id
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Adventure a ON a.characterId = uc.id
|
||||||
|
WHERE uc.id = :id
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun getCharacterWithSprites(id: Long): CharacterDtos.CharacterWithSprites
|
||||||
|
|
||||||
@Query("SELECT * FROM UserCharacter WHERE id = :id")
|
@Query("SELECT * FROM UserCharacter WHERE id = :id")
|
||||||
suspend fun getCharacter(id: Long): UserCharacter
|
suspend fun getCharacter(id: Long): UserCharacter
|
||||||
|
|
||||||
@Query("SELECT * FROM BECharacterData WHERE id = :id")
|
@Query("SELECT * FROM BECharacterData WHERE id = :id")
|
||||||
suspend fun getBeData(id: Long): BECharacterData
|
fun getBeData(id: Long): Flow<BECharacterData>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM VBCharacterData WHERE id = :id")
|
||||||
|
fun getVbData(id: Long): Flow<VBCharacterData>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM SpecialMissions WHERE characterId = :id")
|
||||||
|
fun getSpecialMissions(id: Long): Flow<List<SpecialMissions>>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
uc.*,
|
uc.*,
|
||||||
c.sprite1 AS spriteIdle,
|
c.stage,
|
||||||
c.spritesWidth AS spriteWidth,
|
c.attribute,
|
||||||
c.spritesHeight AS spriteHeight,
|
s.spriteIdle1 AS spriteIdle,
|
||||||
d.isBEm as isBemCard
|
s.spriteIdle2 AS spriteIdle2,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
c.nameSprite as nameSprite,
|
||||||
|
c.nameWidth as nameSpriteWidth,
|
||||||
|
c.nameHeight as nameSpriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.characterId as isInAdventure,
|
||||||
|
uc.isActive as active
|
||||||
FROM UserCharacter uc
|
FROM UserCharacter uc
|
||||||
JOIN Character c ON uc.charId = c.id
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
JOIN Card d ON c.dimId = d.id
|
JOIN Card d ON c.cardId = d.id
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Adventure a ON a.characterId = uc.id
|
||||||
WHERE uc.isActive = 1
|
WHERE uc.isActive = 1
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
suspend fun getActiveCharacter(): CharacterDtos.CharacterWithSprites?
|
fun getActiveCharacter(): Flow<CharacterDtos.CharacterWithSprites?>
|
||||||
|
|
||||||
@Query("DELETE FROM UserCharacter WHERE id = :id")
|
@Query("DELETE FROM UserCharacter WHERE id = :id")
|
||||||
fun deleteCharacterById(id: Long)
|
fun deleteCharacterById(id: Long)
|
||||||
@@ -80,4 +153,85 @@ interface UserCharacterDao {
|
|||||||
|
|
||||||
@Query("UPDATE UserCharacter SET isActive = 1 WHERE id = :id")
|
@Query("UPDATE UserCharacter SET isActive = 1 WHERE id = :id")
|
||||||
fun setActiveCharacter(id: Long)
|
fun setActiveCharacter(id: Long)
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT c.*
|
||||||
|
FROM CardCharacter c
|
||||||
|
join UserCharacter uc on c.id = uc.charId
|
||||||
|
where uc.id = :charId
|
||||||
|
LIMIT 1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun getCharacterInfo(charId: Long): CardCharacter
|
||||||
|
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
INSERT INTO TransformationHistory(monId, stageId, transformationDate)
|
||||||
|
VALUES
|
||||||
|
(:monId,
|
||||||
|
(SELECT id FROM CardCharacter WHERE charaIndex = :stage AND cardId = :dimId),
|
||||||
|
:transformationDate)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
fun insertTransformation(monId: Long, stage: Int, dimId: Long, transformationDate: Long)
|
||||||
|
|
||||||
|
@Upsert
|
||||||
|
fun insertVitals(vararg vitalsHistory: VitalsHistory)
|
||||||
|
|
||||||
|
@Query("""SELECT * FROM VitalsHistory WHERE charId = :charId ORDER BY id ASC""")
|
||||||
|
suspend fun getVitalsHistory(charId: Long): List<VitalsHistory>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
uc.*,
|
||||||
|
c.stage,
|
||||||
|
c.attribute,
|
||||||
|
s.spriteIdle1 AS spriteIdle,
|
||||||
|
s.spriteIdle2 AS spriteIdle2,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
c.nameSprite as nameSprite,
|
||||||
|
c.nameWidth as nameSpriteWidth,
|
||||||
|
c.nameHeight as nameSpriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.characterId = uc.id as isInAdventure,
|
||||||
|
uc.isActive as active
|
||||||
|
FROM UserCharacter uc
|
||||||
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
|
JOIN Card d ON d.id = c.cardId
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Adventure a ON a.characterId = uc.id
|
||||||
|
WHERE uc.characterType = "BEDevice"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun getBECharacters(): List<CharacterDtos.CharacterWithSprites>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
uc.*,
|
||||||
|
c.stage,
|
||||||
|
c.attribute,
|
||||||
|
s.spriteIdle1 AS spriteIdle,
|
||||||
|
s.spriteIdle2 AS spriteIdle2,
|
||||||
|
s.width AS spriteWidth,
|
||||||
|
s.height AS spriteHeight,
|
||||||
|
c.nameSprite as nameSprite,
|
||||||
|
c.nameWidth as nameSpriteWidth,
|
||||||
|
c.nameHeight as nameSpriteHeight,
|
||||||
|
d.isBEm as isBemCard,
|
||||||
|
a.characterId = uc.id as isInAdventure,
|
||||||
|
uc.isActive as active
|
||||||
|
FROM UserCharacter uc
|
||||||
|
JOIN CardCharacter c ON uc.charId = c.id
|
||||||
|
JOIN Card d ON d.id = c.cardId
|
||||||
|
JOIN Sprite s ON s.id = c.spriteId
|
||||||
|
LEFT JOIN Adventure a ON a.characterId = uc.id
|
||||||
|
WHERE uc.characterType = "VBDevice"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
suspend fun getVBDimCharacters(): List<CharacterDtos.CharacterWithSprites>
|
||||||
}
|
}
|
||||||
@@ -2,33 +2,67 @@ package com.github.nacabaro.vbhelper.database
|
|||||||
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
|
import com.github.nacabaro.vbhelper.daos.AdventureDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.CardAdventureDao
|
||||||
import com.github.nacabaro.vbhelper.daos.CharacterDao
|
import com.github.nacabaro.vbhelper.daos.CharacterDao
|
||||||
import com.github.nacabaro.vbhelper.daos.DexDao
|
import com.github.nacabaro.vbhelper.daos.DexDao
|
||||||
import com.github.nacabaro.vbhelper.daos.DiMDao
|
import com.github.nacabaro.vbhelper.daos.CardDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.CardFusionsDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.CardProgressDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.ItemDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.SpecialMissionDao
|
||||||
|
import com.github.nacabaro.vbhelper.daos.SpriteDao
|
||||||
import com.github.nacabaro.vbhelper.daos.UserCharacterDao
|
import com.github.nacabaro.vbhelper.daos.UserCharacterDao
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
import com.github.nacabaro.vbhelper.domain.card.Background
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Card
|
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
|
||||||
import com.github.nacabaro.vbhelper.domain.Sprites
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.CardAdventure
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.CardFusions
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.CardProgress
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.PossibleTransformations
|
||||||
|
import com.github.nacabaro.vbhelper.domain.characters.Sprite
|
||||||
|
import com.github.nacabaro.vbhelper.domain.characters.Adventure
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Dex
|
import com.github.nacabaro.vbhelper.domain.characters.Dex
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
|
import com.github.nacabaro.vbhelper.domain.device_data.TransformationHistory
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VitalsHistory
|
||||||
|
import com.github.nacabaro.vbhelper.domain.items.Items
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
version = 1,
|
version = 1,
|
||||||
entities = [
|
entities = [
|
||||||
Card::class,
|
Card::class,
|
||||||
Character::class,
|
CardProgress::class,
|
||||||
Sprites::class,
|
CardCharacter::class,
|
||||||
|
CardAdventure::class,
|
||||||
|
CardFusions::class,
|
||||||
|
Sprite::class,
|
||||||
UserCharacter::class,
|
UserCharacter::class,
|
||||||
BECharacterData::class,
|
BECharacterData::class,
|
||||||
|
VBCharacterData::class,
|
||||||
|
SpecialMissions::class,
|
||||||
TransformationHistory::class,
|
TransformationHistory::class,
|
||||||
Dex::class
|
VitalsHistory::class,
|
||||||
|
Dex::class,
|
||||||
|
Items::class,
|
||||||
|
Adventure::class,
|
||||||
|
Background::class,
|
||||||
|
PossibleTransformations::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun dimDao(): DiMDao
|
abstract fun cardDao(): CardDao
|
||||||
|
abstract fun cardProgressDao(): CardProgressDao
|
||||||
abstract fun characterDao(): CharacterDao
|
abstract fun characterDao(): CharacterDao
|
||||||
abstract fun userCharacterDao(): UserCharacterDao
|
abstract fun userCharacterDao(): UserCharacterDao
|
||||||
abstract fun dexDao(): DexDao
|
abstract fun dexDao(): DexDao
|
||||||
|
abstract fun itemDao(): ItemDao
|
||||||
|
abstract fun adventureDao(): AdventureDao
|
||||||
|
abstract fun spriteDao(): SpriteDao
|
||||||
|
abstract fun specialMissionDao(): SpecialMissionDao
|
||||||
|
abstract fun cardAdventureDao(): CardAdventureDao
|
||||||
|
abstract fun cardFusionsDao(): CardFusionsDao
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.github.nacabaro.vbhelper.di
|
package com.github.nacabaro.vbhelper.di
|
||||||
|
|
||||||
import com.github.nacabaro.vbhelper.database.AppDatabase
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
|
import com.github.nacabaro.vbhelper.source.CurrencyRepository
|
||||||
import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository
|
import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository
|
||||||
|
|
||||||
interface AppContainer {
|
interface AppContainer {
|
||||||
val db: AppDatabase
|
val db: AppDatabase
|
||||||
val dataStoreSecretsRepository: DataStoreSecretsRepository
|
val dataStoreSecretsRepository: DataStoreSecretsRepository
|
||||||
|
val currencyRepository: CurrencyRepository
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,27 @@
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.datastore.core.DataStore
|
import androidx.datastore.core.DataStore
|
||||||
import androidx.datastore.dataStore
|
import androidx.datastore.dataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import com.github.nacabaro.vbhelper.database.AppDatabase
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
import com.github.nacabaro.vbhelper.di.AppContainer
|
import com.github.nacabaro.vbhelper.di.AppContainer
|
||||||
|
import com.github.nacabaro.vbhelper.source.CurrencyRepository
|
||||||
import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository
|
import com.github.nacabaro.vbhelper.source.DataStoreSecretsRepository
|
||||||
import com.github.nacabaro.vbhelper.source.SecretsSerializer
|
import com.github.nacabaro.vbhelper.source.SecretsSerializer
|
||||||
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
||||||
|
|
||||||
private const val SECRETS_DATA_STORE_NAME = "secrets.pb"
|
private const val SECRETS_DATA_STORE_NAME = "secrets.pb"
|
||||||
|
private const val USER_PREFERENCES_NAME = "user_preferences"
|
||||||
val Context.secretsStore: DataStore<Secrets> by dataStore(
|
val Context.secretsStore: DataStore<Secrets> by dataStore(
|
||||||
fileName = SECRETS_DATA_STORE_NAME,
|
fileName = SECRETS_DATA_STORE_NAME,
|
||||||
serializer = SecretsSerializer
|
serializer = SecretsSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val Context.currencyStore: DataStore<Preferences> by preferencesDataStore(
|
||||||
|
name = USER_PREFERENCES_NAME
|
||||||
|
)
|
||||||
|
|
||||||
class DefaultAppContainer(private val context: Context) : AppContainer {
|
class DefaultAppContainer(private val context: Context) : AppContainer {
|
||||||
|
|
||||||
override val db: AppDatabase by lazy {
|
override val db: AppDatabase by lazy {
|
||||||
@@ -22,10 +29,13 @@ class DefaultAppContainer(private val context: Context) : AppContainer {
|
|||||||
context = context,
|
context = context,
|
||||||
klass = AppDatabase::class.java,
|
klass = AppDatabase::class.java,
|
||||||
"internalDb"
|
"internalDb"
|
||||||
).build()
|
)
|
||||||
|
.createFromAsset("items.db")
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val dataStoreSecretsRepository = DataStoreSecretsRepository(context.secretsStore)
|
override val dataStoreSecretsRepository = DataStoreSecretsRepository(context.secretsStore)
|
||||||
|
|
||||||
|
override val currencyRepository = CurrencyRepository(context.currencyStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.domain
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.ForeignKey
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Card
|
|
||||||
|
|
||||||
@Entity(
|
|
||||||
foreignKeys = [
|
|
||||||
ForeignKey(
|
|
||||||
entity = User::class,
|
|
||||||
parentColumns = ["id"],
|
|
||||||
childColumns = ["userId"],
|
|
||||||
onDelete = ForeignKey.CASCADE
|
|
||||||
),
|
|
||||||
ForeignKey(
|
|
||||||
entity = Card::class,
|
|
||||||
parentColumns = ["id"],
|
|
||||||
childColumns = ["dimId"],
|
|
||||||
onDelete = ForeignKey.CASCADE
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
data class DimProgress(
|
|
||||||
@PrimaryKey val dimId: Int,
|
|
||||||
@PrimaryKey val userId: Int,
|
|
||||||
val currentStage: Int,
|
|
||||||
val unlocked: Boolean
|
|
||||||
)
|
|
||||||
@@ -3,7 +3,6 @@ package com.github.nacabaro.vbhelper.domain
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.domain
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
data class Sprites(
|
|
||||||
@PrimaryKey(autoGenerate = true) val id : Int,
|
|
||||||
val sprite: ByteArray,
|
|
||||||
val width: Int,
|
|
||||||
val height: Int
|
|
||||||
)
|
|
||||||
@@ -3,7 +3,6 @@ package com.github.nacabaro.vbhelper.domain
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = Card::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["cardId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class Background (
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long,
|
||||||
|
val cardId: Long,
|
||||||
|
val background: ByteArray,
|
||||||
|
val backgroundWidth: Int,
|
||||||
|
val backgroundHeight: Int
|
||||||
|
)
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package com.github.nacabaro.vbhelper.domain.characters
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
@@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
|||||||
data class Card(
|
data class Card(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
val id: Long = 0,
|
val id: Long = 0,
|
||||||
val dimId: Int,
|
val cardId: Int,
|
||||||
val logo: ByteArray,
|
val logo: ByteArray,
|
||||||
val logoWidth: Int,
|
val logoWidth: Int,
|
||||||
val logoHeight: Int,
|
val logoHeight: Int,
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = CardCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["characterId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = Card::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["cardId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class CardAdventure(
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
|
val cardId: Long,
|
||||||
|
val characterId: Long,
|
||||||
|
val steps: Int,
|
||||||
|
val bossHp: Int,
|
||||||
|
val bossAp: Int,
|
||||||
|
val bossDp: Int,
|
||||||
|
val bossBp: Int?
|
||||||
|
)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.domain.characters.Sprite
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = Card::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["cardId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = Sprite::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["spriteId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Character represents a character on a card. There should only be one of these per dimId
|
||||||
|
* and monIndex.
|
||||||
|
* TODO: Customs will mean this should be unique per cardName and monIndex
|
||||||
|
*/
|
||||||
|
data class CardCharacter (
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
|
val cardId: Long,
|
||||||
|
val spriteId: Long,
|
||||||
|
val charaIndex: Int,
|
||||||
|
val stage: Int, // These should be replaced with enums
|
||||||
|
val attribute: NfcCharacter.Attribute, // This one too
|
||||||
|
val baseHp: Int,
|
||||||
|
val baseBp: Int,
|
||||||
|
val baseAp: Int,
|
||||||
|
val nameSprite: ByteArray,
|
||||||
|
val nameWidth: Int,
|
||||||
|
val nameHeight: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = CardCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["fromCharaId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = CardCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["toCharaId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class CardFusions(
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long,
|
||||||
|
val fromCharaId: Long,
|
||||||
|
val attribute: NfcCharacter.Attribute,
|
||||||
|
val toCharaId: Long
|
||||||
|
)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = Card::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["cardId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class CardProgress(
|
||||||
|
@PrimaryKey val cardId: Long,
|
||||||
|
val currentStage: Int,
|
||||||
|
val unlocked: Boolean
|
||||||
|
)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.card
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = CardCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["charaId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
),
|
||||||
|
ForeignKey(
|
||||||
|
entity = CardCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["toCharaId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class PossibleTransformations (
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
|
var charaId: Long,
|
||||||
|
val requiredVitals: Int,
|
||||||
|
val requiredTrophies: Int,
|
||||||
|
val requiredBattles: Int,
|
||||||
|
val requiredWinRate: Int,
|
||||||
|
val changeTimerHours: Int,
|
||||||
|
val requiredAdventureLevelCompleted: Int,
|
||||||
|
val toCharaId: Long?
|
||||||
|
)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.characters
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = UserCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["characterId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class Adventure(
|
||||||
|
@PrimaryKey val characterId: Long,
|
||||||
|
val originalDuration: Long,
|
||||||
|
val finishesAdventure: Long
|
||||||
|
)
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.domain.characters
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import androidx.room.ForeignKey
|
|
||||||
|
|
||||||
@Entity(
|
|
||||||
foreignKeys = [
|
|
||||||
ForeignKey(
|
|
||||||
entity = Card::class,
|
|
||||||
parentColumns = ["id"],
|
|
||||||
childColumns = ["dimId"],
|
|
||||||
onDelete = ForeignKey.CASCADE
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
data class Character (
|
|
||||||
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
|
||||||
val dimId: Long,
|
|
||||||
val monIndex: Int,
|
|
||||||
val name: ByteArray,
|
|
||||||
val stage: Int, // These should be replaced with enums
|
|
||||||
val attribute: Int, // This one too
|
|
||||||
val baseHp: Int,
|
|
||||||
val baseBp: Int,
|
|
||||||
val baseAp: Int,
|
|
||||||
val sprite1: ByteArray,
|
|
||||||
val sprite2: ByteArray,
|
|
||||||
val nameWidth: Int,
|
|
||||||
val nameHeight: Int,
|
|
||||||
val spritesWidth: Int,
|
|
||||||
val spritesHeight: Int
|
|
||||||
)
|
|
||||||
@@ -3,11 +3,12 @@ package com.github.nacabaro.vbhelper.domain.characters
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
ForeignKey(
|
ForeignKey(
|
||||||
entity = Character::class,
|
entity = CardCharacter::class,
|
||||||
parentColumns = ["id"],
|
parentColumns = ["id"],
|
||||||
childColumns = ["id"],
|
childColumns = ["id"],
|
||||||
onDelete = ForeignKey.CASCADE
|
onDelete = ForeignKey.CASCADE
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.characters
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
data class Sprite(
|
||||||
|
@PrimaryKey(autoGenerate = true) val id : Int = 0,
|
||||||
|
val spriteIdle1: ByteArray,
|
||||||
|
val spriteIdle2: ByteArray,
|
||||||
|
val spriteWalk1: ByteArray,
|
||||||
|
val spriteWalk2: ByteArray,
|
||||||
|
val spriteRun1: ByteArray,
|
||||||
|
val spriteRun2: ByteArray,
|
||||||
|
val spriteTrain1: ByteArray,
|
||||||
|
val spriteTrain2: ByteArray,
|
||||||
|
val spriteHappy: ByteArray,
|
||||||
|
val spriteSleep: ByteArray,
|
||||||
|
val spriteAttack: ByteArray,
|
||||||
|
val spriteDodge: ByteArray,
|
||||||
|
val width: Int,
|
||||||
|
val height: Int
|
||||||
|
)
|
||||||
+4
-4
@@ -20,7 +20,7 @@ data class BECharacterData (
|
|||||||
val trainingHp: Int,
|
val trainingHp: Int,
|
||||||
val trainingAp: Int,
|
val trainingAp: Int,
|
||||||
val trainingBp: Int,
|
val trainingBp: Int,
|
||||||
val remainingTrainingTimeInMinutes: Int,
|
var remainingTrainingTimeInMinutes: Int,
|
||||||
val itemEffectMentalStateValue: Int,
|
val itemEffectMentalStateValue: Int,
|
||||||
val itemEffectMentalStateMinutesRemaining: Int,
|
val itemEffectMentalStateMinutesRemaining: Int,
|
||||||
val itemEffectActivityLevelValue: Int,
|
val itemEffectActivityLevelValue: Int,
|
||||||
@@ -32,9 +32,9 @@ data class BECharacterData (
|
|||||||
val abilityBranch: Int,
|
val abilityBranch: Int,
|
||||||
val abilityReset: Int,
|
val abilityReset: Int,
|
||||||
val rank: Int,
|
val rank: Int,
|
||||||
val itemType: Int,
|
var itemType: Int,
|
||||||
val itemMultiplier: Int,
|
var itemMultiplier: Int,
|
||||||
val itemRemainingTime: Int,
|
var itemRemainingTime: Int,
|
||||||
val otp0: String,
|
val otp0: String,
|
||||||
val otp1: String,
|
val otp1: String,
|
||||||
val minorVersion: Int,
|
val minorVersion: Int,
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.device_data
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = UserCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["characterId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class SpecialMissions (
|
||||||
|
@PrimaryKey(autoGenerate = true) var id: Long = 0,
|
||||||
|
var characterId: Long,
|
||||||
|
var goal: Int,
|
||||||
|
val watchId: Int,
|
||||||
|
val progress: Int,
|
||||||
|
val status: SpecialMission.Status,
|
||||||
|
val timeElapsedInMinutes: Int,
|
||||||
|
val timeLimitInMinutes: Int,
|
||||||
|
val missionType: SpecialMission.Type
|
||||||
|
)
|
||||||
+2
-2
@@ -3,7 +3,7 @@ package com.github.nacabaro.vbhelper.domain.device_data
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
@@ -14,7 +14,7 @@ import com.github.nacabaro.vbhelper.domain.characters.Character
|
|||||||
onDelete = ForeignKey.CASCADE
|
onDelete = ForeignKey.CASCADE
|
||||||
),
|
),
|
||||||
ForeignKey(
|
ForeignKey(
|
||||||
entity = Character::class,
|
entity = CardCharacter::class,
|
||||||
parentColumns = ["id"],
|
parentColumns = ["id"],
|
||||||
childColumns = ["stageId"],
|
childColumns = ["stageId"],
|
||||||
onDelete = ForeignKey.CASCADE
|
onDelete = ForeignKey.CASCADE
|
||||||
|
|||||||
@@ -5,25 +5,25 @@ import androidx.room.ForeignKey
|
|||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
import com.github.nacabaro.vbhelper.utils.DeviceType
|
import com.github.nacabaro.vbhelper.utils.DeviceType
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
import com.github.nacabaro.vbhelper.domain.card.CardCharacter
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
ForeignKey(
|
ForeignKey(
|
||||||
entity = Character::class,
|
entity = CardCharacter::class,
|
||||||
parentColumns = ["id"],
|
parentColumns = ["id"],
|
||||||
childColumns = ["charId"],
|
childColumns = ["charId"],
|
||||||
onDelete = ForeignKey.CASCADE
|
onDelete = ForeignKey.CASCADE
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
/**
|
||||||
|
* UserCharacter represents and instance of a character. The charId should map to a Character
|
||||||
|
*/
|
||||||
data class UserCharacter (
|
data class UserCharacter (
|
||||||
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
var charId: Long,
|
var charId: Long,
|
||||||
var stage: Int,
|
|
||||||
var attribute: NfcCharacter.Attribute,
|
|
||||||
var ageInDays: Int,
|
var ageInDays: Int,
|
||||||
var nextAdventureMissionStage: Int, // next adventure mission stage on the character's dim
|
|
||||||
var mood: Int,
|
var mood: Int,
|
||||||
var vitalPoints: Int,
|
var vitalPoints: Int,
|
||||||
var transformationCountdown: Int,
|
var transformationCountdown: Int,
|
||||||
|
|||||||
+19
-2
@@ -1,4 +1,21 @@
|
|||||||
package com.github.nacabaro.vbhelper.domain.device_data
|
package com.github.nacabaro.vbhelper.domain.device_data
|
||||||
|
|
||||||
class VBCharacterData {
|
import androidx.room.Entity
|
||||||
}
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = UserCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class VBCharacterData (
|
||||||
|
@PrimaryKey val id: Long,
|
||||||
|
val generation: Int,
|
||||||
|
val totalTrophies: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.device_data
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = UserCharacter::class,
|
||||||
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["charId"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class VitalsHistory (
|
||||||
|
@PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
|
val charId: Long,
|
||||||
|
val year: Int,
|
||||||
|
val month: Int,
|
||||||
|
val day: Int,
|
||||||
|
val vitalPoints: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.domain.items
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
enum class ItemType {
|
||||||
|
VBITEM,
|
||||||
|
BEITEM,
|
||||||
|
UNIVERSAL,
|
||||||
|
SPECIALMISSION
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
data class Items(
|
||||||
|
@PrimaryKey val id: Long,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val itemIcon: Int,
|
||||||
|
val itemLength: Int,
|
||||||
|
val price: Int,
|
||||||
|
val quantity: Int,
|
||||||
|
val itemType: ItemType
|
||||||
|
)
|
||||||
@@ -10,4 +10,24 @@ object CardDtos {
|
|||||||
val totalCharacters: Int,
|
val totalCharacters: Int,
|
||||||
val obtainedCharacters: Int,
|
val obtainedCharacters: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class CardAdventureWithSprites (
|
||||||
|
val characterName: ByteArray,
|
||||||
|
val characterNameWidth: Int,
|
||||||
|
val characterNameHeight: Int,
|
||||||
|
val characterIdleSprite: ByteArray,
|
||||||
|
val characterIdleSpriteWidth: Int,
|
||||||
|
val characterIdleSpriteHeight: Int,
|
||||||
|
val characterAp: Int,
|
||||||
|
val characterBp: Int?,
|
||||||
|
val characterDp: Int,
|
||||||
|
val characterHp: Int,
|
||||||
|
val steps: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CardIcon (
|
||||||
|
val cardIcon: ByteArray,
|
||||||
|
val cardIconWidth: Int,
|
||||||
|
val cardIconHeight: Int
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,76 @@ object CharacterDtos {
|
|||||||
var stage: Int,
|
var stage: Int,
|
||||||
var attribute: NfcCharacter.Attribute,
|
var attribute: NfcCharacter.Attribute,
|
||||||
var ageInDays: Int,
|
var ageInDays: Int,
|
||||||
var nextAdventureMissionStage: Int, // next adventure mission stage on the character's dim
|
var mood: Int,
|
||||||
|
var vitalPoints: Int,
|
||||||
|
var transformationCountdown: Int,
|
||||||
|
var injuryStatus: NfcCharacter.InjuryStatus,
|
||||||
|
var trophies: Int,
|
||||||
|
var currentPhaseBattlesWon: Int,
|
||||||
|
var currentPhaseBattlesLost: Int,
|
||||||
|
var totalBattlesWon: Int,
|
||||||
|
var totalBattlesLost: Int,
|
||||||
|
var activityLevel: Int,
|
||||||
|
var heartRateCurrent: Int,
|
||||||
|
var characterType: DeviceType,
|
||||||
|
val spriteIdle: ByteArray,
|
||||||
|
val spriteIdle2: ByteArray,
|
||||||
|
val spriteWidth: Int,
|
||||||
|
val spriteHeight: Int,
|
||||||
|
val nameSprite: ByteArray,
|
||||||
|
val nameSpriteWidth: Int,
|
||||||
|
val nameSpriteHeight: Int,
|
||||||
|
val isBemCard: Boolean,
|
||||||
|
val isInAdventure: Boolean,
|
||||||
|
val active: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CardCharacterInfo(
|
||||||
|
val cardId: Long,
|
||||||
|
val charId: Int,
|
||||||
|
val stage: Int,
|
||||||
|
val attribute: NfcCharacter.Attribute,
|
||||||
|
val currentStage: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TransformationHistory(
|
||||||
|
val id: Long,
|
||||||
|
val spriteIdle: ByteArray,
|
||||||
|
val spriteWidth: Int,
|
||||||
|
val spriteHeight: Int,
|
||||||
|
val monIndex: Int,
|
||||||
|
val transformationDate: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CardCharaProgress(
|
||||||
|
val id: Long,
|
||||||
|
val spriteIdle: ByteArray,
|
||||||
|
val spriteWidth: Int,
|
||||||
|
val spriteHeight: Int,
|
||||||
|
val nameSprite: ByteArray,
|
||||||
|
val nameSpriteWidth: Int,
|
||||||
|
val nameSpriteHeight: Int,
|
||||||
|
val discoveredOn: Long?,
|
||||||
|
val baseHp: Int,
|
||||||
|
val baseBp: Int,
|
||||||
|
val baseAp: Int,
|
||||||
|
val stage: Int,
|
||||||
|
val attribute: NfcCharacter.Attribute,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class CardProgress(
|
||||||
|
val id: Long,
|
||||||
|
val spriteIdle: ByteArray,
|
||||||
|
val spriteWidth: Int,
|
||||||
|
val spriteHeight: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class AdventureCharacterWithSprites(
|
||||||
|
var id: Long = 0,
|
||||||
|
var charId: Long,
|
||||||
|
var stage: Int,
|
||||||
|
var attribute: NfcCharacter.Attribute,
|
||||||
|
var ageInDays: Int,
|
||||||
var mood: Int,
|
var mood: Int,
|
||||||
var vitalPoints: Int,
|
var vitalPoints: Int,
|
||||||
var transformationCountdown: Int,
|
var transformationCountdown: Int,
|
||||||
@@ -27,28 +96,33 @@ object CharacterDtos {
|
|||||||
val spriteIdle: ByteArray,
|
val spriteIdle: ByteArray,
|
||||||
val spriteWidth: Int,
|
val spriteWidth: Int,
|
||||||
val spriteHeight: Int,
|
val spriteHeight: Int,
|
||||||
val isBemCard: Boolean
|
val isBemCard: Boolean,
|
||||||
|
val finishesAdventure: Long,
|
||||||
|
val originalTimeInMinutes: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DiMInfo(
|
data class EvolutionRequirementsWithSpritesAndObtained(
|
||||||
val cardId: Int,
|
val charaId: Long,
|
||||||
val charId: Int
|
val fromCharaId: Long,
|
||||||
)
|
|
||||||
|
|
||||||
data class TransformationHistory(
|
|
||||||
val id: Long,
|
|
||||||
val spriteIdle: ByteArray,
|
val spriteIdle: ByteArray,
|
||||||
val spriteWidth: Int,
|
val spriteWidth: Int,
|
||||||
val spriteHeight: Int,
|
val spriteHeight: Int,
|
||||||
val monIndex: Int,
|
val discoveredOn: Long?,
|
||||||
val transformationDate: Long
|
val requiredTrophies: Int,
|
||||||
|
val requiredVitals: Int,
|
||||||
|
val requiredBattles: Int,
|
||||||
|
val requiredWinRate: Int,
|
||||||
|
val changeTimerHours: Int,
|
||||||
|
val requiredAdventureLevelCompleted: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CardProgress(
|
data class FusionsWithSpritesAndObtained(
|
||||||
val id: Long,
|
val charaId: Long,
|
||||||
|
val fromCharaId: Long,
|
||||||
val spriteIdle: ByteArray,
|
val spriteIdle: ByteArray,
|
||||||
val spriteWidth: Int,
|
val spriteWidth: Int,
|
||||||
val spriteHeight: Int,
|
val spriteHeight: Int,
|
||||||
val discoveredOn: Long?
|
val discoveredOn: Long?,
|
||||||
|
val fusionAttribute: NfcCharacter.Attribute
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.dtos
|
||||||
|
|
||||||
|
import com.github.nacabaro.vbhelper.domain.items.ItemType
|
||||||
|
|
||||||
|
|
||||||
|
object ItemDtos {
|
||||||
|
data class ItemsWithQuantities(
|
||||||
|
val id: Long,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val itemIcon: Int,
|
||||||
|
val itemLength: Int,
|
||||||
|
val price: Int,
|
||||||
|
val quantity: Int,
|
||||||
|
val itemType: ItemType
|
||||||
|
)
|
||||||
|
|
||||||
|
data class PurchasedItem(
|
||||||
|
val itemId: Long,
|
||||||
|
val itemName: String,
|
||||||
|
val itemDescription: String,
|
||||||
|
val itemIcon: Int,
|
||||||
|
val itemLength: Int,
|
||||||
|
val itemAmount: Int,
|
||||||
|
val itemType: ItemType
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,31 +1,59 @@
|
|||||||
package com.github.nacabaro.vbhelper.navigation
|
package com.github.nacabaro.vbhelper.navigation
|
||||||
|
|
||||||
import android.util.Log
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
import com.github.nacabaro.vbhelper.screens.BattlesScreen
|
import com.github.nacabaro.vbhelper.screens.BattlesScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.DexScreen
|
import com.github.nacabaro.vbhelper.screens.cardScreen.CardsScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.DiMScreen
|
import com.github.nacabaro.vbhelper.screens.cardScreen.CardViewScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreen
|
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.ItemsScreen
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
|
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
|
import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.screens.SettingsScreen
|
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreen
|
||||||
import com.github.nacabaro.vbhelper.screens.SettingsScreenController
|
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewer
|
||||||
import com.github.nacabaro.vbhelper.screens.SpriteViewer
|
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.screens.StorageScreen
|
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ChooseCharacterScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.settingsScreen.SettingsScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.CardAdventureScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.CardScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.settingsScreen.CreditsScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.spriteViewer.SpriteViewerControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.screens.storageScreen.StorageScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.source.StorageRepository
|
||||||
|
|
||||||
data class AppNavigationHandlers(val settingsScreenController: SettingsScreenController, val scanScreenController: ScanScreenControllerImpl)
|
data class AppNavigationHandlers(
|
||||||
|
val settingsScreenController: SettingsScreenControllerImpl,
|
||||||
|
val scanScreenController: ScanScreenControllerImpl,
|
||||||
|
val itemsScreenController: ItemsScreenControllerImpl,
|
||||||
|
val adventureScreenController: AdventureScreenControllerImpl,
|
||||||
|
val storageScreenController: StorageScreenControllerImpl,
|
||||||
|
val homeScreenController: HomeScreenControllerImpl,
|
||||||
|
val spriteViewerController: SpriteViewerControllerImpl,
|
||||||
|
val cardScreenController: CardScreenControllerImpl
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavigation(
|
fun AppNavigation(
|
||||||
applicationNavigationHandlers: AppNavigationHandlers,
|
applicationNavigationHandlers: AppNavigationHandlers,
|
||||||
onClickImportCard: () -> Unit,
|
|
||||||
) {
|
) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
@@ -37,55 +65,81 @@ fun AppNavigation(
|
|||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = NavigationItems.Home.route,
|
startDestination = NavigationItems.Home.route,
|
||||||
|
enterTransition = {
|
||||||
|
fadeIn(
|
||||||
|
animationSpec = tween(200)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
fadeOut(
|
||||||
|
animationSpec = tween(200)
|
||||||
|
)
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(contentPadding)
|
.padding(contentPadding)
|
||||||
|
|
||||||
) {
|
) {
|
||||||
composable(NavigationItems.Battles.route) {
|
composable(NavigationItems.Battles.route) {
|
||||||
BattlesScreen()
|
BattlesScreen()
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Home.route) {
|
composable(NavigationItems.Home.route) {
|
||||||
HomeScreen(
|
HomeScreen(
|
||||||
navController = navController
|
navController = navController,
|
||||||
|
homeScreenController = applicationNavigationHandlers.homeScreenController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Storage.route) {
|
composable(NavigationItems.Storage.route) {
|
||||||
StorageScreen(
|
StorageScreen(
|
||||||
navController = navController
|
navController = navController,
|
||||||
|
adventureScreenController = applicationNavigationHandlers.adventureScreenController,
|
||||||
|
storageScreenController = applicationNavigationHandlers.storageScreenController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Scan.route) {
|
composable(NavigationItems.Scan.route) {
|
||||||
val characterIdString = it.arguments?.getString("characterId")
|
val characterIdString = it.arguments?.getString("characterId")
|
||||||
val characterId = characterIdString?.toLongOrNull()
|
var characterId by remember { mutableStateOf(characterIdString?.toLongOrNull()) }
|
||||||
|
val launchedFromHomeScreen = (characterIdString?.toLongOrNull() == null)
|
||||||
|
|
||||||
|
if (characterId == null) {
|
||||||
|
val context = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val storageRepository = StorageRepository(context.container.db)
|
||||||
|
val characterData by storageRepository.getActiveCharacter().collectAsState(null)
|
||||||
|
if (characterData != null) {
|
||||||
|
characterId = characterData!!.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ScanScreen(
|
ScanScreen(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
scanScreenController = applicationNavigationHandlers.scanScreenController,
|
scanScreenController = applicationNavigationHandlers.scanScreenController,
|
||||||
characterId = characterId
|
characterId = characterId,
|
||||||
|
launchedFromHomeScreen = launchedFromHomeScreen
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Dex.route) {
|
composable(NavigationItems.Dex.route) {
|
||||||
DexScreen(
|
CardsScreen(
|
||||||
navController = navController
|
navController = navController,
|
||||||
|
cardScreenController = applicationNavigationHandlers.cardScreenController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Settings.route) {
|
composable(NavigationItems.Settings.route) {
|
||||||
SettingsScreen(
|
SettingsScreen(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
settingsScreenController = applicationNavigationHandlers.settingsScreenController,
|
settingsScreenController = applicationNavigationHandlers.settingsScreenController
|
||||||
onClickImportCard = onClickImportCard
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.Viewer.route) {
|
composable(NavigationItems.Viewer.route) {
|
||||||
SpriteViewer(
|
SpriteViewer(
|
||||||
navController = navController
|
navController = navController,
|
||||||
|
spriteViewerController = applicationNavigationHandlers.spriteViewerController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(NavigationItems.CardView.route) {
|
composable(NavigationItems.CardView.route) {
|
||||||
val cardId = it.arguments?.getString("cardId")
|
val cardId = it.arguments?.getString("cardId")
|
||||||
if (cardId != null) {
|
if (cardId != null) {
|
||||||
DiMScreen(
|
CardViewScreen(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
dimId = cardId.toLong()
|
cardId = cardId.toLong()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +148,40 @@ fun AppNavigation(
|
|||||||
navController = navController
|
navController = navController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable(NavigationItems.ApplyItem.route) {
|
||||||
|
val itemId = it.arguments?.getString("itemId")
|
||||||
|
if (itemId != null) {
|
||||||
|
ChooseCharacterScreen(
|
||||||
|
itemsScreenController = applicationNavigationHandlers
|
||||||
|
.itemsScreenController,
|
||||||
|
navController = navController,
|
||||||
|
itemId = itemId.toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
composable(NavigationItems.Adventure.route) {
|
||||||
|
AdventureScreen(
|
||||||
|
navController = navController,
|
||||||
|
storageScreenController = applicationNavigationHandlers
|
||||||
|
.adventureScreenController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composable(NavigationItems.Credits.route) {
|
||||||
|
CreditsScreen(
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composable(NavigationItems.CardAdventure.route) {
|
||||||
|
val cardId = it.arguments?.getString("cardId")
|
||||||
|
if (cardId != null) {
|
||||||
|
CardAdventureScreen(
|
||||||
|
navController = navController,
|
||||||
|
cardId = cardId.toLong(),
|
||||||
|
cardScreenController = applicationNavigationHandlers
|
||||||
|
.cardScreenController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BottomNavigationBar(navController: NavController) {
|
fun BottomNavigationBar(navController: NavController) {
|
||||||
@@ -19,14 +19,15 @@ fun BottomNavigationBar(navController: NavController) {
|
|||||||
NavigationItems.Dex,
|
NavigationItems.Dex,
|
||||||
NavigationItems.Storage,
|
NavigationItems.Storage,
|
||||||
)
|
)
|
||||||
|
|
||||||
NavigationBar {
|
NavigationBar {
|
||||||
val currentBackStackEntry = navController.currentBackStackEntryAsState()
|
val currentBackStackEntry = navController.currentBackStackEntryAsState()
|
||||||
val currentRoute = currentBackStackEntry.value?.destination?.route
|
val currentRoute = currentBackStackEntry.value?.destination?.route
|
||||||
|
|
||||||
items.forEach { item ->
|
items.forEach { item ->
|
||||||
NavigationBarItem (
|
NavigationBarItem (
|
||||||
icon = { Icon(painter = painterResource(item.icon), contentDescription = item.label) },
|
icon = { Icon(painter = painterResource(item.icon), contentDescription = stringResource(item.label)) },
|
||||||
label = { Text(item.label) },
|
label = { Text(text = stringResource(item.label)) },
|
||||||
selected = currentRoute == item.route,
|
selected = currentRoute == item.route,
|
||||||
onClick = {
|
onClick = {
|
||||||
navController.navigate(item.route) {
|
navController.navigate(item.route) {
|
||||||
|
|||||||
@@ -1,19 +1,101 @@
|
|||||||
package com.github.nacabaro.vbhelper.navigation
|
package com.github.nacabaro.vbhelper.navigation
|
||||||
|
|
||||||
import com.github.nacabaro.vbhelper.R
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
sealed class NavigationItems (
|
sealed class NavigationItems(
|
||||||
var route: String,
|
val route: String,
|
||||||
var icon: Int,
|
@DrawableRes val icon: Int,
|
||||||
var label: String
|
@StringRes val label: Int
|
||||||
) {
|
) {
|
||||||
object Scan : NavigationItems("Scan/{characterId}", R.drawable.baseline_nfc_24, "Scan")
|
object Scan : NavigationItems(
|
||||||
object Battles : NavigationItems("Battle", R.drawable.baseline_swords_24, "Battle")
|
"Scan/{characterId}",
|
||||||
object Home : NavigationItems("Home", R.drawable.baseline_cottage_24, "Home")
|
R.drawable.baseline_nfc_24,
|
||||||
object Dex : NavigationItems("Dex", R.drawable.baseline_menu_book_24, "Dex")
|
R.string.nav_scan
|
||||||
object Storage : NavigationItems("Storage", R.drawable.baseline_catching_pokemon_24, "Storage")
|
)
|
||||||
object Settings : NavigationItems("Settings", R.drawable.baseline_settings_24, "Settings")
|
|
||||||
object Viewer : NavigationItems("Viewer", R.drawable.baseline_image_24, "Viewer")
|
object Battles : NavigationItems(
|
||||||
object CardView : NavigationItems("Card/{cardId}", R.drawable.baseline_image_24, "Card")
|
"Battle",
|
||||||
object Items : NavigationItems("Items", R.drawable.baseline_data_24, "Items")
|
R.drawable.baseline_swords_24,
|
||||||
|
R.string.nav_battle
|
||||||
|
)
|
||||||
|
|
||||||
|
object Home : NavigationItems(
|
||||||
|
"Home",
|
||||||
|
R.drawable.baseline_cottage_24,
|
||||||
|
R.string.nav_home
|
||||||
|
)
|
||||||
|
|
||||||
|
object Dex : NavigationItems(
|
||||||
|
"Dex",
|
||||||
|
R.drawable.baseline_menu_book_24,
|
||||||
|
R.string.nav_dex
|
||||||
|
)
|
||||||
|
|
||||||
|
object CardAdventure : NavigationItems(
|
||||||
|
"CardAdventure/{cardId}",
|
||||||
|
R.drawable.baseline_fort_24,
|
||||||
|
R.string.nav_card_adventure
|
||||||
|
)
|
||||||
|
|
||||||
|
object Storage : NavigationItems(
|
||||||
|
"Storage",
|
||||||
|
R.drawable.baseline_catching_pokemon_24,
|
||||||
|
R.string.nav_storage
|
||||||
|
)
|
||||||
|
|
||||||
|
object Settings : NavigationItems(
|
||||||
|
"Settings",
|
||||||
|
R.drawable.baseline_settings_24,
|
||||||
|
R.string.nav_settings
|
||||||
|
)
|
||||||
|
|
||||||
|
object Viewer : NavigationItems(
|
||||||
|
"Viewer",
|
||||||
|
R.drawable.baseline_image_24,
|
||||||
|
R.string.nav_viewer
|
||||||
|
)
|
||||||
|
|
||||||
|
object CardView : NavigationItems(
|
||||||
|
"Card/{cardId}",
|
||||||
|
R.drawable.baseline_image_24,
|
||||||
|
R.string.nav_card
|
||||||
|
)
|
||||||
|
|
||||||
|
object Items : NavigationItems(
|
||||||
|
"Items",
|
||||||
|
R.drawable.baseline_data_24,
|
||||||
|
R.string.nav_items
|
||||||
|
)
|
||||||
|
|
||||||
|
object MyItems : NavigationItems(
|
||||||
|
"MyItems",
|
||||||
|
R.drawable.baseline_data_24,
|
||||||
|
R.string.nav_my_items
|
||||||
|
)
|
||||||
|
|
||||||
|
object ItemsStore : NavigationItems(
|
||||||
|
"ItemsStore",
|
||||||
|
R.drawable.baseline_data_24,
|
||||||
|
R.string.nav_items_store
|
||||||
|
)
|
||||||
|
|
||||||
|
object ApplyItem : NavigationItems(
|
||||||
|
"ApplyItem/{itemId}",
|
||||||
|
R.drawable.baseline_data_24,
|
||||||
|
R.string.nav_apply_item
|
||||||
|
)
|
||||||
|
|
||||||
|
object Adventure : NavigationItems(
|
||||||
|
"Adventure",
|
||||||
|
R.drawable.baseline_fort_24,
|
||||||
|
R.string.nav_adventure
|
||||||
|
)
|
||||||
|
|
||||||
|
object Credits : NavigationItems(
|
||||||
|
"Credits",
|
||||||
|
R.drawable.baseline_data_24,
|
||||||
|
R.string.nav_credits
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,36 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
package com.github.nacabaro.vbhelper.screens
|
||||||
|
|
||||||
|
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.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BattlesScreen() {
|
fun BattlesScreen() {
|
||||||
Text("Battles Screen")
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.battles_online_title)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.battles_coming_soon))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
|
||||||
import com.github.nacabaro.vbhelper.components.DexDiMEntry
|
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Card
|
|
||||||
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
|
||||||
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
|
||||||
import com.github.nacabaro.vbhelper.source.DexRepository
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun DexScreen(
|
|
||||||
navController: NavController
|
|
||||||
) {
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
|
||||||
val dexRepository = DexRepository(application.container.db)
|
|
||||||
|
|
||||||
val cardList = remember { mutableStateOf<List<CardDtos.CardProgress>>(emptyList()) }
|
|
||||||
|
|
||||||
LaunchedEffect(dexRepository) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
val newDimList = dexRepository.getAllDims()
|
|
||||||
cardList.value = newDimList // Replace the entire list atomically
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold (
|
|
||||||
topBar = {
|
|
||||||
TopBanner(
|
|
||||||
text = "Discovered characters",
|
|
||||||
onGearClick = {
|
|
||||||
navController.navigate(NavigationItems.Viewer.route)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { contentPadding ->
|
|
||||||
LazyColumn (
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = contentPadding.calculateTopPadding())
|
|
||||||
) {
|
|
||||||
items(cardList.value) {
|
|
||||||
DexDiMEntry(
|
|
||||||
name = it.cardName,
|
|
||||||
logo = BitmapData(
|
|
||||||
bitmap = it.cardLogo,
|
|
||||||
width = it.logoWidth,
|
|
||||||
height = it.logoHeight
|
|
||||||
),
|
|
||||||
onClick = {
|
|
||||||
navController
|
|
||||||
.navigate(
|
|
||||||
NavigationItems
|
|
||||||
.CardView.route
|
|
||||||
.replace("{cardId}", "${it.cardId}")
|
|
||||||
)
|
|
||||||
},
|
|
||||||
obtainedCharacters = it.obtainedCharacters,
|
|
||||||
totalCharacters = it.totalCharacters,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
|
||||||
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ItemsScreen(
|
|
||||||
navController: NavController
|
|
||||||
) {
|
|
||||||
Text(text = "Items")
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsScreen(
|
|
||||||
navController: NavController,
|
|
||||||
settingsScreenController: SettingsScreenController,
|
|
||||||
onClickImportCard: () -> Unit
|
|
||||||
) {
|
|
||||||
Scaffold (
|
|
||||||
topBar = {
|
|
||||||
TopBanner(
|
|
||||||
text = "Settings",
|
|
||||||
onBackClick = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
) { contentPadding ->
|
|
||||||
Column (
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = contentPadding.calculateTopPadding())
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
SettingsSection("NFC Communication")
|
|
||||||
SettingsEntry(title = "Import APK", description = "Import Secrets From Vital Arean 2.1.0 APK") {
|
|
||||||
settingsScreenController.apkFilePickLauncher.launch(arrayOf("*/*"))
|
|
||||||
}
|
|
||||||
SettingsSection("DiM/BEm management")
|
|
||||||
SettingsEntry(title = "Import DiM card", description = "Import DiM/BEm card file", onClick = onClickImportCard)
|
|
||||||
SettingsEntry(title = "Rename DiM/BEm", description = "Set card name") { }
|
|
||||||
SettingsSection("About and credits")
|
|
||||||
SettingsEntry(title = "Credits", description = "Credits") { }
|
|
||||||
SettingsEntry(title = "About", description = "About") { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildFilePickLauncher(activity: ComponentActivity, onItemPicked: (Uri?) -> Unit): ActivityResultLauncher<Array<String>> {
|
|
||||||
return activity.registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
|
||||||
onItemPicked.invoke(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsEntry(
|
|
||||||
title: String,
|
|
||||||
description: String,
|
|
||||||
onClick: () -> Unit
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable { onClick() }
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Text(text = title)
|
|
||||||
Text(
|
|
||||||
text = description,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = MaterialTheme.colorScheme.outline
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SettingsSection(
|
|
||||||
title: String
|
|
||||||
) {
|
|
||||||
Box (
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 16.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.github.nacabaro.vbhelper.source.SecretsImporter
|
|
||||||
import com.github.nacabaro.vbhelper.source.SecretsRepository
|
|
||||||
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
data class SettingsScreenController(val apkFilePickLauncher: ActivityResultLauncher<Array<String>>) {
|
|
||||||
|
|
||||||
class Factory(private val componentActivity: ComponentActivity, private val secretsImporter: SecretsImporter, private val secretsRepository: SecretsRepository) {
|
|
||||||
|
|
||||||
fun buildSettingScreenHandlers(): SettingsScreenController {
|
|
||||||
return SettingsScreenController(
|
|
||||||
apkFilePickLauncher = buildFilePickerActivityLauncher(this::importApk)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildFilePickerActivityLauncher(onResult : (Uri?) ->Unit): ActivityResultLauncher<Array<String>> {
|
|
||||||
return componentActivity.registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
|
||||||
onResult.invoke(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun importApk(uri: Uri?) {
|
|
||||||
if(uri == null) {
|
|
||||||
componentActivity.runOnUiThread {
|
|
||||||
Toast.makeText(componentActivity, "APK Import Cancelled", Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
componentActivity.contentResolver.openInputStream(uri).use {
|
|
||||||
if(it == null) {
|
|
||||||
componentActivity.runOnUiThread {
|
|
||||||
Toast.makeText(
|
|
||||||
componentActivity,
|
|
||||||
"Selected file is empty!",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
var secrets: Secrets? = null
|
|
||||||
try {
|
|
||||||
secrets = secretsImporter.importSecrets(it)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
componentActivity.runOnUiThread {
|
|
||||||
Toast.makeText(componentActivity, "Secrets import failed. Please only select the official Vital Arena App 2.1.0 APK.", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
secretsRepository.updateSecrets(secrets)
|
|
||||||
}.invokeOnCompletion {
|
|
||||||
componentActivity.runOnUiThread {
|
|
||||||
Toast.makeText(componentActivity, "Secrets successfully imported. Connections with devices are now possible.", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.gestures.Orientation
|
|
||||||
import androidx.compose.foundation.gestures.scrollable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Card
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
|
||||||
import androidx.compose.ui.window.DialogProperties
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
|
||||||
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
|
||||||
import com.github.nacabaro.vbhelper.source.StorageRepository
|
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun StorageScreen(
|
|
||||||
navController: NavController
|
|
||||||
) {
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
|
||||||
val storageRepository = StorageRepository(application.container.db)
|
|
||||||
val monList = remember { mutableStateOf<List<CharacterDtos.CharacterWithSprites>>(emptyList()) }
|
|
||||||
|
|
||||||
var selectedCharacter by remember { mutableStateOf<Long?>(null) }
|
|
||||||
|
|
||||||
LaunchedEffect(storageRepository) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
val characterList = storageRepository.getAllCharacters()
|
|
||||||
monList.value = characterList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold (
|
|
||||||
topBar = { TopBanner(text = "My Digimon") }
|
|
||||||
) { contentPadding ->
|
|
||||||
if (monList.value.isEmpty()) {
|
|
||||||
Column (
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(top = contentPadding.calculateTopPadding())
|
|
||||||
.fillMaxSize()
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Nothing to see here",
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyVerticalGrid(
|
|
||||||
columns = GridCells.Fixed(3),
|
|
||||||
modifier = Modifier
|
|
||||||
.scrollable(state = rememberScrollState(), orientation = Orientation.Vertical)
|
|
||||||
.padding(top = contentPadding.calculateTopPadding())
|
|
||||||
) {
|
|
||||||
items(monList.value) { index ->
|
|
||||||
CharacterEntry(
|
|
||||||
icon = BitmapData(
|
|
||||||
bitmap = index.spriteIdle,
|
|
||||||
width = index.spriteWidth,
|
|
||||||
height = index.spriteHeight
|
|
||||||
),
|
|
||||||
onClick = {
|
|
||||||
selectedCharacter = index.id
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (selectedCharacter != null) {
|
|
||||||
StorageDialog(
|
|
||||||
characterId = selectedCharacter!!,
|
|
||||||
onDismissRequest = { selectedCharacter = null },
|
|
||||||
onClickSetActive = {
|
|
||||||
coroutineScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
storageRepository.setActiveCharacter(selectedCharacter!!)
|
|
||||||
selectedCharacter = null
|
|
||||||
}
|
|
||||||
navController.navigate(NavigationItems.Home.route)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSendToBracelet = {
|
|
||||||
navController.navigate(
|
|
||||||
NavigationItems.Scan.route.replace(
|
|
||||||
"{characterId}",
|
|
||||||
selectedCharacter.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun StorageDialog(
|
|
||||||
characterId: Long,
|
|
||||||
onDismissRequest: () -> Unit,
|
|
||||||
onSendToBracelet: () -> Unit,
|
|
||||||
onClickSetActive: () -> Unit
|
|
||||||
) {
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
|
||||||
val storageRepository = StorageRepository(application.container.db)
|
|
||||||
val character = remember { mutableStateOf<UserCharacter?>(null) }
|
|
||||||
|
|
||||||
LaunchedEffect(storageRepository) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
character.value = storageRepository.getSingleCharacter(characterId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialog(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
properties = DialogProperties(
|
|
||||||
dismissOnBackPress = true,
|
|
||||||
dismissOnClickOutside = true
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Card(
|
|
||||||
shape = RoundedCornerShape(16.dp)
|
|
||||||
) {
|
|
||||||
Column (
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
if (character.value != null) {
|
|
||||||
Text(
|
|
||||||
text = character.value?.toString() ?: "Loading...",
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Row (
|
|
||||||
modifier = Modifier
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
Button(
|
|
||||||
onClick = onSendToBracelet
|
|
||||||
) {
|
|
||||||
Text(text = "Send to bracelet")
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = onClickSetActive
|
|
||||||
) {
|
|
||||||
Text(text = "Set active")
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = onDismissRequest
|
|
||||||
) {
|
|
||||||
Text(text = "Close")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.adventureScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AdventureEntry(
|
||||||
|
icon: BitmapData,
|
||||||
|
timeLeft: Long,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
val bitmap = remember (icon.bitmap) { icon.getBitmap() }
|
||||||
|
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
||||||
|
val density: Float = LocalContext.current.resources.displayMetrics.density
|
||||||
|
val dpSize = (icon.width * 4 / density).dp
|
||||||
|
|
||||||
|
Card(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.height(96.dp)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = imageBitmap,
|
||||||
|
contentDescription = null,
|
||||||
|
filterQuality = FilterQuality.None,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(dpSize)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = when {
|
||||||
|
timeLeft < 0 -> "Adventure finished"
|
||||||
|
else -> "Time left: ${formatSeconds(timeLeft)}"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun formatSeconds(totalSeconds: Long): String {
|
||||||
|
val hours = totalSeconds / 3600
|
||||||
|
val minutes = (totalSeconds % 3600) / 60
|
||||||
|
val seconds = totalSeconds % 60
|
||||||
|
|
||||||
|
return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds)
|
||||||
|
}
|
||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.adventureScreen
|
||||||
|
|
||||||
|
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.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.source.StorageRepository
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import java.time.Instant
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AdventureScreen(
|
||||||
|
navController: NavController,
|
||||||
|
storageScreenController: AdventureScreenControllerImpl
|
||||||
|
) {
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val database = application.container.db
|
||||||
|
val storageRepository = StorageRepository(database)
|
||||||
|
val characterList by storageRepository.getAdventureCharacters().collectAsState(emptyList())
|
||||||
|
|
||||||
|
var obtainedItem by remember {
|
||||||
|
mutableStateOf<ItemDtos.PurchasedItem?>(null)
|
||||||
|
}
|
||||||
|
var obtainedCurrency by remember {
|
||||||
|
mutableStateOf(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentTime by produceState(initialValue = Instant.now().epochSecond) {
|
||||||
|
while (true) {
|
||||||
|
value = Instant.now().epochSecond
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cancelAdventureDialog by remember {
|
||||||
|
mutableStateOf<CharacterDtos.AdventureCharacterWithSprites?>(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.adventure_title),
|
||||||
|
onBackClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
if (characterList.isEmpty()) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(R.string.adventure_empty_state))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
) {
|
||||||
|
items(characterList) {
|
||||||
|
AdventureEntry(
|
||||||
|
icon = BitmapData(
|
||||||
|
bitmap = it.spriteIdle,
|
||||||
|
width = it.spriteWidth,
|
||||||
|
height = it.spriteHeight
|
||||||
|
),
|
||||||
|
timeLeft = it.finishesAdventure - currentTime,
|
||||||
|
onClick = {
|
||||||
|
if (it.finishesAdventure < currentTime) {
|
||||||
|
storageScreenController
|
||||||
|
.getItemFromAdventure(it.id) { adventureResult, generatedCurrency ->
|
||||||
|
obtainedItem = adventureResult
|
||||||
|
obtainedCurrency = generatedCurrency
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cancelAdventureDialog = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obtainedItem != null) {
|
||||||
|
ObtainedItemDialog(
|
||||||
|
obtainedItem = obtainedItem!!,
|
||||||
|
obtainedCurrency = obtainedCurrency,
|
||||||
|
onClickDismiss = {
|
||||||
|
obtainedItem = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancelAdventureDialog != null) {
|
||||||
|
CancelAdventureDialog(
|
||||||
|
characterSprite = BitmapData(
|
||||||
|
bitmap = cancelAdventureDialog!!.spriteIdle,
|
||||||
|
width = cancelAdventureDialog!!.spriteWidth,
|
||||||
|
height = cancelAdventureDialog!!.spriteHeight
|
||||||
|
),
|
||||||
|
onDismissRequest = {
|
||||||
|
cancelAdventureDialog = null
|
||||||
|
},
|
||||||
|
onClickConfirm = {
|
||||||
|
storageScreenController.cancelAdventure(cancelAdventureDialog!!.id) {
|
||||||
|
navController.navigate(NavigationItems.Storage.route)
|
||||||
|
}
|
||||||
|
cancelAdventureDialog = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.adventureScreen
|
||||||
|
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
|
||||||
|
interface AdventureScreenController {
|
||||||
|
fun sendCharacterToAdventure(characterId: Long, timeInMinutes: Long)
|
||||||
|
fun getItemFromAdventure(characterId: Long, onResult: (ItemDtos.PurchasedItem, Int) -> Unit)
|
||||||
|
fun cancelAdventure(characterId: Long, onResult: () -> Unit)
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.adventureScreen
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class AdventureScreenControllerImpl(
|
||||||
|
private val componentActivity: ComponentActivity,
|
||||||
|
) : AdventureScreenController {
|
||||||
|
private val application = componentActivity.applicationContext as VBHelper
|
||||||
|
private val database = application.container.db
|
||||||
|
|
||||||
|
override fun sendCharacterToAdventure(characterId: Long, timeInMinutes: Long) {
|
||||||
|
val finishesAdventureAt = timeInMinutes * 60
|
||||||
|
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val characterData = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getCharacter(characterId)
|
||||||
|
|
||||||
|
if (characterData.isActive) {
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.clearActiveCharacter()
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.adventureDao()
|
||||||
|
.insertNewAdventure(characterId, timeInMinutes, finishesAdventureAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemFromAdventure(
|
||||||
|
characterId: Long,
|
||||||
|
onResult: (ItemDtos.PurchasedItem, Int) -> Unit
|
||||||
|
) {
|
||||||
|
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
database
|
||||||
|
.adventureDao()
|
||||||
|
.deleteAdventure(characterId)
|
||||||
|
|
||||||
|
val generatedCurrency = generateRandomCurrency()
|
||||||
|
|
||||||
|
val generatedItem = generateItem(characterId)
|
||||||
|
|
||||||
|
onResult(generatedItem, generatedCurrency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun generateRandomCurrency(): Int {
|
||||||
|
val currentValue = application.container.currencyRepository.currencyValue.first()
|
||||||
|
val random = (2..6).random() * 1000
|
||||||
|
application.container.currencyRepository.setCurrencyValue(currentValue + random)
|
||||||
|
|
||||||
|
return random
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancelAdventure(characterId: Long, onResult: () -> Unit) {
|
||||||
|
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
database
|
||||||
|
.adventureDao()
|
||||||
|
.deleteAdventure(characterId)
|
||||||
|
|
||||||
|
componentActivity
|
||||||
|
.runOnUiThread {
|
||||||
|
Toast.makeText(
|
||||||
|
componentActivity,
|
||||||
|
"Adventure canceled",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
onResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun generateItem(characterId: Long): ItemDtos.PurchasedItem {
|
||||||
|
val character = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getCharacterInfo(characterId)
|
||||||
|
|
||||||
|
val randomItem = database
|
||||||
|
.itemDao()
|
||||||
|
.getAllItems()
|
||||||
|
.first()
|
||||||
|
.random()
|
||||||
|
|
||||||
|
val random = ((Random.nextFloat() * character.stage) + 3).roundToInt()
|
||||||
|
|
||||||
|
database
|
||||||
|
.itemDao()
|
||||||
|
.purchaseItem(
|
||||||
|
itemId = randomItem.id,
|
||||||
|
itemAmount = random
|
||||||
|
)
|
||||||
|
|
||||||
|
return ItemDtos.PurchasedItem(
|
||||||
|
itemId = randomItem.id,
|
||||||
|
itemAmount = random,
|
||||||
|
itemName = randomItem.name,
|
||||||
|
itemIcon = randomItem.itemIcon,
|
||||||
|
itemLength = randomItem.itemLength,
|
||||||
|
itemDescription = randomItem.description,
|
||||||
|
itemType = randomItem.itemType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.adventureScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CancelAdventureDialog(
|
||||||
|
characterSprite: BitmapData,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onClickConfirm: () -> Unit
|
||||||
|
) {
|
||||||
|
val bitmap = remember (characterSprite) { characterSprite.getBitmap() }
|
||||||
|
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
||||||
|
val density: Float = LocalContext.current.resources.displayMetrics.density
|
||||||
|
val dpSize = (characterSprite.width * 4 / density).dp
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest
|
||||||
|
) {
|
||||||
|
Card {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Image(
|
||||||
|
bitmap = imageBitmap,
|
||||||
|
contentDescription = null,
|
||||||
|
filterQuality = FilterQuality.None,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(dpSize)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Are you sure you want to cancel this character's adventure?"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClickConfirm
|
||||||
|
) {
|
||||||
|
Text(text = "Confirm")
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.padding(4.dp))
|
||||||
|
Button(
|
||||||
|
onClick = onDismissRequest
|
||||||
|
) {
|
||||||
|
Text(text = "Dismiss")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardColors
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getImageBitmap
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardAdventureEntry(
|
||||||
|
cardAdventureEntry: CardDtos.CardAdventureWithSprites,
|
||||||
|
obscure: Boolean
|
||||||
|
) {
|
||||||
|
val charaImageBitmapData = BitmapData(
|
||||||
|
bitmap = cardAdventureEntry.characterIdleSprite,
|
||||||
|
width = cardAdventureEntry.characterIdleSpriteWidth,
|
||||||
|
height = cardAdventureEntry.characterIdleSpriteHeight
|
||||||
|
).getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = 4,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
val nameImageBitmapData = BitmapData(
|
||||||
|
bitmap = cardAdventureEntry.characterName,
|
||||||
|
width = cardAdventureEntry.characterNameWidth,
|
||||||
|
height = cardAdventureEntry.characterNameHeight
|
||||||
|
).getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = 3,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
Card (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
){
|
||||||
|
Card (
|
||||||
|
colors = CardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
disabledContentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = charaImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = "Icon",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(charaImageBitmapData.dpWidth)
|
||||||
|
.padding(8.dp),
|
||||||
|
colorFilter = when (obscure) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
|
||||||
|
Column {
|
||||||
|
if (!obscure) {
|
||||||
|
Image(
|
||||||
|
bitmap = nameImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = "Icon",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(nameImageBitmapData.dpWidth)
|
||||||
|
.height(nameImageBitmapData.dpHeight),
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.padding(4.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "HP: ${cardAdventureEntry.characterHp}, DP: ${cardAdventureEntry.characterDp}, AP: ${cardAdventureEntry.characterAp}"
|
||||||
|
)
|
||||||
|
if (cardAdventureEntry.characterBp != null) {
|
||||||
|
Text(text = "BP: ${cardAdventureEntry.characterBp}")
|
||||||
|
}
|
||||||
|
Text(text = "Steps: ${cardAdventureEntry.steps}")
|
||||||
|
} else {
|
||||||
|
Text(text = "????????????????")
|
||||||
|
Text(
|
||||||
|
text = "HP: -, BP: -, AP: -"
|
||||||
|
)
|
||||||
|
if (cardAdventureEntry.characterBp != null) {
|
||||||
|
Text(text = "DP: -")
|
||||||
|
}
|
||||||
|
Text(text = "Steps: -")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardAdventureScreen(
|
||||||
|
navController: NavController,
|
||||||
|
cardScreenController: CardScreenControllerImpl,
|
||||||
|
cardId: Long
|
||||||
|
) {
|
||||||
|
val cardAdventureMissions by cardScreenController
|
||||||
|
.getCardAdventureMissions(cardId)
|
||||||
|
.collectAsState(emptyList())
|
||||||
|
val currentCardAdventure by cardScreenController
|
||||||
|
.getCardProgress(cardId)
|
||||||
|
.collectAsState(0)
|
||||||
|
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.card_adventure_missions_title),
|
||||||
|
onBackClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
.verticalScroll(state = rememberScrollState())
|
||||||
|
) {
|
||||||
|
cardAdventureMissions.mapIndexed { index, it ->
|
||||||
|
CardAdventureEntry(
|
||||||
|
cardAdventureEntry = it,
|
||||||
|
obscure = index > currentCardAdventure - 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardEntry(
|
||||||
|
name: String,
|
||||||
|
logo: BitmapData,
|
||||||
|
obtainedCharacters: Int,
|
||||||
|
totalCharacters: Int,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
displayModify: Boolean,
|
||||||
|
onClickModify: () -> Unit,
|
||||||
|
onClickDelete: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val bitmap = remember (logo.bitmap) { logo.getBitmap() }
|
||||||
|
val imageBitmap = remember(bitmap) { bitmap.asImageBitmap() }
|
||||||
|
val density: Float = LocalContext.current.resources.displayMetrics.density
|
||||||
|
val dpSize = (logo.width * 4 / density).dp
|
||||||
|
|
||||||
|
Card (
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
modifier = modifier,
|
||||||
|
onClick = if (!displayModify) {
|
||||||
|
onClick
|
||||||
|
} else {
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Image (
|
||||||
|
bitmap = imageBitmap,
|
||||||
|
contentDescription = name,
|
||||||
|
filterQuality = FilterQuality.None,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.size(dpSize)
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = name,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.card_entry_characters_obtained,
|
||||||
|
obtainedCharacters,
|
||||||
|
totalCharacters
|
||||||
|
),
|
||||||
|
fontFamily = MaterialTheme.typography.labelSmall.fontFamily,
|
||||||
|
fontSize = MaterialTheme.typography.labelSmall.fontSize,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (displayModify) {
|
||||||
|
Row (
|
||||||
|
modifier = Modifier,
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onClickModify
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Edit,
|
||||||
|
contentDescription = stringResource(R.string.card_entry_edit)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
IconButton(
|
||||||
|
onClick = onClickDelete
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Delete,
|
||||||
|
contentDescription = stringResource(R.string.card_entry_delete)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
interface CardScreenController {
|
||||||
|
fun renameCard(cardId: Long, newName: String, onRenamed: (String) -> Unit)
|
||||||
|
fun deleteCard(cardId: Long, onDeleted: () -> Unit)
|
||||||
|
fun getCardAdventureMissions(cardId: Long): Flow<List<CardDtos.CardAdventureWithSprites>>
|
||||||
|
fun getCardProgress(cardId: Long): Flow<Int>
|
||||||
|
fun getFusionsForCharacters(characterId: Long): Flow<List<CharacterDtos.FusionsWithSpritesAndObtained>>
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CardScreenControllerImpl(
|
||||||
|
private val componentActivity: ComponentActivity,
|
||||||
|
) : CardScreenController {
|
||||||
|
private val application = componentActivity.applicationContext as VBHelper
|
||||||
|
private val database = application.container.db
|
||||||
|
|
||||||
|
override fun renameCard(cardId: Long, newName: String, onRenamed: (String) -> Unit) {
|
||||||
|
componentActivity.lifecycleScope.launch {
|
||||||
|
database
|
||||||
|
.cardDao()
|
||||||
|
.renameCard(cardId.toInt(), newName)
|
||||||
|
|
||||||
|
onRenamed(newName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteCard(cardId: Long, onDeleted: () -> Unit) {
|
||||||
|
componentActivity.lifecycleScope.launch {
|
||||||
|
database
|
||||||
|
.cardDao()
|
||||||
|
.deleteCard(cardId)
|
||||||
|
|
||||||
|
onDeleted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCardAdventureMissions(cardId: Long): Flow<List<CardDtos.CardAdventureWithSprites>> {
|
||||||
|
return database
|
||||||
|
.cardAdventureDao()
|
||||||
|
.getAdventureForCard(cardId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCardProgress(cardId: Long): Flow<Int> {
|
||||||
|
return database
|
||||||
|
.cardProgressDao()
|
||||||
|
.getCardProgress(cardId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFusionsForCharacters(characterId: Long): Flow<List<CharacterDtos.FusionsWithSpritesAndObtained>> {
|
||||||
|
return database
|
||||||
|
.cardFusionsDao()
|
||||||
|
.getFusionsForCharacter(characterId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+38
-18
@@ -1,49 +1,57 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
import com.github.nacabaro.vbhelper.domain.characters.Character
|
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.dialogs.DexCharaDetailsDialog
|
||||||
import com.github.nacabaro.vbhelper.source.DexRepository
|
import com.github.nacabaro.vbhelper.source.DexRepository
|
||||||
import kotlinx.coroutines.launch
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DiMScreen(
|
fun CardViewScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
dimId: Long
|
cardId: Long
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
val dexRepository = DexRepository(application.container.db)
|
val dexRepository = DexRepository(application.container.db)
|
||||||
|
|
||||||
val characterList = remember { mutableStateOf<List<CharacterDtos.CardProgress>>(emptyList()) }
|
val characterList by dexRepository.getCharactersByCardId(cardId).collectAsState(emptyList())
|
||||||
|
|
||||||
LaunchedEffect(dexRepository) {
|
val selectedCharacter = remember { mutableStateOf<CharacterDtos.CardCharaProgress?>(null) }
|
||||||
coroutineScope.launch {
|
|
||||||
val newCharacterList = dexRepository.getCharactersByDimId(dimId)
|
|
||||||
characterList.value = newCharacterList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBanner(
|
TopBanner(
|
||||||
text = "Discovered characters",
|
text = stringResource(R.string.card_view_discovered_characters),
|
||||||
onBackClick = {
|
onBackClick = {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
|
},
|
||||||
|
onAdventureClick = {
|
||||||
|
navController
|
||||||
|
.navigate(route = NavigationItems
|
||||||
|
.CardAdventure
|
||||||
|
.route
|
||||||
|
.replace(
|
||||||
|
"{cardId}",
|
||||||
|
cardId.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -52,9 +60,11 @@ fun DiMScreen(
|
|||||||
columns = GridCells.Fixed(3),
|
columns = GridCells.Fixed(3),
|
||||||
contentPadding = contentPadding
|
contentPadding = contentPadding
|
||||||
) {
|
) {
|
||||||
items(characterList.value) { character ->
|
items(characterList) { character ->
|
||||||
CharacterEntry(
|
CharacterEntry(
|
||||||
onClick = { },
|
onClick = {
|
||||||
|
selectedCharacter.value = character
|
||||||
|
},
|
||||||
obscure = character.discoveredOn == null,
|
obscure = character.discoveredOn == null,
|
||||||
icon = BitmapData(
|
icon = BitmapData(
|
||||||
bitmap = character.spriteIdle,
|
bitmap = character.spriteIdle,
|
||||||
@@ -64,5 +74,15 @@ fun DiMScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectedCharacter.value != null) {
|
||||||
|
DexCharaDetailsDialog(
|
||||||
|
currentChara = selectedCharacter.value!!,
|
||||||
|
obscure = selectedCharacter.value!!.discoveredOn == null,
|
||||||
|
onClickClose = {
|
||||||
|
selectedCharacter.value = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.dialogs.CardDeleteDialog
|
||||||
|
import com.github.nacabaro.vbhelper.screens.cardScreen.dialogs.CardRenameDialog
|
||||||
|
import com.github.nacabaro.vbhelper.source.DexRepository
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardsScreen(
|
||||||
|
navController: NavController,
|
||||||
|
cardScreenController: CardScreenControllerImpl
|
||||||
|
) {
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val dexRepository = DexRepository(application.container.db)
|
||||||
|
val cardList by dexRepository.getAllDims().collectAsState(emptyList())
|
||||||
|
|
||||||
|
val selectedCard = remember { mutableStateOf<CardDtos.CardProgress?>(null) }
|
||||||
|
var clickedDelete by remember { mutableStateOf(false) }
|
||||||
|
var clickedRename by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
var modifyCards by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.cards_my_cards_title),
|
||||||
|
onModifyClick = {
|
||||||
|
modifyCards = !modifyCards
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
LazyColumn (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
) {
|
||||||
|
items(cardList) {
|
||||||
|
CardEntry(
|
||||||
|
name = it.cardName,
|
||||||
|
logo = BitmapData(
|
||||||
|
bitmap = it.cardLogo,
|
||||||
|
width = it.logoWidth,
|
||||||
|
height = it.logoHeight
|
||||||
|
),
|
||||||
|
onClick = {
|
||||||
|
navController
|
||||||
|
.navigate(
|
||||||
|
NavigationItems
|
||||||
|
.CardView.route
|
||||||
|
.replace("{cardId}", "${it.cardId}")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
obtainedCharacters = it.obtainedCharacters,
|
||||||
|
totalCharacters = it.totalCharacters,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
displayModify = modifyCards,
|
||||||
|
onClickModify = {
|
||||||
|
selectedCard.value = it
|
||||||
|
clickedRename = true
|
||||||
|
},
|
||||||
|
onClickDelete = {
|
||||||
|
selectedCard.value = it
|
||||||
|
clickedDelete = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clickedRename) {
|
||||||
|
CardRenameDialog(
|
||||||
|
onDismiss = {
|
||||||
|
clickedRename = false
|
||||||
|
selectedCard.value = null
|
||||||
|
},
|
||||||
|
onRename = { newName ->
|
||||||
|
Log.d("CardsScreen", "New name: $newName")
|
||||||
|
Log.d("CardsScreen", "Card: ${selectedCard.value.toString()}")
|
||||||
|
cardScreenController
|
||||||
|
.renameCard(
|
||||||
|
cardId = selectedCard.value!!.cardId,
|
||||||
|
newName = newName,
|
||||||
|
onRenamed = {
|
||||||
|
clickedRename = false
|
||||||
|
selectedCard.value = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
currentName = selectedCard.value!!.cardName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clickedDelete) {
|
||||||
|
CardDeleteDialog(
|
||||||
|
cardName = selectedCard.value!!.cardName,
|
||||||
|
onDismiss = {
|
||||||
|
clickedDelete = false
|
||||||
|
selectedCard.value = null
|
||||||
|
},
|
||||||
|
onConfirm = {
|
||||||
|
cardScreenController
|
||||||
|
.deleteCard(
|
||||||
|
cardId = selectedCard.value!!.cardId,
|
||||||
|
onDeleted = {
|
||||||
|
clickedDelete = false
|
||||||
|
selectedCard.value = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardDeleteDialog(
|
||||||
|
cardName: String,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onConfirm: () -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismiss
|
||||||
|
|
||||||
|
) {
|
||||||
|
Card ( ) {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Are you sure you want to delete $cardName. This action will also delete all the characters raised from this card.")
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
Row {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = "Confirm")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onConfirm()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = "Delete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardRenameDialog(
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onRename: (String) -> Unit,
|
||||||
|
currentName: String
|
||||||
|
) {
|
||||||
|
var cardName by remember { mutableStateOf(currentName) }
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismiss
|
||||||
|
|
||||||
|
) {
|
||||||
|
Card ( ) {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
TextField(
|
||||||
|
value = cardName,
|
||||||
|
onValueChange = { cardName = it }
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onRename(cardName)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = "Rename")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+287
@@ -0,0 +1,287 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardColors
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.source.DexRepository
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getImageBitmap
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DexCharaDetailsDialog(
|
||||||
|
currentChara: CharacterDtos.CardCharaProgress,
|
||||||
|
obscure: Boolean,
|
||||||
|
onClickClose: () -> Unit
|
||||||
|
) {
|
||||||
|
val nameMultiplier = 3
|
||||||
|
val charaMultiplier = 4
|
||||||
|
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val database = application.container.db
|
||||||
|
val dexRepository = DexRepository(database)
|
||||||
|
|
||||||
|
var showFusions by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val currentCharaPossibleTransformations by dexRepository
|
||||||
|
.getCharacterPossibleTransformations(currentChara.id)
|
||||||
|
.collectAsState(emptyList())
|
||||||
|
|
||||||
|
val currentCharaPossibleFusions by dexRepository
|
||||||
|
.getCharacterPossibleFusions(currentChara.id)
|
||||||
|
.collectAsState(emptyList())
|
||||||
|
|
||||||
|
val romanNumeralsStage = when (currentChara.stage) {
|
||||||
|
1 -> "II"
|
||||||
|
2 -> "III"
|
||||||
|
3 -> "IV"
|
||||||
|
4 -> "V"
|
||||||
|
5 -> "VI"
|
||||||
|
6 -> "VII"
|
||||||
|
else -> "I"
|
||||||
|
}
|
||||||
|
|
||||||
|
val charaBitmapData = BitmapData(
|
||||||
|
bitmap = currentChara.spriteIdle,
|
||||||
|
width = currentChara.spriteWidth,
|
||||||
|
height = currentChara.spriteHeight
|
||||||
|
)
|
||||||
|
val charaImageBitmapData = charaBitmapData.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = charaMultiplier,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
val nameBitmapData = BitmapData(
|
||||||
|
bitmap = currentChara.nameSprite,
|
||||||
|
width = currentChara.nameSpriteWidth,
|
||||||
|
height = currentChara.nameSpriteHeight
|
||||||
|
)
|
||||||
|
val nameImageBitmapData = nameBitmapData.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = nameMultiplier,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onClickClose
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
colors = CardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
disabledContentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = charaImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = stringResource(R.string.dex_chara_icon_description),
|
||||||
|
modifier = Modifier
|
||||||
|
.size(charaImageBitmapData.dpWidth)
|
||||||
|
.padding(8.dp),
|
||||||
|
colorFilter = when (obscure) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
if (!obscure) {
|
||||||
|
Column {
|
||||||
|
Image(
|
||||||
|
bitmap = nameImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = stringResource(R.string.dex_chara_name_icon_description),
|
||||||
|
modifier = Modifier
|
||||||
|
.width(nameImageBitmapData.dpWidth)
|
||||||
|
.height(nameImageBitmapData.dpHeight),
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(4.dp))
|
||||||
|
if (currentChara.baseHp != 65535) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.dex_chara_stats,
|
||||||
|
currentChara.baseHp,
|
||||||
|
currentChara.baseBp,
|
||||||
|
currentChara.baseAp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.dex_chara_stage_attribute,
|
||||||
|
romanNumeralsStage,
|
||||||
|
currentChara.attribute.toString().substring(0, 2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column {
|
||||||
|
Text(stringResource(R.string.dex_chara_unknown_name))
|
||||||
|
Spacer(modifier = Modifier.padding(4.dp))
|
||||||
|
Text(stringResource(R.string.dex_chara_stage_attribute_unknown))
|
||||||
|
Text(stringResource(R.string.dex_chara_stats_unknown))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.padding(16.dp))
|
||||||
|
Column {
|
||||||
|
currentCharaPossibleTransformations.map {
|
||||||
|
val selectedCharaBitmap = BitmapData(
|
||||||
|
bitmap = it.spriteIdle,
|
||||||
|
width = it.spriteWidth,
|
||||||
|
height = it.spriteHeight
|
||||||
|
)
|
||||||
|
val selectedCharaImageBitmap = selectedCharaBitmap.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = 4,
|
||||||
|
obscure = it.discoveredOn == null
|
||||||
|
)
|
||||||
|
|
||||||
|
Card (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
colors = CardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
disabledContentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = selectedCharaImageBitmap.imageBitmap,
|
||||||
|
contentDescription = stringResource(R.string.dex_chara_icon_description),
|
||||||
|
modifier = Modifier
|
||||||
|
.size(selectedCharaImageBitmap.dpWidth)
|
||||||
|
.padding(8.dp),
|
||||||
|
colorFilter = when (it.discoveredOn == null) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.dex_chara_requirements,
|
||||||
|
it.requiredTrophies,
|
||||||
|
it.requiredBattles,
|
||||||
|
it.requiredVitals,
|
||||||
|
it.requiredWinRate,
|
||||||
|
it.changeTimerHours
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.dex_chara_adventure_level,
|
||||||
|
it.requiredAdventureLevelCompleted + 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
if (currentCharaPossibleFusions.isNotEmpty()) {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
showFusions = true
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.dex_chara_fusions_button))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = onClickClose
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.dex_chara_close_button))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showFusions) {
|
||||||
|
DexCharaFusionsDialog(
|
||||||
|
currentChara = currentChara,
|
||||||
|
currentCharaPossibleFusions = currentCharaPossibleFusions,
|
||||||
|
onClickDismiss = {
|
||||||
|
showFusions = false
|
||||||
|
},
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen.dialogs
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardColors
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import com.github.nacabaro.vbhelper.utils.getImageBitmap
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DexCharaFusionsDialog(
|
||||||
|
currentChara: CharacterDtos.CardCharaProgress,
|
||||||
|
currentCharaPossibleFusions: List<CharacterDtos.FusionsWithSpritesAndObtained>,
|
||||||
|
obscure: Boolean,
|
||||||
|
onClickDismiss: () -> Unit,
|
||||||
|
) {
|
||||||
|
val nameMultiplier = 3
|
||||||
|
val charaMultiplier = 4
|
||||||
|
|
||||||
|
val charaBitmapData = BitmapData(
|
||||||
|
bitmap = currentChara.spriteIdle,
|
||||||
|
width = currentChara.spriteWidth,
|
||||||
|
height = currentChara.spriteHeight
|
||||||
|
)
|
||||||
|
val charaImageBitmapData = charaBitmapData.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = charaMultiplier,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
val nameBitmapData = BitmapData(
|
||||||
|
bitmap = currentChara.nameSprite,
|
||||||
|
width = currentChara.nameSpriteWidth,
|
||||||
|
height = currentChara.nameSpriteHeight
|
||||||
|
)
|
||||||
|
val nameImageBitmapData = nameBitmapData.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = nameMultiplier,
|
||||||
|
obscure = obscure
|
||||||
|
)
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onClickDismiss,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Card (
|
||||||
|
colors = CardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
disabledContentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = charaImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = "Icon",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(charaImageBitmapData.dpWidth)
|
||||||
|
.padding(8.dp),
|
||||||
|
colorFilter = when (obscure) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!obscure) {
|
||||||
|
Column {
|
||||||
|
Image(
|
||||||
|
bitmap = nameImageBitmapData.imageBitmap,
|
||||||
|
contentDescription = "Icon",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(nameImageBitmapData.dpWidth)
|
||||||
|
.height(nameImageBitmapData.dpHeight),
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column {
|
||||||
|
Text(text = "????????????????")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.padding(16.dp))
|
||||||
|
Column {
|
||||||
|
currentCharaPossibleFusions.map {
|
||||||
|
val selectedCharaBitmap = BitmapData(
|
||||||
|
bitmap = it.spriteIdle,
|
||||||
|
width = it.spriteWidth,
|
||||||
|
height = it.spriteHeight
|
||||||
|
)
|
||||||
|
val selectedCharaImageBitmap = selectedCharaBitmap.getImageBitmap(
|
||||||
|
context = LocalContext.current,
|
||||||
|
multiplier = 4,
|
||||||
|
obscure = it.discoveredOn == null
|
||||||
|
)
|
||||||
|
|
||||||
|
Card (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
colors = CardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
contentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
disabledContentColor = MaterialTheme.colorScheme.contentColorFor(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = selectedCharaImageBitmap.imageBitmap,
|
||||||
|
contentDescription = "Icon",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(selectedCharaImageBitmap.dpWidth)
|
||||||
|
.padding(8.dp),
|
||||||
|
colorFilter = when (it.discoveredOn == null) {
|
||||||
|
true -> ColorFilter.tint(color = MaterialTheme.colorScheme.secondary)
|
||||||
|
false -> null
|
||||||
|
},
|
||||||
|
filterQuality = FilterQuality.None
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
Text("Combine with ${it.fusionAttribute}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = onClickDismiss
|
||||||
|
) {
|
||||||
|
Text("Close")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.homeScreens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BetaWarning(
|
||||||
|
onDismissRequest: () -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest
|
||||||
|
) {
|
||||||
|
Card {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.beta_warning_message_main)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.beta_warning_message_compatibility)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.beta_warning_message_thanks)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(8.dp))
|
||||||
|
Button(
|
||||||
|
onClick = onDismissRequest
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(R.string.beta_warning_button_dismiss))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,56 +1,121 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.homeScreens
|
package com.github.nacabaro.vbhelper.screens.homeScreens
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
import com.github.nacabaro.vbhelper.utils.DeviceType
|
import com.github.nacabaro.vbhelper.utils.DeviceType
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.screens.homeScreens.screens.BEBEmHomeScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.homeScreens.screens.BEDiMHomeScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.homeScreens.screens.VBDiMHomeScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ObtainedItemDialog
|
||||||
import com.github.nacabaro.vbhelper.source.StorageRepository
|
import com.github.nacabaro.vbhelper.source.StorageRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import com.github.nacabaro.vbhelper.R
|
||||||
import kotlinx.coroutines.withContext
|
import com.github.nacabaro.vbhelper.dtos.CardDtos
|
||||||
|
import com.github.nacabaro.vbhelper.source.CardRepository
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlin.collections.emptyList
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
navController: NavController
|
navController: NavController,
|
||||||
|
homeScreenController: HomeScreenControllerImpl
|
||||||
) {
|
) {
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
val storageRepository = StorageRepository(application.container.db)
|
val storageRepository = StorageRepository(application.container.db)
|
||||||
val activeMon = remember { mutableStateOf<CharacterDtos.CharacterWithSprites?>(null) }
|
val cardRepository = CardRepository(application.container.db)
|
||||||
val transformationHistory = remember { mutableStateOf<List<CharacterDtos.TransformationHistory>?>(null) }
|
|
||||||
val beData = remember { mutableStateOf<BECharacterData?>(null) }
|
|
||||||
val vbData = remember { mutableStateOf<VBCharacterData?>(null) }
|
|
||||||
|
|
||||||
LaunchedEffect(storageRepository, activeMon) {
|
val activeMon by storageRepository
|
||||||
withContext(Dispatchers.IO) {
|
.getActiveCharacter()
|
||||||
activeMon.value = storageRepository.getActiveCharacter()
|
.collectAsState(initial = null)
|
||||||
if (activeMon.value != null) {
|
|
||||||
beData.value = storageRepository.getCharacterBeData(activeMon.value!!.id)
|
val cardIconData by (
|
||||||
transformationHistory.value = storageRepository.getTransformationHistory(activeMon.value!!.id)
|
activeMon
|
||||||
|
?.let { chara ->
|
||||||
|
cardRepository.getCardIconByCharaId(chara.charId)
|
||||||
|
}
|
||||||
|
?: flowOf<CardDtos.CardIcon?>(null)
|
||||||
|
).collectAsState(initial = null)
|
||||||
|
|
||||||
|
val transformationHistory by (
|
||||||
|
activeMon
|
||||||
|
?.let { chara ->
|
||||||
|
storageRepository.getTransformationHistory(chara.id)
|
||||||
|
}
|
||||||
|
?: flowOf(emptyList())
|
||||||
|
).collectAsState(initial = emptyList())
|
||||||
|
|
||||||
|
val vbSpecialMissions by (
|
||||||
|
activeMon
|
||||||
|
?.takeIf { it.characterType == DeviceType.VBDevice }
|
||||||
|
?.let { chara ->
|
||||||
|
storageRepository.getSpecialMissions(chara.id)
|
||||||
|
}
|
||||||
|
?: flowOf(emptyList())
|
||||||
|
).collectAsState(initial = emptyList())
|
||||||
|
|
||||||
|
val vbData by (
|
||||||
|
activeMon
|
||||||
|
?.takeIf { it.characterType == DeviceType.VBDevice }
|
||||||
|
?.let { chara ->
|
||||||
|
storageRepository.getCharacterVbData(chara.id)
|
||||||
|
}
|
||||||
|
?: flowOf<VBCharacterData?>(null)
|
||||||
|
).collectAsState(initial = null)
|
||||||
|
|
||||||
|
val beData by (
|
||||||
|
activeMon
|
||||||
|
?.takeIf { it.characterType == DeviceType.BEDevice }
|
||||||
|
?.let { chara ->
|
||||||
|
storageRepository.getCharacterBeData(chara.id)
|
||||||
|
}
|
||||||
|
?: flowOf<BECharacterData?>(null)
|
||||||
|
).collectAsState(initial = null)
|
||||||
|
|
||||||
|
var adventureMissionsFinished by rememberSaveable { mutableStateOf(false) }
|
||||||
|
var betaWarning by rememberSaveable { mutableStateOf(true) }
|
||||||
|
var collectedItem by remember { mutableStateOf<ItemDtos.PurchasedItem?>(null) }
|
||||||
|
var collectedCurrency by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(true) {
|
||||||
|
homeScreenController
|
||||||
|
.didAdventureMissionsFinish {
|
||||||
|
adventureMissionsFinished = it
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBanner(
|
TopBanner(
|
||||||
text = "VB Helper",
|
text = stringResource(R.string.home_title),
|
||||||
onScanClick = {
|
onScanClick = {
|
||||||
navController.navigate(NavigationItems.Scan.route)
|
navController.navigate(NavigationItems.Scan.route)
|
||||||
},
|
},
|
||||||
@@ -60,7 +125,7 @@ fun HomeScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
if (activeMon.value == null || (beData.value == null && vbData.value == null) || transformationHistory.value == null) {
|
if (activeMon == null || (beData == null && vbData == null) || cardIconData == null || transformationHistory.isEmpty()) {
|
||||||
Column (
|
Column (
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
@@ -68,35 +133,93 @@ fun HomeScreen(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(top = contentPadding.calculateTopPadding())
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
) {
|
) {
|
||||||
Text(text = "Nothing to see here")
|
Text(text = stringResource(R.string.adventure_empty_state))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (activeMon.value!!.isBemCard) {
|
val cardIcon = BitmapData(
|
||||||
Log.d("HomeScreen", "BEDeviceBEm")
|
bitmap = cardIconData!!.cardIcon,
|
||||||
|
width = cardIconData!!.cardIconWidth,
|
||||||
|
height = cardIconData!!.cardIconHeight
|
||||||
|
)
|
||||||
|
|
||||||
|
if (activeMon!!.isBemCard && beData != null) {
|
||||||
BEBEmHomeScreen(
|
BEBEmHomeScreen(
|
||||||
activeMon = activeMon.value!!,
|
activeMon = activeMon!!,
|
||||||
beData = beData.value!!,
|
beData = beData!!,
|
||||||
transformationHistory = transformationHistory.value!!,
|
transformationHistory = transformationHistory,
|
||||||
contentPadding = contentPadding
|
contentPadding = contentPadding,
|
||||||
|
cardIcon = cardIcon
|
||||||
)
|
)
|
||||||
} else if (!activeMon.value!!.isBemCard && activeMon.value!!.characterType == DeviceType.BEDevice) {
|
} else if (!activeMon!!.isBemCard && activeMon!!.characterType == DeviceType.BEDevice && beData != null) {
|
||||||
Log.d("HomeScreen", "BEDevice")
|
|
||||||
BEDiMHomeScreen(
|
BEDiMHomeScreen(
|
||||||
activeMon = activeMon.value!!,
|
activeMon = activeMon!!,
|
||||||
beData = beData.value!!,
|
beData = beData!!,
|
||||||
transformationHistory = transformationHistory.value!!,
|
transformationHistory = transformationHistory,
|
||||||
contentPadding = contentPadding
|
contentPadding = contentPadding,
|
||||||
|
cardIcon = cardIcon
|
||||||
)
|
)
|
||||||
} else {
|
} else if (vbData != null) {
|
||||||
VBDiMHomeScreen(
|
VBDiMHomeScreen(
|
||||||
activeMon = activeMon.value!!,
|
activeMon = activeMon!!,
|
||||||
vbData = vbData.value!!,
|
vbData = vbData!!,
|
||||||
transformationHistory = transformationHistory.value!!,
|
transformationHistory = transformationHistory,
|
||||||
contentPadding = contentPadding
|
contentPadding = contentPadding,
|
||||||
|
specialMissions = vbSpecialMissions,
|
||||||
|
homeScreenController = homeScreenController,
|
||||||
|
onClickCollect = { item, currency ->
|
||||||
|
collectedItem = item
|
||||||
|
collectedCurrency = currency
|
||||||
|
},
|
||||||
|
cardIcon = cardIcon
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (collectedItem != null) {
|
||||||
|
ObtainedItemDialog(
|
||||||
|
obtainedItem = collectedItem!!,
|
||||||
|
obtainedCurrency = collectedCurrency!!,
|
||||||
|
onClickDismiss = {
|
||||||
|
collectedItem = null
|
||||||
|
collectedCurrency = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adventureMissionsFinished) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = { adventureMissionsFinished = false },
|
||||||
|
) {
|
||||||
|
Card {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_adventure_mission_finished),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
adventureMissionsFinished = false
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(R.string.beta_warning_button_dismiss))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (betaWarning) {
|
||||||
|
BetaWarning {
|
||||||
|
betaWarning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.homeScreens
|
||||||
|
|
||||||
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
|
||||||
|
interface HomeScreenController {
|
||||||
|
fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit)
|
||||||
|
fun clearSpecialMission(missionId: Long, missionCompletion: SpecialMission.Status, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit)
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.homeScreens
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.time.Instant
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class HomeScreenControllerImpl(
|
||||||
|
private val componentActivity: ComponentActivity,
|
||||||
|
): HomeScreenController {
|
||||||
|
private val application = componentActivity.applicationContext as VBHelper
|
||||||
|
private val database = application.container.db
|
||||||
|
|
||||||
|
override fun didAdventureMissionsFinish(onCompletion: (Boolean) -> Unit) {
|
||||||
|
componentActivity.lifecycleScope.launch {
|
||||||
|
val currentTime = Instant.now().epochSecond
|
||||||
|
val adventureCharacters = database
|
||||||
|
.adventureDao()
|
||||||
|
.getAdventureCharacters()
|
||||||
|
.first()
|
||||||
|
|
||||||
|
val finishedAdventureCharacters = adventureCharacters.filter { character ->
|
||||||
|
character.finishesAdventure <= currentTime
|
||||||
|
}
|
||||||
|
|
||||||
|
onCompletion(finishedAdventureCharacters.isNotEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearSpecialMission(missionId: Long, missionCompletion: SpecialMission.Status, onCleared: (ItemDtos.PurchasedItem?, Int?) -> Unit) {
|
||||||
|
componentActivity.lifecycleScope.launch {
|
||||||
|
database
|
||||||
|
.specialMissionDao()
|
||||||
|
.clearSpecialMission(missionId)
|
||||||
|
|
||||||
|
if (missionCompletion == SpecialMission.Status.COMPLETED) {
|
||||||
|
val randomItem = database
|
||||||
|
.itemDao()
|
||||||
|
.getAllItems()
|
||||||
|
.first()
|
||||||
|
.random()
|
||||||
|
|
||||||
|
val randomItemAmount = (Random.nextFloat() * 5).roundToInt()
|
||||||
|
|
||||||
|
database
|
||||||
|
.itemDao()
|
||||||
|
.purchaseItem(
|
||||||
|
itemId = randomItem.id,
|
||||||
|
itemAmount = randomItemAmount
|
||||||
|
)
|
||||||
|
|
||||||
|
val purchasedItem = ItemDtos.PurchasedItem(
|
||||||
|
itemId = randomItem.id,
|
||||||
|
itemName = randomItem.name,
|
||||||
|
itemDescription = randomItem.description,
|
||||||
|
itemIcon = randomItem.itemIcon,
|
||||||
|
itemLength = randomItem.itemLength,
|
||||||
|
itemAmount = randomItemAmount,
|
||||||
|
itemType = randomItem.itemType
|
||||||
|
)
|
||||||
|
|
||||||
|
val randomAmount = (2..6).random() * 1000
|
||||||
|
val currentCurrency = application.container.currencyRepository.currencyValue.first()
|
||||||
|
application.container.currencyRepository.setCurrencyValue(currentCurrency + randomAmount)
|
||||||
|
|
||||||
|
onCleared(purchasedItem, randomAmount)
|
||||||
|
} else {
|
||||||
|
onCleared(null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.homeScreens
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun VBDiMHomeScreen(
|
|
||||||
activeMon: CharacterDtos.CharacterWithSprites,
|
|
||||||
vbData: VBCharacterData,
|
|
||||||
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
|
||||||
contentPadding: PaddingValues
|
|
||||||
) {
|
|
||||||
TODO("Not implemented yet")
|
|
||||||
}
|
|
||||||
+23
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.homeScreens
|
package com.github.nacabaro.vbhelper.screens.homeScreens.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -15,8 +15,10 @@ import com.github.nacabaro.vbhelper.R
|
|||||||
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
||||||
import com.github.nacabaro.vbhelper.components.ItemDisplay
|
import com.github.nacabaro.vbhelper.components.ItemDisplay
|
||||||
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
|
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.getIconResource
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ import java.util.Locale
|
|||||||
fun BEBEmHomeScreen(
|
fun BEBEmHomeScreen(
|
||||||
activeMon: CharacterDtos.CharacterWithSprites,
|
activeMon: CharacterDtos.CharacterWithSprites,
|
||||||
beData: BECharacterData,
|
beData: BECharacterData,
|
||||||
|
cardIcon: BitmapData,
|
||||||
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
||||||
contentPadding: PaddingValues
|
contentPadding: PaddingValues
|
||||||
) {
|
) {
|
||||||
@@ -44,6 +47,7 @@ fun BEBEmHomeScreen(
|
|||||||
),
|
),
|
||||||
multiplier = 8,
|
multiplier = 8,
|
||||||
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
||||||
|
cardIcon = cardIcon,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
@@ -153,6 +157,24 @@ fun BEBEmHomeScreen(
|
|||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
)
|
)
|
||||||
|
if (beData.itemRemainingTime != 0) {
|
||||||
|
ItemDisplay(
|
||||||
|
icon = getIconResource(beData.itemType),
|
||||||
|
textValue = "${beData.itemRemainingTime} m",
|
||||||
|
definition = when (beData.itemType) {
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.PPTraining.id -> "PP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.HPTraining.id -> "HP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.APTraining.id -> "AP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.BPTraining.id -> "BP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.AllTraining.id -> "All Training"
|
||||||
|
else -> ""
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Row (
|
Row (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
+42
-10
@@ -1,4 +1,4 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.homeScreens
|
package com.github.nacabaro.vbhelper.screens.homeScreens.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -16,14 +16,17 @@ import com.github.nacabaro.vbhelper.R
|
|||||||
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
||||||
import com.github.nacabaro.vbhelper.components.ItemDisplay
|
import com.github.nacabaro.vbhelper.components.ItemDisplay
|
||||||
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
|
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.getIconResource
|
||||||
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.screens.itemsScreen.ItemsScreenControllerImpl
|
||||||
import com.github.nacabaro.vbhelper.utils.BitmapData
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
import kotlin.text.format
|
import kotlin.text.format
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BEDiMHomeScreen(
|
fun BEDiMHomeScreen(
|
||||||
activeMon: CharacterDtos.CharacterWithSprites,
|
activeMon: CharacterDtos.CharacterWithSprites,
|
||||||
|
cardIcon: BitmapData,
|
||||||
beData: BECharacterData,
|
beData: BECharacterData,
|
||||||
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
||||||
contentPadding: PaddingValues
|
contentPadding: PaddingValues
|
||||||
@@ -33,7 +36,7 @@ fun BEDiMHomeScreen(
|
|||||||
.padding(top = contentPadding.calculateTopPadding())
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
.verticalScroll(state = rememberScrollState())
|
.verticalScroll(state = rememberScrollState())
|
||||||
) {
|
) {
|
||||||
Row (
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
@@ -43,13 +46,14 @@ fun BEDiMHomeScreen(
|
|||||||
width = activeMon.spriteWidth,
|
width = activeMon.spriteWidth,
|
||||||
height = activeMon.spriteHeight
|
height = activeMon.spriteHeight
|
||||||
),
|
),
|
||||||
|
cardIcon = cardIcon,
|
||||||
multiplier = 8,
|
multiplier = 8,
|
||||||
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
)
|
)
|
||||||
Column (
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(0.5f)
|
.weight(0.5f)
|
||||||
.aspectRatio(0.5f)
|
.aspectRatio(0.5f)
|
||||||
@@ -74,7 +78,7 @@ fun BEDiMHomeScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row (
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
@@ -108,7 +112,7 @@ fun BEDiMHomeScreen(
|
|||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row (
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
@@ -130,8 +134,13 @@ fun BEDiMHomeScreen(
|
|||||||
textValue = when {
|
textValue = when {
|
||||||
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
||||||
else -> {
|
else -> {
|
||||||
val battleWinPercentage = activeMon.totalBattlesWon.toFloat() / (activeMon.totalBattlesWon + activeMon.totalBattlesLost).toFloat()
|
val battleWinPercentage =
|
||||||
String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
|
activeMon.totalBattlesWon.toFloat() / (activeMon.totalBattlesWon + activeMon.totalBattlesLost).toFloat()
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"%.2f",
|
||||||
|
battleWinPercentage * 100
|
||||||
|
) + " %" // Specify locale
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
definition = "Total battle win %",
|
definition = "Total battle win %",
|
||||||
@@ -145,8 +154,13 @@ fun BEDiMHomeScreen(
|
|||||||
textValue = when {
|
textValue = when {
|
||||||
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
||||||
else -> {
|
else -> {
|
||||||
val battleWinPercentage = activeMon.currentPhaseBattlesWon.toFloat() / (activeMon.currentPhaseBattlesWon + activeMon.currentPhaseBattlesLost).toFloat()
|
val battleWinPercentage =
|
||||||
String.format(Locale.getDefault(), "%.2f", battleWinPercentage * 100) + " %" // Specify locale
|
activeMon.currentPhaseBattlesWon.toFloat() / (activeMon.currentPhaseBattlesWon + activeMon.currentPhaseBattlesLost).toFloat()
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"%.2f",
|
||||||
|
battleWinPercentage * 100
|
||||||
|
) + " %" // Specify locale
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
definition = "Current phase win %",
|
definition = "Current phase win %",
|
||||||
@@ -155,8 +169,26 @@ fun BEDiMHomeScreen(
|
|||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
)
|
)
|
||||||
|
if (beData.itemRemainingTime != 0) {
|
||||||
|
ItemDisplay(
|
||||||
|
icon = getIconResource(beData.itemType),
|
||||||
|
textValue = "${beData.itemRemainingTime} m",
|
||||||
|
definition = when (beData.itemType) {
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.PPTraining.id -> "PP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.HPTraining.id -> "HP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.APTraining.id -> "AP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.BPTraining.id -> "BP Training"
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.AllTraining.id -> "All Training"
|
||||||
|
else -> ""
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Row (
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.homeScreens.screens
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
||||||
|
import com.github.nacabaro.vbhelper.components.ItemDisplay
|
||||||
|
import com.github.nacabaro.vbhelper.components.SpecialMissionsEntry
|
||||||
|
import com.github.nacabaro.vbhelper.components.TransformationHistoryCard
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.screens.homeScreens.HomeScreenControllerImpl
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import java.util.Locale
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun VBDiMHomeScreen(
|
||||||
|
activeMon: CharacterDtos.CharacterWithSprites,
|
||||||
|
cardIcon: BitmapData,
|
||||||
|
vbData: VBCharacterData,
|
||||||
|
specialMissions: List<SpecialMissions>,
|
||||||
|
homeScreenController: HomeScreenControllerImpl,
|
||||||
|
transformationHistory: List<CharacterDtos.TransformationHistory>,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
|
onClickCollect: (ItemDtos.PurchasedItem?, Int?) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
.verticalScroll(state = rememberScrollState())
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
CharacterEntry(
|
||||||
|
icon = BitmapData(
|
||||||
|
bitmap = activeMon.spriteIdle,
|
||||||
|
width = activeMon.spriteWidth,
|
||||||
|
height = activeMon.spriteHeight
|
||||||
|
),
|
||||||
|
cardIcon = cardIcon,
|
||||||
|
multiplier = 8,
|
||||||
|
shape = androidx.compose.material.MaterialTheme.shapes.small,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.5f)
|
||||||
|
.aspectRatio(0.5f)
|
||||||
|
) {
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_vitals_24,
|
||||||
|
textValue = activeMon.vitalPoints.toString(),
|
||||||
|
definition = stringResource(R.string.home_vbdim_vitals),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.5f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_trophy_24,
|
||||||
|
textValue = activeMon.trophies.toString(),
|
||||||
|
definition = stringResource(R.string.home_vbdim_trophies),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(0.5f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_mood_24,
|
||||||
|
textValue = activeMon.mood.toString(),
|
||||||
|
definition = stringResource(R.string.home_vbdim_mood),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
val transformationCountdownInHours = activeMon.transformationCountdown / 60
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_next_24,
|
||||||
|
textValue = when (transformationCountdownInHours) {
|
||||||
|
0 -> "${activeMon.transformationCountdown} m"
|
||||||
|
else -> "$transformationCountdownInHours h"
|
||||||
|
},
|
||||||
|
definition = stringResource(R.string.home_vbdim_next_timer),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_swords_24,
|
||||||
|
textValue = when {
|
||||||
|
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
||||||
|
else -> {
|
||||||
|
val battleWinPercentage =
|
||||||
|
activeMon.totalBattlesWon.toFloat() / (activeMon.totalBattlesWon + activeMon.totalBattlesLost).toFloat()
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"%.2f",
|
||||||
|
battleWinPercentage * 100
|
||||||
|
) + " %" // Specify locale
|
||||||
|
}
|
||||||
|
},
|
||||||
|
definition = stringResource(R.string.home_vbdim_total_battle_win),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
ItemDisplay(
|
||||||
|
icon = R.drawable.baseline_swords_24,
|
||||||
|
textValue = when {
|
||||||
|
activeMon.totalBattlesLost == 0 -> "0.00 %"
|
||||||
|
else -> {
|
||||||
|
val battleWinPercentage =
|
||||||
|
activeMon.currentPhaseBattlesWon.toFloat() / (activeMon.currentPhaseBattlesWon + activeMon.currentPhaseBattlesLost).toFloat()
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"%.2f",
|
||||||
|
battleWinPercentage * 100
|
||||||
|
) + " %" // Specify locale
|
||||||
|
}
|
||||||
|
},
|
||||||
|
definition = stringResource(R.string.home_vbdim_current_phase_win),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
TransformationHistoryCard(
|
||||||
|
transformationHistory = transformationHistory,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.home_vbdim_special_missions),
|
||||||
|
fontSize = 24.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (mission in specialMissions) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
SpecialMissionsEntry(
|
||||||
|
specialMission = mission,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(8.dp),
|
||||||
|
) {
|
||||||
|
homeScreenController
|
||||||
|
.clearSpecialMission(mission.id, mission.status, onClickCollect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.components.CharacterEntry
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.domain.items.ItemType
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.source.StorageRepository
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChooseCharacterScreen(
|
||||||
|
navController: NavController,
|
||||||
|
itemsScreenController: ItemsScreenControllerImpl,
|
||||||
|
itemId: Long
|
||||||
|
) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val storageRepository = StorageRepository(application.container.db, )
|
||||||
|
val characterList = remember {
|
||||||
|
mutableStateOf<List<CharacterDtos.CharacterWithSprites>>(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedCharacter by remember { mutableStateOf<Long?>(null) }
|
||||||
|
var selectedItem by remember { mutableStateOf<ItemDtos.ItemsWithQuantities?>(null) }
|
||||||
|
|
||||||
|
LaunchedEffect(storageRepository) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
selectedItem = storageRepository.getItem(itemId)
|
||||||
|
when (selectedItem?.itemType) {
|
||||||
|
ItemType.BEITEM -> {
|
||||||
|
characterList.value = storageRepository.getBECharacters()
|
||||||
|
}
|
||||||
|
ItemType.VBITEM -> {
|
||||||
|
characterList.value = storageRepository.getVBCharacters()
|
||||||
|
}
|
||||||
|
ItemType.SPECIALMISSION-> {
|
||||||
|
characterList.value = storageRepository.getVBCharacters()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
characterList.value = storageRepository.getAllCharacters().first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect (selectedCharacter) {
|
||||||
|
if (selectedCharacter != null) {
|
||||||
|
itemsScreenController.applyItem(itemId, selectedCharacter!!) {
|
||||||
|
Toast.makeText(
|
||||||
|
application.applicationContext,
|
||||||
|
application.getString(R.string.choose_character_item_applied),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.choose_character_title),
|
||||||
|
onBackClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
) {
|
||||||
|
items(characterList.value) {
|
||||||
|
CharacterEntry(
|
||||||
|
icon = BitmapData(
|
||||||
|
bitmap = it.spriteIdle,
|
||||||
|
width = it.spriteWidth,
|
||||||
|
height = it.spriteHeight
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
selectedCharacter = it.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
import com.github.nacabaro.vbhelper.domain.items.ItemType
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.ui.theme.VBHelperTheme
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemDialog(
|
||||||
|
item: ItemDtos.ItemsWithQuantities,
|
||||||
|
onClickCancel: () -> Unit,
|
||||||
|
onClickUse: (() -> Unit)? = null,
|
||||||
|
onClickPurchase: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onClickCancel,
|
||||||
|
properties = DialogProperties(
|
||||||
|
dismissOnBackPress = true,
|
||||||
|
dismissOnClickOutside = true
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Box(modifier = Modifier) {
|
||||||
|
// Background image (full size)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getIconResource(item.itemIcon)),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(96.dp)
|
||||||
|
.align(Alignment.Center)
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getLengthResource(item.itemLength)),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.outline,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(64.dp) // Set the size of the overlay image
|
||||||
|
.align(Alignment.BottomEnd) // Align to the top end (top-right corner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
fontSize = MaterialTheme.typography.titleLarge.fontSize,
|
||||||
|
text = item.name,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodyMedium.fontFamily,
|
||||||
|
text = item.description,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
if (onClickPurchase != null) {
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
|
||||||
|
text = stringResource(
|
||||||
|
R.string.item_dialog_costs_credits,
|
||||||
|
item.price
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
|
||||||
|
text = stringResource(
|
||||||
|
R.string.item_dialog_you_have_quantity,
|
||||||
|
item.quantity
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Row (
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
if (onClickUse != null) {
|
||||||
|
Button(
|
||||||
|
onClick = onClickUse
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.item_dialog_use))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onClickPurchase != null) {
|
||||||
|
Button(
|
||||||
|
onClick = onClickPurchase
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.item_dialog_purchase))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
|
Button(
|
||||||
|
onClick = onClickCancel
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.item_dialog_cancel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
fun PreviewItemDialog() {
|
||||||
|
VBHelperTheme {
|
||||||
|
ItemDialog(
|
||||||
|
item = ItemDtos.ItemsWithQuantities(
|
||||||
|
name = "AP Training x3 (60 min)",
|
||||||
|
description = "Boosts AP during training (for 60 minutes)",
|
||||||
|
itemIcon = R.drawable.baseline_attack_24,
|
||||||
|
itemLength = R.drawable.baseline_60_min_timer,
|
||||||
|
quantity = 19,
|
||||||
|
id = 1,
|
||||||
|
price = 500,
|
||||||
|
itemType = ItemType.BEITEM
|
||||||
|
),
|
||||||
|
onClickUse = { },
|
||||||
|
onClickCancel = { }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemElement(
|
||||||
|
item: ItemDtos.ItemsWithQuantities,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: (() -> Unit) = { }
|
||||||
|
) {
|
||||||
|
Card (
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier
|
||||||
|
.aspectRatio(1f)
|
||||||
|
) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getIconResource(item.itemIcon)),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(96.dp)
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getLengthResource(item.itemLength)),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.surfaceTint,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
fun getIconResource(index: Int): Int {
|
||||||
|
return when (index) {
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.PPTraining.id -> R.drawable.baseline_agility_24
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.APTraining.id -> R.drawable.baseline_attack_24
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.HPTraining.id -> R.drawable.baseline_shield_24
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.BPTraining.id -> R.drawable.baseline_trophy_24
|
||||||
|
ItemsScreenControllerImpl.ItemTypes.AllTraining.id -> R.drawable.baseline_arrow_up_24
|
||||||
|
6 -> R.drawable.baseline_timer_24
|
||||||
|
7 -> R.drawable.baseline_rank_24
|
||||||
|
8 -> R.drawable.baseline_vitals_24
|
||||||
|
else -> R.drawable.baseline_question_mark_24
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLengthResource(index: Int): Int {
|
||||||
|
return when (index) {
|
||||||
|
15 -> R.drawable.baseline_15_min_timer
|
||||||
|
30 -> R.drawable.baseline_30_min_timer
|
||||||
|
60 -> R.drawable.baseline_60_min_timer
|
||||||
|
-60 -> R.drawable.baseline_60_min_timer
|
||||||
|
300 -> R.drawable.baseline_5_hour_timer
|
||||||
|
600 -> R.drawable.baseline_10_hour_timer
|
||||||
|
-720 -> R.drawable.baseline_12_hour_timer
|
||||||
|
-1440 -> R.drawable.baseline_24_hour_timer
|
||||||
|
6000 -> R.drawable.baseline_reset_24
|
||||||
|
1000 -> R.drawable.baseline_single_arrow_up
|
||||||
|
2500 -> R.drawable.baseline_double_arrow_up
|
||||||
|
5000 -> R.drawable.baseline_triple_arrow_up
|
||||||
|
9999 -> R.drawable.baseline_health_24
|
||||||
|
-500 -> R.drawable.baseline_single_arrow_down
|
||||||
|
-1000 -> R.drawable.baseline_double_arrow_down
|
||||||
|
-2500 -> R.drawable.baseline_triple_arrow_down
|
||||||
|
-9999 -> R.drawable.baseline_reset_24
|
||||||
|
else -> R.drawable.baseline_question_mark_24
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
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.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
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemsScreen(
|
||||||
|
navController: NavController,
|
||||||
|
) {
|
||||||
|
var selectedTabItem by remember { mutableStateOf(0) }
|
||||||
|
val items = listOf(
|
||||||
|
NavigationItems.MyItems,
|
||||||
|
NavigationItems.ItemsStore
|
||||||
|
)
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
Column {
|
||||||
|
TopBanner(text = stringResource(R.string.items_title))
|
||||||
|
TabRow(
|
||||||
|
selectedTabIndex = selectedTabItem,
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
items.forEachIndexed { index, item ->
|
||||||
|
Tab(
|
||||||
|
text = { Text(text = stringResource(item.label)) },
|
||||||
|
selected = selectedTabItem == index,
|
||||||
|
onClick = { selectedTabItem = index }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
) {
|
||||||
|
when (selectedTabItem) {
|
||||||
|
0 -> MyItems(navController)
|
||||||
|
1 -> ItemsStore(navController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
|
||||||
|
interface ItemsScreenController {
|
||||||
|
fun applyItem(itemId: Long, characterId: Long, onCompletion: () -> Unit)
|
||||||
|
}
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.utils.DeviceType
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class ItemsScreenControllerImpl (
|
||||||
|
private val context: ComponentActivity,
|
||||||
|
): ItemsScreenController {
|
||||||
|
private var database: AppDatabase
|
||||||
|
|
||||||
|
enum class ItemTypes(val id: Int) {
|
||||||
|
PPTraining(1),
|
||||||
|
HPTraining(2),
|
||||||
|
APTraining(3),
|
||||||
|
BPTraining(4),
|
||||||
|
AllTraining(5),
|
||||||
|
EvoTimer(6),
|
||||||
|
LimitTimer(7),
|
||||||
|
Vitals(8),
|
||||||
|
Step8k(9),
|
||||||
|
Step4k(10),
|
||||||
|
Vitals1000(11),
|
||||||
|
Vitals250(12),
|
||||||
|
Battle20(13),
|
||||||
|
Battle5(14),
|
||||||
|
Win10(15),
|
||||||
|
Win4(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val application = context.applicationContext as VBHelper
|
||||||
|
database = application.container.db
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyItem(itemId: Long, characterId: Long, onCompletion: () -> Unit) {
|
||||||
|
context.lifecycleScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val item = getItem(itemId)
|
||||||
|
val characterData = database.userCharacterDao().getCharacter(characterId)
|
||||||
|
var beCharacterData: BECharacterData? = null
|
||||||
|
var vbCharacterData: VBCharacterData? = null
|
||||||
|
|
||||||
|
if (characterData.characterType == DeviceType.BEDevice) {
|
||||||
|
beCharacterData = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getBeData(characterId)
|
||||||
|
.firstOrNull()
|
||||||
|
|
||||||
|
} else if (characterData.characterType == DeviceType.VBDevice) {
|
||||||
|
vbCharacterData = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getVbData(characterId)
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.itemIcon in 1 .. 5 &&
|
||||||
|
characterData.characterType == DeviceType.BEDevice &&
|
||||||
|
beCharacterData != null
|
||||||
|
) {
|
||||||
|
beCharacterData.itemType = item.itemIcon
|
||||||
|
beCharacterData.itemMultiplier = 3
|
||||||
|
beCharacterData.itemRemainingTime = item.itemLength
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.updateBECharacterData(beCharacterData)
|
||||||
|
|
||||||
|
} else if (item.itemIcon == ItemTypes.EvoTimer.id) {
|
||||||
|
characterData.transformationCountdown += item.itemLength
|
||||||
|
if (characterData.transformationCountdown < 0) {
|
||||||
|
characterData.transformationCountdown = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// VB does not like it when the transformationCountdown is 0
|
||||||
|
if (characterData.characterType == DeviceType.VBDevice &&
|
||||||
|
characterData.transformationCountdown <= 0 ) {
|
||||||
|
characterData.transformationCountdown = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.updateCharacter(characterData)
|
||||||
|
|
||||||
|
} else if (
|
||||||
|
item.itemIcon == ItemTypes.LimitTimer.id &&
|
||||||
|
characterData.characterType == DeviceType.BEDevice &&
|
||||||
|
beCharacterData != null
|
||||||
|
) {
|
||||||
|
beCharacterData.remainingTrainingTimeInMinutes += item.itemLength
|
||||||
|
if (beCharacterData.remainingTrainingTimeInMinutes > 6000) {
|
||||||
|
beCharacterData.remainingTrainingTimeInMinutes = 6000
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.updateBECharacterData(beCharacterData)
|
||||||
|
|
||||||
|
} else if (item.itemIcon == ItemTypes.Vitals.id) {
|
||||||
|
characterData.vitalPoints += item.itemLength
|
||||||
|
if (characterData.vitalPoints < 0) {
|
||||||
|
characterData.vitalPoints = 0
|
||||||
|
} else if (characterData.vitalPoints > 9999) {
|
||||||
|
characterData.vitalPoints = 9999
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.updateCharacter(characterData)
|
||||||
|
|
||||||
|
} else if (item.itemIcon in ItemTypes.Step8k.id .. ItemTypes.Win4.id &&
|
||||||
|
characterData.characterType == DeviceType.VBDevice &&
|
||||||
|
vbCharacterData != null
|
||||||
|
) {
|
||||||
|
applySpecialMission(item.itemIcon, item.itemLength, characterId)
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeItem(item.id)
|
||||||
|
|
||||||
|
context.runOnUiThread {
|
||||||
|
onCompletion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun applySpecialMission(itemIcon: Int, itemLength: Int, characterId: Long) {
|
||||||
|
// Hello, it's me, naca! No! I don't like this, I'll see how I can improve it later on...
|
||||||
|
val specialMissionType = when (itemIcon) {
|
||||||
|
ItemTypes.Step8k.id -> SpecialMission.Type.STEPS
|
||||||
|
ItemTypes.Step4k.id -> SpecialMission.Type.STEPS
|
||||||
|
ItemTypes.Vitals1000.id -> SpecialMission.Type.VITALS
|
||||||
|
ItemTypes.Vitals250.id -> SpecialMission.Type.VITALS
|
||||||
|
ItemTypes.Battle20.id -> SpecialMission.Type.BATTLES
|
||||||
|
ItemTypes.Battle5.id -> SpecialMission.Type.BATTLES
|
||||||
|
ItemTypes.Win10.id -> SpecialMission.Type.WINS
|
||||||
|
ItemTypes.Win4.id -> SpecialMission.Type.WINS
|
||||||
|
else -> SpecialMission.Type.NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
val specialMissionGoal = when (itemIcon) {
|
||||||
|
ItemTypes.Step8k.id -> 8000
|
||||||
|
ItemTypes.Step4k.id -> 4000
|
||||||
|
ItemTypes.Vitals1000.id -> 1000
|
||||||
|
ItemTypes.Vitals250.id -> 250
|
||||||
|
ItemTypes.Battle20.id -> 20
|
||||||
|
ItemTypes.Battle5.id -> 5
|
||||||
|
ItemTypes.Win10.id -> 10
|
||||||
|
ItemTypes.Win4.id -> 4
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val availableSpecialMissions = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getSpecialMissions(characterId)
|
||||||
|
|
||||||
|
var firstUnavailableMissionSlot: Long = 0
|
||||||
|
var watchId = 0
|
||||||
|
|
||||||
|
for ((index, mission) in availableSpecialMissions.first().withIndex()) {
|
||||||
|
if (
|
||||||
|
mission.status == SpecialMission.Status.UNAVAILABLE
|
||||||
|
) {
|
||||||
|
firstUnavailableMissionSlot = mission.id
|
||||||
|
watchId = index + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newSpecialMission = SpecialMissions(
|
||||||
|
id = firstUnavailableMissionSlot,
|
||||||
|
characterId = characterId,
|
||||||
|
missionType = specialMissionType,
|
||||||
|
goal = specialMissionGoal,
|
||||||
|
timeLimitInMinutes = itemLength,
|
||||||
|
watchId = watchId,
|
||||||
|
status = SpecialMission.Status.AVAILABLE,
|
||||||
|
progress = 0,
|
||||||
|
timeElapsedInMinutes = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertSpecialMissions(newSpecialMission)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getItem(itemId: Long): ItemDtos.ItemsWithQuantities {
|
||||||
|
return database
|
||||||
|
.itemDao()
|
||||||
|
.getItem(itemId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun consumeItem(itemId: Long) {
|
||||||
|
database
|
||||||
|
.itemDao()
|
||||||
|
.useItem(itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import com.github.nacabaro.vbhelper.source.CurrencyRepository
|
||||||
|
import com.github.nacabaro.vbhelper.source.ItemsRepository
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemsStore(
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val itemsRepository = ItemsRepository(application.container.db)
|
||||||
|
val myItems by itemsRepository.getAllItems().collectAsState(emptyList())
|
||||||
|
|
||||||
|
var selectedElementIndex by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
|
val currencyRepository = application.container.currencyRepository
|
||||||
|
val currentCurrency = currencyRepository.currencyValue.collectAsState(0)
|
||||||
|
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
if (myItems.isEmpty()) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.items_no_items))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column() {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.items_store_credits,
|
||||||
|
currentCurrency.value
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3),
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
items(myItems) { index ->
|
||||||
|
ItemElement(
|
||||||
|
item = index,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp),
|
||||||
|
onClick = {
|
||||||
|
selectedElementIndex = myItems.indexOf(index)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (selectedElementIndex != null) {
|
||||||
|
ItemDialog(
|
||||||
|
item = myItems[selectedElementIndex!!],
|
||||||
|
onClickPurchase = {
|
||||||
|
scope.launch {
|
||||||
|
Toast.makeText(
|
||||||
|
application.applicationContext,
|
||||||
|
application.getString(
|
||||||
|
purchaseItem(
|
||||||
|
application.container.db,
|
||||||
|
myItems[selectedElementIndex!!],
|
||||||
|
currencyRepository
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClickCancel = { selectedElementIndex = null }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun purchaseItem(
|
||||||
|
db: AppDatabase,
|
||||||
|
item: ItemDtos.ItemsWithQuantities,
|
||||||
|
currencyRepository: CurrencyRepository
|
||||||
|
): Int {
|
||||||
|
return if (currencyRepository.currencyValue.first() < item.price) {
|
||||||
|
R.string.items_not_enough_credits
|
||||||
|
} else {
|
||||||
|
db
|
||||||
|
.itemDao()
|
||||||
|
.purchaseItem(
|
||||||
|
item.id,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
|
currencyRepository
|
||||||
|
.setCurrencyValue(
|
||||||
|
currencyRepository.currencyValue.first() - item.price
|
||||||
|
)
|
||||||
|
|
||||||
|
R.string.items_purchase_success
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
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.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.source.ItemsRepository
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyItems(
|
||||||
|
navController: NavController,
|
||||||
|
) {
|
||||||
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
|
val itemsRepository = ItemsRepository(application.container.db)
|
||||||
|
val myItems by itemsRepository.getUserItems().collectAsState(emptyList())
|
||||||
|
|
||||||
|
var selectedElementIndex by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
|
if (myItems.isEmpty()) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.items_no_items))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3),
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
items(myItems) { index ->
|
||||||
|
ItemElement(
|
||||||
|
item = index,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp),
|
||||||
|
onClick = {
|
||||||
|
selectedElementIndex = myItems.indexOf(index)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedElementIndex != null) {
|
||||||
|
ItemDialog(
|
||||||
|
item = myItems[selectedElementIndex!!],
|
||||||
|
onClickUse = {
|
||||||
|
navController
|
||||||
|
.navigate(
|
||||||
|
NavigationItems
|
||||||
|
.ApplyItem.route
|
||||||
|
.replace(
|
||||||
|
"{itemId}",
|
||||||
|
myItems[selectedElementIndex!!].id.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
selectedElementIndex = null
|
||||||
|
},
|
||||||
|
onClickCancel = { selectedElementIndex = null }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.itemsScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.ItemDtos
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ObtainedItemDialog(
|
||||||
|
obtainedItem: ItemDtos.PurchasedItem,
|
||||||
|
obtainedCurrency: Int,
|
||||||
|
onClickDismiss: () -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onClickDismiss
|
||||||
|
) {
|
||||||
|
Card {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row {
|
||||||
|
Box(modifier = Modifier) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getIconResource(obtainedItem.itemIcon)),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(96.dp)
|
||||||
|
.align(Alignment.Center)
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = getLengthResource(obtainedItem.itemLength)),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.outline,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(64.dp)
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
fontSize = MaterialTheme.typography.titleLarge.fontSize,
|
||||||
|
text = obtainedItem.itemName,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodyMedium.fontFamily,
|
||||||
|
text = obtainedItem.itemDescription,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(4.dp)
|
||||||
|
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
|
||||||
|
text = stringResource(
|
||||||
|
R.string.obtained_item_you_have,
|
||||||
|
obtainedItem.itemAmount
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 4.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = MaterialTheme.typography.bodySmall.fontSize,
|
||||||
|
fontFamily = MaterialTheme.typography.bodySmall.fontFamily,
|
||||||
|
text = stringResource(
|
||||||
|
R.string.obtained_item_you_also_got_credits,
|
||||||
|
obtainedCurrency
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 4.dp)
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = onClickDismiss,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(R.string.obtained_item_dismiss))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.scanScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChooseConnectOption(
|
||||||
|
onClickRead: (() -> Unit)? = null,
|
||||||
|
onClickWrite: (() -> Unit)? = null,
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = stringResource(R.string.scan_title),
|
||||||
|
onBackClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(contentPadding)
|
||||||
|
) {
|
||||||
|
ScanButton(
|
||||||
|
text = stringResource(R.string.scan_vb_to_app),
|
||||||
|
disabled = onClickRead == null,
|
||||||
|
onClick = onClickRead?: { },
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
ScanButton(
|
||||||
|
text = stringResource(R.string.scan_app_to_vb),
|
||||||
|
disabled = onClickWrite == null,
|
||||||
|
onClick = onClickWrite?: { },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScanButton(
|
||||||
|
text: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
disabled: Boolean = false,
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = !disabled,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +1,31 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.scanScreen
|
package com.github.nacabaro.vbhelper.screens.scanScreen
|
||||||
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
|
||||||
import com.github.nacabaro.vbhelper.di.VBHelper
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
import com.github.nacabaro.vbhelper.navigation.NavigationItems
|
||||||
|
import com.github.nacabaro.vbhelper.screens.scanScreen.screens.ReadingScreen
|
||||||
|
import com.github.nacabaro.vbhelper.screens.scanScreen.screens.WritingScreen
|
||||||
import com.github.nacabaro.vbhelper.source.StorageRepository
|
import com.github.nacabaro.vbhelper.source.StorageRepository
|
||||||
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.utils.characterToNfc
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
const val SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER = "SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER"
|
const val SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER = "SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER"
|
||||||
|
|
||||||
@@ -46,125 +34,69 @@ fun ScanScreen(
|
|||||||
navController: NavController,
|
navController: NavController,
|
||||||
characterId: Long?,
|
characterId: Long?,
|
||||||
scanScreenController: ScanScreenController,
|
scanScreenController: ScanScreenController,
|
||||||
|
launchedFromHomeScreen: Boolean
|
||||||
) {
|
) {
|
||||||
val secrets by scanScreenController.secretsFlow.collectAsState(null)
|
val secrets by scanScreenController.secretsFlow.collectAsState(null)
|
||||||
var readingScreen by remember { mutableStateOf(false) }
|
|
||||||
var writingScreen by remember { mutableStateOf(false) }
|
|
||||||
var isDoneReadingCharacter by remember { mutableStateOf(false) }
|
|
||||||
var isDoneSendingCard by remember { mutableStateOf(false) }
|
|
||||||
var isDoneWritingCharacter by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
val application = LocalContext.current.applicationContext as VBHelper
|
val application = LocalContext.current.applicationContext as VBHelper
|
||||||
val storageRepository = StorageRepository(application.container.db)
|
val storageRepository = StorageRepository(application.container.db)
|
||||||
var nfcCharacter by remember { mutableStateOf<NfcCharacter?>(null) }
|
var nfcCharacter by remember { mutableStateOf<NfcCharacter?>(null) }
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
LaunchedEffect(storageRepository) {
|
LaunchedEffect(storageRepository) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if(characterId != null && nfcCharacter == null) {
|
/*
|
||||||
nfcCharacter = characterToNfc(context, characterId)
|
First check if there is a character sent through the navigation system
|
||||||
|
If there is not, that means we got here through the home screen nfc button
|
||||||
|
If we got here through the home screen, it does not hurt to check if there is
|
||||||
|
an active character.
|
||||||
|
*/
|
||||||
|
if (characterId != null && nfcCharacter == null) {
|
||||||
|
nfcCharacter = scanScreenController.characterToNfc(characterId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(readingScreen || writingScreen, isDoneSendingCard) {
|
var writingScreen by remember { mutableStateOf(false) }
|
||||||
if(readingScreen) {
|
var readingScreen by remember { mutableStateOf(false) }
|
||||||
scanScreenController.registerActivityLifecycleListener(SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER, object: ActivityLifecycleListener {
|
|
||||||
override fun onPause() {
|
|
||||||
scanScreenController.cancelRead()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
if (writingScreen && nfcCharacter != null && characterId != null) {
|
||||||
scanScreenController.onClickRead(secrets!!) {
|
WritingScreen(
|
||||||
isDoneReadingCharacter = true
|
scanScreenController = scanScreenController,
|
||||||
}
|
nfcCharacter = nfcCharacter!!,
|
||||||
}
|
characterId = characterId,
|
||||||
|
onComplete = {
|
||||||
})
|
|
||||||
scanScreenController.onClickRead(secrets!!) {
|
|
||||||
isDoneReadingCharacter = true
|
|
||||||
}
|
|
||||||
} else if (writingScreen) {
|
|
||||||
scanScreenController.registerActivityLifecycleListener(
|
|
||||||
SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER,
|
|
||||||
object : ActivityLifecycleListener {
|
|
||||||
override fun onPause() {
|
|
||||||
scanScreenController.cancelRead()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
if (!isDoneSendingCard) {
|
|
||||||
scanScreenController.onClickCheckCard(secrets!!, nfcCharacter!!) {
|
|
||||||
isDoneSendingCard = true
|
|
||||||
}
|
|
||||||
} else if (!isDoneWritingCharacter) {
|
|
||||||
scanScreenController.onClickWrite(secrets!!, nfcCharacter!!) {
|
|
||||||
isDoneWritingCharacter = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
if (!isDoneSendingCard) {
|
|
||||||
scanScreenController.onClickCheckCard(secrets!!, nfcCharacter!!) {
|
|
||||||
isDoneSendingCard = true
|
|
||||||
}
|
|
||||||
} else if (!isDoneWritingCharacter) {
|
|
||||||
scanScreenController.onClickWrite(secrets!!, nfcCharacter!!) {
|
|
||||||
isDoneWritingCharacter = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onDispose {
|
|
||||||
if(readingScreen || writingScreen) {
|
|
||||||
scanScreenController.unregisterActivityLifecycleListener(SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER)
|
|
||||||
scanScreenController.cancelRead()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDoneReadingCharacter) {
|
|
||||||
readingScreen = false
|
|
||||||
navController.navigate(NavigationItems.Home.route)
|
|
||||||
} else if (isDoneSendingCard && isDoneWritingCharacter) {
|
|
||||||
writingScreen = false
|
|
||||||
navController.navigate(NavigationItems.Home.route)
|
|
||||||
LaunchedEffect(storageRepository) {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
storageRepository
|
|
||||||
.deleteCharacter(characterId!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readingScreen) {
|
|
||||||
ReadingCharacterScreen("Reading character") {
|
|
||||||
readingScreen = false
|
|
||||||
scanScreenController.cancelRead()
|
|
||||||
}
|
|
||||||
} else if (writingScreen) {
|
|
||||||
if (!isDoneSendingCard) {
|
|
||||||
ReadingCharacterScreen("Sending card") {
|
|
||||||
writingScreen = false
|
writingScreen = false
|
||||||
scanScreenController.cancelRead()
|
navController.navigate(NavigationItems.Home.route)
|
||||||
}
|
},
|
||||||
} else if (!isDoneWritingCharacter) {
|
onCancel = {
|
||||||
ReadingCharacterScreen("Writing character") {
|
|
||||||
isDoneSendingCard = false
|
|
||||||
writingScreen = false
|
writingScreen = false
|
||||||
scanScreenController.cancelRead()
|
navController.navigate(NavigationItems.Home.route)
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
} else if (readingScreen) {
|
||||||
|
ReadingScreen(
|
||||||
|
scanScreenController = scanScreenController,
|
||||||
|
onCancel = {
|
||||||
|
readingScreen = false
|
||||||
|
navController.navigate(NavigationItems.Home.route)
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
readingScreen = false
|
||||||
|
navController.navigate(NavigationItems.Home.route)
|
||||||
|
}
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
ChooseConnectOption(
|
ChooseConnectOption(
|
||||||
onClickRead = when {
|
onClickRead = when {
|
||||||
characterId != null -> null
|
!launchedFromHomeScreen -> null
|
||||||
else -> {
|
else -> {
|
||||||
{
|
{
|
||||||
if(secrets == null) {
|
if(secrets == null) {
|
||||||
Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, context.getString(R.string.scan_secrets_not_initialized), Toast.LENGTH_SHORT).show()
|
||||||
} else if(secrets?.isMissingSecrets() == true) {
|
} else if(secrets?.isMissingSecrets() == true) {
|
||||||
Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, context.getString(R.string.scan_secrets_not_imported), Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
readingScreen = true // kicks off nfc adapter in DisposableEffect
|
readingScreen = true // kicks off nfc adapter in DisposableEffect
|
||||||
}
|
}
|
||||||
@@ -176,71 +108,22 @@ fun ScanScreen(
|
|||||||
else -> {
|
else -> {
|
||||||
{
|
{
|
||||||
if(secrets == null) {
|
if(secrets == null) {
|
||||||
Toast.makeText(context, "Secrets is not yet initialized. Try again.", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, context.getString(R.string.scan_secrets_not_initialized), Toast.LENGTH_SHORT).show()
|
||||||
} else if(secrets?.isMissingSecrets() == true) {
|
} else if(secrets?.isMissingSecrets() == true) {
|
||||||
Toast.makeText(context, "Secrets not yet imported. Go to Settings and Import APK", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, context.getString(R.string.scan_secrets_not_imported), Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
writingScreen = true // kicks off nfc adapter in DisposableEffect
|
writingScreen = true // kicks off nfc adapter in DisposableEffect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
navController = navController
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ChooseConnectOption(
|
|
||||||
onClickRead: (() -> Unit)? = null,
|
|
||||||
onClickWrite: (() -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
topBar = { TopBanner(text = "Scan a Vital Bracelet") }
|
|
||||||
) { contentPadding ->
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(contentPadding)
|
|
||||||
) {
|
|
||||||
ScanButton(
|
|
||||||
text = "Vital Bracelet to App",
|
|
||||||
disabled = onClickRead == null,
|
|
||||||
onClick = onClickRead?: { },
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
ScanButton(
|
|
||||||
text = "App to Vital Bracelet",
|
|
||||||
disabled = onClickWrite == null,
|
|
||||||
onClick = onClickWrite?: { },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ScanButton(
|
|
||||||
text: String,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
disabled: Boolean = false,
|
|
||||||
) {
|
|
||||||
Button(
|
|
||||||
onClick = onClick,
|
|
||||||
modifier = modifier,
|
|
||||||
enabled = !disabled,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun ScanScreenPreview() {
|
fun ScanScreenPreview() {
|
||||||
@@ -255,11 +138,15 @@ fun ScanScreenPreview() {
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) {}
|
override fun flushCharacter(cardId: Long) {}
|
||||||
|
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {}
|
||||||
override fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
|
override fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
|
||||||
override fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
|
override fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit) {}
|
||||||
override fun cancelRead() {}
|
override fun cancelRead() {}
|
||||||
|
override fun characterFromNfc(nfcCharacter: NfcCharacter, onMultipleCards: (List<Card>, NfcCharacter) -> Unit): String { return "" }
|
||||||
|
override suspend fun characterToNfc(characterId: Long): NfcCharacter? { return null }
|
||||||
},
|
},
|
||||||
characterId = null
|
characterId = null,
|
||||||
|
launchedFromHomeScreen = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+10
-1
@@ -2,12 +2,13 @@ package com.github.nacabaro.vbhelper.screens.scanScreen
|
|||||||
|
|
||||||
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
import com.github.nacabaro.vbhelper.source.proto.Secrets
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ScanScreenController {
|
interface ScanScreenController {
|
||||||
val secretsFlow: Flow<Secrets>
|
val secretsFlow: Flow<Secrets>
|
||||||
fun onClickRead(secrets: Secrets, onComplete: ()->Unit)
|
fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit)
|
||||||
fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
|
fun onClickCheckCard(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
|
||||||
fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
|
fun onClickWrite(secrets: Secrets, nfcCharacter: NfcCharacter, onComplete: () -> Unit)
|
||||||
|
|
||||||
@@ -15,4 +16,12 @@ interface ScanScreenController {
|
|||||||
|
|
||||||
fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener)
|
fun registerActivityLifecycleListener(key: String, activityLifecycleListener: ActivityLifecycleListener)
|
||||||
fun unregisterActivityLifecycleListener(key: String)
|
fun unregisterActivityLifecycleListener(key: String)
|
||||||
|
|
||||||
|
fun flushCharacter(cardId: Long)
|
||||||
|
|
||||||
|
fun characterFromNfc(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
onMultipleCards: (List<Card>, NfcCharacter) -> Unit
|
||||||
|
): String
|
||||||
|
suspend fun characterToNfc(characterId: Long): NfcCharacter?
|
||||||
}
|
}
|
||||||
+73
-23
@@ -11,8 +11,13 @@ import android.widget.Toast
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.github.cfogrady.vbnfc.TagCommunicator
|
import com.github.cfogrady.vbnfc.TagCommunicator
|
||||||
|
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.nacabaro.vbhelper.ActivityLifecycleListener
|
import com.github.nacabaro.vbhelper.ActivityLifecycleListener
|
||||||
|
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.ToNfcConverter
|
||||||
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
|
||||||
@@ -20,30 +25,34 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
class ScanScreenControllerImpl(
|
class ScanScreenControllerImpl(
|
||||||
override val secretsFlow: Flow<Secrets>,
|
override val secretsFlow: Flow<Secrets>,
|
||||||
private val nfcHandler: (NfcCharacter)->String,
|
private val componentActivity: ComponentActivity,
|
||||||
private val context: ComponentActivity,
|
|
||||||
private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit,
|
private val registerActivityLifecycleListener: (String, ActivityLifecycleListener)->Unit,
|
||||||
private val unregisterActivityLifecycleListener: (String)->Unit,
|
private val unregisterActivityLifecycleListener: (String)->Unit,
|
||||||
): ScanScreenController {
|
): ScanScreenController {
|
||||||
|
private var lastScannedCharacter: NfcCharacter? = null
|
||||||
private val nfcAdapter: NfcAdapter
|
private val nfcAdapter: NfcAdapter
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(context)
|
val maybeNfcAdapter = NfcAdapter.getDefaultAdapter(componentActivity)
|
||||||
if (maybeNfcAdapter == null) {
|
if (maybeNfcAdapter == null) {
|
||||||
Toast.makeText(context, "No NFC on device!", Toast.LENGTH_SHORT).show()
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_no_nfc_on_device), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
nfcAdapter = maybeNfcAdapter
|
nfcAdapter = maybeNfcAdapter
|
||||||
checkSecrets()
|
checkSecrets()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit) {
|
override fun onClickRead(secrets: Secrets, onComplete: ()->Unit, onMultipleCards: (List<Card>) -> Unit) {
|
||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(secrets) { tagCommunicator ->
|
||||||
val character = tagCommunicator.receiveCharacter()
|
val character = tagCommunicator.receiveCharacter()
|
||||||
val resultMessage = nfcHandler(character)
|
val resultMessage = characterFromNfc(character) { cards, nfcCharacter ->
|
||||||
|
lastScannedCharacter = nfcCharacter
|
||||||
|
onMultipleCards(cards)
|
||||||
|
|
||||||
|
}
|
||||||
onComplete.invoke()
|
onComplete.invoke()
|
||||||
resultMessage
|
resultMessage
|
||||||
}
|
}
|
||||||
@@ -51,7 +60,7 @@ class ScanScreenControllerImpl(
|
|||||||
|
|
||||||
override fun cancelRead() {
|
override fun cancelRead() {
|
||||||
if(nfcAdapter.isEnabled) {
|
if(nfcAdapter.isEnabled) {
|
||||||
nfcAdapter.disableReaderMode(context)
|
nfcAdapter.disableReaderMode(componentActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +83,7 @@ class ScanScreenControllerImpl(
|
|||||||
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(context, buildOnReadTag(secrets, handlerFunc), NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
nfcAdapter.enableReaderMode(componentActivity, buildOnReadTag(secrets, handlerFunc), NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -85,26 +94,26 @@ class ScanScreenControllerImpl(
|
|||||||
return { tag->
|
return { tag->
|
||||||
val nfcData = NfcA.get(tag)
|
val nfcData = NfcA.get(tag)
|
||||||
if (nfcData == null) {
|
if (nfcData == null) {
|
||||||
context.runOnUiThread {
|
componentActivity.runOnUiThread {
|
||||||
Toast.makeText(context, "Tag detected is not VB", Toast.LENGTH_SHORT).show()
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_tag_not_vb), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nfcData.connect()
|
nfcData.connect()
|
||||||
nfcData.use {
|
nfcData.use {
|
||||||
val tagCommunicator = TagCommunicator.getInstance(nfcData, secrets.getCryptographicTransformerMap())
|
val tagCommunicator = TagCommunicator.getInstance(nfcData, secrets.getCryptographicTransformerMap())
|
||||||
val successText = handlerFunc(tagCommunicator)
|
val successText = handlerFunc(tagCommunicator)
|
||||||
context.runOnUiThread {
|
componentActivity.runOnUiThread {
|
||||||
Toast.makeText(context, successText, Toast.LENGTH_SHORT).show()
|
Toast.makeText(componentActivity, successText, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkSecrets() {
|
private fun checkSecrets() {
|
||||||
context.lifecycleScope.launch(Dispatchers.IO) {
|
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
if(secretsFlow.stateIn(context.lifecycleScope).value.isMissingSecrets()) {
|
if(secretsFlow.stateIn(componentActivity.lifecycleScope).value.isMissingSecrets()) {
|
||||||
context.runOnUiThread {
|
componentActivity.runOnUiThread {
|
||||||
Toast.makeText(context, "Missing Secrets. Go to settings and import Vital Arena APK", Toast.LENGTH_SHORT).show()
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_missing_secrets), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,12 +126,20 @@ class ScanScreenControllerImpl(
|
|||||||
) {
|
) {
|
||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(secrets) { tagCommunicator ->
|
||||||
try {
|
try {
|
||||||
tagCommunicator.sendCharacter(nfcCharacter)
|
if (nfcCharacter is VBNfcCharacter) {
|
||||||
|
Log.d("SendCharacter", "VBNfcCharacter")
|
||||||
|
val castNfcCharacter: VBNfcCharacter = nfcCharacter
|
||||||
|
tagCommunicator.sendCharacter(castNfcCharacter)
|
||||||
|
} else if (nfcCharacter is BENfcCharacter) {
|
||||||
|
Log.d("SendCharacter", "BENfcCharacter")
|
||||||
|
val castNfcCharacter: BENfcCharacter = nfcCharacter
|
||||||
|
tagCommunicator.sendCharacter(castNfcCharacter)
|
||||||
|
}
|
||||||
onComplete.invoke()
|
onComplete.invoke()
|
||||||
"Sent character successfully!"
|
componentActivity.getString(R.string.scan_sent_character_success)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
Log.e("TAG", e.stackTraceToString())
|
Log.e("TAG", e.stackTraceToString())
|
||||||
"Whoops"
|
componentActivity.getString(R.string.scan_error_generic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,13 +152,46 @@ class ScanScreenControllerImpl(
|
|||||||
handleTag(secrets) { tagCommunicator ->
|
handleTag(secrets) { tagCommunicator ->
|
||||||
tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId)
|
tagCommunicator.prepareDIMForCharacter(nfcCharacter.dimId)
|
||||||
onComplete.invoke()
|
onComplete.invoke()
|
||||||
"Sent DIM successfully!"
|
componentActivity.getString(R.string.scan_sent_dim_success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
// EXTRACTED DIRECTLY FROM EXAMPLE APP
|
||||||
private fun showWirelessSettings() {
|
private fun showWirelessSettings() {
|
||||||
Toast.makeText(context, "NFC must be enabled", Toast.LENGTH_SHORT).show()
|
Toast.makeText(componentActivity, componentActivity.getString(R.string.scan_nfc_must_be_enabled), Toast.LENGTH_SHORT).show()
|
||||||
context.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
|
componentActivity.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun characterFromNfc(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
onMultipleCards: (List<Card>, NfcCharacter) -> Unit
|
||||||
|
): String {
|
||||||
|
val nfcConverter = FromNfcConverter(
|
||||||
|
componentActivity = componentActivity
|
||||||
|
)
|
||||||
|
return nfcConverter.addCharacter(nfcCharacter, onMultipleCards)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun characterToNfc(characterId: Long): NfcCharacter {
|
||||||
|
val nfcGenerator = ToNfcConverter(
|
||||||
|
componentActivity = componentActivity
|
||||||
|
)
|
||||||
|
|
||||||
|
val character = nfcGenerator.characterToNfc(characterId)
|
||||||
|
Log.d("CharacterType", character.toString())
|
||||||
|
return character
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun flushCharacter(cardId: Long) {
|
||||||
|
val nfcConverter = FromNfcConverter(
|
||||||
|
componentActivity = componentActivity
|
||||||
|
)
|
||||||
|
|
||||||
|
componentActivity.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
if (lastScannedCharacter != null) {
|
||||||
|
nfcConverter.addCharacterUsingCard(lastScannedCharacter!!, cardId)
|
||||||
|
lastScannedCharacter = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.cardScreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
|
import com.github.nacabaro.vbhelper.screens.scanScreen.cardSelect.ScanCardEntry
|
||||||
|
import com.github.nacabaro.vbhelper.utils.BitmapData
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChooseCard(
|
||||||
|
cards: List<Card>,
|
||||||
|
onCardSelected: (Card) -> Unit
|
||||||
|
) {
|
||||||
|
Scaffold (
|
||||||
|
topBar = {
|
||||||
|
TopBanner(
|
||||||
|
text = "Choose card",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { contentPadding ->
|
||||||
|
LazyColumn (
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = contentPadding.calculateTopPadding())
|
||||||
|
) {
|
||||||
|
items(cards) {
|
||||||
|
ScanCardEntry(
|
||||||
|
name = it.name,
|
||||||
|
logo = BitmapData(
|
||||||
|
it.logo,
|
||||||
|
it.logoWidth,
|
||||||
|
it.logoHeight
|
||||||
|
),
|
||||||
|
onClick = {
|
||||||
|
onCardSelected(it)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-10
@@ -1,4 +1,4 @@
|
|||||||
package com.github.nacabaro.vbhelper.components
|
package com.github.nacabaro.vbhelper.screens.scanScreen.cardSelect
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -21,11 +21,9 @@ import com.github.nacabaro.vbhelper.utils.BitmapData
|
|||||||
import com.github.nacabaro.vbhelper.utils.getBitmap
|
import com.github.nacabaro.vbhelper.utils.getBitmap
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DexDiMEntry(
|
fun ScanCardEntry(
|
||||||
name: String,
|
name: String,
|
||||||
logo: BitmapData,
|
logo: BitmapData,
|
||||||
obtainedCharacters: Int,
|
|
||||||
totalCharacters: Int,
|
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
@@ -56,17 +54,12 @@ fun DexDiMEntry(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = name,
|
text = name,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
)
|
)
|
||||||
Text(
|
|
||||||
text = "$obtainedCharacters of $totalCharacters characters obtained",
|
|
||||||
fontFamily = MaterialTheme.typography.labelSmall.fontFamily,
|
|
||||||
fontSize = MaterialTheme.typography.labelSmall.fontSize,
|
|
||||||
modifier = Modifier
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+303
@@ -0,0 +1,303 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.scanScreen.converters
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import com.github.cfogrady.vbnfc.be.BENfcCharacter
|
||||||
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
|
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.domain.card.Card
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.BECharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.SpecialMissions
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VBCharacterData
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.VitalsHistory
|
||||||
|
import com.github.nacabaro.vbhelper.utils.DeviceType
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
|
class FromNfcConverter (
|
||||||
|
componentActivity: ComponentActivity
|
||||||
|
) {
|
||||||
|
private val application = componentActivity.applicationContext as VBHelper
|
||||||
|
private val database = application.container.db
|
||||||
|
|
||||||
|
|
||||||
|
fun addCharacterUsingCard(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
cardId: Long
|
||||||
|
): String {
|
||||||
|
val cardData = database
|
||||||
|
.cardDao()
|
||||||
|
.getCardById(cardId)
|
||||||
|
|
||||||
|
if (cardData == null) {
|
||||||
|
return "Card not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
return insertCharacter(nfcCharacter, cardData)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun addCharacter(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
onMultipleCards: (List<Card>, NfcCharacter) -> Unit
|
||||||
|
): String {
|
||||||
|
val appReservedCardId = nfcCharacter
|
||||||
|
.appReserved2[0].toLong()
|
||||||
|
|
||||||
|
var cardData: Card? = null
|
||||||
|
|
||||||
|
if (appReservedCardId != 0L) {
|
||||||
|
val fetchedCard = database
|
||||||
|
.cardDao()
|
||||||
|
.getCardById(appReservedCardId)
|
||||||
|
|
||||||
|
if (fetchedCard == null) {
|
||||||
|
return "Card not found"
|
||||||
|
} else if (fetchedCard.cardId == nfcCharacter.dimId.toInt()) {
|
||||||
|
cardData = fetchedCard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardData == null) {
|
||||||
|
val allCards = database
|
||||||
|
.cardDao()
|
||||||
|
.getCardByCardId(nfcCharacter.dimId.toInt())
|
||||||
|
|
||||||
|
if (allCards.isEmpty())
|
||||||
|
return "Card not found"
|
||||||
|
|
||||||
|
if (allCards.size > 1) {
|
||||||
|
onMultipleCards(allCards, nfcCharacter)
|
||||||
|
return "Multiple cards found"
|
||||||
|
}
|
||||||
|
|
||||||
|
cardData = allCards[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return insertCharacter(nfcCharacter, cardData)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun insertCharacter(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
cardData: Card
|
||||||
|
): String {
|
||||||
|
val cardCharData = database
|
||||||
|
.characterDao()
|
||||||
|
.getCharacterByMonIndex(nfcCharacter.charIndex.toInt(), cardData.id)
|
||||||
|
|
||||||
|
updateCardProgress(nfcCharacter, cardData)
|
||||||
|
|
||||||
|
val characterData = UserCharacter(
|
||||||
|
charId = cardCharData.id,
|
||||||
|
ageInDays = nfcCharacter.ageInDays.toInt(),
|
||||||
|
mood = nfcCharacter.mood.toInt(),
|
||||||
|
vitalPoints = nfcCharacter.vitalPoints.toInt(),
|
||||||
|
transformationCountdown = nfcCharacter.transformationCountdownInMinutes.toInt(),
|
||||||
|
injuryStatus = nfcCharacter.injuryStatus,
|
||||||
|
trophies = nfcCharacter.trophies.toInt(),
|
||||||
|
currentPhaseBattlesWon = nfcCharacter.currentPhaseBattlesWon.toInt(),
|
||||||
|
currentPhaseBattlesLost = nfcCharacter.currentPhaseBattlesLost.toInt(),
|
||||||
|
totalBattlesWon = nfcCharacter.totalBattlesWon.toInt(),
|
||||||
|
totalBattlesLost = nfcCharacter.totalBattlesLost.toInt(),
|
||||||
|
activityLevel = nfcCharacter.activityLevel.toInt(),
|
||||||
|
heartRateCurrent = nfcCharacter.heartRateCurrent.toInt(),
|
||||||
|
characterType = when (nfcCharacter) {
|
||||||
|
is BENfcCharacter -> DeviceType.BEDevice
|
||||||
|
else -> DeviceType.VBDevice
|
||||||
|
},
|
||||||
|
isActive = true
|
||||||
|
)
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.clearActiveCharacter()
|
||||||
|
|
||||||
|
val characterId: Long = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertCharacterData(characterData)
|
||||||
|
|
||||||
|
if (nfcCharacter is BENfcCharacter) {
|
||||||
|
addBeCharacterToDatabase(
|
||||||
|
characterId = characterId,
|
||||||
|
nfcCharacter = nfcCharacter
|
||||||
|
)
|
||||||
|
} else if (nfcCharacter is VBNfcCharacter) {
|
||||||
|
addVbCharacterToDatabase(
|
||||||
|
characterId = characterId,
|
||||||
|
nfcCharacter = nfcCharacter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
addTransformationHistoryToDatabase(
|
||||||
|
characterId = characterId,
|
||||||
|
nfcCharacter = nfcCharacter,
|
||||||
|
dimData = cardData
|
||||||
|
)
|
||||||
|
|
||||||
|
addVitalsHistoryToDatabase(
|
||||||
|
characterId = characterId,
|
||||||
|
nfcCharacter = nfcCharacter
|
||||||
|
)
|
||||||
|
|
||||||
|
return "Done reading character!"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun updateCardProgress(
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
cardData: Card
|
||||||
|
) {
|
||||||
|
database
|
||||||
|
.cardProgressDao()
|
||||||
|
.updateCardProgress(
|
||||||
|
currentStage = nfcCharacter.nextAdventureMissionStage.toInt(),
|
||||||
|
cardId = cardData.id,
|
||||||
|
unlocked = nfcCharacter.nextAdventureMissionStage.toInt() > cardData.stageCount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun addVbCharacterToDatabase(
|
||||||
|
characterId: Long,
|
||||||
|
nfcCharacter: VBNfcCharacter
|
||||||
|
) {
|
||||||
|
val extraCharacterData = VBCharacterData(
|
||||||
|
id = characterId,
|
||||||
|
generation = nfcCharacter.generation.toInt(),
|
||||||
|
totalTrophies = nfcCharacter.totalTrophies.toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertVBCharacterData(extraCharacterData)
|
||||||
|
|
||||||
|
addSpecialMissionsToDatabase(nfcCharacter, characterId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun addSpecialMissionsToDatabase(
|
||||||
|
nfcCharacter: VBNfcCharacter,
|
||||||
|
characterId: Long
|
||||||
|
) {
|
||||||
|
val specialMissionsWatch = nfcCharacter.specialMissions
|
||||||
|
val specialMissionsDb = specialMissionsWatch.map { item ->
|
||||||
|
SpecialMissions(
|
||||||
|
characterId = characterId,
|
||||||
|
goal = item.goal.toInt(),
|
||||||
|
watchId = item.id.toInt(),
|
||||||
|
progress = item.progress.toInt(),
|
||||||
|
status = item.status,
|
||||||
|
timeElapsedInMinutes = item.timeElapsedInMinutes.toInt(),
|
||||||
|
timeLimitInMinutes = item.timeLimitInMinutes.toInt(),
|
||||||
|
missionType = item.type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertSpecialMissions(*specialMissionsDb.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun addBeCharacterToDatabase(
|
||||||
|
characterId: Long,
|
||||||
|
nfcCharacter: BENfcCharacter
|
||||||
|
) {
|
||||||
|
val extraCharacterData = BECharacterData(
|
||||||
|
id = characterId,
|
||||||
|
trainingHp = nfcCharacter.trainingHp.toInt(),
|
||||||
|
trainingAp = nfcCharacter.trainingAp.toInt(),
|
||||||
|
trainingBp = nfcCharacter.trainingBp.toInt(),
|
||||||
|
remainingTrainingTimeInMinutes = nfcCharacter.remainingTrainingTimeInMinutes.toInt(),
|
||||||
|
itemEffectActivityLevelValue = nfcCharacter.itemEffectActivityLevelValue.toInt(),
|
||||||
|
itemEffectMentalStateValue = nfcCharacter.itemEffectMentalStateValue.toInt(),
|
||||||
|
itemEffectMentalStateMinutesRemaining = nfcCharacter.itemEffectMentalStateMinutesRemaining.toInt(),
|
||||||
|
itemEffectActivityLevelMinutesRemaining = nfcCharacter.itemEffectActivityLevelMinutesRemaining.toInt(),
|
||||||
|
itemEffectVitalPointsChangeValue = nfcCharacter.itemEffectVitalPointsChangeValue.toInt(),
|
||||||
|
itemEffectVitalPointsChangeMinutesRemaining = nfcCharacter.itemEffectVitalPointsChangeMinutesRemaining.toInt(),
|
||||||
|
abilityRarity = nfcCharacter.abilityRarity,
|
||||||
|
abilityType = nfcCharacter.abilityType.toInt(),
|
||||||
|
abilityBranch = nfcCharacter.abilityBranch.toInt(),
|
||||||
|
abilityReset = nfcCharacter.abilityReset.toInt(),
|
||||||
|
rank = nfcCharacter.abilityReset.toInt(),
|
||||||
|
itemType = nfcCharacter.itemType.toInt(),
|
||||||
|
itemMultiplier = nfcCharacter.itemMultiplier.toInt(),
|
||||||
|
itemRemainingTime = nfcCharacter.itemRemainingTime.toInt(),
|
||||||
|
otp0 = "", //nfcCharacter.value!!.otp0.toString(),
|
||||||
|
otp1 = "", //nfcCharacter.value!!.otp1.toString(),
|
||||||
|
minorVersion = nfcCharacter.characterCreationFirmwareVersion.minorVersion.toInt(),
|
||||||
|
majorVersion = nfcCharacter.characterCreationFirmwareVersion.majorVersion.toInt(),
|
||||||
|
)
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertBECharacterData(extraCharacterData)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun addVitalsHistoryToDatabase(
|
||||||
|
characterId: Long,
|
||||||
|
nfcCharacter: NfcCharacter
|
||||||
|
) {
|
||||||
|
val vitalsHistoryWatch = nfcCharacter.vitalHistory
|
||||||
|
val vitalsHistory = vitalsHistoryWatch.map { historyElement ->
|
||||||
|
val year = if (historyElement.year.toInt() !in 2021 .. 2035) 0 else historyElement.year.toInt()
|
||||||
|
|
||||||
|
VitalsHistory(
|
||||||
|
charId = characterId,
|
||||||
|
year = year,
|
||||||
|
month = historyElement.month.toInt(),
|
||||||
|
day = historyElement.day.toInt(),
|
||||||
|
vitalPoints = historyElement.vitalsGained.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertVitals(*vitalsHistory.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun addTransformationHistoryToDatabase(
|
||||||
|
characterId: Long,
|
||||||
|
nfcCharacter: NfcCharacter,
|
||||||
|
dimData: Card
|
||||||
|
) {
|
||||||
|
val transformationHistoryWatch = nfcCharacter.transformationHistory
|
||||||
|
transformationHistoryWatch.map { item ->
|
||||||
|
if (item.toCharIndex.toInt() != 255) {
|
||||||
|
val date = GregorianCalendar(
|
||||||
|
item.year.toInt(),
|
||||||
|
item.month.toInt(),
|
||||||
|
item.day.toInt()
|
||||||
|
)
|
||||||
|
.time
|
||||||
|
.time
|
||||||
|
|
||||||
|
database
|
||||||
|
.userCharacterDao()
|
||||||
|
.insertTransformation(
|
||||||
|
characterId,
|
||||||
|
item.toCharIndex.toInt(),
|
||||||
|
dimData.id,
|
||||||
|
date
|
||||||
|
)
|
||||||
|
|
||||||
|
database
|
||||||
|
.dexDao()
|
||||||
|
.insertCharacter(
|
||||||
|
item.toCharIndex.toInt(),
|
||||||
|
dimData.id,
|
||||||
|
date
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+298
@@ -0,0 +1,298 @@
|
|||||||
|
package com.github.nacabaro.vbhelper.screens.scanScreen.converters
|
||||||
|
|
||||||
|
import android.icu.util.Calendar
|
||||||
|
import android.icu.util.TimeZone
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import com.github.cfogrady.vbnfc.be.BENfcCharacter
|
||||||
|
import com.github.cfogrady.vbnfc.be.FirmwareVersion
|
||||||
|
import com.github.cfogrady.vbnfc.data.NfcCharacter
|
||||||
|
import com.github.cfogrady.vbnfc.vb.SpecialMission
|
||||||
|
import com.github.cfogrady.vbnfc.vb.VBNfcCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.database.AppDatabase
|
||||||
|
import com.github.nacabaro.vbhelper.di.VBHelper
|
||||||
|
import com.github.nacabaro.vbhelper.domain.device_data.UserCharacter
|
||||||
|
import com.github.nacabaro.vbhelper.dtos.CharacterDtos
|
||||||
|
import com.github.nacabaro.vbhelper.utils.DeviceType
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class ToNfcConverter(
|
||||||
|
private val componentActivity: ComponentActivity
|
||||||
|
) {
|
||||||
|
private val application: VBHelper = componentActivity.applicationContext as VBHelper
|
||||||
|
private val database: AppDatabase = application.container.db
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun characterToNfc(
|
||||||
|
characterId: Long
|
||||||
|
): NfcCharacter {
|
||||||
|
val app = componentActivity.applicationContext as VBHelper
|
||||||
|
val database = app.container.db
|
||||||
|
|
||||||
|
val userCharacter = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getCharacter(characterId)
|
||||||
|
|
||||||
|
val characterInfo = database
|
||||||
|
.characterDao()
|
||||||
|
.getCharacterInfo(userCharacter.charId)
|
||||||
|
|
||||||
|
return if (userCharacter.characterType == DeviceType.BEDevice)
|
||||||
|
nfcToBENfc(characterId, characterInfo, userCharacter)
|
||||||
|
else
|
||||||
|
nfcToVBNfc(characterId, characterInfo, userCharacter)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun nfcToVBNfc(
|
||||||
|
characterId: Long,
|
||||||
|
characterInfo: CharacterDtos.CardCharacterInfo,
|
||||||
|
userCharacter: UserCharacter
|
||||||
|
): VBNfcCharacter {
|
||||||
|
val vbData = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getVbData(characterId)
|
||||||
|
.first()
|
||||||
|
|
||||||
|
val paddedTransformationArray = generateTransformationHistory(characterId, 9)
|
||||||
|
|
||||||
|
val watchSpecialMissions = generateSpecialMissionsArray(characterId)
|
||||||
|
|
||||||
|
val nfcData = VBNfcCharacter(
|
||||||
|
dimId = characterInfo.cardId.toUShort(),
|
||||||
|
charIndex = characterInfo.charId.toUShort(),
|
||||||
|
stage = characterInfo.stage.toByte(),
|
||||||
|
attribute = characterInfo.attribute,
|
||||||
|
ageInDays = userCharacter.ageInDays.toByte(),
|
||||||
|
nextAdventureMissionStage = characterInfo.currentStage.toByte(),
|
||||||
|
mood = userCharacter.mood.toByte(),
|
||||||
|
vitalPoints = userCharacter.vitalPoints.toUShort(),
|
||||||
|
transformationCountdownInMinutes = userCharacter.transformationCountdown.toUShort(),
|
||||||
|
injuryStatus = userCharacter.injuryStatus,
|
||||||
|
trophies = userCharacter.trophies.toUShort(),
|
||||||
|
currentPhaseBattlesWon = userCharacter.currentPhaseBattlesWon.toUShort(),
|
||||||
|
currentPhaseBattlesLost = userCharacter.currentPhaseBattlesLost.toUShort(),
|
||||||
|
totalBattlesWon = userCharacter.totalBattlesWon.toUShort(),
|
||||||
|
totalBattlesLost = userCharacter.totalBattlesLost.toUShort(),
|
||||||
|
activityLevel = userCharacter.activityLevel.toByte(),
|
||||||
|
heartRateCurrent = userCharacter.heartRateCurrent.toUByte(),
|
||||||
|
transformationHistory = paddedTransformationArray,
|
||||||
|
vitalHistory = generateVitalsHistoryArray(characterId),
|
||||||
|
appReserved1 = ByteArray(12) {0},
|
||||||
|
appReserved2 = generateUShortAppReserved(userCharacter),
|
||||||
|
generation = vbData.generation.toUShort(),
|
||||||
|
totalTrophies = vbData.totalTrophies.toUShort(),
|
||||||
|
specialMissions = watchSpecialMissions.toTypedArray()
|
||||||
|
)
|
||||||
|
|
||||||
|
return nfcData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun generateUShortAppReserved(
|
||||||
|
userCharacter: UserCharacter
|
||||||
|
): Array<UShort> {
|
||||||
|
val cardData = database
|
||||||
|
.cardDao()
|
||||||
|
.getCardByCharacterId(userCharacter.id)
|
||||||
|
.first()
|
||||||
|
|
||||||
|
val appReserved = Array<UShort>(3) {
|
||||||
|
0u
|
||||||
|
}
|
||||||
|
|
||||||
|
appReserved[0] = cardData.id.toUShort()
|
||||||
|
|
||||||
|
return appReserved
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun generateSpecialMissionsArray(
|
||||||
|
characterId: Long
|
||||||
|
): List<SpecialMission> {
|
||||||
|
val specialMissions = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getSpecialMissions(characterId)
|
||||||
|
.first()
|
||||||
|
|
||||||
|
val watchSpecialMissions = specialMissions.map {
|
||||||
|
SpecialMission(
|
||||||
|
goal = it.goal.toUShort(),
|
||||||
|
id = it.watchId.toUShort(),
|
||||||
|
progress = it.progress.toUShort(),
|
||||||
|
status = it.status,
|
||||||
|
timeElapsedInMinutes = it.timeElapsedInMinutes.toUShort(),
|
||||||
|
timeLimitInMinutes = it.timeLimitInMinutes.toUShort(),
|
||||||
|
type = it.missionType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return watchSpecialMissions
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun generateVitalsHistoryArray(
|
||||||
|
characterId: Long
|
||||||
|
): Array<NfcCharacter.DailyVitals> {
|
||||||
|
val vitalsHistory = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getVitalsHistory(characterId)
|
||||||
|
|
||||||
|
val nfcVitalsHistory = Array(7) {
|
||||||
|
NfcCharacter.DailyVitals(0u, 0u, 0u, 0u)
|
||||||
|
}
|
||||||
|
|
||||||
|
vitalsHistory.mapIndexed { index, historyElement ->
|
||||||
|
var actualYear = 0
|
||||||
|
if (historyElement.year != 2000) {
|
||||||
|
actualYear = historyElement.year
|
||||||
|
}
|
||||||
|
nfcVitalsHistory[index] = NfcCharacter.DailyVitals(
|
||||||
|
day = historyElement.day.toUByte(),
|
||||||
|
month = historyElement.month.toUByte(),
|
||||||
|
year = actualYear.toUShort(),
|
||||||
|
vitalsGained = vitalsHistory[index].vitalPoints.toUShort()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
nfcVitalsHistory.map {
|
||||||
|
Log.d("NFC", it.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nfcVitalsHistory
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun nfcToBENfc(
|
||||||
|
characterId: Long,
|
||||||
|
characterInfo: CharacterDtos.CardCharacterInfo,
|
||||||
|
userCharacter: UserCharacter
|
||||||
|
): BENfcCharacter {
|
||||||
|
val beData = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getBeData(characterId)
|
||||||
|
.first()
|
||||||
|
|
||||||
|
val paddedTransformationArray = generateTransformationHistory(characterId)
|
||||||
|
|
||||||
|
val nfcData = BENfcCharacter(
|
||||||
|
dimId = characterInfo.cardId.toUShort(),
|
||||||
|
charIndex = characterInfo.charId.toUShort(),
|
||||||
|
stage = characterInfo.stage.toByte(),
|
||||||
|
attribute = characterInfo.attribute,
|
||||||
|
ageInDays = userCharacter.ageInDays.toByte(),
|
||||||
|
nextAdventureMissionStage = characterInfo.currentStage.toByte(),
|
||||||
|
mood = userCharacter.mood.toByte(),
|
||||||
|
vitalPoints = userCharacter.vitalPoints.toUShort(),
|
||||||
|
itemEffectMentalStateValue = beData.itemEffectMentalStateValue.toByte(),
|
||||||
|
itemEffectMentalStateMinutesRemaining = beData.itemEffectMentalStateMinutesRemaining.toByte(),
|
||||||
|
itemEffectActivityLevelValue = beData.itemEffectActivityLevelValue.toByte(),
|
||||||
|
itemEffectActivityLevelMinutesRemaining = beData.itemEffectActivityLevelMinutesRemaining.toByte(),
|
||||||
|
itemEffectVitalPointsChangeValue = beData.itemEffectVitalPointsChangeValue.toByte(),
|
||||||
|
itemEffectVitalPointsChangeMinutesRemaining = beData.itemEffectVitalPointsChangeMinutesRemaining.toByte(),
|
||||||
|
transformationCountdownInMinutes = userCharacter.transformationCountdown.toUShort(),
|
||||||
|
injuryStatus = userCharacter.injuryStatus,
|
||||||
|
trainingPp = userCharacter.trophies.toUShort(),
|
||||||
|
currentPhaseBattlesWon = userCharacter.currentPhaseBattlesWon.toUShort(),
|
||||||
|
currentPhaseBattlesLost = userCharacter.currentPhaseBattlesLost.toUShort(),
|
||||||
|
totalBattlesWon = userCharacter.totalBattlesWon.toUShort(),
|
||||||
|
totalBattlesLost = userCharacter.totalBattlesLost.toUShort(),
|
||||||
|
activityLevel = userCharacter.activityLevel.toByte(),
|
||||||
|
heartRateCurrent = userCharacter.heartRateCurrent.toUByte(),
|
||||||
|
transformationHistory = paddedTransformationArray,
|
||||||
|
vitalHistory = generateVitalsHistoryArray(characterId),
|
||||||
|
appReserved1 = ByteArray(12) {0},
|
||||||
|
appReserved2 = Array(3) {0u},
|
||||||
|
trainingHp = beData.trainingHp.toUShort(),
|
||||||
|
trainingAp = beData.trainingAp.toUShort(),
|
||||||
|
trainingBp = beData.trainingBp.toUShort(),
|
||||||
|
remainingTrainingTimeInMinutes = beData.remainingTrainingTimeInMinutes.toUShort(),
|
||||||
|
abilityRarity = beData.abilityRarity,
|
||||||
|
abilityType = beData.abilityType.toUShort(),
|
||||||
|
abilityBranch = beData.abilityBranch.toUShort(),
|
||||||
|
abilityReset = beData.abilityReset.toByte(),
|
||||||
|
rank = beData.rank.toByte(),
|
||||||
|
itemType = beData.itemType.toByte(),
|
||||||
|
itemMultiplier = beData.itemMultiplier.toByte(),
|
||||||
|
itemRemainingTime = beData.itemRemainingTime.toByte(),
|
||||||
|
otp0 = byteArrayOf(8),
|
||||||
|
otp1 = byteArrayOf(8),
|
||||||
|
characterCreationFirmwareVersion = FirmwareVersion(
|
||||||
|
minorVersion = beData.minorVersion.toByte(),
|
||||||
|
majorVersion = beData.majorVersion.toByte()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return nfcData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun generateTransformationHistory(
|
||||||
|
characterId: Long,
|
||||||
|
length: Int = 8
|
||||||
|
): Array<NfcCharacter.Transformation> {
|
||||||
|
val transformationHistory = database
|
||||||
|
.userCharacterDao()
|
||||||
|
.getTransformationHistory(characterId)
|
||||||
|
.first()
|
||||||
|
.map {
|
||||||
|
val date = Date(it.transformationDate)
|
||||||
|
val calendar = android.icu.util.GregorianCalendar(TimeZone.getTimeZone("UTC"))
|
||||||
|
calendar.time = date
|
||||||
|
|
||||||
|
Log.d(
|
||||||
|
"TransformationHistory",
|
||||||
|
"Year: ${calendar.get(Calendar.YEAR)}, " +
|
||||||
|
"Month: ${calendar.get(Calendar.MONTH) + 1}, " +
|
||||||
|
"Day: ${calendar.get(Calendar.DAY_OF_MONTH)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
NfcCharacter.Transformation(
|
||||||
|
toCharIndex = it.monIndex.toUByte(),
|
||||||
|
year = calendar
|
||||||
|
.get(Calendar.YEAR)
|
||||||
|
.toUShort(),
|
||||||
|
month = (calendar
|
||||||
|
.get(Calendar.MONTH) + 1)
|
||||||
|
.toUByte(),
|
||||||
|
day = calendar
|
||||||
|
.get(Calendar.DAY_OF_MONTH)
|
||||||
|
.toUByte()
|
||||||
|
)
|
||||||
|
}.toTypedArray()
|
||||||
|
|
||||||
|
val paddedTransformationArray = padTransformationArray(transformationHistory, length)
|
||||||
|
|
||||||
|
return paddedTransformationArray
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun padTransformationArray(
|
||||||
|
transformationArray: Array<NfcCharacter.Transformation>,
|
||||||
|
length: Int
|
||||||
|
): Array<NfcCharacter.Transformation> {
|
||||||
|
if (transformationArray.size >= 8) {
|
||||||
|
return transformationArray
|
||||||
|
}
|
||||||
|
|
||||||
|
val paddedArray = Array(length) {
|
||||||
|
NfcCharacter.Transformation(
|
||||||
|
toCharIndex = 255u,
|
||||||
|
year = 65535u,
|
||||||
|
month = 255u,
|
||||||
|
day = 255u
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(transformationArray, 0, paddedArray, 0, transformationArray.size)
|
||||||
|
return paddedArray
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-5
@@ -1,4 +1,4 @@
|
|||||||
package com.github.nacabaro.vbhelper.screens.scanScreen
|
package com.github.nacabaro.vbhelper.screens.scanScreen.screens
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -10,17 +10,22 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
|
import com.github.nacabaro.vbhelper.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReadingCharacterScreen(
|
fun ActionScreen(
|
||||||
topBannerText: String,
|
topBannerText: String,
|
||||||
onClickCancel: () -> Unit,
|
onClickCancel: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold (
|
Scaffold (
|
||||||
topBar = {
|
topBar = {
|
||||||
TopBanner(topBannerText)
|
TopBanner(
|
||||||
|
text = topBannerText,
|
||||||
|
onBackClick = onClickCancel
|
||||||
|
)
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column (
|
Column (
|
||||||
@@ -30,12 +35,12 @@ fun ReadingCharacterScreen(
|
|||||||
.padding(innerPadding)
|
.padding(innerPadding)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Text("Place your Vital Bracelet near the reader...")
|
Text(stringResource(R.string.action_place_near_reader))
|
||||||
Button(
|
Button(
|
||||||
onClick = onClickCancel,
|
onClick = onClickCancel,
|
||||||
modifier = Modifier.padding(16.dp)
|
modifier = Modifier.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
Text("Cancel")
|
Text(stringResource(R.string.action_cancel))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user