Start implementing search
This commit is contained in:
parent
e5a8586560
commit
72fe8363b8
4 changed files with 1096 additions and 10 deletions
|
|
@ -7,13 +7,23 @@ import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextField
|
||||||
|
import androidx.compose.material.TextFieldColors
|
||||||
import androidx.compose.runtime.Composable
|
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.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.geometry.CornerRadius
|
import androidx.compose.ui.geometry.CornerRadius
|
||||||
|
|
@ -28,8 +38,12 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import io.kamel.image.KamelImage
|
import io.kamel.image.KamelImage
|
||||||
import io.kamel.image.asyncPainterResource
|
import io.kamel.image.asyncPainterResource
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.jetbrains.compose.resources.ExperimentalResourceApi
|
import org.jetbrains.compose.resources.ExperimentalResourceApi
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class HomeScreen: Screen {
|
class HomeScreen: Screen {
|
||||||
|
|
||||||
|
|
@ -38,6 +52,8 @@ class HomeScreen: Screen {
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val orange = Color(0xFFffa500)
|
val orange = Color(0xFFffa500)
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
Box(modifier = Modifier.background(color = orange).fillMaxSize()) {
|
Box(modifier = Modifier.background(color = orange).fillMaxSize()) {
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = GridCells.Adaptive(minSize = 256.dp),
|
columns = GridCells.Adaptive(minSize = 256.dp),
|
||||||
|
|
@ -88,6 +104,20 @@ class HomeScreen: Screen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
value = searchQuery,
|
||||||
|
onValueChange = { newName -> searchQuery = newName;
|
||||||
|
if (PokemonNames.names.contains(searchQuery.lowercase(Locale.getDefault()))) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val newMap = loadPokemonDataFromName(searchQuery);
|
||||||
|
newMap?.let { pokemap.clear(); pokemap.addAll(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.background(color = Color.White),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
1025
composeApp/src/commonMain/composeResources/files/pokemon-names.txt
Normal file
1025
composeApp/src/commonMain/composeResources/files/pokemon-names.txt
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -37,6 +37,7 @@ import java.util.Locale
|
||||||
|
|
||||||
var pokemap = ArrayList<Pokemon>()
|
var pokemap = ArrayList<Pokemon>()
|
||||||
val apiString = "https://pokeapi.co/api/v2/pokemon/"
|
val apiString = "https://pokeapi.co/api/v2/pokemon/"
|
||||||
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
@OptIn(ExperimentalResourceApi::class)
|
||||||
val pokemonTypeDrawableMap = hashMapOf(
|
val pokemonTypeDrawableMap = hashMapOf(
|
||||||
"normal" to Res.drawable.normal,
|
"normal" to Res.drawable.normal,
|
||||||
|
|
@ -59,7 +60,6 @@ val pokemonTypeDrawableMap = hashMapOf(
|
||||||
"fairy" to Res.drawable.fairy
|
"fairy" to Res.drawable.fairy
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
@Preview
|
@Preview
|
||||||
fun App() {
|
fun App() {
|
||||||
|
|
@ -67,14 +67,14 @@ fun App() {
|
||||||
|
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
if (!dataLoaded) {
|
if (!dataLoaded) {
|
||||||
Navigator(screen = LoadingScreen()) {
|
Navigator(screen = LoadingScreen()) { navigator ->
|
||||||
navigator -> FadeTransition(navigator)
|
FadeTransition(navigator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load data asynchronously
|
// Load data asynchronously
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
pokemap = withContext(Dispatchers.IO) {
|
pokemap = withContext(Dispatchers.IO) {
|
||||||
loadPokemonData(apiString, 1, 10)
|
loadPokemonData(1, 10)
|
||||||
} as ArrayList<Pokemon>
|
} as ArrayList<Pokemon>
|
||||||
|
|
||||||
pokemap.forEach { pokemon ->
|
pokemap.forEach { pokemon ->
|
||||||
|
|
@ -87,25 +87,26 @@ fun App() {
|
||||||
} else {
|
} else {
|
||||||
println("Pokemon should show up any second!")
|
println("Pokemon should show up any second!")
|
||||||
//Display Pokemon Grid
|
//Display Pokemon Grid
|
||||||
Navigator(screen = HomeScreen()) {
|
Navigator(screen = HomeScreen()) { navigator ->
|
||||||
navigator -> SlideTransition(navigator)
|
SlideTransition(navigator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to load Pokemon data asynchronously, leave suspend even if IDE complains
|
// Function to load Pokemon data asynchronously, leave suspend even if IDE complains
|
||||||
suspend fun loadPokemonData(apiString: String, startId: Int, endId: Int): List<Pokemon> {
|
suspend fun loadPokemonData(startId: Int, endId: Int): List<Pokemon> {
|
||||||
val pokemap = ArrayList<Pokemon>()
|
val pokemap = ArrayList<Pokemon>()
|
||||||
for (i in startId..endId) {
|
for (i in startId..endId) {
|
||||||
val json = JSONObject(URL(apiString + i).readText());
|
val json = JSONObject(URL(apiString + i).readText());
|
||||||
val sprites = json.optJSONObject("sprites")
|
val sprites = json.optJSONObject("sprites")
|
||||||
val type: String = json.getJSONArray("types").optJSONObject(0).optJSONObject("type").optString("name")
|
val type: String =
|
||||||
|
json.getJSONArray("types").optJSONObject(0).optJSONObject("type")?.optString("name") ?: "null"
|
||||||
val name: String = json.optString("name")
|
val name: String = json.optString("name")
|
||||||
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
|
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
|
||||||
|
|
||||||
val pokemon = Pokemon(
|
val pokemon = Pokemon(
|
||||||
name, URL(sprites.optString("front_default")), type, json.optInt("id")
|
name, URL(sprites?.optString("front_default") ?: "null"), type, json.optInt("id")
|
||||||
)
|
)
|
||||||
|
|
||||||
pokemap.add(pokemon)
|
pokemap.add(pokemon)
|
||||||
|
|
@ -113,6 +114,31 @@ suspend fun loadPokemonData(apiString: String, startId: Int, endId: Int): List<P
|
||||||
return pokemap
|
return pokemap
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPokeMap(): ArrayList<Pokemon> {
|
suspend fun loadPokemonDataFromName(name: String): ArrayList<Pokemon>? {
|
||||||
|
if (name.equals("")) return null
|
||||||
|
var json: JSONObject = JSONObject("{}")
|
||||||
|
try {
|
||||||
|
json = JSONObject(URL(apiString + name).readText());
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val sprites = json.optJSONObject("sprites")
|
||||||
|
val type: String =
|
||||||
|
json.getJSONArray("types").optJSONObject(0).optJSONObject("type")?.optString("name") ?: "null"
|
||||||
|
val name: String = json.optString("name")
|
||||||
|
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
|
||||||
|
|
||||||
|
val pokemon = Pokemon(
|
||||||
|
name, URL(sprites?.optString("front_default") ?: "null"), type, json.optInt("id")
|
||||||
|
)
|
||||||
|
|
||||||
|
val pokemap = ArrayList<Pokemon>()
|
||||||
|
|
||||||
|
pokemap.add(pokemon)
|
||||||
|
|
||||||
return pokemap
|
return pokemap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPokeMap(): ArrayList<Pokemon> {
|
||||||
|
return pokemap
|
||||||
|
}
|
||||||
5
composeApp/src/commonMain/kotlin/PokemonNames.kt
Normal file
5
composeApp/src/commonMain/kotlin/PokemonNames.kt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
object PokemonNames {
|
||||||
|
val names: ArrayList<String> = arrayListOf(
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue