diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 753ad0e..00f6931 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -91,4 +91,11 @@ dependencies { implementation("com.google.android.material:material:1.2.0") implementation(libs.protobuf.javalite) implementation("androidx.compose.material:material") + + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("com.google.code.gson:gson:2.10.1") + + // HTTP request logging + implementation("com.squareup.okhttp3:logging-interceptor:4.11.0") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d3a5163..c28d47b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/OpponentsDataModel.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/OpponentsDataModel.kt new file mode 100644 index 0000000..8bff492 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/OpponentsDataModel.kt @@ -0,0 +1,5 @@ +package com.github.nacabaro.vbhelper.battle + +data class OpponentsDataModel ( + val opponentsList: ArrayList +):java.io.Serializable \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPDataModel.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPDataModel.kt new file mode 100644 index 0000000..e0b55f7 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPDataModel.kt @@ -0,0 +1,13 @@ +package com.github.nacabaro.vbhelper.battle + +data class PVPDataModel ( + val status: String, + val state: Int, + val currentRound: Int, + val playerHP: Int, + val opponentHP: Int, + val playerAttackHit: Boolean, + val playerAttackDamage: Int, + val opponentAttackDamage: Int, + val winner: String +):java.io.Serializable \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPService.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPService.kt new file mode 100644 index 0000000..8bc6ba2 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/PVPService.kt @@ -0,0 +1,13 @@ +package com.github.nacabaro.vbhelper.battle + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +interface PVPService { + @GET("api/pvp") + // This method returns a Call object with a generic + // type of DataModel, which represents + // the data model for the response. + fun getwinner(@Query("apiStage") apiStage: Int, @Query("playerID") playerID: Int, @Query("playerDigi") playerDigi: String, @Query("playerStage") playerStage: Int, @Query("critBar") critBar: Int, @Query("opponentDigi") opponentDigi: String, @Query("opponentStage") opponentStage: Int): Call +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/RetrofitHelper.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/RetrofitHelper.kt new file mode 100644 index 0000000..1cfca0e --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/RetrofitHelper.kt @@ -0,0 +1,179 @@ +package com.github.nacabaro.vbhelper.battle + +import android.content.Context +import retrofit2.Retrofit +import android.widget.Toast +import retrofit2.* +import retrofit2.converter.gson.GsonConverterFactory + +class RetrofitHelper { + + fun getOpponents(context: Context, stage: String, callback: (OpponentsDataModel) -> Unit) { + println("RetrofitHelper: Starting API call for stage: $stage") + + try { + // Create a Retrofit instance with the base URL and + // a GsonConverterFactory for parsing the response. + val retrofit: Retrofit = Retrofit.Builder().baseUrl("http://192.168.0.230:8080/").addConverterFactory( + GsonConverterFactory.create()).build() + println("RetrofitHelper: Retrofit instance created") + + // Create an ApiService instance from the Retrofit instance. + val service: OpponentService = retrofit.create(OpponentService::class.java) + println("RetrofitHelper: Service created") + + // Call the getopponents() method of the ApiService + // to make an API request. + val call: Call = service.getopponents(stage) + println("RetrofitHelper: API call created, enqueueing...") + + // Use the enqueue() method of the Call object to + // make an asynchronous API request. + call.enqueue(object : Callback { + override fun onFailure(call: Call, t: Throwable) { + println("RetrofitHelper: API call failed: ${t.message}") + t.printStackTrace() + Toast.makeText(context, "Request Fail", Toast.LENGTH_SHORT).show() + } + + override fun onResponse(call: Call, response: Response) { + println("RetrofitHelper: API response received - Code: ${response.code()}") + println("RetrofitHelper: Response body: ${response.body()}") + + if(response.isSuccessful){ + println("RetrofitHelper: Response successful, calling callback") + val opponentsList: OpponentsDataModel = response.body() as OpponentsDataModel + callback(opponentsList) + } else { + println("RetrofitHelper: Response not successful - Error: ${response.errorBody()?.string()}") + } + } + }) + } catch (e: Exception) { + println("RetrofitHelper: Exception in getOpponents: ${e.message}") + e.printStackTrace() + } + } + + /* + fun getCombatWinner(context: Context, stage: String, callback: (CombatDataModel) -> Unit) { + + // Create a Retrofit instance with the base URL and + // a GsonConverterFactory for parsing the response. + val retrofit: Retrofit = Retrofit.Builder().baseUrl("http://192.168.0.230:8080/").addConverterFactory( + GsonConverterFactory.create()).build() + + // Create an ApiService instance from the Retrofit instance. + val service: CombatService = retrofit.create(CombatService::class.java) + + // Call the getwinner() method of the ApiService + // to make an API request. + val call: Call = service.getwinner(stage) + + // Use the enqueue() method of the Call object to + // make an asynchronous API request. + call.enqueue(object : Callback { + // This is an anonymous inner class that implements the Callback interface. + + override fun onFailure(call: Call, t: Throwable) { + // This method is called when the API request fails. + Toast.makeText(context, "Request Fail", Toast.LENGTH_SHORT).show() + } + + override fun onResponse(call: Call, response: Response) { + // This method is called when the API response is received successfully. + + if(response.isSuccessful){ + // If the response is successful, parse the + // response body to a DataModel object. + val winner: CombatDataModel = response.body() as CombatDataModel + + // Call the callback function with the DataModel + // object as a parameter. + callback(winner) + } + } + }) + } + + fun getBattleWinner(context: Context, playerDigi: String, playerStage: Int, opponentDigi: String, opponentStage: Int, callback: (BattleDataModel) -> Unit) { + + // Create a Retrofit instance with the base URL and + // a GsonConverterFactory for parsing the response. + val retrofit: Retrofit = Retrofit.Builder().baseUrl("http://192.168.0.230:8080/").addConverterFactory( + GsonConverterFactory.create()).build() + + // Create an ApiService instance from the Retrofit instance. + val service: BattleService = retrofit.create(BattleService::class.java) + + // Call the getwinner() method of the ApiService + // to make an API request. + val call: Call = service.getwinner(playerDigi, playerStage, opponentDigi, opponentStage) + + // Use the enqueue() method of the Call object to + // make an asynchronous API request. + call.enqueue(object : Callback { + // This is an anonymous inner class that implements the Callback interface. + + override fun onFailure(call: Call, t: Throwable) { + // This method is called when the API request fails. + Toast.makeText(context, "Request Fail", Toast.LENGTH_SHORT).show() + } + + override fun onResponse(call: Call, response: Response) { + // This method is called when the API response is received successfully. + + if(response.isSuccessful){ + // If the response is successful, parse the + // response body to a DataModel object. + val winner: BattleDataModel = response.body() as BattleDataModel + + // Call the callback function with the DataModel + // object as a parameter. + callback(winner) + } + } + }) + } + */ + + fun getPVPWinner(context: Context, apiStage: Int, playerID: Int, playerDigi: String, playerStage: Int, critBar: Int, opponentDigi: String, opponentStage: Int, callback: (PVPDataModel) -> Unit) { + + // Create a Retrofit instance with the base URL and + // a GsonConverterFactory for parsing the response. + val retrofit: Retrofit = Retrofit.Builder().baseUrl("http://192.168.0.230:8080/").addConverterFactory( + GsonConverterFactory.create()).build() + + // Create an ApiService instance from the Retrofit instance. + val service: PVPService = retrofit.create(PVPService::class.java) + + // Call the getwinner() method of the ApiService + // to make an API request. + val call: Call = service.getwinner(apiStage, playerID, playerDigi, playerStage, critBar, opponentDigi, opponentStage) + + // Use the enqueue() method of the Call object to + // make an asynchronous API request. + call.enqueue(object : Callback { + // This is an anonymous inner class that implements the Callback interface. + + override fun onFailure(call: Call, t: Throwable) { + // This method is called when the API request fails. + Toast.makeText(context, "Request Fail", Toast.LENGTH_SHORT).show() + } + + override fun onResponse(call: Call, response: Response) { + // This method is called when the API response is received successfully. + + if(response.isSuccessful){ + // If the response is successful, parse the + // response body to a DataModel object. + val apiResults: PVPDataModel = response.body() as PVPDataModel + + // Call the callback function with the DataModel + // object as a parameter. + callback(apiResults) + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt index b50ef12..7a334be 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt @@ -9,10 +9,269 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.material3.Button +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.unit.dp +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.foundation.layout.Box +import androidx.compose.ui.platform.LocalContext +import androidx.compose.material3.ExperimentalMaterial3Api +import com.github.nacabaro.vbhelper.battle.APIBattleCharacter import com.github.nacabaro.vbhelper.components.TopBanner +import com.github.nacabaro.vbhelper.battle.RetrofitHelper +@OptIn(ExperimentalMaterial3Api::class) @Composable fun BattlesScreen() { + var currentView by remember { mutableStateOf("main") } + + var opponentsList by remember { mutableStateOf(ArrayList()) } + + var activeCharacter by remember { mutableStateOf(null) } + + var expanded by remember { mutableStateOf(false) } + var selectedStage by remember { mutableStateOf("") } + + val context = LocalContext.current + + val rookieButton = @Composable { + Button( + onClick = { + println("Rookie button clicked - starting API call") + try { + RetrofitHelper().getOpponents(context, "rookie") { opponents -> + println("API call completed successfully") + try { + println("Received opponents data: $opponents") + println("Opponents list size: ${opponents.opponentsList.size}") + + // For loop to check opponents and print their names + for (opponent in opponents.opponentsList) { + println("Opponent: ${opponent.name}") + } + + // Store the opponents in your ArrayList + opponentsList.clear() + opponentsList.addAll(opponents.opponentsList) + + println("Updated opponentsList size: ${opponentsList.size}") + println("About to change view to rookie") + currentView = "rookie" + println("View changed to rookie") + } catch (e: Exception) { + println("Error processing opponents data: ${e.message}") + e.printStackTrace() + } + } + } catch (e: Exception) { + println("Error calling getOpponents: ${e.message}") + e.printStackTrace() + } + } + ) { + Text("Rookie Battles") + } + } + + val championButton = @Composable { + Button( + onClick = { + println("Champion button clicked - starting API call") + try { + RetrofitHelper().getOpponents(context, "champion") { opponents -> + println("API call completed successfully") + try { + println("Received opponents data: $opponents") + println("Opponents list size: ${opponents.opponentsList.size}") + + // For loop to check opponents and print their names + for (opponent in opponents.opponentsList) { + println("Opponent: ${opponent.name}") + } + + // Store the opponents in your ArrayList + opponentsList.clear() + opponentsList.addAll(opponents.opponentsList) + + println("Updated opponentsList size: ${opponentsList.size}") + println("About to change view to champion") + currentView = "champion" + println("View changed to champion") + } catch (e: Exception) { + println("Error processing opponents data: ${e.message}") + e.printStackTrace() + } + } + } catch (e: Exception) { + println("Error calling getOpponents: ${e.message}") + e.printStackTrace() + } + } + ) { + Text("Champion Battles") + } + } + + val ultimateButton = @Composable { + Button( + onClick = { + println("Ultimate button clicked - starting API call") + try { + RetrofitHelper().getOpponents(context, "ultimate") { opponents -> + println("API call completed successfully") + try { + println("Received opponents data: $opponents") + println("Opponents list size: ${opponents.opponentsList.size}") + + // For loop to check opponents and print their names + for (opponent in opponents.opponentsList) { + println("Opponent: ${opponent.name}") + } + + // Store the opponents in your ArrayList + opponentsList.clear() + opponentsList.addAll(opponents.opponentsList) + + println("Updated opponentsList size: ${opponentsList.size}") + println("About to change view to ultimate") + currentView = "ultimate" + println("View changed to ultimate") + } catch (e: Exception) { + println("Error processing opponents data: ${e.message}") + e.printStackTrace() + } + } + } catch (e: Exception) { + println("Error calling getOpponents: ${e.message}") + e.printStackTrace() + } + } + ) { + Text("Ultimate Battles") + } + } + + val megaButton = @Composable { + Button( + onClick = { + println("Mega button clicked - starting API call") + try { + RetrofitHelper().getOpponents(context, "mega") { opponents -> + println("API call completed successfully") + try { + println("Received opponents data: $opponents") + println("Opponents list size: ${opponents.opponentsList.size}") + + // For loop to check opponents and print their names + for (opponent in opponents.opponentsList) { + println("Opponent: ${opponent.name}") + } + + // Store the opponents in your ArrayList + opponentsList.clear() + opponentsList.addAll(opponents.opponentsList) + + println("Updated opponentsList size: ${opponentsList.size}") + println("About to change view to mega") + currentView = "mega" + println("View changed to mega") + } catch (e: Exception) { + println("Error processing opponents data: ${e.message}") + e.printStackTrace() + } + } + } catch (e: Exception) { + println("Error calling getOpponents: ${e.message}") + e.printStackTrace() + } + } + ) { + Text("Mega Battles") + } + } + + val backButton = @Composable { + Button( + onClick = { + currentView = "main" + } + ) { + Text("Back") + } + } + + val characterDropdown = @Composable { currentStage: String -> + // Create hardcoded character lists for each stage + val rookieCharacters = listOf( + APIBattleCharacter("AGUMON", "degimon_name_Dim012_003", "dim012_mon03", 0, 1, 1800, 1800, 2400.0f, 700.0f), + APIBattleCharacter("PULSEMON", "degimon_name_Dim000_003", "dim000_mon03", 0, 1, 1800, 1800, 2400.0f, 700.0f), + APIBattleCharacter("DORUMON", "degimon_name_dim137_mon03", "dim137_mon03", 0, 1, 3000, 3000, 5100.0f, 1050.0f) + ) + + val championCharacters = listOf( + APIBattleCharacter("GREYMON","degimon_name_Dim012_004","dim012_mon04",1,1,2000, 2000, 3000.0f,900.0f), + APIBattleCharacter("TYRANNOMON","degimon_name_Dim008_006","dim008_mon06",1,3,2000, 2000, 2400.0f,600.0f), + APIBattleCharacter("DORUGAMON","degimon_name_dim137_mon05","dim137_mon05",1,3,3500, 3500, 5200.0f,1200.0f) + ) + + val ultimateCharacters = listOf( + APIBattleCharacter("METALGREYMON (VIRUS)","degimon_name_Dim014_005","dim014_mon05",2,2,2640, 2640, 2450.0f,800.0f), + APIBattleCharacter("MAMEMON", "degimon_name_Dim000_005", "dim000_mon05", 2, 1, 3000, 3000, 4000.0f, 1000.0f), + APIBattleCharacter("DORUGREYMON","degimon_name_dim137_mon09","dim137_mon09",2,3,5000, 5000, 6400.0f,1400.0f) + ) + + val megaCharacters = listOf( + APIBattleCharacter("WARGREYMON","degimon_name_Dim012_014","dim012_mon14",3,1,3080, 3080, 3825.0f,800.0f), + APIBattleCharacter("SLAYERDRAMON","degimon_name_dim129_mon15","dim129_mon15",3,1,4800, 4800, 6300.0f,1950.0f), + APIBattleCharacter("BREAKDRAMON","degimon_name_dim129_mon17","dim129_mon17",3,2,6000, 6000, 4000.0f,1980.0f) + ) + + // Get the appropriate character list based on current stage + val characterList = when (currentStage.lowercase()) { + "rookie" -> rookieCharacters + "champion" -> championCharacters + "ultimate" -> ultimateCharacters + "mega" -> megaCharacters + else -> rookieCharacters + } + + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = !expanded } + ) { + OutlinedTextField( + value = selectedStage.ifEmpty { "Select Character" }, + onValueChange = {}, + readOnly = true, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + modifier = Modifier.menuAnchor() + ) + + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + characterList.forEach { character -> + DropdownMenuItem( + text = { Text(character.name) }, + onClick = { + selectedStage = character.name + activeCharacter = character + expanded = false + println("Selected character: ${character.name}") + } + ) + } + } + } + } + Scaffold ( topBar = { TopBanner( @@ -27,7 +286,156 @@ fun BattlesScreen() { .padding(top = contentPadding.calculateTopPadding()) .fillMaxSize() ) { - Text("Coming soon") + when (currentView) { + "main" -> { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + rookieButton() + championButton() + ultimateButton() + megaButton() + } + } + + + "rookie" -> { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Rookie Battle View") + + // Add character selection dropdown + characterDropdown("rookie") + + // Display buttons for each opponent + opponentsList.forEach { opponent -> + Button( + onClick = { + activeCharacter = opponent + println("Selected character: ${opponent.name}") + // You can add battle logic here + }, + modifier = Modifier.padding(vertical = 4.dp) + ) { + Text("Battle ${opponent.name}") + } + } + + // Show selected character info + activeCharacter?.let { character -> + Text("Active Character: ${character.name}") + Text("HP: ${character.currentHp}/${character.baseHp}") + Text("BP: ${character.baseBp}") + Text("AP: ${character.baseAp}") + } + + backButton() + } + } + + "champion" -> { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Champion Battle View") + + // Add character selection dropdown + characterDropdown("champion") + + // Display buttons for each opponent + opponentsList.forEach { opponent -> + Button( + onClick = { + activeCharacter = opponent + println("Selected character: ${opponent.name}") + }, + modifier = Modifier.padding(vertical = 4.dp) + ) { + Text("Battle ${opponent.name}") + } + } + + // Show selected character info + activeCharacter?.let { character -> + Text("Active Character: ${character.name}") + Text("HP: ${character.currentHp}/${character.baseHp}") + Text("BP: ${character.baseBp}") + Text("AP: ${character.baseAp}") + } + + backButton() + } + } + + "ultimate" -> { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Ultimate Battle View") + + // Add character selection dropdown + characterDropdown("ultimate") + + // Display buttons for each opponent + opponentsList.forEach { opponent -> + Button( + onClick = { + activeCharacter = opponent + println("Selected character: ${opponent.name}") + }, + modifier = Modifier.padding(vertical = 4.dp) + ) { + Text("Battle ${opponent.name}") + } + } + + // Show selected character info + activeCharacter?.let { character -> + Text("Active Character: ${character.name}") + Text("HP: ${character.currentHp}/${character.baseHp}") + Text("BP: ${character.baseBp}") + Text("AP: ${character.baseAp}") + } + + backButton() + } + } + + "mega" -> { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Mega Battle View") + + // Add character selection dropdown + characterDropdown("mega") + + // Display buttons for each opponent + opponentsList.forEach { opponent -> + Button( + onClick = { + activeCharacter = opponent + println("Selected character: ${opponent.name}") + }, + modifier = Modifier.padding(vertical = 4.dp) + ) { + Text("Battle ${opponent.name}") + } + } + + // Show selected character info + activeCharacter?.let { character -> + Text("Active Character: ${character.name}") + Text("HP: ${character.currentHp}/${character.baseHp}") + Text("BP: ${character.baseBp}") + Text("AP: ${character.baseAp}") + } + + backButton() + } + } + } } } }