Skip to content

Commit

Permalink
improves clean architecture design (#14)
Browse files Browse the repository at this point in the history
* improves clean architecture design

* update: tests

* fix: unit tests

* fix: cicd

* fix: ci/cd

* update: ci order

* update: ci order

* update: ci order

* fix: ci/cd padding values
  • Loading branch information
AbrahamCardenesAcid authored Jan 12, 2023
1 parent fa10e8c commit 1e05372
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 46 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ jobs:
with:
distribution: 'zulu'
java-version: 11
- name: run lint and unitTest
run: ./gradlew lintDebug testDebugUnitTest
- name: run instrumented tests
uses: reactivecircus/[email protected]
with:
api-level: 31
arch: x86_64
script: ./gradlew connectedCheck
- name: run lint and unitTest
run: ./gradlew lintDebug testDebugUnitTest
47 changes: 25 additions & 22 deletions app/src/main/java/com/example/boilerplatecompose/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberScaffoldState
import androidx.compose.ui.Modifier
Expand All @@ -29,31 +30,33 @@ class MainActivity : ComponentActivity() {
val navController = rememberNavController()
Scaffold(
modifier = Modifier.fillMaxSize(),
scaffoldState = rememberScaffoldState()
) {
NavHost(
navController = navController,
startDestination = Route.POKEMON_LIST
) {
composable(Route.POKEMON_LIST) {
PokemonsScreen(onCardClick = { position ->
navController.navigate(Route.DETAIL + "/$position")
})
}

composable(
Route.DETAIL + "/{position}",
arguments = listOf(
navArgument("position") {
type = NavType.IntType
}
)
scaffoldState = rememberScaffoldState(),
content = { padding ->
NavHost(
navController = navController,
startDestination = Route.POKEMON_LIST,
modifier = Modifier.padding(padding)
) {
val position = it.arguments?.getInt("position")!!
PokemonDetail(position = position)
composable(Route.POKEMON_LIST) {
PokemonsScreen(onCardClick = { position ->
navController.navigate(Route.DETAIL + "/$position")
})
}

composable(
Route.DETAIL + "/{position}",
arguments = listOf(
navArgument("position") {
type = NavType.IntType
}
)
) {
val position = it.arguments?.getInt("position")!!
PokemonDetail(position = position)
}
}
}
}
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ interface PokemonDao {
@Query("select * from pokemonentity limit :limit offset :offset")
suspend fun getPokemons(offset: Int, limit: Int): List<PokemonEntity>

@Query("select count(*) from pokemonentity")
suspend fun getCount(): Int

suspend fun insertOrUpdate(
pokemon: PokemonEntity
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ class PokemonLocalDataSource
suspend fun getPokemons(offset: Int, limit: Int): List<PokemonEntity> {
return pokemonDao.getPokemons(offset, limit)
}

suspend fun getCount(): Int {
return pokemonDao.getCount()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.example.pokemon_data.dataSource.local.PokemonLocalDataSource
import com.example.pokemon_data.dataSource.local.toDomain
import com.example.pokemon_data.dataSource.remote.PokemonNetworkDataSource
import com.example.pokemon_data.dataSource.remote.networkMappers.toEntity
import com.example.pokemon_domain.models.Pokemon
import com.example.pokemon_domain.models.Pokemons
import com.example.pokemon_domain.repository.PokemonRepository
import kotlinx.coroutines.flow.Flow
Expand All @@ -19,29 +20,41 @@ constructor(
) : PokemonRepository {
override suspend fun pokemons(offset: Int, limit: Int): Flow<Resource<Pokemons>> {
return flow {
try {
var count = 0
val response = network.getPokemons(offset, limit)

if (response is Resource.Success) {
count = response.data!!.count
response.data!!.pokemonsInfo.forEach { pokemon ->
local.insert(pokemon.toEntity())
}
}

val localPokemons = local.getPokemons(offset, limit)
// throw Exception("Forced exception")
val cachedPokemons = getLocalPokemons(offset, limit)

var count = local.getCount()
if (count == 0) count = 1000

val pokemons = localPokemons.map { pokemonEntity ->
pokemonEntity.toDomain()

val response = network.getPokemons(offset, limit)
if (response is Resource.Success) {
count = response.data!!.count
response.data!!.pokemonsInfo.forEach { pokemon ->
local.insert(pokemon.toEntity())
}
val pokemons = getLocalPokemons(offset, limit)

if (count == 0) count = 1000

emit(Resource.Success(Pokemons(count = count, pokemonsInfo = pokemons)))
} catch (e: Exception) {
emit(Resource.Error(e))
} else {
emit(Resource.Success(Pokemons(count = count, pokemonsInfo = cachedPokemons)))
emit(Resource.Error(response.exception!!))
}

}
}

private suspend fun getLocalPokemons(
offset: Int,
limit: Int
): List<Pokemon> {
val localPokemons = local.getPokemons(offset, limit)

return localPokemons.map { pokemonEntity ->
pokemonEntity.toDomain()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.pokemon_presentation.viewModels

import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand All @@ -9,6 +10,8 @@ import com.example.core.Resource
import com.example.pokemon_domain.models.Pokemons
import com.example.pokemon_domain.useCases.GetPokemonsUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand All @@ -27,14 +30,21 @@ class PokemonsViewModel @Inject constructor(

init {
viewModelScope.launch {
pokemonsUseCase().collect {
when (it) {
is Resource.Error -> TODO()
is Resource.Success -> {
state = it.data!!
pokemonsUseCase()
.onStart {
// Load state for example
}
.catch { exception -> println(exception.stackTraceToString()) }
.collect {
when (it) {
is Resource.Error -> {
Log.d("ErrorRepository", it.exception!!.stackTraceToString())
}
is Resource.Success -> {
state = it.data!!
}
}
}
}
}
}

Expand All @@ -47,7 +57,10 @@ class PokemonsViewModel @Inject constructor(
pokemonsUseCase.nextPage(offset = state.pokemonsInfo.size, limit = limit)
.collect {
when (it) {
is Resource.Error -> TODO()
is Resource.Error -> Log.d(
"ErrorRepository",
it.exception!!.stackTraceToString()
)
is Resource.Success -> {
val originalList = state.pokemonsInfo
val newList = it.data!!.pokemonsInfo
Expand Down

0 comments on commit 1e05372

Please sign in to comment.