diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 38e3e75..f0098bf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -7,6 +7,7 @@ plugins { alias(libs.plugins.detekt) alias(libs.plugins.ksp) alias(libs.plugins.compose.compiler) + alias(libs.plugins.junit5) alias(libs.plugins.jetbrains.kotlin.serialization) } @@ -115,6 +116,7 @@ dependencies { testImplementation(libs.androidx.arch.core) androidTestImplementation(composeBom) + androidTestImplementation(libs.androidx.test.rules) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.arch.core) androidTestImplementation(libs.androidx.compose.ui.test) diff --git a/app/src/main/kotlin/de/entikore/composedex/data/remote/RemoteDataSource.kt b/app/src/main/kotlin/de/entikore/composedex/data/remote/RemoteDataSource.kt index b41d829..228d407 100644 --- a/app/src/main/kotlin/de/entikore/composedex/data/remote/RemoteDataSource.kt +++ b/app/src/main/kotlin/de/entikore/composedex/data/remote/RemoteDataSource.kt @@ -38,9 +38,9 @@ class RemoteDataSource( suspend fun getPokemonInfoRemoteBySpeciesName(name: String): ApiResponse = withContext(dispatcher) { return@withContext try { - val pokemonWithSpeciesAndTypesRemote = getSpeciesWithPokemonTypeAndVarieties(name) + val initialPokemonInfo = getSpeciesWithPokemonTypeAndVarieties(name) ApiResponse.success( - getPokemonInfoRemoteByName(pokemonWithSpeciesAndTypesRemote) + fetchAndProcessEvolutionChain(initialPokemonInfo) ) } catch (exception: RemoteDataSourceException) { ApiResponse.error( @@ -53,9 +53,9 @@ class RemoteDataSource( suspend fun getPokemonInfoRemoteByName(name: String): ApiResponse = withContext(dispatcher) { return@withContext try { - val pokemonWithSpeciesAndTypesRemote = getPokemonWithSpeciesAndType(name) + val initialPokemonInfo = getPokemonWithSpeciesAndType(name) ApiResponse.success( - getPokemonInfoRemoteByName(pokemonWithSpeciesAndTypesRemote) + fetchAndProcessEvolutionChain(initialPokemonInfo) ) } catch (exception: RemoteDataSourceException) { ApiResponse.error( @@ -68,9 +68,9 @@ class RemoteDataSource( suspend fun getPokemonInfoRemoteById(id: Int): ApiResponse = withContext(dispatcher) { return@withContext try { - val pokemonWithSpeciesAndTypesRemote = getPokemonWithSpeciesAndType(id) + val initialPokemonInfo = getPokemonWithSpeciesAndType(id) ApiResponse.success( - getPokemonInfoRemoteByName(pokemonWithSpeciesAndTypesRemote) + fetchAndProcessEvolutionChain(initialPokemonInfo) ) } catch (exception: RemoteDataSourceException) { ApiResponse.error(ERROR_POKEMON_ID_NOT_FOUND.format(id), exception) @@ -175,7 +175,7 @@ class RemoteDataSource( return PokemonInfoRemote(pokemon, species, types) } - private suspend fun getPokemonInfoRemoteByName( + private suspend fun fetchAndProcessEvolutionChain( pokemonWithSpeciesAndTypesRemote: PokemonInfoRemote ): PokemonInfoRemote { var chain: EvolutionChainRemote? = null @@ -186,7 +186,32 @@ class RemoteDataSource( ) }.getSuccessOrThrow() } - return pokemonWithSpeciesAndTypesRemote.copy(evolutionChain = processChain(chain = chain?.chain)) + return pokemonWithSpeciesAndTypesRemote.copy(evolutionChain = processEvolutionChain(chain = chain?.chain)) + } + + private fun processChain( + currentChainRemote: ChainRemote?, + currentRank: Int, + evolutionMap: MutableMap> + ) { + if (currentChainRemote == null) return + + val chainLink = ChainLink( + currentChainRemote.species.name, + getUrlPath(currentChainRemote.species.url), + currentChainRemote.isBaby + ) + evolutionMap.computeIfAbsent(currentRank) { mutableListOf() }.add(chainLink) + + for (nextEvolution in currentChainRemote.evolvesTo) { + processChain(nextEvolution, currentRank + 1, evolutionMap) + } + } + + private fun processEvolutionChain(chain: ChainRemote?): Map> { + val evolutionMap = mutableMapOf>() + processChain(chain, 0, evolutionMap) + return evolutionMap.mapValues { it.value.toList() } } companion object { @@ -197,22 +222,5 @@ class RemoteDataSource( const val ERROR_GENERATIONS = "Could not fetch generations" const val ERROR_GENERATION_NOT_FOUND = "Generation with name %s not found" const val ERROR_GENERATION_ID_NOT_FOUND = "Generation with id %s not found" - - private fun processChain( - map: Map> = mutableMapOf(), - chain: ChainRemote?, - rank: Int = 0 - ): Map> { - val chainList = map.toMutableMap() - if (chain == null) return chainList - val oldList = chainList[rank].orEmpty().toMutableList().apply { - add(ChainLink(chain.species.name, getUrlPath(chain.species.url), chain.isBaby)) - } - chainList[rank] = oldList - for (link in chain.evolvesTo) { - chainList.putAll(processChain(chainList, link, rank + 1)) - } - return chainList - } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9035556..6034a8b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ targetSdk = "36" minSdk = "24" # Dependency versions -androidGradlePlugin = "8.12.0" +androidGradlePlugin = "8.12.1" androidxComposeBom = "2025.08.00" androidxTest = "1.7.0" androidxTestRunner = "1.7.0" @@ -78,6 +78,7 @@ retrofit-converter-moshi = { group = "com.squareup.retrofit2", name = "converter timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } # Development Environment Dependencies +androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTest" } androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-arch-core = { group = "androidx.arch.core", name = "core-testing", version.ref = "archTesting" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55..8bdaf60 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68..2a84e18 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..ef07e01 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.