Skip to content

Commit c490b0c

Browse files
authored
revamp demo app with sprites and viewmodel (#143)
1 parent 3c71fcf commit c490b0c

File tree

13 files changed

+347
-146
lines changed

13 files changed

+347
-146
lines changed

demo-app/build.gradle.kts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ android {
2424

2525
defaultConfig {
2626
applicationId = "co.pokeapi.pokekotlin.demoapp"
27-
minSdk = 24
28-
compileSdk = 35
29-
targetSdk = 35
27+
minSdk = 30
28+
compileSdk = 36
29+
targetSdk = 36
3030
versionCode = 1
3131
versionName = project.version.toString()
3232
}
@@ -74,36 +74,44 @@ kotlin {
7474

7575
all { languageSettings { optIn("androidx.compose.material3.ExperimentalMaterial3Api") } }
7676

77-
commonMain.dependencies {
78-
implementation(compose.components.resources)
79-
implementation(compose.foundation)
80-
implementation(compose.material3)
81-
implementation(compose.runtime)
82-
implementation(compose.ui)
83-
implementation(libs.androidx.navigation.compose)
84-
implementation(projects.pokekotlin)
77+
commonMain {
78+
dependencies {
79+
implementation(compose.components.resources)
80+
implementation(compose.foundation)
81+
implementation(compose.material3)
82+
implementation(compose.material3AdaptiveNavigationSuite)
83+
implementation(compose.runtime)
84+
implementation(compose.ui)
85+
86+
implementation(libs.androidx.navigation.compose)
87+
implementation(libs.androidx.lifecycle.viewmodel.compose)
88+
implementation(libs.coil.compose)
89+
implementation(libs.coil.network.ktor3)
90+
91+
implementation(project.dependencies.platform(libs.koin.bom))
92+
implementation(libs.koin.core)
93+
implementation(libs.koin.compose)
94+
implementation(libs.koin.composeViewmodel)
95+
implementation(libs.koin.composeViewmodelNavigation)
96+
97+
implementation(projects.pokekotlin)
98+
}
8599
}
86100

87101
androidMain {
88102
dependencies {
89103
implementation(libs.androidx.activity.compose)
90104
implementation(libs.kotlinx.coroutines.android)
105+
implementation(libs.koin.android)
91106
}
92107
}
93108

94-
val nonAndroidMain by creating { dependsOn(commonMain.get()) }
95-
96109
desktopMain.apply {
97-
dependsOn(nonAndroidMain)
98110
dependencies {
99111
implementation(compose.desktop.currentOs)
100112
implementation(libs.kotlinx.coroutines.swing)
101113
}
102114
}
103-
104-
appleMain { dependsOn(nonAndroidMain) }
105-
jsMain { dependsOn(nonAndroidMain) }
106-
wasmJsMain { dependsOn(nonAndroidMain) }
107115
}
108116
}
109117

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
package co.pokeapi.pokekotlin.demoapp
22

3-
import android.os.Build
43
import android.os.Bundle
54
import androidx.activity.ComponentActivity
65
import androidx.activity.compose.setContent
76
import androidx.activity.enableEdgeToEdge
8-
import androidx.compose.material3.ColorScheme
9-
import androidx.compose.material3.darkColorScheme
10-
import androidx.compose.material3.dynamicDarkColorScheme
11-
import androidx.compose.material3.dynamicLightColorScheme
12-
import androidx.compose.material3.lightColorScheme
13-
import androidx.compose.runtime.Composable
14-
import androidx.compose.ui.platform.LocalContext
157

168
class MainActivity : ComponentActivity() {
179
override fun onCreate(savedInstanceState: Bundle?) {
@@ -20,14 +12,3 @@ class MainActivity : ComponentActivity() {
2012
setContent { DemoApp() }
2113
}
2214
}
23-
24-
@Composable
25-
actual fun getDefaultColorScheme(isDark: Boolean): ColorScheme {
26-
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
27-
return when {
28-
dynamicColor && isDark -> dynamicDarkColorScheme(LocalContext.current)
29-
dynamicColor && !isDark -> dynamicLightColorScheme(LocalContext.current)
30-
isDark -> darkColorScheme()
31-
else -> lightColorScheme()
32-
}
33-
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package co.pokeapi.pokekotlin.demoapp.util
2+
3+
import kotlinx.coroutines.Dispatchers
4+
5+
actual val ioDispatcher = Dispatchers.IO
Lines changed: 21 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,30 @@
11
package co.pokeapi.pokekotlin.demoapp
22

3-
import androidx.compose.foundation.clickable
4-
import androidx.compose.foundation.layout.*
5-
import androidx.compose.foundation.lazy.LazyColumn
6-
import androidx.compose.foundation.lazy.items
7-
import androidx.compose.material3.*
8-
import androidx.compose.runtime.*
9-
import androidx.compose.ui.Alignment
10-
import androidx.compose.ui.Modifier
11-
import androidx.compose.ui.text.style.TextOverflow
3+
import androidx.compose.foundation.isSystemInDarkTheme
4+
import androidx.compose.material3.MaterialTheme
5+
import androidx.compose.material3.darkColorScheme
6+
import androidx.compose.material3.lightColorScheme
7+
import androidx.compose.runtime.Composable
128
import co.pokeapi.pokekotlin.PokeApi
13-
import co.pokeapi.pokekotlin.model.NamedApiResource
14-
import co.pokeapi.pokekotlin.model.NamedApiResourceList
15-
import co.pokeapi.pokekotlin.model.PokemonSpecies
16-
17-
@Composable
18-
fun PokemonListItem(pokemon: PokemonSpecies) {
19-
ListItem(
20-
modifier = Modifier.clickable(onClick = {}),
21-
headlineContent = { Text(pokemon.names.first { it.language.name == "en" }.name) },
22-
supportingContent = {
23-
Text(
24-
pokemon.flavorTextEntries
25-
.filter { it.language.name == "en" }
26-
.maxBy { it.version.id }
27-
.flavorText
28-
.replace(Regex("\\s"), " "),
29-
maxLines = 2,
30-
overflow = TextOverflow.Ellipsis,
31-
)
32-
},
33-
)
34-
}
35-
36-
@Composable
37-
fun PokemonListItemPlaceholder(summary: NamedApiResource) {
38-
ListItem(headlineContent = { Text("Loading: ${summary.name}") })
39-
}
40-
41-
@Composable
42-
fun PokemonListItemError(summary: NamedApiResource, message: String) {
43-
ListItem(
44-
headlineContent = { Text("Failed to load: ${summary.name}") },
45-
supportingContent = { Text(message) },
46-
)
47-
}
48-
49-
@Composable
50-
fun PokemonList(padding: PaddingValues, pokemon: NamedApiResourceList) {
51-
Box(Modifier.consumeWindowInsets(padding).fillMaxSize()) {
52-
LazyColumn(contentPadding = padding) {
53-
items(pokemon.results) { summary ->
54-
var result by remember { mutableStateOf<Result<PokemonSpecies>?>(null) }
55-
LaunchedEffect(Unit) { result = runCatching { PokeApi.getPokemonSpecies(summary.id) } }
56-
result
57-
?.onSuccess { PokemonListItem(it) }
58-
?.onFailure { PokemonListItemError(summary, it.message ?: "Unknown error") }
59-
?: PokemonListItemPlaceholder(summary)
60-
}
61-
}
62-
}
63-
}
64-
65-
@Composable
66-
fun CenteredLoading(padding: PaddingValues) {
67-
Box(
68-
Modifier.consumeWindowInsets(padding).padding(padding).fillMaxSize(),
69-
contentAlignment = Alignment.Center,
70-
) {
71-
CircularProgressIndicator()
72-
}
73-
}
74-
75-
@Composable
76-
fun ErrorMessage(padding: PaddingValues, message: String) {
77-
Box(
78-
Modifier.consumeWindowInsets(padding).padding(padding).fillMaxSize(),
79-
contentAlignment = Alignment.Center,
80-
) {
81-
Text(message)
82-
}
9+
import co.pokeapi.pokekotlin.demoapp.screens.PokemonListScreen
10+
import co.pokeapi.pokekotlin.demoapp.screens.PokemonListScreenViewModel
11+
import org.koin.compose.KoinApplication
12+
import org.koin.core.module.dsl.viewModel
13+
import org.koin.dsl.module
14+
15+
private val appModule = module {
16+
single<PokeApi> { PokeApi.Default }
17+
viewModel { PokemonListScreenViewModel(get()) }
8318
}
8419

8520
@Composable
8621
fun DemoApp() {
87-
MaterialTheme(colorScheme = getDefaultColorScheme()) {
88-
Scaffold(
89-
topBar = { TopAppBar(title = { Text("PokeKotlin Demo") }) },
90-
content = { innerPadding ->
91-
var result by remember { mutableStateOf<Result<NamedApiResourceList>?>(null) }
92-
LaunchedEffect(Unit) { result = runCatching { PokeApi.getPokemonSpeciesList(0, 100000) } }
93-
result
94-
?.onSuccess { PokemonList(innerPadding, it) }
95-
?.onFailure {
96-
ErrorMessage(
97-
padding = innerPadding,
98-
message = result!!.exceptionOrNull()!!.message ?: "Unknown error",
99-
)
100-
} ?: CenteredLoading(innerPadding)
101-
},
102-
)
22+
KoinApplication(application = { modules(appModule) }) {
23+
MaterialTheme(
24+
colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
25+
) {
26+
// TODO nav
27+
PokemonListScreen()
28+
}
10329
}
10430
}
105-
106-
@Composable expect fun getDefaultColorScheme(isDark: Boolean = false): ColorScheme

0 commit comments

Comments
 (0)