M app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/CardDao.kt +2 -1
@@ 5,6 5,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.github.nacabaro.vbhelper.domain.card.Card
+import kotlinx.coroutines.flow.Flow
@Dao
interface CardDao {
@@ 26,7 27,7 @@ interface CardDao {
WHERE uc.id = :id
"""
)
- suspend fun getCardByCharacterId(id: Long): Card
+ fun getCardByCharacterId(id: Long): Flow<Card>
@Query("UPDATE Card SET name = :newName WHERE id = :id")
suspend fun renameCard(id: Int, newName: String)
M app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt => app/src/main/java/com/github/nacabaro/vbhelper/daos/UserCharacterDao.kt +2 -1
@@ 13,6 13,7 @@ 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 kotlinx.coroutines.flow.Flow
@Dao
interface UserCharacterDao {
@@ 76,7 77,7 @@ interface UserCharacterDao {
LEFT JOIN Adventure a ON a.characterId = uc.id
"""
)
- suspend fun getAllCharacters(): List<CharacterDtos.CharacterWithSprites>
+ fun getAllCharacters(): Flow<List<CharacterDtos.CharacterWithSprites>>
@Query(
"""
M app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ChooseCharacterScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/itemsScreen/ChooseCharacterScreen.kt +3 -2
@@ 24,6 24,7 @@ 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
@@ 35,7 36,7 @@ fun ChooseCharacterScreen(
) {
val coroutineScope = rememberCoroutineScope()
val application = LocalContext.current.applicationContext as VBHelper
- val storageRepository = StorageRepository(application.container.db)
+ val storageRepository = StorageRepository(application.container.db, )
val characterList = remember {
mutableStateOf<List<CharacterDtos.CharacterWithSprites>>(emptyList())
}
@@ 57,7 58,7 @@ fun ChooseCharacterScreen(
characterList.value = storageRepository.getVBCharacters()
}
else -> {
- characterList.value = storageRepository.getAllCharacters()
+ characterList.value = storageRepository.getAllCharacters().first()
}
}
}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ChooseConnectionScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ChooseConnectionScreen.kt +78 -0
@@ 0,0 1,78 @@
+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.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import com.github.nacabaro.vbhelper.components.TopBanner
+
+@Composable
+fun ChooseConnectOption(
+ onClickRead: (() -> Unit)? = null,
+ onClickWrite: (() -> Unit)? = null,
+ navController: NavController
+) {
+ Scaffold(
+ topBar = {
+ TopBanner(
+ text = "Scan a Vital Bracelet",
+ onBackClick = {
+ navController.popBackStack()
+ }
+ )
+ }
+ ) { 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)
+ )
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ScanScreen.kt +24 -208
@@ 1,38 1,24 @@
package com.github.nacabaro.vbhelper.screens.scanScreen
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.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
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.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import com.github.cfogrady.vbnfc.data.NfcCharacter
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.domain.card.Card
import com.github.nacabaro.vbhelper.navigation.NavigationItems
-import com.github.nacabaro.vbhelper.screens.cardScreen.ChooseCard
+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.isMissingSecrets
import com.github.nacabaro.vbhelper.source.proto.Secrets
@@ 55,8 41,6 @@ fun ScanScreen(
val storageRepository = StorageRepository(application.container.db)
var nfcCharacter by remember { mutableStateOf<NfcCharacter?>(null) }
- var cardsRead by remember { mutableStateOf<List<Card>?>(null) }
-
val context = LocalContext.current
LaunchedEffect(storageRepository) {
@@ 73,143 57,33 @@ fun ScanScreen(
}
}
- var readingScreen by remember { mutableStateOf(false) }
var writingScreen by remember { mutableStateOf(false) }
- var cardSelectScreen by remember { mutableStateOf(false) }
- var isDoneReadingCharacter by remember { mutableStateOf(false) }
- var isDoneSendingCard by remember { mutableStateOf(false) }
- var isDoneWritingCharacter by remember { mutableStateOf(false) }
-
- DisposableEffect(readingScreen) {
- if(readingScreen) {
- scanScreenController.registerActivityLifecycleListener(
- SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER,
- object: ActivityLifecycleListener {
- override fun onPause() {
- scanScreenController.cancelRead()
- }
-
- override fun onResume() {
- scanScreenController.onClickRead(
- secrets = secrets!!,
- onComplete = {
- isDoneReadingCharacter = true
- },
- onMultipleCards = { cards ->
- cardsRead = cards
- readingScreen = false
- cardSelectScreen = true
- isDoneReadingCharacter = true
- }
- )
- }
- }
- )
- scanScreenController.onClickRead(
- secrets = secrets!!,
- onComplete = {
- isDoneReadingCharacter = true
- },
- onMultipleCards = { cards ->
- cardsRead = cards
- readingScreen = false
- cardSelectScreen = true
- isDoneReadingCharacter = true
- }
- )
- }
- onDispose {
- if(readingScreen) {
- scanScreenController.unregisterActivityLifecycleListener(
- SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER
- )
- scanScreenController.cancelRead()
- }
- }
- }
-
- DisposableEffect(writingScreen, isDoneSendingCard) {
- 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 (secrets != null && nfcCharacter != null) {
- if (!isDoneSendingCard) {
- scanScreenController.onClickCheckCard(secrets!!, nfcCharacter!!) {
- isDoneSendingCard = true
- }
- } else if (!isDoneWritingCharacter) {
- scanScreenController.onClickWrite(secrets!!, nfcCharacter!!) {
- isDoneWritingCharacter = true
- }
- }
- }
-
- onDispose {
- if(writingScreen) {
- scanScreenController.unregisterActivityLifecycleListener(SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER)
- scanScreenController.cancelRead()
- }
- }
- }
-
- if (isDoneReadingCharacter && !cardSelectScreen) {
- 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!!)
- }
- }
- }
+ var readingScreen by remember { mutableStateOf(false) }
- if (readingScreen) {
- ReadingCharacterScreen("Reading character") {
- readingScreen = false
- scanScreenController.cancelRead()
- }
- } else if (writingScreen) {
- if (!isDoneSendingCard) {
- ReadingCharacterScreen("Sending card") {
+ if (writingScreen && nfcCharacter != null && characterId != null) {
+ WritingScreen(
+ scanScreenController = scanScreenController,
+ nfcCharacter = nfcCharacter!!,
+ characterId = characterId,
+ onComplete = {
writingScreen = false
- scanScreenController.cancelRead()
- }
- } else if (!isDoneWritingCharacter) {
- ReadingCharacterScreen("Writing character") {
- isDoneSendingCard = false
+ navController.navigate(NavigationItems.Home.route)
+ },
+ onCancel = {
writingScreen = false
- scanScreenController.cancelRead()
+ navController.navigate(NavigationItems.Home.route)
}
- }
- } else if (cardSelectScreen) {
- ChooseCard(
- cards = cardsRead!!,
- onCardSelected = { card ->
- cardSelectScreen = false
- scanScreenController.flushCharacter(card.id)
+ )
+ } else if (readingScreen) {
+ ReadingScreen(
+ scanScreenController = scanScreenController,
+ onCancel = {
+ readingScreen = false
+ navController.navigate(NavigationItems.Home.route)
+ },
+ onComplete = {
+ readingScreen = false
+ navController.navigate(NavigationItems.Home.route)
}
)
} else {
@@ 247,66 121,8 @@ fun ScanScreen(
}
}
-@Composable
-fun ChooseConnectOption(
- onClickRead: (() -> Unit)? = null,
- onClickWrite: (() -> Unit)? = null,
- navController: NavController
-) {
- Scaffold(
- topBar = {
- TopBanner(
- text = "Scan a Vital Bracelet",
- onBackClick = {
- navController.popBackStack()
- }
- )
- }
- ) { 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)
@Composable
fun ScanScreenPreview() {
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/FromNfcConverter.kt +3 -4
@@ 1,13 1,11 @@
package com.github.nacabaro.vbhelper.screens.scanScreen.converters
-import android.util.Log
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.card.CardProgress
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
@@ 250,10 248,11 @@ class FromNfcConverter (
) {
val vitalsHistoryWatch = nfcCharacter.vitalHistory
val vitalsHistory = vitalsHistoryWatch.map { historyElement ->
- Log.d("VitalsHistory", "${historyElement.year.toInt()} ${historyElement.month.toInt()} ${historyElement.day.toInt()}")
+ val year = if (historyElement.year.toInt() !in 2021 .. 2035) 0 else historyElement.year.toInt()
+
VitalsHistory(
charId = characterId,
- year = historyElement.year.toInt(),
+ year = year,
month = historyElement.month.toInt(),
day = historyElement.day.toInt(),
vitalPoints = historyElement.vitalsGained.toInt()
M app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/converters/ToNfcConverter.kt +2 -0
@@ 14,6 14,7 @@ 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(
@@ 96,6 97,7 @@ class ToNfcConverter(
val cardData = database
.cardDao()
.getCardByCharacterId(userCharacter.id)
+ .first()
val appReserved = Array<UShort>(3) {
0u
R app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/ReadingCharacter.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/ActionScreen.kt +6 -3
@@ 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.Column
@@ 14,13 14,16 @@ import androidx.compose.ui.unit.dp
import com.github.nacabaro.vbhelper.components.TopBanner
@Composable
-fun ReadingCharacterScreen(
+fun ActionScreen(
topBannerText: String,
onClickCancel: () -> Unit,
) {
Scaffold (
topBar = {
- TopBanner(topBannerText)
+ TopBanner(
+ text = topBannerText,
+ onBackClick = onClickCancel
+ )
}
) { innerPadding ->
Column (
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/ReadCharacterScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/ReadCharacterScreen.kt +59 -0
@@ 0,0 1,59 @@
+package com.github.nacabaro.vbhelper.screens.scanScreen.screens
+
+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.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.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.components.TopBanner
+
+@Composable
+fun ReadCharacterScreen(
+ onClickCancel: () -> Unit,
+ onClickConfirm: () -> Unit
+) {
+ Scaffold(
+ topBar = {
+ TopBanner(
+ text = "Read character",
+ onBackClick = onClickCancel
+ )
+ }
+ ) { innerPadding ->
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .padding(innerPadding)
+ .fillMaxSize()
+ ) {
+ Text(
+ text = "Prepare your device!",
+ textAlign = TextAlign.Center
+ )
+
+ Text(
+ text = "Go to connect and when ready press confirm!",
+ textAlign = TextAlign.Center
+ )
+
+ Spacer(
+ modifier = Modifier.padding(8.dp)
+ )
+
+ Button(
+ onClick = onClickConfirm,
+ ) {
+ Text("Confirm")
+ }
+ }
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/ReadingScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/ReadingScreen.kt +109 -0
@@ 0,0 1,109 @@
+package com.github.nacabaro.vbhelper.screens.scanScreen.screens
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+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 com.github.nacabaro.vbhelper.ActivityLifecycleListener
+import com.github.nacabaro.vbhelper.domain.card.Card
+import com.github.nacabaro.vbhelper.screens.cardScreen.ChooseCard
+import com.github.nacabaro.vbhelper.screens.scanScreen.SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER
+import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenController
+
+@Composable
+fun ReadingScreen(
+ scanScreenController: ScanScreenController,
+ onCancel: () -> Unit,
+ onComplete: () -> Unit
+) {
+ val secrets by scanScreenController.secretsFlow.collectAsState(null)
+
+ var cardsRead by remember { mutableStateOf<List<Card>?>(null) }
+
+ var readingScreen by remember { mutableStateOf(false) }
+ var isDoneReadingCharacter by remember { mutableStateOf(false) }
+ var cardSelectScreen by remember { mutableStateOf(false) }
+
+ DisposableEffect(readingScreen) {
+ if(readingScreen) {
+ scanScreenController.registerActivityLifecycleListener(
+ SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER,
+ object: ActivityLifecycleListener {
+ override fun onPause() {
+ scanScreenController.cancelRead()
+ }
+
+ override fun onResume() {
+ scanScreenController.onClickRead(
+ secrets = secrets!!,
+ onComplete = {
+ isDoneReadingCharacter = true
+ },
+ onMultipleCards = { cards ->
+ cardsRead = cards
+ readingScreen = false
+ cardSelectScreen = true
+ isDoneReadingCharacter = true
+ }
+ )
+ }
+ }
+ )
+ scanScreenController.onClickRead(
+ secrets = secrets!!,
+ onComplete = {
+ isDoneReadingCharacter = true
+ },
+ onMultipleCards = { cards ->
+ cardsRead = cards
+ readingScreen = false
+ cardSelectScreen = true
+ isDoneReadingCharacter = true
+ }
+ )
+ }
+ onDispose {
+ if(readingScreen) {
+ scanScreenController.unregisterActivityLifecycleListener(
+ SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER
+ )
+ scanScreenController.cancelRead()
+ }
+ }
+ }
+
+ if (isDoneReadingCharacter && !cardSelectScreen) {
+ readingScreen = false
+ onComplete()
+ }
+
+ if (!readingScreen) {
+ ReadCharacterScreen(
+ onClickConfirm = {
+ readingScreen = true
+ },
+ onClickCancel = {
+ onCancel()
+ }
+ )
+ }
+
+ if (readingScreen) {
+ ActionScreen("Reading character") {
+ readingScreen = false
+ scanScreenController.cancelRead()
+ onCancel()
+ }
+ } else if (cardSelectScreen) {
+ ChooseCard(
+ cards = cardsRead!!,
+ onCardSelected = { card ->
+ cardSelectScreen = false
+ scanScreenController.flushCharacter(card.id)
+ }
+ )
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WriteCardScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WriteCardScreen.kt +132 -0
@@ 0,0 1,132 @@
+package com.github.nacabaro.vbhelper.screens.scanScreen.screens
+
+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.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+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.Scaffold
+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.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.domain.card.Card
+import com.github.nacabaro.vbhelper.source.ScanRepository
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getImageBitmap
+
+@Composable
+fun WriteCardScreen(
+ characterId: Long,
+ onClickCancel: () -> Unit,
+ onClickConfirm: () -> Unit
+) {
+ val application = LocalContext.current.applicationContext as VBHelper
+ val database = application.container.db
+ val scanRepository = ScanRepository(database)
+ val cardDetails by scanRepository.getCardDetails(characterId).collectAsState(Card(
+ id = 0,
+ cardId = 0,
+ name = "",
+ logo = byteArrayOf(),
+ logoHeight = 0,
+ logoWidth = 0,
+ stageCount = 0,
+ isBEm = false
+ ))
+
+ Scaffold(
+ topBar = {
+ TopBanner(
+ text = "Writing card details",
+ onBackClick = onClickCancel
+ )
+ }
+ ) { innerPadding ->
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .padding(innerPadding)
+ .fillMaxSize()
+ ) {
+ Card (
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(8.dp)
+ ) {
+ Row (
+ modifier = Modifier.padding(16.dp),
+ ){
+ if (cardDetails.logoHeight > 0 && cardDetails.logoWidth > 0) {
+ val charaBitmapData = BitmapData(
+ bitmap = cardDetails.logo,
+ width = cardDetails.logoWidth,
+ height = cardDetails.logoHeight
+ )
+ val charaImageBitmapData = charaBitmapData.getImageBitmap(
+ context = LocalContext.current,
+ multiplier = 4,
+ obscure = false
+ )
+
+ 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),
+ filterQuality = FilterQuality.None
+ )
+ }
+ }
+
+ Spacer(
+ modifier = Modifier.width(8.dp)
+ )
+
+ Column {
+ Text("Get your device Ready!")
+ Text("You will need ${cardDetails.name} card!")
+ }
+ }
+
+ }
+
+ Button(
+ onClick = onClickConfirm,
+ ) {
+ Text("Confirm")
+ }
+ }
+ }
+}
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WriteCharacterScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WriteCharacterScreen.kt +135 -0
@@ 0,0 1,135 @@
+package com.github.nacabaro.vbhelper.screens.scanScreen.screens
+
+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.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+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.Scaffold
+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.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.FilterQuality
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import com.github.nacabaro.vbhelper.components.TopBanner
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.domain.card.Card
+import com.github.nacabaro.vbhelper.source.ScanRepository
+import com.github.nacabaro.vbhelper.utils.BitmapData
+import com.github.nacabaro.vbhelper.utils.getImageBitmap
+
+@Composable
+fun WriteCharacterScreen(
+ characterId: Long,
+ onClickCancel: () -> Unit,
+ onClickConfirm: () -> Unit
+) {
+ val application = LocalContext.current.applicationContext as VBHelper
+ val database = application.container.db
+ val scanRepository = ScanRepository(database)
+ val cardDetails by scanRepository.getCardDetails(characterId).collectAsState(Card(
+ id = 0,
+ cardId = 0,
+ name = "",
+ logo = byteArrayOf(),
+ logoHeight = 0,
+ logoWidth = 0,
+ stageCount = 0,
+ isBEm = false
+ ))
+
+ Scaffold(
+ topBar = {
+ TopBanner(
+ text = "Writing character",
+ onBackClick = onClickCancel
+ )
+ }
+ ) { innerPadding ->
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .padding(innerPadding)
+ .fillMaxSize()
+ ) {
+ Card (
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(8.dp)
+ ) {
+ Row (
+ modifier = Modifier.padding(16.dp),
+ ){
+ if (cardDetails.logoHeight > 0 && cardDetails.logoWidth > 0) {
+ val charaBitmapData = BitmapData(
+ bitmap = cardDetails.logo,
+ width = cardDetails.logoWidth,
+ height = cardDetails.logoHeight
+ )
+ val charaImageBitmapData = charaBitmapData.getImageBitmap(
+ context = LocalContext.current,
+ multiplier = 4,
+ obscure = false
+ )
+
+ 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),
+ filterQuality = FilterQuality.None
+ )
+ }
+ }
+
+ Spacer(
+ modifier = Modifier.width(8.dp)
+ )
+
+ Column {
+ Text("Card installed successfully!!")
+ Text("Wait until your device is ready, then tap 'Confirm'")
+ }
+ }
+
+ }
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ Button(
+ onClick = onClickConfirm,
+ ) {
+ Text("Confirm")
+ }
+ }
+ }
+}<
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WritingScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/scanScreen/screens/WritingScreen.kt +140 -0
@@ 0,0 1,140 @@
+package com.github.nacabaro.vbhelper.screens.scanScreen.screens
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+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.platform.LocalContext
+import com.github.cfogrady.vbnfc.data.NfcCharacter
+import com.github.nacabaro.vbhelper.ActivityLifecycleListener
+import com.github.nacabaro.vbhelper.di.VBHelper
+import com.github.nacabaro.vbhelper.screens.scanScreen.SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER
+import com.github.nacabaro.vbhelper.screens.scanScreen.ScanScreenController
+import com.github.nacabaro.vbhelper.source.StorageRepository
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+@Composable
+fun WritingScreen(
+ scanScreenController: ScanScreenController,
+ characterId: Long,
+ nfcCharacter: NfcCharacter,
+ onComplete: () -> Unit,
+ onCancel: () -> Unit,
+) {
+ val secrets by scanScreenController.secretsFlow.collectAsState(null)
+
+ val application = LocalContext.current.applicationContext as VBHelper
+ val storageRepository = StorageRepository(application.container.db)
+
+ var writing by remember { mutableStateOf(false) }
+ var writingScreen by remember { mutableStateOf(false) }
+ var writingConfirmScreen by remember { mutableStateOf(false) }
+ var isDoneSendingCard by remember { mutableStateOf(false) }
+ var isDoneWritingCharacter by remember { mutableStateOf(false) }
+
+ DisposableEffect(writing) {
+ if (writing) {
+ 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 (secrets != null) {
+ if (!isDoneSendingCard) {
+ scanScreenController.onClickCheckCard(secrets!!, nfcCharacter) {
+ isDoneSendingCard = true
+ }
+ } else if (!isDoneWritingCharacter) {
+ scanScreenController.onClickWrite(secrets!!, nfcCharacter) {
+ isDoneWritingCharacter = true
+ }
+ }
+ }
+ }
+
+ onDispose {
+ if (writing) {
+ scanScreenController.unregisterActivityLifecycleListener(
+ SCAN_SCREEN_ACTIVITY_LIFECYCLE_LISTENER
+ )
+ scanScreenController.cancelRead()
+ }
+ }
+ }
+
+ if (!writingScreen) {
+ writing = false
+ WriteCardScreen (
+ characterId = characterId,
+ onClickCancel = {
+ scanScreenController.cancelRead()
+ onCancel()
+ },
+ onClickConfirm = {
+ writingScreen = true
+ }
+ )
+ } else if (!isDoneSendingCard) {
+ writing = true
+ ActionScreen("Sending card") {
+ scanScreenController.cancelRead()
+ onCancel()
+ }
+ } else if (!writingConfirmScreen) {
+ writing = false
+ WriteCharacterScreen (
+ characterId = characterId,
+ onClickCancel = {
+ scanScreenController.cancelRead()
+ onCancel()
+ },
+ onClickConfirm = {
+ writingConfirmScreen = true
+ }
+ )
+ } else if (!isDoneWritingCharacter) {
+ writing = true
+ ActionScreen("Writing character") {
+ isDoneSendingCard = false
+ scanScreenController.cancelRead()
+ onCancel()
+ }
+ }
+
+ var completedWriting by remember { mutableStateOf(false) }
+
+ LaunchedEffect(isDoneSendingCard, isDoneWritingCharacter) {
+ withContext(Dispatchers.IO) {
+ if (isDoneSendingCard && isDoneWritingCharacter) {
+ storageRepository
+ .deleteCharacter(characterId)
+ completedWriting = true
+ }
+ }
+ }
+
+ if (completedWriting) {
+ onComplete()
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageDialog.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageDialog.kt +8 -0
@@ 38,6 38,7 @@ import kotlinx.coroutines.launch
fun StorageDialog(
characterId: Long,
onDismissRequest: () -> Unit,
+ onClickDelete: () -> Unit,
onSendToBracelet: () -> Unit,
onClickSetActive: () -> Unit,
onClickSendToAdventure: (time: Long) -> Unit
@@ 144,6 145,13 @@ fun StorageDialog(
Button(
modifier = Modifier
.fillMaxWidth(),
+ onClick = onClickDelete
+ ) {
+ Text(text = "Delete character")
+ }
+ Button(
+ modifier = Modifier
+ .fillMaxWidth(),
onClick = onDismissRequest
) {
Text(text = "Close")
M app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreen.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreen.kt +16 -15
@@ 1,5 1,6 @@
package com.github.nacabaro.vbhelper.screens.storageScreen
+import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
@@ 14,11 15,10 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
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.remember
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ 28,12 28,10 @@ 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.dtos.CharacterDtos
import com.github.nacabaro.vbhelper.navigation.NavigationItems
import com.github.nacabaro.vbhelper.screens.adventureScreen.AdventureScreenControllerImpl
import com.github.nacabaro.vbhelper.source.StorageRepository
import com.github.nacabaro.vbhelper.utils.BitmapData
-import kotlinx.coroutines.launch
@Composable
@@ 42,18 40,11 @@ fun StorageScreen(
storageScreenController: StorageScreenControllerImpl,
adventureScreenController: AdventureScreenControllerImpl
) {
- 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) }
+ val characterList by storageRepository.getAllCharacters().collectAsState(initial = emptyList())
- LaunchedEffect(storageRepository, selectedCharacter) {
- coroutineScope.launch {
- val characterList = storageRepository.getAllCharacters()
- monList.value = characterList
- }
- }
+ var selectedCharacter by remember { mutableStateOf<Long?>(null) }
Scaffold (
topBar = {
@@ 65,7 56,7 @@ fun StorageScreen(
)
}
) { contentPadding ->
- if (monList.value.isEmpty()) {
+ if (characterList.isEmpty()) {
Column (
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
@@ 86,7 77,7 @@ fun StorageScreen(
.scrollable(state = rememberScrollState(), orientation = Orientation.Vertical)
.padding(top = contentPadding.calculateTopPadding())
) {
- items(monList.value) { index ->
+ items(characterList) { index ->
CharacterEntry(
icon = BitmapData(
bitmap = index.spriteIdle,
@@ 138,6 129,16 @@ fun StorageScreen(
timeInMinutes = time
)
selectedCharacter = null
+ },
+ onClickDelete = {
+ storageScreenController
+ .deleteCharacter(
+ characterId = selectedCharacter!!,
+ onCompletion = {
+ Log.d("StorageScreen", "Character deleted")
+ }
+ )
+ selectedCharacter = null
}
)
}
M app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenController.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenController.kt +1 -0
@@ 2,4 2,5 @@ package com.github.nacabaro.vbhelper.screens.storageScreen
interface StorageScreenController {
fun setActive(characterId: Long, onCompletion: () -> Unit)
+ fun deleteCharacter(characterId: Long, onCompletion: () -> Unit)
}=
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenControllerImpl.kt => app/src/main/java/com/github/nacabaro/vbhelper/screens/storageScreen/StorageScreenControllerImpl.kt +17 -0
@@ 28,4 28,21 @@ class StorageScreenControllerImpl(
}
}
}
+
+ override fun deleteCharacter(characterId: Long, onCompletion: () -> Unit) {
+ componentActivity.lifecycleScope.launch(Dispatchers.IO) {
+ database
+ .userCharacterDao()
+ .deleteCharacterById(characterId)
+
+ componentActivity.runOnUiThread {
+ Toast.makeText(
+ componentActivity,
+ "Character deleted!",
+ Toast.LENGTH_SHORT
+ ).show()
+ onCompletion()
+ }
+ }
+ }
}=
\ No newline at end of file
A app/src/main/java/com/github/nacabaro/vbhelper/source/ScanRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/ScanRepository.kt +13 -0
@@ 0,0 1,13 @@
+package com.github.nacabaro.vbhelper.source
+
+import com.github.nacabaro.vbhelper.database.AppDatabase
+import com.github.nacabaro.vbhelper.domain.card.Card
+import kotlinx.coroutines.flow.Flow
+
+class ScanRepository(
+ val database: AppDatabase
+) {
+ fun getCardDetails(characterId: Long): Flow<Card> {
+ return database.cardDao().getCardByCharacterId(characterId)
+ }
+}<
\ No newline at end of file
M app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt => app/src/main/java/com/github/nacabaro/vbhelper/source/StorageRepository.kt +2 -1
@@ 6,11 6,12 @@ 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 kotlinx.coroutines.flow.Flow
class StorageRepository (
private val db: AppDatabase
) {
- suspend fun getAllCharacters(): List<CharacterDtos.CharacterWithSprites> {
+ fun getAllCharacters(): Flow<List<CharacterDtos.CharacterWithSprites>> {
return db.userCharacterDao().getAllCharacters()
}