Skip to content

Commit 0bfda2b

Browse files
committed
✨ implement default coroutine dispatcher in repositories
- convert USE CASES to Singleton
1 parent 7557471 commit 0bfda2b

File tree

10 files changed

+79
-22
lines changed

10 files changed

+79
-22
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ android {
4242
dependencies {
4343
implementation 'androidx.core:core-ktx:1.7.0'
4444
implementation 'androidx.appcompat:appcompat:1.4.1'
45-
implementation 'com.google.android.material:material:1.6.0'
45+
implementation 'com.google.android.material:material:1.6.1'
4646
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
4747
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
4848
testImplementation 'junit:junit:4.13.2'

app/src/main/java/com/juarez/upaxdemo/di/AppModule.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,37 @@ import com.google.firebase.firestore.CollectionReference
44
import com.google.firebase.storage.StorageReference
55
import com.juarez.upaxdemo.map.data.LocationsRepository
66
import com.juarez.upaxdemo.map.data.LocationsRepositoryImp
7+
import com.juarez.upaxdemo.movies.data.MovieLocalDataSource
8+
import com.juarez.upaxdemo.movies.data.MovieRemoteDataSource
9+
import com.juarez.upaxdemo.movies.data.MovieRepository
10+
import com.juarez.upaxdemo.movies.data.MovieRepositoryImpl
711
import com.juarez.upaxdemo.photo.data.ImagesRepository
812
import com.juarez.upaxdemo.photo.data.ImagesRepositoryImp
913
import dagger.Module
1014
import dagger.Provides
1115
import dagger.hilt.InstallIn
1216
import dagger.hilt.components.SingletonComponent
17+
import kotlinx.coroutines.Dispatchers
1318

1419
@Module
1520
@InstallIn(SingletonComponent::class)
1621
object AppModule {
1722

1823
@Provides
1924
fun provideLocationsRepository(collectionReference: CollectionReference): LocationsRepository {
20-
return LocationsRepositoryImp(collectionReference)
25+
return LocationsRepositoryImp(collectionReference, Dispatchers.IO)
2126
}
2227

2328
@Provides
2429
fun provideImagesRepository(storageReference: StorageReference): ImagesRepository {
25-
return ImagesRepositoryImp(storageReference)
30+
return ImagesRepositoryImp(storageReference, Dispatchers.IO)
31+
}
32+
33+
@Provides
34+
fun provideMovieRepository(
35+
remoteDataSource: MovieRemoteDataSource,
36+
localDataSource: MovieLocalDataSource
37+
): MovieRepository {
38+
return MovieRepositoryImpl(remoteDataSource, localDataSource, Dispatchers.IO)
2639
}
2740
}

app/src/main/java/com/juarez/upaxdemo/map/data/LocationsRepository.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package com.juarez.upaxdemo.map.data
33
import com.google.firebase.firestore.CollectionReference
44
import com.google.firebase.firestore.ktx.toObjects
55
import com.juarez.upaxdemo.utils.Resource
6+
import kotlinx.coroutines.CoroutineDispatcher
7+
import kotlinx.coroutines.Dispatchers
68
import kotlinx.coroutines.flow.Flow
79
import kotlinx.coroutines.flow.flow
810
import kotlinx.coroutines.tasks.await
11+
import kotlinx.coroutines.withContext
912
import javax.inject.Inject
1013

1114
interface LocationsRepository {
@@ -15,16 +18,17 @@ interface LocationsRepository {
1518

1619
class LocationsRepositoryImp @Inject constructor(
1720
private val locationsCollection: CollectionReference,
21+
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.IO
1822
) : LocationsRepository {
1923

2024
override suspend fun saveLocation(location: Location) {
21-
locationsCollection.add(location).await()
25+
withContext(defaultDispatcher) { locationsCollection.add(location).await() }
2226
}
2327

2428
override fun getLocations(): Flow<Resource<List<Location>>> = flow {
2529
emit(Resource.Loading(true))
2630
try {
27-
val snapshot = locationsCollection.get().await()
31+
val snapshot = withContext(defaultDispatcher) { locationsCollection.get().await() }
2832
val locations = snapshot.toObjects<Location>()
2933
emit(Resource.Success(locations))
3034
} catch (e: Exception) {

app/src/main/java/com/juarez/upaxdemo/movies/data/MovieRepository.kt

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,77 @@ package com.juarez.upaxdemo.movies.data
22

33
import com.juarez.upaxdemo.utils.NetworkResponse
44
import com.juarez.upaxdemo.utils.Resource
5+
import kotlinx.coroutines.CoroutineDispatcher
6+
import kotlinx.coroutines.Dispatchers
57
import kotlinx.coroutines.flow.Flow
68
import kotlinx.coroutines.flow.flow
79
import kotlinx.coroutines.flow.map
10+
import kotlinx.coroutines.withContext
811
import javax.inject.Inject
912

10-
class MovieRepository @Inject constructor(
13+
interface MovieRepository {
14+
fun getAllPopularMovies(): Flow<Resource<List<Movie>>>
15+
fun getAllTopRatedMovies(): Flow<Resource<List<Movie>>>
16+
fun getMovieDetail(movieId: Int): Flow<Resource<Movie>>
17+
val popularMovies: Flow<List<Movie>>
18+
val topRatedMovies: Flow<List<Movie>>
19+
}
20+
21+
class MovieRepositoryImpl @Inject constructor(
1122
private val remoteDataSource: MovieRemoteDataSource,
1223
private val localDataSource: MovieLocalDataSource,
13-
) {
24+
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.IO
25+
) : MovieRepository {
1426

15-
fun getAllPopularMovies(): Flow<Resource<List<Movie>>> = flow {
27+
override fun getAllPopularMovies(): Flow<Resource<List<Movie>>> = flow {
1628
emit(Resource.Loading(true))
1729
val total = localDataSource.getTotalPopularMovies()
1830
if (total < 1) {
19-
val response = remoteDataSource.getPopularMoviesAPI()
31+
val response = withContext(defaultDispatcher) { remoteDataSource.getPopularMoviesAPI() }
32+
2033
if (response is NetworkResponse.Success) {
2134
localDataSource.saveMovies(response.data!!.map { it.toEntity("popular") })
2235
} else emit(Resource.Error(response.message!!))
2336
}
2437
emit(Resource.Loading(false))
2538
}
2639

27-
fun getAllTopRatedMovies(): Flow<Resource<List<Movie>>> = flow {
40+
override fun getAllTopRatedMovies(): Flow<Resource<List<Movie>>> = flow {
2841
emit(Resource.Loading(true))
2942
val total = localDataSource.getTotalTopRatedMovies()
3043
if (total < 1) {
31-
val response = remoteDataSource.getTopRatedMovies()
44+
val response = withContext(defaultDispatcher) { remoteDataSource.getTopRatedMovies() }
45+
3246
if (response is NetworkResponse.Success) {
3347
localDataSource.saveMovies(response.data!!.map { it.toEntity("top") })
3448
} else emit(Resource.Error(response.message!!))
3549
}
3650
emit(Resource.Loading(false))
3751
}
3852

39-
fun getMovieDetail(movieId: Int): Flow<Resource<Movie>> = flow {
53+
override fun getMovieDetail(movieId: Int): Flow<Resource<Movie>> = flow {
4054
emit(Resource.Loading(true))
4155
val movie = localDataSource.getMovieById(movieId)
4256
if (movie != null) {
4357
emit(Resource.Success(movie.toModel()))
4458
} else {
45-
val response = remoteDataSource.getMovieDetail(movieId)
59+
val response = withContext(defaultDispatcher) {
60+
remoteDataSource.getMovieDetail(movieId)
61+
}
62+
4663
if (response is NetworkResponse.Success) emit(Resource.Success(response.data!!))
4764
else emit(Resource.Error(response.message!!))
4865
}
4966
emit(Resource.Loading(false))
5067
}
5168

52-
val popularMovies: Flow<List<Movie>> = localDataSource.popularMovies.map { movieEntities ->
53-
movieEntities.map { movieEntity -> movieEntity.toModel() }
54-
}
69+
override val popularMovies: Flow<List<Movie>> =
70+
localDataSource.popularMovies.map { movieEntities ->
71+
movieEntities.map { movieEntity -> movieEntity.toModel() }
72+
}
5573

56-
val topRatedMovies: Flow<List<Movie>> = localDataSource.topRatedMovies.map { movieEntities ->
57-
movieEntities.map { movieEntity -> movieEntity.toModel() }
58-
}
74+
override val topRatedMovies: Flow<List<Movie>> =
75+
localDataSource.topRatedMovies.map { movieEntities ->
76+
movieEntities.map { movieEntity -> movieEntity.toModel() }
77+
}
5978
}

app/src/main/java/com/juarez/upaxdemo/movies/domain/GetMovieDetailUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import com.juarez.upaxdemo.movies.data.MovieRepository
55
import com.juarez.upaxdemo.utils.Resource
66
import kotlinx.coroutines.flow.Flow
77
import javax.inject.Inject
8+
import javax.inject.Singleton
89

10+
@Singleton
911
class GetMovieDetailUseCase @Inject constructor(private val repository: MovieRepository) {
1012
operator fun invoke(movieId: Int): Flow<Resource<Movie>> = repository.getMovieDetail(movieId)
1113
}

app/src/main/java/com/juarez/upaxdemo/movies/domain/GetPopularMoviesUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import com.juarez.upaxdemo.movies.data.MovieRepository
55
import com.juarez.upaxdemo.utils.Resource
66
import kotlinx.coroutines.flow.Flow
77
import javax.inject.Inject
8+
import javax.inject.Singleton
89

10+
@Singleton
911
class GetPopularMoviesUseCase @Inject constructor(private val repository: MovieRepository) {
1012
operator fun invoke(): Flow<Resource<List<Movie>>> = repository.getAllPopularMovies()
1113
}

app/src/main/java/com/juarez/upaxdemo/movies/domain/GetTopRatedMoviesUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import com.juarez.upaxdemo.movies.data.MovieRepository
55
import com.juarez.upaxdemo.utils.Resource
66
import kotlinx.coroutines.flow.Flow
77
import javax.inject.Inject
8+
import javax.inject.Singleton
89

10+
@Singleton
911
class GetTopRatedMoviesUseCase @Inject constructor(private val repository: MovieRepository) {
1012
operator fun invoke(): Flow<Resource<List<Movie>>> = repository.getAllTopRatedMovies()
1113
}

app/src/main/java/com/juarez/upaxdemo/movies/domain/PopularMoviesUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import com.juarez.upaxdemo.movies.data.Movie
44
import com.juarez.upaxdemo.movies.data.MovieRepository
55
import kotlinx.coroutines.flow.Flow
66
import javax.inject.Inject
7+
import javax.inject.Singleton
78

9+
@Singleton
810
class PopularMoviesUseCase @Inject constructor(private val repository: MovieRepository) {
911
operator fun invoke(): Flow<List<Movie>> = repository.popularMovies
1012
}

app/src/main/java/com/juarez/upaxdemo/movies/domain/TopRatedMoviesUseCase.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import com.juarez.upaxdemo.movies.data.Movie
44
import com.juarez.upaxdemo.movies.data.MovieRepository
55
import kotlinx.coroutines.flow.Flow
66
import javax.inject.Inject
7+
import javax.inject.Singleton
78

9+
@Singleton
810
class TopRatedMoviesUseCase @Inject constructor(private val repository: MovieRepository) {
911
operator fun invoke(): Flow<List<Movie>> = repository.topRatedMovies
1012
}

app/src/main/java/com/juarez/upaxdemo/photo/data/ImagesRepository.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import android.net.Uri
44
import com.google.firebase.storage.StorageReference
55
import com.juarez.upaxdemo.utils.FirebaseResult
66
import com.juarez.upaxdemo.utils.Resource
7+
import kotlinx.coroutines.CoroutineDispatcher
8+
import kotlinx.coroutines.Dispatchers
79
import kotlinx.coroutines.flow.Flow
810
import kotlinx.coroutines.flow.flow
911
import kotlinx.coroutines.tasks.await
12+
import kotlinx.coroutines.withContext
1013
import javax.inject.Inject
1114

1215
interface ImagesRepository {
@@ -17,17 +20,23 @@ interface ImagesRepository {
1720

1821
class ImagesRepositoryImp @Inject constructor(
1922
private val storageReference: StorageReference,
23+
private val defaultDispatcher: CoroutineDispatcher = Dispatchers.IO
2024
) : ImagesRepository {
25+
2126
override fun uploadImage(uri: Uri, fileName: String): Flow<Resource<Boolean>> = flow {
2227
emit(Resource.Loading(true))
23-
storageReference.child("images/${fileName}").putFile(uri).await()
28+
withContext(defaultDispatcher) {
29+
storageReference.child("images/${fileName}").putFile(uri).await()
30+
}
2431
emit(Resource.Success(true))
2532
emit(Resource.Loading(false))
2633
}
2734

2835
override fun getImages(): Flow<FirebaseResult<MutableList<Photo>>> = flow {
2936
emit(FirebaseResult.Loading(true))
30-
val images = storageReference.child("images/").listAll().await()
37+
val images = withContext(defaultDispatcher) {
38+
storageReference.child("images/").listAll().await()
39+
}
3140
val imageUrls = mutableListOf<Photo>()
3241
images.items.forEach { img ->
3342
val url = img.downloadUrl.await()
@@ -41,7 +50,9 @@ class ImagesRepositoryImp @Inject constructor(
4150

4251
override fun deleteImage(filename: String): Flow<FirebaseResult<Boolean>> = flow {
4352
emit(FirebaseResult.Loading(true))
44-
storageReference.child(("images/${filename}")).delete().await()
53+
withContext(defaultDispatcher) {
54+
storageReference.child(("images/${filename}")).delete().await()
55+
}
4556
emit(FirebaseResult.Success(true))
4657
emit(FirebaseResult.Loading(false))
4758
}

0 commit comments

Comments
 (0)