1 year ago

#371156

test-img

OEThe11

Passing a pokemon name to pull out it's information from an API Endpoint in Jetpack Compose Navigation

I have created a Pokemon App with Jetpack Compose. I have two screens. One where the names of the pokemon is being displayed, and a second screen where the details of a selected pokemon will be shown. What I want to achieve is passing the name of the pokemon to a url when it's selected, and getting the information on to the second screen.

const val POKE_DETAILS = "api/v2/pokemon/{name}/"

Network File

interface NetworkingService{
    @GET(Endpoints.POKE_LIST)
    suspend fun getListResponse(
        @Query("limit") limit: String = "151"
    ): Response<GetPokemonListResponse>

    @GET(Endpoints.POKE_DETAILS)
    suspend fun getDetailsResponse(
        @Path("name") name: String
    ): GetPokemonDetailResponse

}

object PokemonNetworkObject{
    val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
    val retroFit: Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .build()

    val networkingServices: NetworkingService by lazy {
        retroFit.create(NetworkingService::class.java)
    }
    val apiClient = ApiClient(networkingServices)
}

Compose Screens

@Preview
@Composable
fun PokemonListPage(pokemonViewModel: PokemonListViewModel = viewModel(), navController: NavController){

    val pokeList = pokemonViewModel.pokemonStateData.collectAsState().value

    Surface(
        modifier = Modifier
            .fillMaxHeight()
            .fillMaxWidth(),
    ) {
        Scaffold(topBar =
        {
            TopAppBar(
                backgroundColor = Color.DarkGray,
                elevation = 0.dp,
            ) {
                Row(modifier = Modifier
                    .fillMaxWidth(),
                    horizontalArrangement = Arrangement.Center
                ){
                    Text(
                        text = "POKEDEX",
                        fontWeight = FontWeight.Bold,
                        fontSize = 25.sp,
                        color = Color.Magenta
                    )
                }
            }
        }, backgroundColor = Color.DarkGray){
            PokemonCards(pokemons = pokeList!!, navController = navController))
        }



//        PokemonCards(pokemons = pokeList!!)
    }
}

@Composable
private fun PokemonCards(pokemons: List<PokeListEntity>, navController: NavController) {
    LazyColumn{
        items(pokemons){ pokemon ->
            PokemonCard(pokemon = pokemon, navController = navController)
        }
        }
    }

@Composable
private fun PokemonCard(pokemon: PokeListEntity, navController: NavController) {
    Card(
        modifier = Modifier
            .width(500.dp)
            .requiredHeight(100.dp)
            .padding(10.dp),
        backgroundColor = Color.Cyan,
        shape = RoundedCornerShape(corner = CornerSize(10.dp)),
        elevation = 5.dp
    ) {
        Row(
            modifier = Modifier
                .padding(start = 16.dp, end = 16.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(
                text = pokemon.name,
                fontSize = 25.sp,
                fontWeight = FontWeight.Bold
            )

            Button(
                onClick = { 
                  navController.navigate(route = "pokemon_detail_screen/${pokemon.name}")
                }) {
                Text(text = "INFO")
            }
        }
    }
}

Details Screen

 @Preview
    @Composable
    fun PokemonDetailScreen(
detailViewModel: DetailViewModel = viewModel(), 
navController: NavController,
pokemonName: String // This Variable
) {
    
        val details by detailViewModel.detailState.observeAsState()
    
        Surface(
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight(),
            color = Color.DarkGray
        ) {
            DetailCard(field = details!!)
    
        }
    }
    
    @Composable
    private fun DetailCard(field: GetPokemonDetailResponse) {
        Card(
            modifier = Modifier
                .requiredHeight(300.dp)
                .fillMaxWidth()
                .padding(10.dp),
            backgroundColor = Color.Cyan,
            shape = RoundedCornerShape(corner = CornerSize(15.dp)),
            elevation = 10.dp
        ) {
            Column(
                modifier = Modifier
                    .fillMaxHeight()
                    .fillMaxWidth()
                    .padding(10.dp),
                verticalArrangement = Arrangement.SpaceEvenly,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                DetailFields("Name:", field = field.name)
                Divider(thickness = 4.dp)
                DetailFields("Height:", field = "${field.height}.in")
                Divider(thickness = 4.dp)
                DetailFields("Weight:", field = "${field.weight}.lbs")
            }
        }
    }
    
    @Composable
    private fun DetailFields(title: String, field: String) {
        Column() {
            Text(
                title,
                fontSize = 20.sp
            )
            Text(
                field,
                fontSize = 30.sp,
                fontWeight = FontWeight.Bold
            )
        }
    
    }

MainActivity

class MainActivity : ComponentActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
          PokeDexComposeTheme {
              Surface(
                  modifier = Modifier.fillMaxSize()
                ) {
                  val navController = rememberNavController()
                  NavHost(
                      navController = navController,
                      startDestination = "pokemon_list_page"
                  ) {
                      composable("pokemon_list_page") {
                          PokemonListPage(navController = navController)
                      }
                      composable(
                          "pokemon_detail_screen/{name}",
                          arguments = listOf(
                              navArgument("name") {
                                  type = NavType.StringType
                              }
                          )
                      ) {
                          // The navBackStackEntry contains the arguments
                          val pokemonName = remember {
                              it.arguments?.getString("name")
                          }

                          PokemonDetailScreen(
                              pokemonName = pokemonName?.lowercase() ?: "",
                              navController = navController)
                      }
                  }
//                  val pokeListViewModel = viewModel<PokemonListViewModel>()
//                  PokemonListPage(pokeListViewModel)
              }
          }
        }
    }
}

This is still pretty new to me. Any Suggestions are definitely welcomed. Thanks.


Update I have created a Navigation Component, but i don't know where to pass the pokemonName String value in the Details Screen

*Here is a copy of the project, if you want to test some things out. https://drive.google.com/drive/folders/1gLH_Q3jYLhn-6ad0LMBeZHb8HyT8FszC?usp=sharing

android

kotlin

android-jetpack-compose

jetpack-compose-navigation

0 Answers

Your Answer

Accepted video resources