From f7bd5019218e6d77fc86f1388531a60c41f857fd Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 16:30:09 +0200 Subject: [PATCH 1/8] Instaid of getting the species, get the pokemon itself --- app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt index 3129be2..8087606 100644 --- a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt @@ -19,13 +19,13 @@ data class PokemonSpecies( @SerializedName("url") val url: String ) -data class PokemonSpeciesResponse( +data class PokemonResponse( @SerializedName("results") val results: List ) interface PokeApiService { - @GET("pokemon-species/?offset=0&limit=1025") - suspend fun getPokemonSpecies(): PokemonSpeciesResponse + @GET("pokemon/?offset=0&limit=1025") + suspend fun getPokemon(): PokemonResponse } class PokeSearchViewModel : ViewModel() { @@ -48,7 +48,7 @@ class PokeSearchViewModel : ViewModel() { private fun fetchPokemonSpecies() { viewModelScope.launch { try { - val response = service.getPokemonSpecies() + val response = service.getPokemon() _initialPokemonList.value = response.results _filteredPokemonList.value = listOf(PokemonSpecies("Please enter a search term", "")); } catch (e: IOException) { From e433bad681c74de80acc15448437d07aca36a9bb Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 16:47:03 +0200 Subject: [PATCH 2/8] Get details from api, instaid of displaying message just return empty list --- .../com/ti/mobpo/ui/PokeSearchViewModel.kt | 61 +++++++++++++++++-- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 2 +- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt index 8087606..f04ba50 100644 --- a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt @@ -6,10 +6,12 @@ import com.google.gson.annotations.SerializedName import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.forEach import kotlinx.coroutines.launch import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.GET +import retrofit2.http.Path import java.io.IOException private const val BASE_URL = "https://pokeapi.co/api/v2/"; @@ -23,9 +25,39 @@ data class PokemonResponse( @SerializedName("results") val results: List ) +data class PokemonDetails( + val id: Int, + val name: String, + val types: List, + @SerializedName("sprites") val sprites: Sprites +) + +data class Type( + @SerializedName("type") val typeName: TypeName +) + +data class TypeName( + @SerializedName("name") val name: String +) + +data class Sprites( + @SerializedName("other") val other: Other +) + +data class Other( + @SerializedName("official-artwork") val officialArtwork: OfficialArtwork +) + +data class OfficialArtwork( + @SerializedName("front_default") val frontDefault: String +) + interface PokeApiService { - @GET("pokemon/?offset=0&limit=1025") + @GET("pokemon/?offset=0&limit=2000") suspend fun getPokemon(): PokemonResponse + + @GET("pokemon/{id}") + suspend fun getPokemonDetails(@Path("id") id: Int): PokemonDetails } class PokeSearchViewModel : ViewModel() { @@ -38,6 +70,7 @@ class PokeSearchViewModel : ViewModel() { private val _initialPokemonList = MutableStateFlow?>(null) private val _filteredPokemonList = MutableStateFlow?>(null) + private val _pokemonDetails = MutableStateFlow?>(null) val pokemonList: StateFlow?> = _filteredPokemonList.asStateFlow() @@ -50,7 +83,6 @@ class PokeSearchViewModel : ViewModel() { try { val response = service.getPokemon() _initialPokemonList.value = response.results - _filteredPokemonList.value = listOf(PokemonSpecies("Please enter a search term", "")); } catch (e: IOException) { /*TODO*/ } @@ -62,8 +94,29 @@ class PokeSearchViewModel : ViewModel() { if (query.isNotBlank() && initialPokemonList != null) { val filteredList = initialPokemonList.filter { it.name.contains(query, ignoreCase = true) } _filteredPokemonList.value = filteredList.take(SHOW_LIMIT); - } else { - _filteredPokemonList.value = listOf(PokemonSpecies("Please enter a search term", "")); + fetchPokemonDetailsForFilteredPokemonList() } } + val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() + private fun fetchPokemonDetailsForFilteredPokemonList() { + val filteredPokemonList = _filteredPokemonList.value ?: return + + viewModelScope.launch { + try { + val detailsList = mutableListOf() + for (pokemonSpecies in filteredPokemonList) { + val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) + detailsList.add(details) + } + _pokemonDetails.value = detailsList + } catch (e: IOException) { + /* Handle error */ + } + } + } + + private fun extractPokemonId(url: String): Int { + val parts = url.split("/") + return parts[parts.size - 2].toInt() + } } \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index f7e3a02..c50fe64 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -27,7 +27,7 @@ fun PokeSearchScreen(pokeSearchViewModel: PokeSearchViewModel) { @Composable fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { - val searchResults by pokeSearchViewModel.pokemonList.collectAsState() + val searchResults by pokeSearchViewModel.pokemonDetails.collectAsState() Column( verticalArrangement = Arrangement.Top, From d82cedd526319a29b594b4e05a66de748b1c4c43 Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 17:08:56 +0200 Subject: [PATCH 3/8] Remove useless stuff --- .../main/java/com/ti/mobpo/data/PokeModels.kt | 39 ++++++++ .../com/ti/mobpo/ui/PokeSearchViewModel.kt | 89 ++----------------- 2 files changed, 47 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/com/ti/mobpo/data/PokeModels.kt diff --git a/app/src/main/java/com/ti/mobpo/data/PokeModels.kt b/app/src/main/java/com/ti/mobpo/data/PokeModels.kt new file mode 100644 index 0000000..e94bf81 --- /dev/null +++ b/app/src/main/java/com/ti/mobpo/data/PokeModels.kt @@ -0,0 +1,39 @@ +package com.ti.mobpo.data + +import com.google.gson.annotations.SerializedName + +data class PokemonSpecies( + @SerializedName("name") val name: String, + @SerializedName("url") val url: String +) + +data class PokemonResponse( + @SerializedName("results") val results: List +) + +data class PokemonDetails( + val id: Int, + val name: String, + val types: List, + @SerializedName("sprites") val sprites: Sprites +) + +data class Type( + @SerializedName("type") val typeName: TypeName +) + +data class TypeName( + @SerializedName("name") val name: String +) + +data class Sprites( + @SerializedName("other") val other: Other +) + +data class Other( + @SerializedName("official-artwork") val officialArtwork: OfficialArtwork +) + +data class OfficialArtwork( + @SerializedName("front_default") val frontDefault: String +) \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt index f04ba50..c4c42da 100644 --- a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt @@ -2,63 +2,17 @@ package com.ti.mobpo.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.google.gson.annotations.SerializedName +import com.ti.mobpo.data.PokemonDetails +import com.ti.mobpo.network.PokeApiService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.forEach import kotlinx.coroutines.launch import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.http.GET -import retrofit2.http.Path import java.io.IOException -private const val BASE_URL = "https://pokeapi.co/api/v2/"; -private const val SHOW_LIMIT = 20; -data class PokemonSpecies( - @SerializedName("name") val name: String, - @SerializedName("url") val url: String -) - -data class PokemonResponse( - @SerializedName("results") val results: List -) - -data class PokemonDetails( - val id: Int, - val name: String, - val types: List, - @SerializedName("sprites") val sprites: Sprites -) - -data class Type( - @SerializedName("type") val typeName: TypeName -) - -data class TypeName( - @SerializedName("name") val name: String -) - -data class Sprites( - @SerializedName("other") val other: Other -) - -data class Other( - @SerializedName("official-artwork") val officialArtwork: OfficialArtwork -) - -data class OfficialArtwork( - @SerializedName("front_default") val frontDefault: String -) - -interface PokeApiService { - @GET("pokemon/?offset=0&limit=2000") - suspend fun getPokemon(): PokemonResponse - - @GET("pokemon/{id}") - suspend fun getPokemonDetails(@Path("id") id: Int): PokemonDetails -} +private const val BASE_URL = "https://pokeapi.co/api/v2/" class PokeSearchViewModel : ViewModel() { private val retrofit = Retrofit.Builder() @@ -68,43 +22,16 @@ class PokeSearchViewModel : ViewModel() { private val service = retrofit.create(PokeApiService::class.java) - private val _initialPokemonList = MutableStateFlow?>(null) - private val _filteredPokemonList = MutableStateFlow?>(null) private val _pokemonDetails = MutableStateFlow?>(null) + val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() - val pokemonList: StateFlow?> = _filteredPokemonList.asStateFlow() - - init { - fetchPokemonSpecies() - } - - private fun fetchPokemonSpecies() { + fun search(query: String) { viewModelScope.launch { try { val response = service.getPokemon() - _initialPokemonList.value = response.results - } catch (e: IOException) { - /*TODO*/ - } - } - } - - fun search(query: String) { - val initialPokemonList = _initialPokemonList.value - if (query.isNotBlank() && initialPokemonList != null) { - val filteredList = initialPokemonList.filter { it.name.contains(query, ignoreCase = true) } - _filteredPokemonList.value = filteredList.take(SHOW_LIMIT); - fetchPokemonDetailsForFilteredPokemonList() - } - } - val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() - private fun fetchPokemonDetailsForFilteredPokemonList() { - val filteredPokemonList = _filteredPokemonList.value ?: return - - viewModelScope.launch { - try { + val filteredList = response.results.filter { it.name.contains(query, ignoreCase = true) } val detailsList = mutableListOf() - for (pokemonSpecies in filteredPokemonList) { + for (pokemonSpecies in filteredList) { val details = service.getPokemonDetails(extractPokemonId(pokemonSpecies.url)) detailsList.add(details) } @@ -119,4 +46,4 @@ class PokeSearchViewModel : ViewModel() { val parts = url.split("/") return parts[parts.size - 2].toInt() } -} \ No newline at end of file +} From e7d53f67b0d3cc82cd967b899e7b26333541b6cc Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 17:09:27 +0200 Subject: [PATCH 4/8] Remove useless stuff --- .../java/com/ti/mobpo/network/PokeApiService.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/java/com/ti/mobpo/network/PokeApiService.kt diff --git a/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt new file mode 100644 index 0000000..93fcc59 --- /dev/null +++ b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt @@ -0,0 +1,14 @@ +package com.ti.mobpo.network + +import com.ti.mobpo.data.PokemonDetails +import com.ti.mobpo.data.PokemonResponse +import retrofit2.http.GET +import retrofit2.http.Path + +interface PokeApiService { + @GET("pokemon/?offset=0&limit=2000") + suspend fun getPokemon(): PokemonResponse + + @GET("pokemon/{id}") + suspend fun getPokemonDetails(@Path("id") id: Int): PokemonDetails +} From 1f17e6066f30e29acc138a1f83bcbb9a0223ff11 Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 17:33:47 +0200 Subject: [PATCH 5/8] Fully move api according to dev.android.com basics --- .../java/com/ti/mobpo/network/PokeApiService.kt | 15 +++++++++++++++ .../java/com/ti/mobpo/ui/PokeSearchViewModel.kt | 10 +++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt index 93fcc59..a72b54e 100644 --- a/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt +++ b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt @@ -2,9 +2,18 @@ package com.ti.mobpo.network import com.ti.mobpo.data.PokemonDetails import com.ti.mobpo.data.PokemonResponse +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.GET import retrofit2.http.Path +private const val BASE_URL = "https://pokeapi.co/api/v2/" + +private val retrofit = Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + interface PokeApiService { @GET("pokemon/?offset=0&limit=2000") suspend fun getPokemon(): PokemonResponse @@ -12,3 +21,9 @@ interface PokeApiService { @GET("pokemon/{id}") suspend fun getPokemonDetails(@Path("id") id: Int): PokemonDetails } + +object PokeApi { + val retrofitService : PokeApiService by lazy { + retrofit.create(PokeApiService::class.java) + } +} diff --git a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt index c4c42da..b189d0c 100644 --- a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt @@ -3,6 +3,7 @@ package com.ti.mobpo.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ti.mobpo.data.PokemonDetails +import com.ti.mobpo.network.PokeApi import com.ti.mobpo.network.PokeApiService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -12,15 +13,10 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.io.IOException -private const val BASE_URL = "https://pokeapi.co/api/v2/" + class PokeSearchViewModel : ViewModel() { - private val retrofit = Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .build() - - private val service = retrofit.create(PokeApiService::class.java) + private val service = PokeApi.retrofitService; private val _pokemonDetails = MutableStateFlow?>(null) val pokemonDetails: StateFlow?> = _pokemonDetails.asStateFlow() From 3352417e12a459fcbc8d4cb89ba017aa44c77758 Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 17:38:29 +0200 Subject: [PATCH 6/8] Move folders --- app/src/main/java/com/ti/mobpo/{data => model}/PokeModels.kt | 2 +- app/src/main/java/com/ti/mobpo/network/PokeApiService.kt | 4 ++-- app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) rename app/src/main/java/com/ti/mobpo/{data => model}/PokeModels.kt (96%) diff --git a/app/src/main/java/com/ti/mobpo/data/PokeModels.kt b/app/src/main/java/com/ti/mobpo/model/PokeModels.kt similarity index 96% rename from app/src/main/java/com/ti/mobpo/data/PokeModels.kt rename to app/src/main/java/com/ti/mobpo/model/PokeModels.kt index e94bf81..81c8799 100644 --- a/app/src/main/java/com/ti/mobpo/data/PokeModels.kt +++ b/app/src/main/java/com/ti/mobpo/model/PokeModels.kt @@ -1,4 +1,4 @@ -package com.ti.mobpo.data +package com.ti.mobpo.model import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt index a72b54e..e5ecb3a 100644 --- a/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt +++ b/app/src/main/java/com/ti/mobpo/network/PokeApiService.kt @@ -1,7 +1,7 @@ package com.ti.mobpo.network -import com.ti.mobpo.data.PokemonDetails -import com.ti.mobpo.data.PokemonResponse +import com.ti.mobpo.model.PokemonDetails +import com.ti.mobpo.model.PokemonResponse import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.GET diff --git a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt index b189d0c..a36b747 100644 --- a/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt +++ b/app/src/main/java/com/ti/mobpo/ui/PokeSearchViewModel.kt @@ -2,15 +2,12 @@ package com.ti.mobpo.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.ti.mobpo.data.PokemonDetails +import com.ti.mobpo.model.PokemonDetails import com.ti.mobpo.network.PokeApi -import com.ti.mobpo.network.PokeApiService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory import java.io.IOException From 9ee9d5af0ec4e9ba56a834721dc4539d93b76000 Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 17:53:35 +0200 Subject: [PATCH 7/8] Display images --- app/build.gradle.kts | 5 +- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 53 ++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 360f9ab..796bb03 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,6 +66,7 @@ dependencies { debugImplementation(libs.androidx.ui.test.manifest) implementation("androidx.navigation:navigation-compose:$nav_version") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1") - implementation("com.squareup.retrofit2:retrofit:2.9.0") - implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("com.squareup.retrofit2:retrofit:2.11.0") + implementation("com.squareup.retrofit2:converter-gson:2.11.0") + implementation("io.coil-kt:coil-compose:2.6.0") } \ No newline at end of file diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index c50fe64..e43013c 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -1,24 +1,40 @@ package com.ti.mobpo.ui.screens +import androidx.compose.foundation.Image import com.ti.mobpo.ui.PokeSearchViewModel import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio 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.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text 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.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.ti.mobpo.R import com.ti.mobpo.ui.SearchBar import androidx.lifecycle.viewmodel.compose.viewModel +import com.ti.mobpo.model.PokemonDetails +import coil.compose.AsyncImage +import coil.request.ImageRequest +import com.ti.mobpo.ui.theme.MobileSecurityTheme @Composable fun PokeSearchScreen(pokeSearchViewModel: PokeSearchViewModel) { @@ -44,8 +60,12 @@ fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { searchResults?.let { results -> if (results.isNotEmpty()) { - results.forEach { pokemon -> - Text(text = pokemon.name) + LazyVerticalGrid( + columns = GridCells.Adaptive(150.dp), + ) { + items(items = results, key = { pokemon -> pokemon.id }) { pokemon -> + PokemonCard(pokemon) + } } } else { Text("No results found") @@ -54,9 +74,38 @@ fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { } } + +@Composable +fun PokemonCard(pokemon: PokemonDetails) { + Card( + shape = MaterialTheme.shapes.medium, + elevation = CardDefaults.cardElevation(defaultElevation = 8.dp), + modifier = Modifier + .padding(4.dp) + .fillMaxWidth() + .aspectRatio(1f) + ) { + AsyncImage( + model = ImageRequest.Builder(context = LocalContext.current).data(pokemon.sprites.other.officialArtwork.frontDefault) + .crossfade(true).build(), + contentDescription = pokemon.name, + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxWidth() + ) + } +} + + @Preview(showBackground = true) @Composable fun PokeSearchApp(){ val pokeSearchViewModel: PokeSearchViewModel = viewModel() PokeSearchScreen(pokeSearchViewModel) +} + +@Preview(showBackground = true) +@Composable +fun PhotosGridScreenPreview() { + MobileSecurityTheme { + } } \ No newline at end of file From 8419c74f5fae54ec374cf31410a58772f3f13f99 Mon Sep 17 00:00:00 2001 From: Joren Date: Mon, 29 Apr 2024 18:00:35 +0200 Subject: [PATCH 8/8] Add name of pokemon under its image --- .../com/ti/mobpo/ui/screens/PokeSearch.kt | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt index e43013c..cffe645 100644 --- a/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt +++ b/app/src/main/java/com/ti/mobpo/ui/screens/PokeSearch.kt @@ -10,6 +10,7 @@ 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.wrapContentSize import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -62,6 +63,7 @@ fun PokeSearch(pokeSearchViewModel: PokeSearchViewModel) { if (results.isNotEmpty()) { LazyVerticalGrid( columns = GridCells.Adaptive(150.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) ) { items(items = results, key = { pokemon -> pokemon.id }) { pokemon -> PokemonCard(pokemon) @@ -85,13 +87,28 @@ fun PokemonCard(pokemon: PokemonDetails) { .fillMaxWidth() .aspectRatio(1f) ) { - AsyncImage( - model = ImageRequest.Builder(context = LocalContext.current).data(pokemon.sprites.other.officialArtwork.frontDefault) - .crossfade(true).build(), - contentDescription = pokemon.name, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxWidth() - ) + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Bottom + ) { + AsyncImage( + model = ImageRequest.Builder(context = LocalContext.current).data(pokemon.sprites.other.officialArtwork.frontDefault) + .crossfade(true).build(), + contentDescription = pokemon.name, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) + Text( + text = pokemon.name.replace("-", " "), + style = MaterialTheme.typography.bodySmall, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp, vertical = 4.dp) // Adjust padding as needed + .wrapContentSize(Alignment.Center) + ) + } } }