diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt index bf4ece8..75c1619 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/App.kt @@ -37,6 +37,27 @@ import java.util.Locale var pokemap = ArrayList() val apiString = "https://pokeapi.co/api/v2/pokemon/" +@OptIn(ExperimentalResourceApi::class) +val pokemonTypeDrawableMap = hashMapOf( + "normal" to Res.drawable.normal, + "fire" to Res.drawable.fire, + "water" to Res.drawable.water, + "electric" to Res.drawable.electric, + "grass" to Res.drawable.grass, + "ice" to Res.drawable.ice, + "fighting" to Res.drawable.fighting, + "poison" to Res.drawable.poison, + "ground" to Res.drawable.ground, + "flying" to Res.drawable.flying, + "psychic" to Res.drawable.psychic, + "bug" to Res.drawable.bug, + "rock" to Res.drawable.rock, + "ghost" to Res.drawable.ghost, + "dragon" to Res.drawable.dragon, + "dark" to Res.drawable.dark, + "steel" to Res.drawable.steel, + "fairy" to Res.drawable.fairy +) @OptIn(ExperimentalResourceApi::class) @Composable @@ -44,27 +65,6 @@ val apiString = "https://pokeapi.co/api/v2/pokemon/" fun App() { var dataLoaded by remember { mutableStateOf(false) } - val pokemonTypeDrawableMap = hashMapOf( - "normal" to Res.drawable.normal, - "fire" to Res.drawable.fire, - "water" to Res.drawable.water, - "electric" to Res.drawable.electric, - "grass" to Res.drawable.grass, - "ice" to Res.drawable.ice, - "fighting" to Res.drawable.fighting, - "poison" to Res.drawable.poison, - "ground" to Res.drawable.ground, - "flying" to Res.drawable.flying, - "psychic" to Res.drawable.psychic, - "bug" to Res.drawable.bug, - "rock" to Res.drawable.rock, - "ghost" to Res.drawable.ghost, - "dragon" to Res.drawable.dragon, - "dark" to Res.drawable.dark, - "steel" to Res.drawable.steel, - "fairy" to Res.drawable.fairy - ) - MaterialTheme { if (!dataLoaded) { Navigator(screen = LoadingScreen()) { @@ -87,7 +87,7 @@ fun App() { } else { println("Pokemon should show up any second!") //Display Pokemon Grid - Navigator(screen = HomeScreen(getPokeMap(), pokemonTypeDrawableMap)) { + Navigator(screen = HomeScreen()) { navigator -> SlideTransition(navigator) } } diff --git a/composeApp/src/commonMain/kotlin/DetailScreen.kt b/composeApp/src/commonMain/kotlin/DetailScreen.kt index 9ffe867..10b765d 100644 --- a/composeApp/src/commonMain/kotlin/DetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/DetailScreen.kt @@ -19,15 +19,17 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack 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.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PaintingStyle.Companion.Stroke -import androidx.compose.ui.graphics.PathEffect -import androidx.compose.ui.graphics.drawscope.DrawStyle import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -39,7 +41,6 @@ import io.kamel.image.KamelImage import io.kamel.image.asyncPainterResource import org.json.JSONObject import java.net.URL -import java.util.Locale data class DetailScreen( val pokemon: Pokemon @@ -49,86 +50,118 @@ data class DetailScreen( override fun Content() { val navigator = LocalNavigator.currentOrThrow val orange = Color(0xFFffa500) - val apiString = "https://pokeapi.co/api/v2/pokemon/" - val json = JSONObject(URL(apiString + pokemon.name.lowercase()).readText()); - val type: String = - json.getJSONArray("types").optJSONObject(0).optJSONObject("type").optString("name") - val name: String = json.optString("name") - .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } - val xp: String = json.optString("base_experience") - val height: String = json.optString("height") - val weight: String = json.optString("weight") - Box( - modifier = Modifier.background(color = Color.White).fillMaxSize(), - contentAlignment = Alignment.Center - ) { - //Back Button - Button(onClick = { navigator.pop() }, modifier = Modifier.align(Alignment.TopStart), colors = ButtonDefaults.buttonColors(backgroundColor = orange, contentColor = Color.White)) { - Text("Back") - } - //Details - Column( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally - ) { - KamelImage( - resource = asyncPainterResource(pokemon.imageUrl), - modifier = Modifier.size(256.dp), - contentDescription = "", - alignment = Alignment.Center - ) + var dataLoaded by remember { mutableStateOf(false) } + + var pokemonData by remember { mutableStateOf(null) } + + LaunchedEffect(Unit) { + pokemonData = fetchPokemonDetails(); + dataLoaded = true; + } + + LaunchedEffect(dataLoaded, this) { + if (dataLoaded) { + navigator.push(this@DetailScreen) } + } + + if (!dataLoaded) { + navigator.push(LoadingScreen()) + } else { Box( - modifier = Modifier.size(256.dp).padding(5.dp), contentAlignment = Alignment.Center + modifier = Modifier.background(color = Color.White).fillMaxSize(), + contentAlignment = Alignment.Center ) { - Canvas(modifier = Modifier.matchParentSize()) { - drawRoundRect( - color = Color.White, - topLeft = Offset(0f, 0f), - size = Size(size.width, size.height), - cornerRadius = CornerRadius(20f, 20f), + //Back Button + Button( + onClick = { navigator.popAll(); navigator.push(HomeScreen()) }, + modifier = Modifier.align(Alignment.TopStart), + colors = ButtonDefaults.buttonColors( + backgroundColor = orange, contentColor = Color.White ) - drawRoundRect( - color = Color.Black, - topLeft = Offset(0f, 0f), - size = Size(size.width, size.height), - cornerRadius = CornerRadius(20f, 20f), - style = Stroke(1.dp.toPx()) + ) { + Text("Home") + } + //Details + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally + ) { + KamelImage( + resource = asyncPainterResource(pokemon.imageUrl), + modifier = Modifier.size(256.dp), + contentDescription = "", + alignment = Alignment.Center ) } - Column( - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.padding(16.dp) + //Details + Box( + modifier = Modifier.size(256.dp).padding(5.dp), + contentAlignment = Alignment.Center ) { - Text( - "Name: $name", - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Bold - ) - Text( - "Type: $type", - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Bold - ) - Text( - "Base XP: $xp", - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Bold - ) - Text( - "Height: $height", - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Bold - ) - Text( - "Weight: ${weight}kg", - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Bold - ) + Canvas(modifier = Modifier.matchParentSize()) { + drawRoundRect( + color = Color.White, + topLeft = Offset(0f, 0f), + size = Size(size.width, size.height), + cornerRadius = CornerRadius(20f, 20f), + ) + drawRoundRect( + color = Color.Black, + topLeft = Offset(0f, 0f), + size = Size(size.width, size.height), + cornerRadius = CornerRadius(20f, 20f), + style = Stroke(1.dp.toPx()) + ) + } + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(16.dp) + ) { + Text( + "Name: ${pokemonData?.name}", + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Bold + ) + Text( + "Type: ${pokemonData?.type}", + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Bold + ) + Text( + "Base XP: ${pokemonData?.baseExperience}", + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Bold + ) + Text( + "Height: ${pokemonData?.height}", + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Bold + ) + Text( + "Weight: ${pokemonData?.weight}kg", + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.Bold + ) + } + } + //Stats + Progress Bars + Box( + modifier = Modifier.size(512.dp).padding(5.dp), + contentAlignment = Alignment.Center + ) { + } } } } + + //Leave suspend + suspend fun fetchPokemonDetails(): PokemonData { + val apiString = "https://pokeapi.co/api/v2/pokemon/${pokemon.name.lowercase()}" + val json = JSONObject(URL(apiString).readText()) + return PokemonData.fromJson(json) + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/PokemonData.kt b/composeApp/src/commonMain/kotlin/PokemonData.kt new file mode 100644 index 0000000..5125039 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/PokemonData.kt @@ -0,0 +1,48 @@ +import org.json.JSONObject +import java.util.Locale + +data class PokemonData( + val name: String, + val type: String, + val baseExperience: Int, + val height: Int, // Height in decimetres + val weight: Int, // Weight in hectograms + val hp: Int, + val attack: Int, + val defense: Int, + val specialAttack: Int, + val specialDefense: Int, + val speed: Int +) { + companion object { + fun fromJson(json: JSONObject): PokemonData { + val name = json.optString("name") + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + val type = json.getJSONArray("types").optJSONObject(0).optJSONObject("type") + .optString("name") + val baseExperience = json.optInt("base_experience") + val height = json.optInt("height") + val weight = json.optInt("weight") + val hp = json.getJSONArray("stats").optJSONObject(0).optInt("base_stat") + val attack = json.getJSONArray("stats").optJSONObject(1).optInt("base_stat") + val defense = json.getJSONArray("stats").optJSONObject(2).optInt("base_stat") + val specialAttack = json.getJSONArray("stats").optJSONObject(3).optInt("base_stat") + val specialDefense = json.getJSONArray("stats").optJSONObject(4).optInt("base_stat") + val speed = json.getJSONArray("stats").optJSONObject(5).optInt("base_stat") + + return PokemonData( + name = name, + type = type, + baseExperience = baseExperience, + height = height, + weight = weight, + hp = hp, + attack = attack, + defense = defense, + specialAttack = specialAttack, + specialDefense = specialDefense, + speed = speed + ) + } + } +}