migrate to multidatabase structure and clean up code

This commit is contained in:
Carlos Martinez
2020-02-13 12:40:28 -03:00
parent e3900ca9db
commit e61c123068
43 changed files with 219 additions and 190 deletions

View File

@@ -1,9 +1,9 @@
package com.hako.userlist.feature
import com.hako.base.domain.database.dao.UserDao
import com.hako.base.domain.database.entities.UserEntity
import com.hako.userlist.domain.datasource.UserDao
import com.hako.userlist.domain.datasource.UserlistRemoteApi
import com.hako.userlist.model.User
import com.hako.userlist.model.UserEntity
import com.hako.userlist.model.UserRemote
import io.reactivex.Single
class MockUserDao(private val userList: List<UserEntity>) : UserDao {
@@ -22,8 +22,8 @@ class MockUserDao(private val userList: List<UserEntity>) : UserDao {
override fun nukeDatabase() {}
}
class MockUserApi(private val userList: List<User>) : UserlistRemoteApi {
class MockUserApi(private val userRemoteList: List<UserRemote>) : UserlistRemoteApi {
override fun getUsers() = Single.fromCallable { getAllUsers() }
private fun getAllUsers() = userList
private fun getAllUsers() = userRemoteList
}

View File

@@ -2,14 +2,14 @@ package com.hako.userlist.feature
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.test.platform.app.InstrumentationRegistry
import com.hako.base.domain.database.dao.UserDao
import com.hako.base.domain.database.entities.UserEntity
import com.hako.testing.isTextDisplayed
import com.hako.userlist.domain.datasource.UserDao
import com.hako.userlist.domain.datasource.UserlistRemoteApi
import com.hako.userlist.domain.usecase.GetFavoriteUsers
import com.hako.userlist.domain.usecase.GetUsers
import com.hako.userlist.domain.usecase.SetFavoriteStatus
import com.hako.userlist.model.User
import com.hako.userlist.model.UserEntity
import com.hako.userlist.model.UserRemote
import com.hako.userlist.model.toUserEntity
import com.hako.userlist.viewmodel.UserlistViewmodel
import org.junit.After
@@ -28,7 +28,7 @@ class UserlistFragmentTest {
startKoin {
InstrumentationRegistry.getInstrumentation().targetContext
modules(module {
factory { GetUsers(get()) }
factory { GetUsers(get(), get()) }
factory { GetFavoriteUsers(get()) }
factory { SetFavoriteStatus(get()) }
viewModel { UserlistViewmodel() }
@@ -92,7 +92,7 @@ class UserlistRobot {
}
private fun loadTwoBasicUsers() = listOf(
User(
UserRemote(
1,
"Marian Arriaga",
"mariancita",
@@ -100,7 +100,7 @@ class UserlistRobot {
"+56873912",
"www.test.com"
),
User(
UserRemote(
2,
"Carlos Martinez",
"carlitos",

View File

@@ -1,2 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hako.friendlist_userlist" />
package="com.hako.userlist" />

View File

@@ -1,6 +1,9 @@
package com.hako.userlist.di
import androidx.room.Room
import com.hako.base.domain.network.RemoteClient
import com.hako.userlist.BuildConfig
import com.hako.userlist.domain.clients.LocalClient
import com.hako.userlist.domain.datasource.UserlistRemoteApi
import com.hako.userlist.domain.usecase.GetFavoriteUsers
import com.hako.userlist.domain.usecase.GetUsers
@@ -10,8 +13,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
val userlistModules = module {
single { Room.databaseBuilder(get(), LocalClient::class.java, BuildConfig.DB_NAME).build() }
factory { get<LocalClient>().userDao() }
factory { get<RemoteClient>().getClient(UserlistRemoteApi::class.java) }
factory { GetUsers(get()) }
factory { GetUsers(get(), get()) }
factory { GetFavoriteUsers(get()) }
factory { SetFavoriteStatus(get()) }

View File

@@ -0,0 +1,11 @@
package com.hako.userlist.domain.clients
import androidx.room.Database
import androidx.room.RoomDatabase
import com.hako.userlist.domain.datasource.UserDao
import com.hako.userlist.model.UserEntity
@Database(entities = [UserEntity::class], version = 1, exportSchema = false)
abstract class LocalClient : RoomDatabase() {
abstract fun userDao(): UserDao
}

View File

@@ -0,0 +1,33 @@
package com.hako.userlist.domain.datasource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.hako.userlist.model.UserEntity
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun save(entity: UserEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveAll(entities: List<UserEntity>)
@Query("UPDATE ${UserEntity.TABLE_NAME} SET isFavorite = :favorite WHERE id = :id")
fun saveFavorite(id: Int, favorite: Boolean): Int
@Query("SELECT * FROM ${UserEntity.TABLE_NAME} ORDER BY id ASC")
fun getAllUsers(): List<UserEntity>
@Query("SELECT * FROM ${UserEntity.TABLE_NAME} WHERE isFavorite = 1 ORDER BY id ASC")
fun getFavoriteUsers(): List<UserEntity>
@Query("SELECT COUNT(*) FROM ${UserEntity.TABLE_NAME}")
fun count(): Int
@Query("DELETE FROM ${UserEntity.TABLE_NAME}")
fun nukeDatabase()
}

View File

@@ -1,11 +1,11 @@
package com.hako.userlist.domain.datasource
import com.hako.userlist.model.User
import com.hako.userlist.model.UserRemote
import io.reactivex.Single
import retrofit2.http.GET
interface UserlistRemoteApi {
@GET("/users")
fun getUsers(): Single<List<User>>
fun getUsers(): Single<List<UserRemote>>
}

View File

@@ -1,7 +1,7 @@
package com.hako.userlist.domain.usecase
import com.hako.base.domain.database.dao.UserDao
import com.hako.userlist.model.UserViewable
import com.hako.userlist.domain.datasource.UserDao
import com.hako.userlist.model.User
import com.hako.userlist.model.toUserViewable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
@@ -9,7 +9,7 @@ import io.reactivex.schedulers.Schedulers
class GetFavoriteUsers(private val dao: UserDao) {
fun execute(
onSuccess: (List<UserViewable>) -> Unit,
onSuccess: (List<User>) -> Unit,
onEmpty: () -> Unit,
onError: (Throwable) -> Unit
) {

View File

@@ -1,21 +1,17 @@
package com.hako.userlist.domain.usecase
import com.hako.base.domain.database.dao.UserDao
import com.hako.userlist.domain.datasource.UserDao
import com.hako.userlist.domain.datasource.UserlistRemoteApi
import com.hako.userlist.model.UserViewable
import com.hako.userlist.model.User
import com.hako.userlist.model.toUserEntity
import com.hako.userlist.model.toUserViewable
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import org.koin.core.KoinComponent
import org.koin.core.get
class GetUsers(private val dao: UserDao) : KoinComponent {
private val api: UserlistRemoteApi = get()
class GetUsers(private val dao: UserDao, private val api: UserlistRemoteApi) {
fun execute(
onSuccess: (List<UserViewable>) -> Unit,
onSuccess: (List<User>) -> Unit,
onError: (Throwable) -> Unit,
onLoading: () -> Unit,
onEmpty: () -> Unit

View File

@@ -1,6 +1,6 @@
package com.hako.userlist.domain.usecase
import com.hako.base.domain.database.dao.UserDao
import com.hako.userlist.domain.datasource.UserDao
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers

View File

@@ -12,10 +12,10 @@ import com.hako.base.extensions.observeNonNull
import com.hako.base.extensions.visible
import com.hako.base.navigation.NavigationRouter
import com.hako.base.navigation.ShowFabButton
import com.hako.userlist.model.UserViewable
import com.hako.userlist.model.User
import com.hako.userlist.viewmodel.UserlistViewmodel
import com.hako.userlist.widget.UserlistAdapter
import com.hako.friendlist_userlist.R
import com.hako.userlist.R
import com.hako.userlist.navigation.UserlistNavigation
import kotlinx.android.synthetic.main.fragment_userlist.*
import org.koin.android.ext.android.inject
@@ -88,7 +88,7 @@ open class UserlistFragment : Fragment(), ShowFabButton {
Timber.e(throwable)
}
private fun handleFetchSuccess(users: List<UserViewable>) {
private fun handleFetchSuccess(users: List<User>) {
listAdapter.addAll(users)
}

View File

@@ -1,12 +1,14 @@
package com.hako.userlist.model
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import com.hako.base.domain.database.entities.UserEntity
import kotlinx.android.parcel.Parcelize
@Parcelize
data class User(
data class UserRemote(
@SerializedName("id") val id: Int,
@SerializedName("name") val realName: String,
@SerializedName("username") val userName: String,
@@ -15,14 +17,30 @@ data class User(
@SerializedName("website") val website: String
) : Parcelable
data class UserViewable(
@Entity(tableName = UserEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)])
data class UserEntity(
@PrimaryKey
val id: Int,
val realName: String,
val userName: String,
val email: String,
val phone: String,
val website: String,
val isFavorite: Boolean = false
) {
companion object {
const val TABLE_NAME = "users"
}
}
data class User(
val id: Int,
val realName: String,
val userName: String,
var isFavorite: Boolean
)
fun User.toUserEntity() = UserEntity(this.id, this.realName, this.userName, this.email, this.phone, this.website)
fun UserRemote.toUserEntity() = UserEntity(this.id, this.realName, this.userName, this.email, this.phone, this.website)
fun UserEntity.toUserViewable() = UserViewable(this.id, this.realName, this.userName, this.isFavorite)
fun UserEntity.toUserViewable() = User(this.id, this.realName, this.userName, this.isFavorite)

View File

@@ -8,13 +8,13 @@ import com.hako.base.domain.network.RequestStatus.*
import com.hako.userlist.domain.usecase.GetFavoriteUsers
import com.hako.userlist.domain.usecase.GetUsers
import com.hako.userlist.domain.usecase.SetFavoriteStatus
import com.hako.userlist.model.UserViewable
import com.hako.userlist.model.User
import org.koin.core.KoinComponent
import org.koin.core.get
class UserlistViewmodel : ViewModel(), KoinComponent {
val userList = MutableLiveData<Either<Throwable, List<UserViewable>>>()
val userList = MutableLiveData<Either<Throwable, List<User>>>()
val favoriteError = MutableLiveData<Int>()
val emptyMessage = MutableLiveData<String>()
val requestStatus = MutableLiveData<RequestStatus>()

View File

@@ -5,20 +5,20 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.hako.base.extensions.autoNotify
import com.hako.userlist.model.UserViewable
import com.hako.friendlist_userlist.R
import com.hako.userlist.model.User
import com.hako.userlist.R
import kotlinx.android.synthetic.main.item_user_card.view.*
import kotlin.properties.Delegates
class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var items by Delegates.observable(emptyList<UserViewable>()) { _, oldList, newList ->
private var items by Delegates.observable(emptyList<User>()) { _, oldList, newList ->
autoNotify(oldList, newList) { old, new -> old.id == new.id }
notifyDataSetChanged()
}
var onItemClick: (UserViewable) -> Unit = { }
var onFavoriteClick: (UserViewable) -> Unit = { }
var onItemClick: (User) -> Unit = { }
var onFavoriteClick: (User) -> Unit = { }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
UserViewHolder(
@@ -31,7 +31,7 @@ class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
fun getItem(position: Int) = items[position]
fun addAll(list: List<UserViewable>) {
fun addAll(list: List<User>) {
items = list
}
@@ -46,12 +46,12 @@ class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class UserViewHolder(
private val view: View,
private val onItemClick: (UserViewable) -> Unit,
private val onFavoriteClick: (UserViewable) -> Unit
private val onItemClick: (User) -> Unit,
private val onFavoriteClick: (User) -> Unit
) :
RecyclerView.ViewHolder(view) {
fun bind(user: UserViewable) = with(view) {
fun bind(user: User) = with(view) {
item_user_card_real_name.text = user.realName
item_user_card_user_name.text = user.userName
if (user.isFavorite) {