Refactoring
This commit is contained in:
@@ -6,6 +6,7 @@ import com.ericampire.android.androidstudycase.app.room.AppDatabase
|
||||
import com.ericampire.android.androidstudycase.data.room.AnimatorDao
|
||||
import com.ericampire.android.androidstudycase.data.room.BlogDao
|
||||
import com.ericampire.android.androidstudycase.data.room.LottieFilesDao
|
||||
import com.ericampire.android.androidstudycase.data.room.UserDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -25,6 +26,11 @@ object RoomModule {
|
||||
return db.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideUserDao(appDatabase: AppDatabase): UserDao {
|
||||
return appDatabase.userDao
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideBlogDao(appDatabase: AppDatabase): BlogDao {
|
||||
return appDatabase.blogDao
|
||||
|
||||
@@ -2,22 +2,23 @@ package com.ericampire.android.androidstudycase.app.room
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import com.ericampire.android.androidstudycase.data.room.AnimatorDao
|
||||
import com.ericampire.android.androidstudycase.data.room.BlogDao
|
||||
import com.ericampire.android.androidstudycase.data.room.LottieFilesDao
|
||||
import com.ericampire.android.androidstudycase.data.room.UserDao
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Animator
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Blog
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Lottiefile
|
||||
import com.ericampire.android.androidstudycase.util.room.DateConverter
|
||||
import com.ericampire.android.androidstudycase.domain.entity.User
|
||||
|
||||
@Database(
|
||||
entities = [Blog::class, Animator::class, Lottiefile::class],
|
||||
entities = [Blog::class, Animator::class, Lottiefile::class, User::class],
|
||||
version = 2,
|
||||
exportSchema = false
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract val blogDao: BlogDao
|
||||
abstract val userDao: UserDao
|
||||
abstract val animatorDao: AnimatorDao
|
||||
abstract val lottieFileDao: LottieFilesDao
|
||||
}
|
||||
-5
@@ -2,7 +2,6 @@ package com.ericampire.android.androidstudycase.presentation.screen.home.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.MaterialTheme
|
||||
@@ -12,13 +11,11 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.airbnb.lottie.compose.*
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Lottiefile
|
||||
import com.ericampire.android.androidstudycase.presentation.screen.explore.ui.LottieFileItemView
|
||||
import com.ericampire.android.androidstudycase.presentation.theme.AndroidStudyCaseTheme
|
||||
import com.ericampire.android.androidstudycase.presentation.theme.AppColor
|
||||
import com.ericampire.android.androidstudycase.util.LottieFileProvider
|
||||
@@ -70,13 +67,11 @@ fun FeaturedLottieFileView(
|
||||
maxLines = 1,
|
||||
text = lottiefile.name,
|
||||
style = MaterialTheme.typography.h6,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = lottiefile.createdBy?.name ?: "",
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -5,6 +5,8 @@ import androidx.compose.ui.graphics.Color
|
||||
|
||||
|
||||
object AppColor {
|
||||
val Teal = Color(0xFF1C7373)
|
||||
val PaleBlue = Color(0xFFD3F6F6)
|
||||
val PrimaryColor = Color(0xFF2BEAED)
|
||||
val PrimaryColorDark = Color(0xFF006B78)
|
||||
val Purple700 = Color(0xFF3700B3)
|
||||
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
package com.ericampire.android.androidstudycase.data.datasource.animator
|
||||
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Animator
|
||||
import com.ericampire.android.androidstudycase.util.Result
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
||||
interface AnimatorDataSource {
|
||||
suspend fun findAll(): List<Animator>
|
||||
fun findAll(): Flow<Result<List<Animator>>>
|
||||
suspend fun save(animator: Animator)
|
||||
}
|
||||
+7
-2
@@ -2,14 +2,19 @@ package com.ericampire.android.androidstudycase.data.datasource.animator
|
||||
|
||||
import com.ericampire.android.androidstudycase.data.room.AnimatorDao
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Animator
|
||||
import com.ericampire.android.androidstudycase.util.Result
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
class LocalAnimatorDataSource @Inject constructor(
|
||||
private val animatorDao: AnimatorDao
|
||||
) : AnimatorDataSource {
|
||||
|
||||
override suspend fun findAll(): List<Animator> {
|
||||
return animatorDao.findAll()
|
||||
override fun findAll(): Flow<Result<List<Animator>>> {
|
||||
return animatorDao.findAll().map {
|
||||
Result.Success(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun save(animator: Animator) {
|
||||
|
||||
+9
-2
@@ -13,9 +13,16 @@ import javax.inject.Inject
|
||||
class RemoteAnimatorDataSource @Inject constructor(
|
||||
private val httpClient: HttpClient
|
||||
) : AnimatorDataSource {
|
||||
override suspend fun findAll(): List<Animator> {
|
||||
|
||||
override fun findAll(): Flow<Result<List<Animator>>> {
|
||||
return flow {
|
||||
try {
|
||||
val data = httpClient.get<AnimatorApiResponse>(ApiUrl.Animator.featured)
|
||||
return data.animatorAnimatorData.featuredAnimators.results
|
||||
emit(Result.Success(data.animatorAnimatorData.featuredAnimators.results))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun save(animator: Animator) {
|
||||
|
||||
+10
@@ -9,9 +9,12 @@ import com.ericampire.android.androidstudycase.data.datasource.blog.RemoteBlogDa
|
||||
import com.ericampire.android.androidstudycase.data.datasource.lottiefiles.LocalLottieFileDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.lottiefiles.LottieFileDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.lottiefiles.RemoteLottieFileDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.user.LocalUserDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.user.UserDataSource
|
||||
import com.ericampire.android.androidstudycase.data.room.AnimatorDao
|
||||
import com.ericampire.android.androidstudycase.data.room.BlogDao
|
||||
import com.ericampire.android.androidstudycase.data.room.LottieFilesDao
|
||||
import com.ericampire.android.androidstudycase.data.room.UserDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -62,6 +65,13 @@ object DataSourceModule {
|
||||
return LocalBlogDataSource(dao)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideLocalUserDataSource(
|
||||
dao: UserDao
|
||||
): UserDataSource {
|
||||
return LocalUserDataSource(dao)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideRemoteAnimatorDataSource(
|
||||
httpClient: HttpClient
|
||||
|
||||
+12
@@ -6,12 +6,15 @@ import com.ericampire.android.androidstudycase.data.datasource.blog.LocalBlogDat
|
||||
import com.ericampire.android.androidstudycase.data.datasource.blog.RemoteBlogDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.lottiefiles.LocalLottieFileDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.lottiefiles.RemoteLottieFileDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.user.LocalUserDataSource
|
||||
import com.ericampire.android.androidstudycase.data.repository.AnimatorRepositoryImpl
|
||||
import com.ericampire.android.androidstudycase.data.repository.BlogRepositoryImpl
|
||||
import com.ericampire.android.androidstudycase.data.repository.LottieFileRepositoryImpl
|
||||
import com.ericampire.android.androidstudycase.data.repository.UserRepositoryImpl
|
||||
import com.ericampire.android.androidstudycase.domain.repository.AnimatorRepository
|
||||
import com.ericampire.android.androidstudycase.domain.repository.BlogRepository
|
||||
import com.ericampire.android.androidstudycase.domain.repository.LottieFileRepository
|
||||
import com.ericampire.android.androidstudycase.domain.repository.UserRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
@@ -33,6 +36,15 @@ object RepositoryModule {
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideUserRepository(
|
||||
localDataSource: LocalUserDataSource,
|
||||
): UserRepository {
|
||||
return UserRepositoryImpl(
|
||||
localDataSource = localDataSource,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideLottieFileRepository(
|
||||
localDataSource: LocalLottieFileDataSource,
|
||||
|
||||
+10
-12
@@ -6,8 +6,6 @@ import com.ericampire.android.androidstudycase.domain.repository.AnimatorReposit
|
||||
import com.ericampire.android.androidstudycase.util.Result
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@@ -16,19 +14,19 @@ class AnimatorRepositoryImpl @Inject constructor(
|
||||
private val localDataSource: AnimatorDataSource,
|
||||
) : AnimatorRepository {
|
||||
override fun findAll(): Flow<Result<List<Animator>>> {
|
||||
return flow {
|
||||
try {
|
||||
refreshData()
|
||||
emit(Result.Success(localDataSource.findAll()))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
return localDataSource.findAll()
|
||||
}
|
||||
|
||||
private suspend fun refreshData() {
|
||||
remoteDataSource.findAll().forEach {
|
||||
localDataSource.save(it)
|
||||
private fun refreshData() {
|
||||
suspend {
|
||||
remoteDataSource.findAll().collect {
|
||||
if (it is Result.Success) {
|
||||
it.data.forEach { animator ->
|
||||
localDataSource.save(animator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-14
@@ -1,14 +1,11 @@
|
||||
package com.ericampire.android.androidstudycase.data.repository
|
||||
|
||||
import com.ericampire.android.androidstudycase.data.datasource.animator.AnimatorDataSource
|
||||
import com.ericampire.android.androidstudycase.data.datasource.blog.BlogDataSource
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Animator
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Blog
|
||||
import com.ericampire.android.androidstudycase.domain.repository.AnimatorRepository
|
||||
import com.ericampire.android.androidstudycase.domain.repository.BlogRepository
|
||||
import com.ericampire.android.androidstudycase.util.Result
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import javax.inject.Inject
|
||||
|
||||
class BlogRepositoryImpl @Inject constructor(
|
||||
@@ -16,19 +13,19 @@ class BlogRepositoryImpl @Inject constructor(
|
||||
private val localDataSource: BlogDataSource,
|
||||
) : BlogRepository {
|
||||
override fun findAll(): Flow<Result<List<Blog>>> {
|
||||
return flow {
|
||||
try {
|
||||
refreshData()
|
||||
emit(Result.Success(localDataSource.findAll()))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
return localDataSource.findAll()
|
||||
}
|
||||
|
||||
private suspend fun refreshData() {
|
||||
remoteDataSource.findAll().forEach {
|
||||
localDataSource.save(it)
|
||||
private fun refreshData() {
|
||||
suspend {
|
||||
remoteDataSource.findAll().collect {
|
||||
if (it is Result.Success) {
|
||||
it.data.forEach { blog ->
|
||||
localDataSource.save(blog)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-29
@@ -5,52 +5,39 @@ import com.ericampire.android.androidstudycase.domain.entity.Lottiefile
|
||||
import com.ericampire.android.androidstudycase.domain.repository.LottieFileRepository
|
||||
import com.ericampire.android.androidstudycase.util.Result
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import javax.inject.Inject
|
||||
|
||||
class LottieFileRepositoryImpl @Inject constructor(
|
||||
private val localDataSource: LottieFileDataSource,
|
||||
private val remoteDataSource: LottieFileDataSource,
|
||||
) : LottieFileRepository {
|
||||
|
||||
override fun findRecent(): Flow<Result<List<Lottiefile>>> {
|
||||
return flow {
|
||||
try {
|
||||
val recentFiles = remoteDataSource.findRecent()
|
||||
refreshData(recentFiles)
|
||||
emit(Result.Success(localDataSource.findRecent()))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
return recentFiles
|
||||
}
|
||||
|
||||
private suspend fun refreshData(data: List<Lottiefile>) {
|
||||
data.forEach {
|
||||
localDataSource.save(it)
|
||||
private fun refreshData(data: Flow<Result<List<Lottiefile>>>) {
|
||||
suspend {
|
||||
data.collect {
|
||||
if (it is Result.Success) {
|
||||
it.data.forEach { file -> localDataSource.save(file) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun findPopular(): Flow<Result<List<Lottiefile>>> {
|
||||
return flow {
|
||||
try {
|
||||
val recentFiles = remoteDataSource.findPopular()
|
||||
refreshData(recentFiles)
|
||||
emit(Result.Success(localDataSource.findPopular()))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
val files = remoteDataSource.findPopular()
|
||||
refreshData(files)
|
||||
return files
|
||||
}
|
||||
|
||||
override fun findFeatured(): Flow<Result<List<Lottiefile>>> {
|
||||
return flow {
|
||||
try {
|
||||
val recentFiles = remoteDataSource.findFeatured()
|
||||
refreshData(recentFiles)
|
||||
emit(Result.Success(localDataSource.findFeatured()))
|
||||
} catch (e: Exception) {
|
||||
emit(Result.Error(e))
|
||||
}
|
||||
}
|
||||
val files = remoteDataSource.findFeatured()
|
||||
refreshData(files)
|
||||
return files
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Animator
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface AnimatorDao {
|
||||
@@ -13,5 +14,5 @@ interface AnimatorDao {
|
||||
suspend fun save(animator: Animator)
|
||||
|
||||
@Query("SELECT * FROM Animator")
|
||||
suspend fun findAll(): List<Animator>
|
||||
fun findAll(): Flow<List<Animator>>
|
||||
}
|
||||
+4
-3
@@ -5,6 +5,7 @@ import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.ericampire.android.androidstudycase.domain.entity.Lottiefile
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface LottieFilesDao {
|
||||
@@ -12,11 +13,11 @@ interface LottieFilesDao {
|
||||
suspend fun save(lottiefile: Lottiefile)
|
||||
|
||||
@Query("SELECT * FROM Lottiefile")
|
||||
suspend fun findPopular(): List<Lottiefile>
|
||||
fun findPopular(): Flow<List<Lottiefile>>
|
||||
|
||||
@Query("SELECT * FROM Lottiefile")
|
||||
suspend fun findFeatured(): List<Lottiefile>
|
||||
fun findFeatured(): Flow<List<Lottiefile>>
|
||||
|
||||
@Query("SELECT * FROM Lottiefile")
|
||||
suspend fun findRecent(): List<Lottiefile>
|
||||
fun findRecent(): Flow<List<Lottiefile>>
|
||||
}
|
||||
+4
-5
@@ -1,7 +1,8 @@
|
||||
package com.ericampire.android.androidstudycase.domain.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -40,11 +41,9 @@ data class Lottiefile(
|
||||
var gifUrl: String? = "",
|
||||
var videoUrl: String? = "",
|
||||
var imageUrl: String? = "",
|
||||
var name: String = "",
|
||||
// @TypeConverters(DateConverter::class)
|
||||
// @Serializable(with = DateSerializer::class)
|
||||
@ColumnInfo(name = "file_name") var name: String = "",
|
||||
var createdAt: String = "",
|
||||
@Ignore var createdBy: Animator? = null
|
||||
@Embedded var createdBy: Animator? = null
|
||||
)
|
||||
|
||||
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package com.ericampire.android.androidstudycase.domain.usecase
|
||||
|
||||
internal class SaveUserUseCaseTest
|
||||
@@ -12,4 +12,6 @@
|
||||
<string name="txt_browse_all">Browse all free Animation</string>
|
||||
<string name="txt_browse_all_desc">Access to 1000s of Lottie animations</string>
|
||||
<string name="txt_go_to_explore">Go to Explore</string>
|
||||
<string name="txt_login">Login</string>
|
||||
<string name="txt_hello_stranger">Hello Stranger</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user