Setup API calls to use User ID.

This commit is contained in:
lightheel 2025-11-17 15:06:42 -05:00
parent 29ff2805c3
commit b0c5d6375d
3 changed files with 68 additions and 16 deletions

View File

@ -1,7 +1,20 @@
package com.github.nacabaro.vbhelper.battle package com.github.nacabaro.vbhelper.battle
data class AdditionalInfo(
val avatar: String? = null,
val id: Long? = null,
val name: String? = null,
val status: String? = null
)
data class UserInfo(
val userId: String? = null,
val additionalInfo: AdditionalInfo? = null
)
data class AuthenticateResponse( data class AuthenticateResponse(
val success: Boolean, val success: Boolean,
val message: String? = null val message: String? = null,
val userInfo: UserInfo? = null
) )

View File

@ -218,6 +218,7 @@ fun AnimatedDamageNumber(
@Composable @Composable
fun BattleScreen( fun BattleScreen(
userId: Long? = null,
stage: String, stage: String,
playerName: String, playerName: String,
opponentName: String, opponentName: String,
@ -227,6 +228,9 @@ fun BattleScreen(
context: android.content.Context? = null, context: android.content.Context? = null,
selectedBackgroundSet: Int = 0 selectedBackgroundSet: Int = 0
) { ) {
// Capture userId parameter for use in lambdas - use remember to ensure it's accessible in all scopes
val currentUserId = remember { userId }
val battleSystem = remember { ArenaBattleSystem() } val battleSystem = remember { ArenaBattleSystem() }
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
@ -621,6 +625,7 @@ fun BattleScreen(
0 -> { 0 -> {
// Middle screen - both Digimon // Middle screen - both Digimon
MiddleBattleView( MiddleBattleView(
userId = currentUserId,
battleSystem = battleSystem, battleSystem = battleSystem,
stage = stage, stage = stage,
playerName = playerName, playerName = playerName,
@ -757,6 +762,7 @@ fun BattleScreen(
@Composable @Composable
fun MiddleBattleView( fun MiddleBattleView(
userId: Long? = null,
battleSystem: ArenaBattleSystem, battleSystem: ArenaBattleSystem,
stage: String, stage: String,
playerName: String, playerName: String,
@ -1072,6 +1078,9 @@ fun MiddleBattleView(
onClick = { onClick = {
println("Attack button clicked!") println("Attack button clicked!")
// Capture userId for use in this lambda
val playerUserId = userId
// Get crit bar progress as float (0.0f to 100.0f) // Get crit bar progress as float (0.0f to 100.0f)
val critBarProgressFloat = battleSystem.critBarProgress.toFloat() val critBarProgressFloat = battleSystem.critBarProgress.toFloat()
@ -1100,7 +1109,7 @@ fun MiddleBattleView(
RetrofitHelper().getPVPWinner( RetrofitHelper().getPVPWinner(
ctx, ctx,
1, 1,
2, playerUserId?.toInt() ?: 2,
activeCharacter?.name ?: "Player", activeCharacter?.name ?: "Player",
playerStage, playerStage,
opponentStage, opponentStage,
@ -1653,6 +1662,7 @@ fun BattlesScreen() {
// Auth state // Auth state
var isAuthenticated by remember { mutableStateOf(false) } var isAuthenticated by remember { mutableStateOf(false) }
var isCheckingAuth by remember { mutableStateOf(true) } var isCheckingAuth by remember { mutableStateOf(true) }
var userId by remember { mutableStateOf<Long?>(null) }
// Track processed tokens to prevent duplicate API calls // Track processed tokens to prevent duplicate API calls
var processedTokens by remember { mutableStateOf<Set<String>>(emptySet()) } var processedTokens by remember { mutableStateOf<Set<String>>(emptySet()) }
@ -1777,37 +1787,40 @@ fun BattlesScreen() {
} }
if (token != null && token.isNotEmpty()) { if (token != null && token.isNotEmpty()) {
// Check if we've already processed this token // Check if we've already successfully processed this token
if (!processedTokens.contains(token)) { if (!processedTokens.contains(token)) {
// Mark token as being processed
processedTokens = processedTokens + token
println("BATTLESCREEN: Received token from URI: $token (URI: $uri)") println("BATTLESCREEN: Received token from URI: $token (URI: $uri)")
// Exchange token with battle server // Exchange token with battle server
RetrofitHelper().authenticate(context, token) { response -> RetrofitHelper().authenticate(context, token) { response ->
if (response.success) { if (response.success) {
// Only mark as processed after successful authentication
processedTokens = processedTokens + token
// Extract userId from response
val extractedUserId = response.userInfo?.userId?.toLongOrNull()
kotlinx.coroutines.CoroutineScope(Dispatchers.IO).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.IO).launch {
battleAuthContainer.authRepository.setAuthenticated(true, token) battleAuthContainer.authRepository.setAuthenticated(true, token, extractedUserId)
} }
// Update UI state on main thread // Update UI state on main thread
kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch {
isAuthenticated = true isAuthenticated = true
isCheckingAuth = false isCheckingAuth = false
println("BATTLESCREEN: Authentication successful") userId = extractedUserId
println("BATTLESCREEN: Authentication successful, userId: $extractedUserId")
android.widget.Toast.makeText(context, "Authentication successful!", android.widget.Toast.LENGTH_SHORT).show() android.widget.Toast.makeText(context, "Authentication successful!", android.widget.Toast.LENGTH_SHORT).show()
} }
} else { } else {
println("BATTLESCREEN: Authentication failed: ${response.message}") println("BATTLESCREEN: Authentication failed: ${response.message}")
// Don't mark as processed on failure - allow retry with a new token
// Show toast on main thread // Show toast on main thread
kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch {
android.widget.Toast.makeText(context, "Authentication failed: ${response.message}", android.widget.Toast.LENGTH_SHORT).show() android.widget.Toast.makeText(context, "Authentication failed: ${response.message}", android.widget.Toast.LENGTH_SHORT).show()
} }
// Remove token from processed set on failure so it can be retried if needed
processedTokens = processedTokens - token
} }
} }
} else { } else {
println("BATTLESCREEN: Token already processed, skipping: $token") println("BATTLESCREEN: Token already successfully processed, skipping: $token")
} }
} else { } else {
println("BATTLESCREEN: No token found in URI: $uri (checked 'c' and 'token' parameters)") println("BATTLESCREEN: No token found in URI: $uri (checked 'c' and 'token' parameters)")
@ -1820,7 +1833,13 @@ fun BattlesScreen() {
val authRepository = battleAuthContainer.authRepository val authRepository = battleAuthContainer.authRepository
val localAuthState = authRepository.isAuthenticated.first() val localAuthState = authRepository.isAuthenticated.first()
val storedToken = authRepository.authToken.first() val storedToken = authRepository.authToken.first()
println("BATTLESCREEN: Local authentication status - isAuthenticated: $localAuthState, hasToken: ${storedToken != null}") val storedUserId = authRepository.userId.first()
println("BATTLESCREEN: Local authentication status - isAuthenticated: $localAuthState, hasToken: ${storedToken != null}, userId: $storedUserId")
// Load stored userId if available
if (storedUserId != null) {
userId = storedUserId
}
// Only check for token in intent if it's a fresh deep link (ACTION_VIEW intent) // Only check for token in intent if it's a fresh deep link (ACTION_VIEW intent)
// This prevents processing stale tokens from previous sessions // This prevents processing stale tokens from previous sessions
@ -1844,9 +1863,17 @@ fun BattlesScreen() {
// Update UI on main thread // Update UI on main thread
kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch { kotlinx.coroutines.CoroutineScope(Dispatchers.Main).launch {
if (response.success) { if (response.success) {
println("BATTLESCREEN: Token validation successful") val extractedUserId = response.userInfo?.userId?.toLongOrNull() ?: storedUserId
// Update stored userId if we got a new one
if (extractedUserId != null && extractedUserId != storedUserId) {
kotlinx.coroutines.CoroutineScope(Dispatchers.IO).launch {
authRepository.setAuthenticated(true, storedToken, extractedUserId)
}
}
println("BATTLESCREEN: Token validation successful, userId: $extractedUserId")
isAuthenticated = true isAuthenticated = true
isCheckingAuth = false isCheckingAuth = false
userId = extractedUserId
} else { } else {
println("BATTLESCREEN: Token validation failed: ${response.message}") println("BATTLESCREEN: Token validation failed: ${response.message}")
// Clear authentication state // Clear authentication state
@ -2382,7 +2409,7 @@ fun BattlesScreen() {
else -> 0 else -> 0
} }
RetrofitHelper().getPVPWinner(context, 0, 2, cardId, apiStage, 0, opponent.charaId, apiStage) { apiResult -> RetrofitHelper().getPVPWinner(context, 0, userId?.toInt() ?: 2, cardId, apiStage, 0, opponent.charaId, apiStage) { apiResult ->
// Update player character HP from API response // Update player character HP from API response
activeCharacter = activeCharacter?.copy( activeCharacter = activeCharacter?.copy(
baseHp = apiResult.playerHP, baseHp = apiResult.playerHP,
@ -2447,6 +2474,7 @@ fun BattlesScreen() {
"battle-main" -> { "battle-main" -> {
BattleScreen( BattleScreen(
userId = userId,
stage = currentStage, stage = currentStage,
playerName = activeCharacter?.name ?: "Player", playerName = activeCharacter?.name ?: "Player",
opponentName = selectedOpponent?.name ?: "Opponent", opponentName = selectedOpponent?.name ?: "Opponent",
@ -2487,7 +2515,7 @@ fun BattlesScreen() {
RetrofitHelper().getPVPWinner( RetrofitHelper().getPVPWinner(
context, context,
1, 1,
2, userId?.toInt() ?: 2,
activeCharacter?.name ?: "Player", activeCharacter?.name ?: "Player",
playerStage, playerStage,
opponentStage, opponentStage,
@ -2501,7 +2529,7 @@ fun BattlesScreen() {
RetrofitHelper().getPVPWinner( RetrofitHelper().getPVPWinner(
context, context,
2, 2,
2, userId?.toInt() ?: 2,
activeCharacter?.name ?: "Player", activeCharacter?.name ?: "Player",
playerStage, playerStage,
opponentStage, opponentStage,

View File

@ -5,6 +5,7 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -14,6 +15,7 @@ class AuthRepository(
private companion object { private companion object {
val IS_AUTHENTICATED = booleanPreferencesKey("is_authenticated") val IS_AUTHENTICATED = booleanPreferencesKey("is_authenticated")
val AUTH_TOKEN = stringPreferencesKey("auth_token") val AUTH_TOKEN = stringPreferencesKey("auth_token")
val USER_ID = longPreferencesKey("user_id")
} }
val isAuthenticated: Flow<Boolean> = dataStore.data val isAuthenticated: Flow<Boolean> = dataStore.data
@ -26,12 +28,20 @@ class AuthRepository(
preferences[AUTH_TOKEN] preferences[AUTH_TOKEN]
} }
suspend fun setAuthenticated(isAuthenticated: Boolean, token: String? = null) { val userId: Flow<Long?> = dataStore.data
.map { preferences ->
preferences[USER_ID]
}
suspend fun setAuthenticated(isAuthenticated: Boolean, token: String? = null, userId: Long? = null) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[IS_AUTHENTICATED] = isAuthenticated preferences[IS_AUTHENTICATED] = isAuthenticated
if (token != null) { if (token != null) {
preferences[AUTH_TOKEN] = token preferences[AUTH_TOKEN] = token
} }
if (userId != null) {
preferences[USER_ID] = userId
}
} }
} }
@ -39,6 +49,7 @@ class AuthRepository(
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[IS_AUTHENTICATED] = false preferences[IS_AUTHENTICATED] = false
preferences.remove(AUTH_TOKEN) preferences.remove(AUTH_TOKEN)
preferences.remove(USER_ID)
} }
} }
} }