mirror of
https://github.com/imcarlost/Friendlists.git
synced 2026-04-10 02:46:54 -04:00
migrate to multidatabase structure and clean up code
This commit is contained in:
@@ -1,8 +1,12 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply from: '../core.gradle'
|
apply from: '../core.gradle'
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultConfig {
|
||||||
|
buildConfigField "String", "DB_NAME", '"albumlist.db"'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':base')
|
implementation project(':base')
|
||||||
testImplementation project(':testing')
|
|
||||||
androidTestImplementation project(':testing')
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.hako.albumlist.di
|
package com.hako.albumlist.di
|
||||||
|
|
||||||
|
import androidx.room.Room
|
||||||
|
import com.hako.albumlist.BuildConfig
|
||||||
|
import com.hako.albumlist.domain.clients.LocalClient
|
||||||
import com.hako.albumlist.domain.datasource.AlbumlistRemoteApi
|
import com.hako.albumlist.domain.datasource.AlbumlistRemoteApi
|
||||||
import com.hako.albumlist.domain.usecase.GetAlbum
|
import com.hako.albumlist.domain.usecase.GetAlbum
|
||||||
import com.hako.albumlist.viewmodel.AlbumlistViewmodel
|
import com.hako.albumlist.viewmodel.AlbumlistViewmodel
|
||||||
@@ -8,8 +11,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val albumListModules = module {
|
val albumListModules = module {
|
||||||
|
|
||||||
|
single { Room.databaseBuilder(get(), LocalClient::class.java, BuildConfig.DB_NAME).build() }
|
||||||
|
factory { get<LocalClient>().albumDao() }
|
||||||
|
|
||||||
factory { get<RemoteClient>().getClient(AlbumlistRemoteApi::class.java) }
|
factory { get<RemoteClient>().getClient(AlbumlistRemoteApi::class.java) }
|
||||||
factory { GetAlbum(get()) }
|
factory { GetAlbum(get(), get()) }
|
||||||
|
|
||||||
viewModel { AlbumlistViewmodel() }
|
viewModel { AlbumlistViewmodel() }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.hako.albumlist.domain.clients
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import com.hako.albumlist.domain.datasource.AlbumDao
|
||||||
|
import com.hako.albumlist.model.AlbumEntity
|
||||||
|
|
||||||
|
@Database(entities = [AlbumEntity::class], version = 1, exportSchema = false)
|
||||||
|
abstract class LocalClient : RoomDatabase() {
|
||||||
|
abstract fun albumDao(): AlbumDao
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.hako.base.domain.database.dao
|
package com.hako.albumlist.domain.datasource
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import com.hako.base.domain.database.entities.AlbumEntity
|
import com.hako.albumlist.model.AlbumEntity
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface AlbumDao {
|
interface AlbumDao {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.hako.albumlist.domain.datasource
|
package com.hako.albumlist.domain.datasource
|
||||||
|
|
||||||
import com.hako.albumlist.model.Album
|
import com.hako.albumlist.model.AlbumRemote
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
@@ -10,5 +10,5 @@ interface AlbumlistRemoteApi {
|
|||||||
@GET("/albums")
|
@GET("/albums")
|
||||||
fun getAlbums(
|
fun getAlbums(
|
||||||
@Query("userId") userId: Int
|
@Query("userId") userId: Int
|
||||||
): Single<List<Album>>
|
): Single<List<AlbumRemote>>
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,18 @@
|
|||||||
package com.hako.albumlist.domain.usecase
|
package com.hako.albumlist.domain.usecase
|
||||||
|
|
||||||
|
import com.hako.albumlist.domain.datasource.AlbumDao
|
||||||
import com.hako.albumlist.domain.datasource.AlbumlistRemoteApi
|
import com.hako.albumlist.domain.datasource.AlbumlistRemoteApi
|
||||||
import com.hako.albumlist.model.AlbumViewable
|
import com.hako.albumlist.model.Album
|
||||||
import com.hako.albumlist.model.toAlbumEntity
|
import com.hako.albumlist.model.toAlbumEntity
|
||||||
import com.hako.albumlist.model.toAlbumViewable
|
import com.hako.albumlist.model.toAlbumViewable
|
||||||
import com.hako.base.domain.database.dao.AlbumDao
|
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.koin.core.KoinComponent
|
|
||||||
import org.koin.core.get
|
|
||||||
|
|
||||||
class GetAlbum(private val dao: AlbumDao) : KoinComponent {
|
class GetAlbum(private val dao: AlbumDao, private val api: AlbumlistRemoteApi) {
|
||||||
|
|
||||||
private val api: AlbumlistRemoteApi = get()
|
|
||||||
|
|
||||||
fun execute(
|
fun execute(
|
||||||
userId: Int,
|
userId: Int,
|
||||||
onSuccess: (List<AlbumViewable>) -> Unit,
|
onSuccess: (List<Album>) -> Unit,
|
||||||
onError: (Throwable) -> Unit,
|
onError: (Throwable) -> Unit,
|
||||||
onLoading: () -> Unit
|
onLoading: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.hako.albumlist.R
|
import com.hako.albumlist.R
|
||||||
import com.hako.albumlist.model.AlbumViewable
|
import com.hako.albumlist.model.Album
|
||||||
import com.hako.albumlist.navigation.AlbumlistNavigation
|
import com.hako.albumlist.navigation.AlbumlistNavigation
|
||||||
import com.hako.albumlist.viewmodel.AlbumlistViewmodel
|
import com.hako.albumlist.viewmodel.AlbumlistViewmodel
|
||||||
import com.hako.albumlist.widget.AlbumlistAdapter
|
import com.hako.albumlist.widget.AlbumlistAdapter
|
||||||
@@ -72,7 +72,7 @@ class AlbumlistFragment : Fragment() {
|
|||||||
Timber.e(throwable)
|
Timber.e(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFetchSuccess(users: List<AlbumViewable>) {
|
private fun handleFetchSuccess(users: List<Album>) {
|
||||||
listAdapter.addAll(users)
|
listAdapter.addAll(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,38 @@
|
|||||||
package com.hako.albumlist.model
|
package com.hako.albumlist.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import com.hako.base.domain.database.entities.AlbumEntity
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Album(
|
data class AlbumRemote(
|
||||||
@SerializedName("id") val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
@SerializedName("userId") val userId: Int,
|
@SerializedName("userId") val userId: Int,
|
||||||
@SerializedName("title") val title: String
|
@SerializedName("title") val title: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
data class AlbumViewable(
|
@Entity(tableName = AlbumEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)])
|
||||||
|
data class AlbumEntity(
|
||||||
|
@PrimaryKey
|
||||||
|
val id: Int,
|
||||||
|
val userId: Int,
|
||||||
|
val title: String
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
const val TABLE_NAME = "albums"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Album(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val userId: Int,
|
val userId: Int,
|
||||||
val title: String
|
val title: String
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Album.toAlbumEntity() = AlbumEntity(this.id, this.userId, this.title)
|
fun AlbumRemote.toAlbumEntity() = AlbumEntity(this.id, this.userId, this.title)
|
||||||
|
|
||||||
fun AlbumEntity.toAlbumViewable() = AlbumViewable(this.id, this.userId, this.title)
|
fun AlbumEntity.toAlbumViewable() = Album(this.id, this.userId, this.title)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.hako.albumlist.viewmodel
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.hako.albumlist.domain.usecase.GetAlbum
|
import com.hako.albumlist.domain.usecase.GetAlbum
|
||||||
import com.hako.albumlist.model.AlbumViewable
|
import com.hako.albumlist.model.Album
|
||||||
import com.hako.base.domain.network.RequestStatus
|
import com.hako.base.domain.network.RequestStatus
|
||||||
import com.hako.base.domain.network.RequestStatus.Ready
|
import com.hako.base.domain.network.RequestStatus.Ready
|
||||||
import com.hako.base.domain.network.RequestStatus.Loading
|
import com.hako.base.domain.network.RequestStatus.Loading
|
||||||
@@ -14,7 +14,7 @@ import org.koin.core.get
|
|||||||
|
|
||||||
class AlbumlistViewmodel : ViewModel(), KoinComponent {
|
class AlbumlistViewmodel : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
val data = MutableLiveData<Either<Throwable, List<AlbumViewable>>>()
|
val data = MutableLiveData<Either<Throwable, List<Album>>>()
|
||||||
val requestStatus = MutableLiveData<RequestStatus>()
|
val requestStatus = MutableLiveData<RequestStatus>()
|
||||||
|
|
||||||
private val getAlbum: GetAlbum = get()
|
private val getAlbum: GetAlbum = get()
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.hako.albumlist.R
|
import com.hako.albumlist.R
|
||||||
import com.hako.albumlist.model.AlbumViewable
|
import com.hako.albumlist.model.Album
|
||||||
import com.hako.base.extensions.autoNotify
|
import com.hako.base.extensions.autoNotify
|
||||||
import kotlinx.android.synthetic.main.item_album_card.view.*
|
import kotlinx.android.synthetic.main.item_album_card.view.*
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class AlbumlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
class AlbumlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private var items by Delegates.observable(emptyList<AlbumViewable>()) { _, oldList, newList ->
|
private var items by Delegates.observable(emptyList<Album>()) { _, oldList, newList ->
|
||||||
autoNotify(oldList, newList) { old, new -> old.id == new.id }
|
autoNotify(oldList, newList) { old, new -> old.id == new.id }
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
var onItemClick: (AlbumViewable) -> Unit = { }
|
var onItemClick: (Album) -> Unit = { }
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||||
AlbumViewHolder(
|
AlbumViewHolder(
|
||||||
@@ -29,7 +29,7 @@ class AlbumlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||||||
|
|
||||||
fun getItem(position: Int) = items[position]
|
fun getItem(position: Int) = items[position]
|
||||||
|
|
||||||
fun addAll(list: List<AlbumViewable>) {
|
fun addAll(list: List<Album>) {
|
||||||
items = list
|
items = list
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ class AlbumlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AlbumViewHolder(private val view: View,
|
class AlbumViewHolder(private val view: View,
|
||||||
private val onItemClick: (AlbumViewable) -> Unit) :
|
private val onItemClick: (Album) -> Unit) :
|
||||||
RecyclerView.ViewHolder(view) {
|
RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
fun bind(album: AlbumViewable) = with(view) {
|
fun bind(album: Album) = with(view) {
|
||||||
item_album_card_album_name.text = album.title
|
item_album_card_album_name.text = album.title
|
||||||
item_album_card_container.setOnClickListener {
|
item_album_card_container.setOnClickListener {
|
||||||
onItemClick(album)
|
onItemClick(album)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ android {
|
|||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
buildConfigField "String", "DB_NAME", '"friendlists.db"'
|
|
||||||
buildConfigField "String", "BASE_ENDPOINT", '"https://jsonplaceholder.typicode.com/"'
|
buildConfigField "String", "BASE_ENDPOINT", '"https://jsonplaceholder.typicode.com/"'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +56,4 @@ dependencies {
|
|||||||
implementation project(":userlist")
|
implementation project(":userlist")
|
||||||
implementation project(":albumlist")
|
implementation project(":albumlist")
|
||||||
implementation project(":photolist")
|
implementation project(":photolist")
|
||||||
testImplementation project(':testing')
|
|
||||||
androidTestImplementation project(':testing')
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.hako.friendlists.di
|
package com.hako.friendlists.di
|
||||||
|
|
||||||
import androidx.room.Room
|
|
||||||
import com.hako.base.domain.database.DatabaseClient
|
|
||||||
import com.hako.base.domain.network.RemoteClient
|
import com.hako.base.domain.network.RemoteClient
|
||||||
import com.hako.base.navigation.NavigationRouter
|
import com.hako.base.navigation.NavigationRouter
|
||||||
import com.hako.friendlists.BuildConfig
|
import com.hako.friendlists.BuildConfig
|
||||||
@@ -11,12 +9,6 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val appModules = module {
|
val appModules = module {
|
||||||
// Room database
|
|
||||||
single { Room.databaseBuilder(get(), DatabaseClient::class.java, BuildConfig.DB_NAME).build() }
|
|
||||||
factory { get<DatabaseClient>().userDao() }
|
|
||||||
factory { get<DatabaseClient>().albumDao() }
|
|
||||||
factory { get<DatabaseClient>().photoDao() }
|
|
||||||
|
|
||||||
// Retrofit
|
// Retrofit
|
||||||
single { RemoteClient(BuildConfig.BASE_ENDPOINT) }
|
single { RemoteClient(BuildConfig.BASE_ENDPOINT) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.hako.base.domain.database
|
|
||||||
|
|
||||||
import androidx.room.Database
|
|
||||||
import androidx.room.RoomDatabase
|
|
||||||
import com.hako.base.domain.database.dao.AlbumDao
|
|
||||||
import com.hako.base.domain.database.dao.PhotoDao
|
|
||||||
import com.hako.base.domain.database.dao.UserDao
|
|
||||||
import com.hako.base.domain.database.entities.AlbumEntity
|
|
||||||
import com.hako.base.domain.database.entities.PhotoEntity
|
|
||||||
import com.hako.base.domain.database.entities.UserEntity
|
|
||||||
|
|
||||||
@Database(entities = [UserEntity::class, AlbumEntity::class, PhotoEntity::class], version = 1, exportSchema = false)
|
|
||||||
abstract class DatabaseClient : RoomDatabase() {
|
|
||||||
abstract fun userDao(): UserDao
|
|
||||||
abstract fun albumDao(): AlbumDao
|
|
||||||
abstract fun photoDao(): PhotoDao
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.hako.base.domain.database.entities
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.Index
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
|
|
||||||
@Entity(tableName = AlbumEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)])
|
|
||||||
data class AlbumEntity(
|
|
||||||
@PrimaryKey
|
|
||||||
val id: Int,
|
|
||||||
val userId: Int,
|
|
||||||
val title: String
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
const val TABLE_NAME = "albums"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.hako.base.domain.database.entities
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.Index
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
|
|
||||||
@Entity(tableName = PhotoEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)])
|
|
||||||
data class PhotoEntity(
|
|
||||||
@PrimaryKey
|
|
||||||
val id: Int,
|
|
||||||
val albumId: Int,
|
|
||||||
val title: String,
|
|
||||||
val photoUrl: String,
|
|
||||||
val thumbnailUrl: String
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
const val TABLE_NAME = "photos"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.hako.base.domain.database.entities
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.Index
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
|
|
||||||
@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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,3 +31,7 @@ android {
|
|||||||
abortOnError false
|
abortOnError false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
kapt deps.room.compiler
|
||||||
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply from: '../core.gradle'
|
apply from: '../core.gradle'
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultConfig {
|
||||||
|
buildConfigField "String", "DB_NAME", '"photolist.db"'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':base')
|
implementation project(':base')
|
||||||
testImplementation project(':testing')
|
|
||||||
androidTestImplementation project(':testing')
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.hako.photolist.di
|
package com.hako.photolist.di
|
||||||
|
|
||||||
|
import androidx.room.Room
|
||||||
import com.hako.base.domain.network.RemoteClient
|
import com.hako.base.domain.network.RemoteClient
|
||||||
|
import com.hako.photolist.BuildConfig
|
||||||
|
import com.hako.photolist.domain.clients.LocalClient
|
||||||
import com.hako.photolist.domain.datasource.PhotolistRemoteApi
|
import com.hako.photolist.domain.datasource.PhotolistRemoteApi
|
||||||
import com.hako.photolist.domain.usecase.GetPhoto
|
import com.hako.photolist.domain.usecase.GetPhoto
|
||||||
import com.hako.photolist.viewmodel.PhotolistViewmodel
|
import com.hako.photolist.viewmodel.PhotolistViewmodel
|
||||||
@@ -8,8 +11,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val photoListModules = module {
|
val photoListModules = module {
|
||||||
|
|
||||||
|
single { Room.databaseBuilder(get(), LocalClient::class.java, BuildConfig.DB_NAME).build() }
|
||||||
|
factory { get<LocalClient>().photoDao() }
|
||||||
|
|
||||||
factory { get<RemoteClient>().getClient(PhotolistRemoteApi::class.java) }
|
factory { get<RemoteClient>().getClient(PhotolistRemoteApi::class.java) }
|
||||||
factory { GetPhoto(get()) }
|
factory { GetPhoto(get(), get()) }
|
||||||
|
|
||||||
viewModel { PhotolistViewmodel() }
|
viewModel { PhotolistViewmodel() }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.hako.photolist.domain.clients
|
||||||
|
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import com.hako.photolist.domain.datasource.PhotoDao
|
||||||
|
import com.hako.photolist.model.PhotoEntity
|
||||||
|
|
||||||
|
@Database(entities = [PhotoEntity::class], version = 1, exportSchema = false)
|
||||||
|
abstract class LocalClient : RoomDatabase() {
|
||||||
|
abstract fun photoDao(): PhotoDao
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.hako.base.domain.database.dao
|
package com.hako.photolist.domain.datasource
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import com.hako.base.domain.database.entities.PhotoEntity
|
import com.hako.photolist.model.PhotoEntity
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface PhotoDao {
|
interface PhotoDao {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.hako.photolist.domain.datasource
|
package com.hako.photolist.domain.datasource
|
||||||
|
|
||||||
import com.hako.photolist.model.Photo
|
import com.hako.photolist.model.PhotoRemote
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
@@ -10,5 +10,5 @@ interface PhotolistRemoteApi {
|
|||||||
@GET("/photos")
|
@GET("/photos")
|
||||||
fun getPhotos(
|
fun getPhotos(
|
||||||
@Query("albumId") albumId: Int
|
@Query("albumId") albumId: Int
|
||||||
): Single<List<Photo>>
|
): Single<List<PhotoRemote>>
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
package com.hako.photolist.domain.usecase
|
package com.hako.photolist.domain.usecase
|
||||||
|
|
||||||
import com.hako.base.domain.database.dao.PhotoDao
|
import com.hako.photolist.domain.datasource.PhotoDao
|
||||||
import com.hako.photolist.domain.datasource.PhotolistRemoteApi
|
import com.hako.photolist.domain.datasource.PhotolistRemoteApi
|
||||||
import com.hako.photolist.model.*
|
import com.hako.photolist.model.*
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.koin.core.KoinComponent
|
|
||||||
import org.koin.core.get
|
|
||||||
|
|
||||||
class GetPhoto(private val dao: PhotoDao) : KoinComponent {
|
class GetPhoto(private val dao: PhotoDao, private val api: PhotolistRemoteApi) {
|
||||||
|
|
||||||
private val api: PhotolistRemoteApi = get()
|
|
||||||
|
|
||||||
fun execute(
|
fun execute(
|
||||||
albumId: Int,
|
albumId: Int,
|
||||||
onSuccess: (List<PhotoViewable>) -> Unit,
|
onSuccess: (List<Photo>) -> Unit,
|
||||||
onError: (Throwable) -> Unit,
|
onError: (Throwable) -> Unit,
|
||||||
onLoading: () -> Unit
|
onLoading: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import com.hako.base.extensions.gone
|
|||||||
import com.hako.base.extensions.observeNonNull
|
import com.hako.base.extensions.observeNonNull
|
||||||
import com.hako.base.extensions.visible
|
import com.hako.base.extensions.visible
|
||||||
import com.hako.photolist.R
|
import com.hako.photolist.R
|
||||||
import com.hako.photolist.model.PhotoViewable
|
import com.hako.photolist.model.Photo
|
||||||
import com.hako.photolist.viewmodel.PhotolistViewmodel
|
import com.hako.photolist.viewmodel.PhotolistViewmodel
|
||||||
import com.hako.photolist.widget.PhotolistAdapter
|
import com.hako.photolist.widget.PhotolistAdapter
|
||||||
import kotlinx.android.synthetic.main.fragment_photolist.*
|
import kotlinx.android.synthetic.main.fragment_photolist.*
|
||||||
@@ -68,7 +68,7 @@ class PhotolistFragment : Fragment() {
|
|||||||
Timber.e(throwable)
|
Timber.e(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFetchSuccess(photos: List<PhotoViewable>) {
|
private fun handleFetchSuccess(photos: List<Photo>) {
|
||||||
listAdapter.addAll(photos)
|
listAdapter.addAll(photos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package com.hako.photolist.model
|
package com.hako.photolist.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import com.hako.base.domain.database.entities.PhotoEntity
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Photo(
|
data class PhotoRemote(
|
||||||
@SerializedName("id") val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
@SerializedName("albumId") val albumId: Int,
|
@SerializedName("albumId") val albumId: Int,
|
||||||
@SerializedName("title") val title: String,
|
@SerializedName("title") val title: String,
|
||||||
@@ -14,14 +16,28 @@ data class Photo(
|
|||||||
@SerializedName("thumbnailUrl") val thumbnailUrl: String
|
@SerializedName("thumbnailUrl") val thumbnailUrl: String
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
data class PhotoViewable(
|
@Entity(tableName = PhotoEntity.TABLE_NAME, indices = [Index(value = ["id"], unique = true)])
|
||||||
|
data class PhotoEntity(
|
||||||
|
@PrimaryKey
|
||||||
|
val id: Int,
|
||||||
|
val albumId: Int,
|
||||||
|
val title: String,
|
||||||
|
val photoUrl: String,
|
||||||
|
val thumbnailUrl: String
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
const val TABLE_NAME = "photos"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Photo(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val albumId: Int,
|
val albumId: Int,
|
||||||
val title: String,
|
val title: String,
|
||||||
val photoUrl: String
|
val photoUrl: String
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Photo.toPhotoEntity() = PhotoEntity(this.id, this.albumId, this.title, this.photoUrl, this.thumbnailUrl)
|
fun PhotoRemote.toPhotoEntity() = PhotoEntity(this.id, this.albumId, this.title, this.photoUrl, this.thumbnailUrl)
|
||||||
|
|
||||||
fun PhotoEntity.toPhotoViewable() = PhotoViewable(this.id, this.albumId, this.title, this.photoUrl)
|
fun PhotoEntity.toPhotoViewable() = Photo(this.id, this.albumId, this.title, this.photoUrl)
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import com.hako.base.domain.network.RequestStatus.Loading
|
|||||||
import com.hako.base.domain.network.RequestStatus.Errored
|
import com.hako.base.domain.network.RequestStatus.Errored
|
||||||
import com.hako.base.domain.Either
|
import com.hako.base.domain.Either
|
||||||
import com.hako.photolist.domain.usecase.GetPhoto
|
import com.hako.photolist.domain.usecase.GetPhoto
|
||||||
import com.hako.photolist.model.PhotoViewable
|
import com.hako.photolist.model.Photo
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
import org.koin.core.get
|
import org.koin.core.get
|
||||||
|
|
||||||
class PhotolistViewmodel : ViewModel(), KoinComponent {
|
class PhotolistViewmodel : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
val data = MutableLiveData<Either<Throwable, List<PhotoViewable>>>()
|
val data = MutableLiveData<Either<Throwable, List<Photo>>>()
|
||||||
val requestStatus = MutableLiveData<RequestStatus>()
|
val requestStatus = MutableLiveData<RequestStatus>()
|
||||||
|
|
||||||
private val getPhoto: GetPhoto = get()
|
private val getPhoto: GetPhoto = get()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.hako.base.extensions.autoNotify
|
import com.hako.base.extensions.autoNotify
|
||||||
import com.hako.photolist.R
|
import com.hako.photolist.R
|
||||||
import com.hako.photolist.model.PhotoViewable
|
import com.hako.photolist.model.Photo
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import kotlinx.android.synthetic.main.item_photo_card.view.*
|
import kotlinx.android.synthetic.main.item_photo_card.view.*
|
||||||
import org.koin.core.KoinComponent
|
import org.koin.core.KoinComponent
|
||||||
@@ -15,7 +15,7 @@ import kotlin.properties.Delegates
|
|||||||
|
|
||||||
class PhotolistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
class PhotolistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private var items by Delegates.observable(emptyList<PhotoViewable>()) { _, oldList, newList ->
|
private var items by Delegates.observable(emptyList<Photo>()) { _, oldList, newList ->
|
||||||
autoNotify(oldList, newList) { old, new -> old.id == new.id }
|
autoNotify(oldList, newList) { old, new -> old.id == new.id }
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ class PhotolistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||||||
|
|
||||||
fun getItem(position: Int) = items[position]
|
fun getItem(position: Int) = items[position]
|
||||||
|
|
||||||
fun addAll(list: List<PhotoViewable>) {
|
fun addAll(list: List<Photo>) {
|
||||||
items = list
|
items = list
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class PhotoViewHolder(private val view: View) :
|
|||||||
|
|
||||||
private val picasso: Picasso by inject()
|
private val picasso: Picasso by inject()
|
||||||
|
|
||||||
fun bind(photo: PhotoViewable) = with(view) {
|
fun bind(photo: Photo) = with(view) {
|
||||||
picasso.load(photo.photoUrl)
|
picasso.load(photo.photoUrl)
|
||||||
.placeholder(R.drawable.img_photo_placeholder)
|
.placeholder(R.drawable.img_photo_placeholder)
|
||||||
.fit()
|
.fit()
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply from: '../core.gradle'
|
apply from: '../core.gradle'
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultConfig {
|
||||||
|
buildConfigField "String", "DB_NAME", '"userlist.db"'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':base')
|
implementation project(':base')
|
||||||
testImplementation project(':testing')
|
testImplementation project(':testing')
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.hako.userlist.feature
|
package com.hako.userlist.feature
|
||||||
|
|
||||||
import com.hako.base.domain.database.dao.UserDao
|
import com.hako.userlist.domain.datasource.UserDao
|
||||||
import com.hako.base.domain.database.entities.UserEntity
|
|
||||||
import com.hako.userlist.domain.datasource.UserlistRemoteApi
|
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
|
import io.reactivex.Single
|
||||||
|
|
||||||
class MockUserDao(private val userList: List<UserEntity>) : UserDao {
|
class MockUserDao(private val userList: List<UserEntity>) : UserDao {
|
||||||
@@ -22,8 +22,8 @@ class MockUserDao(private val userList: List<UserEntity>) : UserDao {
|
|||||||
override fun nukeDatabase() {}
|
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() }
|
override fun getUsers() = Single.fromCallable { getAllUsers() }
|
||||||
|
|
||||||
private fun getAllUsers() = userList
|
private fun getAllUsers() = userRemoteList
|
||||||
}
|
}
|
||||||
@@ -2,14 +2,14 @@ package com.hako.userlist.feature
|
|||||||
|
|
||||||
import androidx.fragment.app.testing.launchFragmentInContainer
|
import androidx.fragment.app.testing.launchFragmentInContainer
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
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.testing.isTextDisplayed
|
||||||
|
import com.hako.userlist.domain.datasource.UserDao
|
||||||
import com.hako.userlist.domain.datasource.UserlistRemoteApi
|
import com.hako.userlist.domain.datasource.UserlistRemoteApi
|
||||||
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
||||||
import com.hako.userlist.domain.usecase.GetUsers
|
import com.hako.userlist.domain.usecase.GetUsers
|
||||||
import com.hako.userlist.domain.usecase.SetFavoriteStatus
|
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.model.toUserEntity
|
||||||
import com.hako.userlist.viewmodel.UserlistViewmodel
|
import com.hako.userlist.viewmodel.UserlistViewmodel
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
@@ -28,7 +28,7 @@ class UserlistFragmentTest {
|
|||||||
startKoin {
|
startKoin {
|
||||||
InstrumentationRegistry.getInstrumentation().targetContext
|
InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
modules(module {
|
modules(module {
|
||||||
factory { GetUsers(get()) }
|
factory { GetUsers(get(), get()) }
|
||||||
factory { GetFavoriteUsers(get()) }
|
factory { GetFavoriteUsers(get()) }
|
||||||
factory { SetFavoriteStatus(get()) }
|
factory { SetFavoriteStatus(get()) }
|
||||||
viewModel { UserlistViewmodel() }
|
viewModel { UserlistViewmodel() }
|
||||||
@@ -92,7 +92,7 @@ class UserlistRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadTwoBasicUsers() = listOf(
|
private fun loadTwoBasicUsers() = listOf(
|
||||||
User(
|
UserRemote(
|
||||||
1,
|
1,
|
||||||
"Marian Arriaga",
|
"Marian Arriaga",
|
||||||
"mariancita",
|
"mariancita",
|
||||||
@@ -100,7 +100,7 @@ class UserlistRobot {
|
|||||||
"+56873912",
|
"+56873912",
|
||||||
"www.test.com"
|
"www.test.com"
|
||||||
),
|
),
|
||||||
User(
|
UserRemote(
|
||||||
2,
|
2,
|
||||||
"Carlos Martinez",
|
"Carlos Martinez",
|
||||||
"carlitos",
|
"carlitos",
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.hako.friendlist_userlist" />
|
package="com.hako.userlist" />
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.hako.userlist.di
|
package com.hako.userlist.di
|
||||||
|
|
||||||
|
import androidx.room.Room
|
||||||
import com.hako.base.domain.network.RemoteClient
|
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.datasource.UserlistRemoteApi
|
||||||
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
||||||
import com.hako.userlist.domain.usecase.GetUsers
|
import com.hako.userlist.domain.usecase.GetUsers
|
||||||
@@ -10,8 +13,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val userlistModules = 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 { get<RemoteClient>().getClient(UserlistRemoteApi::class.java) }
|
||||||
factory { GetUsers(get()) }
|
factory { GetUsers(get(), get()) }
|
||||||
factory { GetFavoriteUsers(get()) }
|
factory { GetFavoriteUsers(get()) }
|
||||||
factory { SetFavoriteStatus(get()) }
|
factory { SetFavoriteStatus(get()) }
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.hako.base.domain.database.dao
|
package com.hako.userlist.domain.datasource
|
||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import com.hako.base.domain.database.entities.UserEntity
|
import com.hako.userlist.model.UserEntity
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface UserDao {
|
interface UserDao {
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.hako.userlist.domain.datasource
|
package com.hako.userlist.domain.datasource
|
||||||
|
|
||||||
import com.hako.userlist.model.User
|
import com.hako.userlist.model.UserRemote
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
|
||||||
interface UserlistRemoteApi {
|
interface UserlistRemoteApi {
|
||||||
|
|
||||||
@GET("/users")
|
@GET("/users")
|
||||||
fun getUsers(): Single<List<User>>
|
fun getUsers(): Single<List<UserRemote>>
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.hako.userlist.domain.usecase
|
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.model.UserViewable
|
import com.hako.userlist.model.User
|
||||||
import com.hako.userlist.model.toUserViewable
|
import com.hako.userlist.model.toUserViewable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
@@ -9,7 +9,7 @@ import io.reactivex.schedulers.Schedulers
|
|||||||
class GetFavoriteUsers(private val dao: UserDao) {
|
class GetFavoriteUsers(private val dao: UserDao) {
|
||||||
|
|
||||||
fun execute(
|
fun execute(
|
||||||
onSuccess: (List<UserViewable>) -> Unit,
|
onSuccess: (List<User>) -> Unit,
|
||||||
onEmpty: () -> Unit,
|
onEmpty: () -> Unit,
|
||||||
onError: (Throwable) -> Unit
|
onError: (Throwable) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
package com.hako.userlist.domain.usecase
|
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.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.toUserEntity
|
||||||
import com.hako.userlist.model.toUserViewable
|
import com.hako.userlist.model.toUserViewable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.koin.core.KoinComponent
|
|
||||||
import org.koin.core.get
|
|
||||||
|
|
||||||
class GetUsers(private val dao: UserDao) : KoinComponent {
|
class GetUsers(private val dao: UserDao, private val api: UserlistRemoteApi) {
|
||||||
|
|
||||||
private val api: UserlistRemoteApi = get()
|
|
||||||
|
|
||||||
fun execute(
|
fun execute(
|
||||||
onSuccess: (List<UserViewable>) -> Unit,
|
onSuccess: (List<User>) -> Unit,
|
||||||
onError: (Throwable) -> Unit,
|
onError: (Throwable) -> Unit,
|
||||||
onLoading: () -> Unit,
|
onLoading: () -> Unit,
|
||||||
onEmpty: () -> Unit
|
onEmpty: () -> Unit
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.hako.userlist.domain.usecase
|
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.Single
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import com.hako.base.extensions.observeNonNull
|
|||||||
import com.hako.base.extensions.visible
|
import com.hako.base.extensions.visible
|
||||||
import com.hako.base.navigation.NavigationRouter
|
import com.hako.base.navigation.NavigationRouter
|
||||||
import com.hako.base.navigation.ShowFabButton
|
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.viewmodel.UserlistViewmodel
|
||||||
import com.hako.userlist.widget.UserlistAdapter
|
import com.hako.userlist.widget.UserlistAdapter
|
||||||
import com.hako.friendlist_userlist.R
|
import com.hako.userlist.R
|
||||||
import com.hako.userlist.navigation.UserlistNavigation
|
import com.hako.userlist.navigation.UserlistNavigation
|
||||||
import kotlinx.android.synthetic.main.fragment_userlist.*
|
import kotlinx.android.synthetic.main.fragment_userlist.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
@@ -88,7 +88,7 @@ open class UserlistFragment : Fragment(), ShowFabButton {
|
|||||||
Timber.e(throwable)
|
Timber.e(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFetchSuccess(users: List<UserViewable>) {
|
private fun handleFetchSuccess(users: List<User>) {
|
||||||
listAdapter.addAll(users)
|
listAdapter.addAll(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package com.hako.userlist.model
|
package com.hako.userlist.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Index
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import com.hako.base.domain.database.entities.UserEntity
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class User(
|
data class UserRemote(
|
||||||
@SerializedName("id") val id: Int,
|
@SerializedName("id") val id: Int,
|
||||||
@SerializedName("name") val realName: String,
|
@SerializedName("name") val realName: String,
|
||||||
@SerializedName("username") val userName: String,
|
@SerializedName("username") val userName: String,
|
||||||
@@ -15,14 +17,30 @@ data class User(
|
|||||||
@SerializedName("website") val website: String
|
@SerializedName("website") val website: String
|
||||||
) : Parcelable
|
) : 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 id: Int,
|
||||||
val realName: String,
|
val realName: String,
|
||||||
val userName: String,
|
val userName: String,
|
||||||
var isFavorite: Boolean
|
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)
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import com.hako.base.domain.network.RequestStatus.*
|
|||||||
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
import com.hako.userlist.domain.usecase.GetFavoriteUsers
|
||||||
import com.hako.userlist.domain.usecase.GetUsers
|
import com.hako.userlist.domain.usecase.GetUsers
|
||||||
import com.hako.userlist.domain.usecase.SetFavoriteStatus
|
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.KoinComponent
|
||||||
import org.koin.core.get
|
import org.koin.core.get
|
||||||
|
|
||||||
class UserlistViewmodel : ViewModel(), KoinComponent {
|
class UserlistViewmodel : ViewModel(), KoinComponent {
|
||||||
|
|
||||||
val userList = MutableLiveData<Either<Throwable, List<UserViewable>>>()
|
val userList = MutableLiveData<Either<Throwable, List<User>>>()
|
||||||
val favoriteError = MutableLiveData<Int>()
|
val favoriteError = MutableLiveData<Int>()
|
||||||
val emptyMessage = MutableLiveData<String>()
|
val emptyMessage = MutableLiveData<String>()
|
||||||
val requestStatus = MutableLiveData<RequestStatus>()
|
val requestStatus = MutableLiveData<RequestStatus>()
|
||||||
|
|||||||
@@ -5,20 +5,20 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.hako.base.extensions.autoNotify
|
import com.hako.base.extensions.autoNotify
|
||||||
import com.hako.userlist.model.UserViewable
|
import com.hako.userlist.model.User
|
||||||
import com.hako.friendlist_userlist.R
|
import com.hako.userlist.R
|
||||||
import kotlinx.android.synthetic.main.item_user_card.view.*
|
import kotlinx.android.synthetic.main.item_user_card.view.*
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
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 }
|
autoNotify(oldList, newList) { old, new -> old.id == new.id }
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
var onItemClick: (UserViewable) -> Unit = { }
|
var onItemClick: (User) -> Unit = { }
|
||||||
var onFavoriteClick: (UserViewable) -> Unit = { }
|
var onFavoriteClick: (User) -> Unit = { }
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||||
UserViewHolder(
|
UserViewHolder(
|
||||||
@@ -31,7 +31,7 @@ class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||||||
|
|
||||||
fun getItem(position: Int) = items[position]
|
fun getItem(position: Int) = items[position]
|
||||||
|
|
||||||
fun addAll(list: List<UserViewable>) {
|
fun addAll(list: List<User>) {
|
||||||
items = list
|
items = list
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ class UserlistAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||||||
|
|
||||||
class UserViewHolder(
|
class UserViewHolder(
|
||||||
private val view: View,
|
private val view: View,
|
||||||
private val onItemClick: (UserViewable) -> Unit,
|
private val onItemClick: (User) -> Unit,
|
||||||
private val onFavoriteClick: (UserViewable) -> Unit
|
private val onFavoriteClick: (User) -> Unit
|
||||||
) :
|
) :
|
||||||
RecyclerView.ViewHolder(view) {
|
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_real_name.text = user.realName
|
||||||
item_user_card_user_name.text = user.userName
|
item_user_card_user_name.text = user.userName
|
||||||
if (user.isFavorite) {
|
if (user.isFavorite) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ ext.deps = [:]
|
|||||||
def versions = [:]
|
def versions = [:]
|
||||||
versions.kotlin = "1.3.41"
|
versions.kotlin = "1.3.41"
|
||||||
versions.gradle = "3.5.3"
|
versions.gradle = "3.5.3"
|
||||||
|
versions.room = "2.2.3"
|
||||||
|
|
||||||
def deps = [:]
|
def deps = [:]
|
||||||
|
|
||||||
@@ -22,6 +23,11 @@ kotlin.version = "$versions.kotlin"
|
|||||||
kotlin.std_lib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
|
kotlin.std_lib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin"
|
||||||
deps.kotlin = kotlin
|
deps.kotlin = kotlin
|
||||||
|
|
||||||
|
def room = [:]
|
||||||
|
room.runtime = "androidx.room:room-runtime:$versions.room"
|
||||||
|
room.compiler = "androidx.room:room-compiler:$versions.room"
|
||||||
|
deps.room = room
|
||||||
|
|
||||||
ext.deps = deps
|
ext.deps = deps
|
||||||
|
|
||||||
static def addRepos(RepositoryHandler handler) {
|
static def addRepos(RepositoryHandler handler) {
|
||||||
|
|||||||
Reference in New Issue
Block a user