diff --git a/albumlist/build.gradle b/albumlist/build.gradle index e59dcbe..2a9fa2d 100644 --- a/albumlist/build.gradle +++ b/albumlist/build.gradle @@ -1,8 +1,12 @@ apply plugin: 'com.android.library' apply from: '../core.gradle' +android { + defaultConfig { + buildConfigField "String", "DB_NAME", '"albumlist.db"' + } +} + dependencies { implementation project(':base') - testImplementation project(':testing') - androidTestImplementation project(':testing') } \ No newline at end of file diff --git a/albumlist/src/main/java/com/hako/albumlist/di/AlbumlistModules.kt b/albumlist/src/main/java/com/hako/albumlist/di/AlbumlistModules.kt index a578b68..cd55c6e 100644 --- a/albumlist/src/main/java/com/hako/albumlist/di/AlbumlistModules.kt +++ b/albumlist/src/main/java/com/hako/albumlist/di/AlbumlistModules.kt @@ -1,5 +1,8 @@ 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.usecase.GetAlbum import com.hako.albumlist.viewmodel.AlbumlistViewmodel @@ -8,8 +11,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module val albumListModules = module { + + single { Room.databaseBuilder(get(), LocalClient::class.java, BuildConfig.DB_NAME).build() } + factory { get().albumDao() } + factory { get().getClient(AlbumlistRemoteApi::class.java) } - factory { GetAlbum(get()) } + factory { GetAlbum(get(), get()) } viewModel { AlbumlistViewmodel() } } \ No newline at end of file diff --git a/albumlist/src/main/java/com/hako/albumlist/domain/clients/LocalClient.kt b/albumlist/src/main/java/com/hako/albumlist/domain/clients/LocalClient.kt new file mode 100644 index 0000000..3db3583 --- /dev/null +++ b/albumlist/src/main/java/com/hako/albumlist/domain/clients/LocalClient.kt @@ -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 +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt b/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumDao.kt similarity index 86% rename from base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt rename to albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumDao.kt index 54abdad..395aff3 100644 --- a/base/src/main/java/com/hako/base/domain/database/dao/AlbumDao.kt +++ b/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.domain.database.dao +package com.hako.albumlist.domain.datasource import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.hako.base.domain.database.entities.AlbumEntity +import com.hako.albumlist.model.AlbumEntity @Dao interface AlbumDao { diff --git a/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumlistRemoteApi.kt b/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumlistRemoteApi.kt index 249822e..5e59a5f 100644 --- a/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumlistRemoteApi.kt +++ b/albumlist/src/main/java/com/hako/albumlist/domain/datasource/AlbumlistRemoteApi.kt @@ -1,6 +1,6 @@ package com.hako.albumlist.domain.datasource -import com.hako.albumlist.model.Album +import com.hako.albumlist.model.AlbumRemote import io.reactivex.Single import retrofit2.http.GET import retrofit2.http.Query @@ -10,5 +10,5 @@ interface AlbumlistRemoteApi { @GET("/albums") fun getAlbums( @Query("userId") userId: Int - ): Single> + ): Single> } \ No newline at end of file diff --git a/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt b/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt index fe59945..d2bf46f 100644 --- a/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt +++ b/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt @@ -1,22 +1,18 @@ package com.hako.albumlist.domain.usecase +import com.hako.albumlist.domain.datasource.AlbumDao 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.toAlbumViewable -import com.hako.base.domain.database.dao.AlbumDao import io.reactivex.Single import io.reactivex.schedulers.Schedulers -import org.koin.core.KoinComponent -import org.koin.core.get -class GetAlbum(private val dao: AlbumDao) : KoinComponent { - - private val api: AlbumlistRemoteApi = get() +class GetAlbum(private val dao: AlbumDao, private val api: AlbumlistRemoteApi) { fun execute( userId: Int, - onSuccess: (List) -> Unit, + onSuccess: (List) -> Unit, onError: (Throwable) -> Unit, onLoading: () -> Unit ) { diff --git a/albumlist/src/main/java/com/hako/albumlist/feature/AlbumlistFragment.kt b/albumlist/src/main/java/com/hako/albumlist/feature/AlbumlistFragment.kt index 7165129..650b813 100644 --- a/albumlist/src/main/java/com/hako/albumlist/feature/AlbumlistFragment.kt +++ b/albumlist/src/main/java/com/hako/albumlist/feature/AlbumlistFragment.kt @@ -7,7 +7,7 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager 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.viewmodel.AlbumlistViewmodel import com.hako.albumlist.widget.AlbumlistAdapter @@ -72,7 +72,7 @@ class AlbumlistFragment : Fragment() { Timber.e(throwable) } - private fun handleFetchSuccess(users: List) { + private fun handleFetchSuccess(users: List) { listAdapter.addAll(users) } diff --git a/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt b/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt index fde8f21..b77b580 100644 --- a/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt +++ b/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt @@ -1,24 +1,38 @@ package com.hako.albumlist.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.AlbumEntity import kotlinx.android.parcel.Parcelize @Parcelize -data class Album( +data class AlbumRemote( @SerializedName("id") val id: Int, @SerializedName("userId") val userId: Int, @SerializedName("title") val title: String ) : 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 userId: Int, 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) diff --git a/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt b/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt index ed795b4..2b9cb7d 100644 --- a/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt +++ b/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt @@ -3,7 +3,7 @@ package com.hako.albumlist.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel 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.Ready import com.hako.base.domain.network.RequestStatus.Loading @@ -14,7 +14,7 @@ import org.koin.core.get class AlbumlistViewmodel : ViewModel(), KoinComponent { - val data = MutableLiveData>>() + val data = MutableLiveData>>() val requestStatus = MutableLiveData() private val getAlbum: GetAlbum = get() diff --git a/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt b/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt index a67596a..a3316f8 100644 --- a/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt +++ b/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt @@ -5,19 +5,19 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.hako.albumlist.R -import com.hako.albumlist.model.AlbumViewable +import com.hako.albumlist.model.Album import com.hako.base.extensions.autoNotify import kotlinx.android.synthetic.main.item_album_card.view.* import kotlin.properties.Delegates class AlbumlistAdapter : RecyclerView.Adapter() { - private var items by Delegates.observable(emptyList()) { _, oldList, newList -> + private var items by Delegates.observable(emptyList()) { _, oldList, newList -> autoNotify(oldList, newList) { old, new -> old.id == new.id } notifyDataSetChanged() } - var onItemClick: (AlbumViewable) -> Unit = { } + var onItemClick: (Album) -> Unit = { } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = AlbumViewHolder( @@ -29,7 +29,7 @@ class AlbumlistAdapter : RecyclerView.Adapter() { fun getItem(position: Int) = items[position] - fun addAll(list: List) { + fun addAll(list: List) { items = list } @@ -43,10 +43,10 @@ class AlbumlistAdapter : RecyclerView.Adapter() { } class AlbumViewHolder(private val view: View, - private val onItemClick: (AlbumViewable) -> Unit) : + private val onItemClick: (Album) -> Unit) : 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_container.setOnClickListener { onItemClick(album) diff --git a/app/build.gradle b/app/build.gradle index 605e231..67517cc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,6 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - buildConfigField "String", "DB_NAME", '"friendlists.db"' buildConfigField "String", "BASE_ENDPOINT", '"https://jsonplaceholder.typicode.com/"' } @@ -57,6 +56,4 @@ dependencies { implementation project(":userlist") implementation project(":albumlist") implementation project(":photolist") - testImplementation project(':testing') - androidTestImplementation project(':testing') } diff --git a/app/src/main/java/com/hako/friendlists/di/AppModules.kt b/app/src/main/java/com/hako/friendlists/di/AppModules.kt index 46e5d03..6b9e11e 100644 --- a/app/src/main/java/com/hako/friendlists/di/AppModules.kt +++ b/app/src/main/java/com/hako/friendlists/di/AppModules.kt @@ -1,7 +1,5 @@ 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.navigation.NavigationRouter import com.hako.friendlists.BuildConfig @@ -11,12 +9,6 @@ import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module val appModules = module { - // Room database - single { Room.databaseBuilder(get(), DatabaseClient::class.java, BuildConfig.DB_NAME).build() } - factory { get().userDao() } - factory { get().albumDao() } - factory { get().photoDao() } - // Retrofit single { RemoteClient(BuildConfig.BASE_ENDPOINT) } diff --git a/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt b/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt deleted file mode 100644 index b78a001..0000000 --- a/base/src/main/java/com/hako/base/domain/database/DatabaseClient.kt +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/entities/Album.kt b/base/src/main/java/com/hako/base/domain/database/entities/Album.kt deleted file mode 100644 index a6174ad..0000000 --- a/base/src/main/java/com/hako/base/domain/database/entities/Album.kt +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/entities/Photos.kt b/base/src/main/java/com/hako/base/domain/database/entities/Photos.kt deleted file mode 100644 index 68432f7..0000000 --- a/base/src/main/java/com/hako/base/domain/database/entities/Photos.kt +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/entities/User.kt b/base/src/main/java/com/hako/base/domain/database/entities/User.kt deleted file mode 100644 index 6756461..0000000 --- a/base/src/main/java/com/hako/base/domain/database/entities/User.kt +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/core.gradle b/core.gradle index db3b581..3238692 100644 --- a/core.gradle +++ b/core.gradle @@ -30,4 +30,8 @@ android { lintOptions { abortOnError false } +} + +dependencies { + kapt deps.room.compiler } \ No newline at end of file diff --git a/photolist/build.gradle b/photolist/build.gradle index e59dcbe..564e76f 100644 --- a/photolist/build.gradle +++ b/photolist/build.gradle @@ -1,8 +1,12 @@ apply plugin: 'com.android.library' apply from: '../core.gradle' +android { + defaultConfig { + buildConfigField "String", "DB_NAME", '"photolist.db"' + } +} + dependencies { implementation project(':base') - testImplementation project(':testing') - androidTestImplementation project(':testing') } \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt b/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt index 41b0c45..84a2f1c 100644 --- a/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt +++ b/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt @@ -1,6 +1,9 @@ package com.hako.photolist.di +import androidx.room.Room 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.usecase.GetPhoto import com.hako.photolist.viewmodel.PhotolistViewmodel @@ -8,8 +11,12 @@ import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module val photoListModules = module { + + single { Room.databaseBuilder(get(), LocalClient::class.java, BuildConfig.DB_NAME).build() } + factory { get().photoDao() } + factory { get().getClient(PhotolistRemoteApi::class.java) } - factory { GetPhoto(get()) } + factory { GetPhoto(get(), get()) } viewModel { PhotolistViewmodel() } } \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/domain/clients/LocalClient.kt b/photolist/src/main/java/com/hako/photolist/domain/clients/LocalClient.kt new file mode 100644 index 0000000..288a0cf --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/domain/clients/LocalClient.kt @@ -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 +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotoDao.kt similarity index 86% rename from base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt rename to photolist/src/main/java/com/hako/photolist/domain/datasource/PhotoDao.kt index f6a2623..25fa4c2 100644 --- a/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt +++ b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotoDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.domain.database.dao +package com.hako.photolist.domain.datasource import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.hako.base.domain.database.entities.PhotoEntity +import com.hako.photolist.model.PhotoEntity @Dao interface PhotoDao { diff --git a/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt index 4b8ce88..0ca4945 100644 --- a/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt +++ b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt @@ -1,6 +1,6 @@ package com.hako.photolist.domain.datasource -import com.hako.photolist.model.Photo +import com.hako.photolist.model.PhotoRemote import io.reactivex.Single import retrofit2.http.GET import retrofit2.http.Query @@ -10,5 +10,5 @@ interface PhotolistRemoteApi { @GET("/photos") fun getPhotos( @Query("albumId") albumId: Int - ): Single> + ): Single> } \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt b/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt index 9e172df..f33af34 100644 --- a/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt +++ b/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt @@ -1,20 +1,16 @@ 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.model.* import io.reactivex.Single import io.reactivex.schedulers.Schedulers -import org.koin.core.KoinComponent -import org.koin.core.get -class GetPhoto(private val dao: PhotoDao) : KoinComponent { - - private val api: PhotolistRemoteApi = get() +class GetPhoto(private val dao: PhotoDao, private val api: PhotolistRemoteApi) { fun execute( albumId: Int, - onSuccess: (List) -> Unit, + onSuccess: (List) -> Unit, onError: (Throwable) -> Unit, onLoading: () -> Unit ) { diff --git a/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt b/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt index 99904a7..ba4c744 100644 --- a/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt +++ b/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt @@ -11,7 +11,7 @@ import com.hako.base.extensions.gone import com.hako.base.extensions.observeNonNull import com.hako.base.extensions.visible 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.widget.PhotolistAdapter import kotlinx.android.synthetic.main.fragment_photolist.* @@ -68,7 +68,7 @@ class PhotolistFragment : Fragment() { Timber.e(throwable) } - private fun handleFetchSuccess(photos: List) { + private fun handleFetchSuccess(photos: List) { listAdapter.addAll(photos) } diff --git a/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt b/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt index 14d2516..9923ec9 100644 --- a/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt +++ b/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt @@ -1,12 +1,14 @@ package com.hako.photolist.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.PhotoEntity import kotlinx.android.parcel.Parcelize @Parcelize -data class Photo( +data class PhotoRemote( @SerializedName("id") val id: Int, @SerializedName("albumId") val albumId: Int, @SerializedName("title") val title: String, @@ -14,14 +16,28 @@ data class Photo( @SerializedName("thumbnailUrl") val thumbnailUrl: String ) : 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 albumId: Int, val title: 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) diff --git a/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt b/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt index 3123854..9a94106 100644 --- a/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt +++ b/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt @@ -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.Either 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.get class PhotolistViewmodel : ViewModel(), KoinComponent { - val data = MutableLiveData>>() + val data = MutableLiveData>>() val requestStatus = MutableLiveData() private val getPhoto: GetPhoto = get() diff --git a/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt b/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt index f4f143e..b421fb8 100644 --- a/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt +++ b/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt @@ -6,7 +6,7 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.hako.base.extensions.autoNotify import com.hako.photolist.R -import com.hako.photolist.model.PhotoViewable +import com.hako.photolist.model.Photo import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.item_photo_card.view.* import org.koin.core.KoinComponent @@ -15,7 +15,7 @@ import kotlin.properties.Delegates class PhotolistAdapter : RecyclerView.Adapter() { - private var items by Delegates.observable(emptyList()) { _, oldList, newList -> + private var items by Delegates.observable(emptyList()) { _, oldList, newList -> autoNotify(oldList, newList) { old, new -> old.id == new.id } notifyDataSetChanged() } @@ -29,7 +29,7 @@ class PhotolistAdapter : RecyclerView.Adapter() { fun getItem(position: Int) = items[position] - fun addAll(list: List) { + fun addAll(list: List) { items = list } @@ -47,7 +47,7 @@ class PhotoViewHolder(private val view: View) : private val picasso: Picasso by inject() - fun bind(photo: PhotoViewable) = with(view) { + fun bind(photo: Photo) = with(view) { picasso.load(photo.photoUrl) .placeholder(R.drawable.img_photo_placeholder) .fit() diff --git a/userlist/build.gradle b/userlist/build.gradle index 4bf1bc9..f0af555 100644 --- a/userlist/build.gradle +++ b/userlist/build.gradle @@ -1,6 +1,12 @@ apply plugin: 'com.android.library' apply from: '../core.gradle' +android { + defaultConfig { + buildConfigField "String", "DB_NAME", '"userlist.db"' + } +} + dependencies { implementation project(':base') testImplementation project(':testing') diff --git a/userlist/src/androidTest/java/com/hako/userlist/feature/Mocks.kt b/userlist/src/androidTest/java/com/hako/userlist/feature/Mocks.kt index a6c771f..90069b0 100644 --- a/userlist/src/androidTest/java/com/hako/userlist/feature/Mocks.kt +++ b/userlist/src/androidTest/java/com/hako/userlist/feature/Mocks.kt @@ -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) : UserDao { @@ -22,8 +22,8 @@ class MockUserDao(private val userList: List) : UserDao { override fun nukeDatabase() {} } -class MockUserApi(private val userList: List) : UserlistRemoteApi { +class MockUserApi(private val userRemoteList: List) : UserlistRemoteApi { override fun getUsers() = Single.fromCallable { getAllUsers() } - private fun getAllUsers() = userList + private fun getAllUsers() = userRemoteList } \ No newline at end of file diff --git a/userlist/src/androidTest/java/com/hako/userlist/feature/UserlistFragmentTest.kt b/userlist/src/androidTest/java/com/hako/userlist/feature/UserlistFragmentTest.kt index 77c91d2..387d746 100644 --- a/userlist/src/androidTest/java/com/hako/userlist/feature/UserlistFragmentTest.kt +++ b/userlist/src/androidTest/java/com/hako/userlist/feature/UserlistFragmentTest.kt @@ -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", diff --git a/userlist/src/main/AndroidManifest.xml b/userlist/src/main/AndroidManifest.xml index d577ea7..373f62d 100644 --- a/userlist/src/main/AndroidManifest.xml +++ b/userlist/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ + package="com.hako.userlist" /> diff --git a/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt b/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt index f31580e..5590279 100644 --- a/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt +++ b/userlist/src/main/java/com/hako/userlist/di/UserlistModules.kt @@ -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().userDao() } + factory { get().getClient(UserlistRemoteApi::class.java) } - factory { GetUsers(get()) } + factory { GetUsers(get(), get()) } factory { GetFavoriteUsers(get()) } factory { SetFavoriteStatus(get()) } diff --git a/userlist/src/main/java/com/hako/userlist/domain/clients/LocalClient.kt b/userlist/src/main/java/com/hako/userlist/domain/clients/LocalClient.kt new file mode 100644 index 0000000..a7b4fd7 --- /dev/null +++ b/userlist/src/main/java/com/hako/userlist/domain/clients/LocalClient.kt @@ -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 +} \ No newline at end of file diff --git a/base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserDao.kt similarity index 89% rename from base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt rename to userlist/src/main/java/com/hako/userlist/domain/datasource/UserDao.kt index f373651..7b9399b 100644 --- a/base/src/main/java/com/hako/base/domain/database/dao/UserDao.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserDao.kt @@ -1,10 +1,10 @@ -package com.hako.base.domain.database.dao +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.base.domain.database.entities.UserEntity +import com.hako.userlist.model.UserEntity @Dao interface UserDao { diff --git a/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt index 8ffd5b5..785bf01 100644 --- a/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/datasource/UserlistRemoteApi.kt @@ -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> + fun getUsers(): Single> } \ No newline at end of file diff --git a/userlist/src/main/java/com/hako/userlist/domain/usecase/GetFavoriteUsers.kt b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetFavoriteUsers.kt index c656e6e..2358730 100644 --- a/userlist/src/main/java/com/hako/userlist/domain/usecase/GetFavoriteUsers.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetFavoriteUsers.kt @@ -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) -> Unit, + onSuccess: (List) -> Unit, onEmpty: () -> Unit, onError: (Throwable) -> Unit ) { diff --git a/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt index 28ec6e3..027a386 100644 --- a/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/usecase/GetUsers.kt @@ -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) -> Unit, + onSuccess: (List) -> Unit, onError: (Throwable) -> Unit, onLoading: () -> Unit, onEmpty: () -> Unit diff --git a/userlist/src/main/java/com/hako/userlist/domain/usecase/SetFavoriteStatus.kt b/userlist/src/main/java/com/hako/userlist/domain/usecase/SetFavoriteStatus.kt index 6afdcac..23293d5 100644 --- a/userlist/src/main/java/com/hako/userlist/domain/usecase/SetFavoriteStatus.kt +++ b/userlist/src/main/java/com/hako/userlist/domain/usecase/SetFavoriteStatus.kt @@ -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 diff --git a/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt index db86a70..6b87640 100644 --- a/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt +++ b/userlist/src/main/java/com/hako/userlist/feature/UserlistFragment.kt @@ -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) { + private fun handleFetchSuccess(users: List) { listAdapter.addAll(users) } diff --git a/userlist/src/main/java/com/hako/userlist/model/UserModels.kt b/userlist/src/main/java/com/hako/userlist/model/UserModels.kt index 0fe1412..746e5d3 100644 --- a/userlist/src/main/java/com/hako/userlist/model/UserModels.kt +++ b/userlist/src/main/java/com/hako/userlist/model/UserModels.kt @@ -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) diff --git a/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt b/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt index 600cca4..db96952 100644 --- a/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt +++ b/userlist/src/main/java/com/hako/userlist/viewmodel/UserlistViewmodel.kt @@ -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>>() + val userList = MutableLiveData>>() val favoriteError = MutableLiveData() val emptyMessage = MutableLiveData() val requestStatus = MutableLiveData() diff --git a/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt index 25dd99f..a9719f7 100644 --- a/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt +++ b/userlist/src/main/java/com/hako/userlist/widget/UserlistAdapter.kt @@ -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() { - private var items by Delegates.observable(emptyList()) { _, oldList, newList -> + private var items by Delegates.observable(emptyList()) { _, 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() { fun getItem(position: Int) = items[position] - fun addAll(list: List) { + fun addAll(list: List) { items = list } @@ -46,12 +46,12 @@ class UserlistAdapter : RecyclerView.Adapter() { 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) { diff --git a/versions.gradle b/versions.gradle index ec55c79..defa9a7 100644 --- a/versions.gradle +++ b/versions.gradle @@ -3,6 +3,7 @@ ext.deps = [:] def versions = [:] versions.kotlin = "1.3.41" versions.gradle = "3.5.3" +versions.room = "2.2.3" def deps = [:] @@ -22,6 +23,11 @@ kotlin.version = "$versions.kotlin" kotlin.std_lib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.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 static def addRepos(RepositoryHandler handler) {