Skip to content

Commit

Permalink
Room multiplatform
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbel committed May 14, 2024
1 parent b100280 commit 5a1598a
Show file tree
Hide file tree
Showing 43 changed files with 425 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")

package org.michaelbel.movies.interactor

import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import org.michaelbel.movies.common.list.MovieList
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.Query

actual interface MovieBlockingInteractor {

fun moviesPagingData(
movieList: MovieList
): Flow<PagingData<MoviePojo>>

fun moviesPagingData(
searchQuery: Query
): Flow<PagingData<MoviePojo>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.michaelbel.movies.interactor.di

import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
import org.michaelbel.movies.analytics.di.moviesAnalyticsKoinModule
import org.michaelbel.movies.common.dispatchers.di.dispatchersKoinModule
import org.michaelbel.movies.interactor.MovieBlockingInteractor
import org.michaelbel.movies.interactor.impl.MovieBlockingInteractorImpl
import org.michaelbel.movies.persistence.database.di.moviesDatabaseKoinModule
import org.michaelbel.movies.repository.di.repositoryBlockingKoinModule

actual val interactorBlockingKoinModule = module {
includes(
dispatchersKoinModule,
repositoryBlockingKoinModule,
moviesDatabaseKoinModule,
moviesAnalyticsKoinModule
)
singleOf(::MovieBlockingInteractorImpl) { bind<MovieBlockingInteractor>() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@file:OptIn(ExperimentalPagingApi::class)

package org.michaelbel.movies.interactor.impl

import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow
import org.michaelbel.movies.common.list.MovieList
import org.michaelbel.movies.interactor.LocaleInteractor
import org.michaelbel.movies.interactor.MovieBlockingInteractor
import org.michaelbel.movies.interactor.ktx.nameOrLocalList
import org.michaelbel.movies.interactor.remote.FeedMoviesRemoteMediator
import org.michaelbel.movies.interactor.remote.SearchMoviesRemoteMediator
import org.michaelbel.movies.network.model.MovieResponse
import org.michaelbel.movies.persistence.database.MoviesDatabase
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.Query
import org.michaelbel.movies.repository.MovieBlockingRepository
import org.michaelbel.movies.repository.MovieRepository
import org.michaelbel.movies.repository.PagingKeyRepository
import org.michaelbel.movies.repository.SearchRepository

internal class MovieBlockingInteractorImpl(
private val localeInteractor: LocaleInteractor,
private val searchRepository: SearchRepository,
private val movieRepository: MovieRepository,
private val movieBlockingRepository: MovieBlockingRepository,
private val pagingKeyRepository: PagingKeyRepository,
private val moviesDatabase: MoviesDatabase
): MovieBlockingInteractor {

override fun moviesPagingData(
movieList: MovieList
): Flow<PagingData<MoviePojo>> {
return Pager(
config = PagingConfig(
pageSize = MovieResponse.DEFAULT_PAGE_SIZE,
enablePlaceholders = true
),
remoteMediator = FeedMoviesRemoteMediator(
localeInteractor = localeInteractor,
movieRepository = movieRepository,
pagingKeyRepository = pagingKeyRepository,
moviesDatabase = moviesDatabase,
pagingKey = MovieList.name(movieList)
),
pagingSourceFactory = { movieBlockingRepository.moviesPagingSource(movieList.nameOrLocalList) }
).flow
}

override fun moviesPagingData(
searchQuery: Query
): Flow<PagingData<MoviePojo>> {
return Pager(
config = PagingConfig(
pageSize = MovieResponse.DEFAULT_PAGE_SIZE,
enablePlaceholders = true
),
remoteMediator = SearchMoviesRemoteMediator(
localeInteractor = localeInteractor,
pagingKeyRepository = pagingKeyRepository,
searchRepository = searchRepository,
movieRepository = movieRepository,
moviesDatabase = moviesDatabase,
query = searchQuery
),
pagingSourceFactory = { movieBlockingRepository.moviesPagingSource(searchQuery) }
).flow
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.michaelbel.movies.interactor

expect interface MovieBlockingInteractor
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
package org.michaelbel.movies.interactor

import androidx.paging.PagingData
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow
import org.michaelbel.movies.common.list.MovieList
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.entity.mini.MovieDbMini
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.Limit
import org.michaelbel.movies.persistence.database.typealiases.MovieId
import org.michaelbel.movies.persistence.database.typealiases.PagingKey
import org.michaelbel.movies.persistence.database.typealiases.Query

interface MovieInteractor {

fun moviesPagingData(
movieList: MovieList
): Flow<PagingData<MoviePojo>>

fun moviesPagingData(
searchQuery: Query
): Flow<PagingData<MoviePojo>>

fun moviesPagingSource(
pagingKey: PagingKey
): PagingSource<Int, MoviePojo>

fun moviesFlow(
pagingKey: PagingKey,
limit: Limit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.michaelbel.movies.interactor.di

import org.koin.core.module.Module
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
import org.michaelbel.movies.analytics.di.moviesAnalyticsKoinModule
import org.michaelbel.movies.common.dispatchers.di.dispatchersKoinModule
import org.michaelbel.movies.interactor.AccountInteractor
import org.michaelbel.movies.interactor.AuthenticationInteractor
import org.michaelbel.movies.interactor.ImageInteractor
import org.michaelbel.movies.interactor.Interactor
import org.michaelbel.movies.interactor.LocaleInteractor
import org.michaelbel.movies.interactor.MovieInteractor
import org.michaelbel.movies.interactor.NotificationInteractor
import org.michaelbel.movies.interactor.SearchInteractor
import org.michaelbel.movies.interactor.SettingsInteractor
import org.michaelbel.movies.interactor.SuggestionInteractor
import org.michaelbel.movies.interactor.impl.AccountInteractorImpl
import org.michaelbel.movies.interactor.impl.AuthenticationInteractorImpl
import org.michaelbel.movies.interactor.impl.ImageInteractorImpl
import org.michaelbel.movies.interactor.impl.MovieInteractorImpl
import org.michaelbel.movies.interactor.impl.NotificationInteractorImpl
import org.michaelbel.movies.interactor.impl.SearchInteractorImpl
import org.michaelbel.movies.interactor.impl.SettingsInteractorImpl
import org.michaelbel.movies.interactor.impl.SuggestionInteractorImpl
import org.michaelbel.movies.interactor.impl.LocaleInteractorImpl
import org.michaelbel.movies.persistence.database.di.moviesDatabaseKoinModule
import org.michaelbel.movies.repository.di.repositoryKoinModule

expect val interactorBlockingKoinModule: Module
Original file line number Diff line number Diff line change
@@ -1,87 +1,23 @@
@file:OptIn(ExperimentalPagingApi::class)

package org.michaelbel.movies.interactor.impl

import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import org.michaelbel.movies.common.dispatchers.MoviesDispatchers
import org.michaelbel.movies.common.list.MovieList
import org.michaelbel.movies.interactor.LocaleInteractor
import org.michaelbel.movies.interactor.MovieInteractor
import org.michaelbel.movies.interactor.ktx.nameOrLocalList
import org.michaelbel.movies.interactor.remote.FeedMoviesRemoteMediator
import org.michaelbel.movies.interactor.remote.SearchMoviesRemoteMediator
import org.michaelbel.movies.network.model.MovieResponse
import org.michaelbel.movies.persistence.database.MoviesDatabase
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.entity.mini.MovieDbMini
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.Limit
import org.michaelbel.movies.persistence.database.typealiases.MovieId
import org.michaelbel.movies.persistence.database.typealiases.PagingKey
import org.michaelbel.movies.persistence.database.typealiases.Query
import org.michaelbel.movies.repository.MovieRepository
import org.michaelbel.movies.repository.PagingKeyRepository
import org.michaelbel.movies.repository.SearchRepository

internal class MovieInteractorImpl(
private val dispatchers: MoviesDispatchers,
private val localeInteractor: LocaleInteractor,
private val searchRepository: SearchRepository,
private val movieRepository: MovieRepository,
private val pagingKeyRepository: PagingKeyRepository,
private val moviesDatabase: MoviesDatabase
private val movieRepository: MovieRepository
): MovieInteractor {

override fun moviesPagingData(
movieList: MovieList
): Flow<PagingData<MoviePojo>> {
return Pager(
config = PagingConfig(
pageSize = MovieResponse.DEFAULT_PAGE_SIZE,
enablePlaceholders = true
),
remoteMediator = FeedMoviesRemoteMediator(
localeInteractor = localeInteractor,
movieRepository = movieRepository,
pagingKeyRepository = pagingKeyRepository,
moviesDatabase = moviesDatabase,
pagingKey = MovieList.name(movieList)
),
pagingSourceFactory = { movieRepository.moviesPagingSource(movieList.nameOrLocalList) }
).flow
}

override fun moviesPagingData(
searchQuery: Query
): Flow<PagingData<MoviePojo>> {
return Pager(
config = PagingConfig(
pageSize = MovieResponse.DEFAULT_PAGE_SIZE,
enablePlaceholders = true
),
remoteMediator = SearchMoviesRemoteMediator(
localeInteractor = localeInteractor,
pagingKeyRepository = pagingKeyRepository,
searchRepository = searchRepository,
movieRepository = movieRepository,
moviesDatabase = moviesDatabase,
query = searchQuery
),
pagingSourceFactory = { movieRepository.moviesPagingSource(searchQuery) }
).flow
}

override fun moviesPagingSource(
pagingKey: PagingKey
): PagingSource<Int, MoviePojo> {
return movieRepository.moviesPagingSource(pagingKey)
}

override fun moviesFlow(
pagingKey: PagingKey,
limit: Limit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")

package org.michaelbel.movies.interactor

actual interface MovieBlockingInteractor
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.michaelbel.movies.interactor.di

import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module
import org.michaelbel.movies.analytics.di.moviesAnalyticsKoinModule
import org.michaelbel.movies.common.dispatchers.di.dispatchersKoinModule
import org.michaelbel.movies.interactor.MovieBlockingInteractor
import org.michaelbel.movies.interactor.impl.MovieBlockingInteractorImpl
import org.michaelbel.movies.persistence.database.di.moviesDatabaseKoinModule
import org.michaelbel.movies.repository.di.repositoryBlockingKoinModule

actual val interactorBlockingKoinModule = module {
includes(
dispatchersKoinModule,
repositoryBlockingKoinModule,
moviesDatabaseKoinModule,
moviesAnalyticsKoinModule
)
singleOf(::MovieBlockingInteractorImpl) { bind<MovieBlockingInteractor>() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@file:OptIn(ExperimentalPagingApi::class)

package org.michaelbel.movies.interactor.impl

import androidx.paging.ExperimentalPagingApi
import org.michaelbel.movies.interactor.MovieBlockingInteractor
import org.michaelbel.movies.repository.MovieBlockingRepository

internal class MovieBlockingInteractorImpl(
private val movieBlockingRepository: MovieBlockingRepository
): MovieBlockingInteractor
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.michaelbel.movies.network

import okhttp3.logging.HttpLoggingInterceptor
import org.koin.dsl.module

internal val httpLoggingInterceptorKoinModule = module {
single<HttpLoggingInterceptor> { HttpLoggingInterceptor() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.michaelbel.movies.network.apiKeyInterceptorKoinModule
import org.michaelbel.movies.network.chuckerKoinModule
import org.michaelbel.movies.network.config.TMDB_API_ENDPOINT
import org.michaelbel.movies.network.flakerKoinModule
import org.michaelbel.movies.network.httpLoggingInterceptorKoinModule
import org.michaelbel.movies.network.okhttp.ApikeyInterceptor

private const val REQUEST_TIMEOUT_MILLIS = 10_000L
Expand All @@ -28,7 +29,8 @@ actual val ktorKoinModule = module {
includes(
chuckerKoinModule,
flakerKoinModule,
apiKeyInterceptorKoinModule
apiKeyInterceptorKoinModule,
httpLoggingInterceptorKoinModule
)
single<HttpClient> {
val ktor = HttpClient(OkHttp) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")

package org.michaelbel.movies.persistence.database

import androidx.paging.PagingSource
import org.michaelbel.movies.persistence.database.dao.MovieBlockingDao
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.PagingKey

actual class MovieBlockingPersistence internal constructor(
private val movieBlockingDao: MovieBlockingDao
) {

fun pagingSource(pagingKey: PagingKey): PagingSource<Int, MoviePojo> {
return movieBlockingDao.pagingSource(pagingKey)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")

package org.michaelbel.movies.persistence.database.dao

import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import org.michaelbel.movies.persistence.database.entity.pojo.MoviePojo
import org.michaelbel.movies.persistence.database.typealiases.PagingKey

@Dao
internal actual interface MovieBlockingDao {

@Transaction
@Query("SELECT * FROM movies WHERE movieList = :pagingKey ORDER BY position ASC")
fun pagingSource(pagingKey: PagingKey): PagingSource<Int, MoviePojo>
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ private fun createRoomDatabase(app: Application): AppDatabase {
val dbFile = app.getDatabasePath(AppDatabase.DATABASE_NAME)
return Room.databaseBuilder<AppDatabase>(app, dbFile.absolutePath)
.setQueryCoroutineContext(Dispatchers.IO)
.fallbackToDestructiveMigration(dropAllTables = true)
.build()
}
Loading

0 comments on commit 5a1598a

Please sign in to comment.