Skip to content

Commit

Permalink
Fix #9 Use Etag on all calls
Browse files Browse the repository at this point in the history
  • Loading branch information
herrbert74 committed Nov 7, 2024
1 parent d016e39 commit 2b5af1e
Show file tree
Hide file tree
Showing 19 changed files with 129 additions and 55 deletions.
47 changes: 24 additions & 23 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".FlickSlateApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FlickSlate"
tools:targetApi="31">
<activity
android:name=".main.FlickSlateActivity"
android:exported="true"
android:theme="@style/Theme.FlickSlate">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<application
android:name=".FlickSlateApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FlickSlate"
tools:targetApi="31">
<activity
android:name=".main.FlickSlateActivity"
android:exported="true"
android:theme="@style/Theme.FlickSlate">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@ import kotlinx.coroutines.flow.Flow
interface NowPlayingMoviesDataSource {

interface Local {

suspend fun purgeDatabase()

suspend fun insertNowPlayingMovies(movies: List<Movie>, page: Int)

suspend fun insertNowPlayingMoviesPageData(page: PageData)

fun getNowPlayingMovies(page: Int): Flow<PagingReply<Movie>?>

suspend fun getEtag(page: Int): String

}

interface Remote {

suspend fun getNowPlayingMovies(page: Int?): Outcome<PagingReply<Movie>>
suspend fun getNowPlayingMovies(etag: String? = null, page: Int?): Outcome<PagingReply<Movie>>

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ interface PopularMoviesDataSource {

fun getPopularMovies(page: Int): Flow<PagingReply<Movie>?>

suspend fun getEtag(page: Int): String?

}

interface Remote {

suspend fun getPopularMovies(page: Int?): Outcome<PagingReply<Movie>>
suspend fun getPopularMovies(etag: String? = null, page: Int? = null): Outcome<PagingReply<Movie>>

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ interface UpcomingMoviesDataSource {

fun getUpcomingMovies(page: Int): Flow<PagingReply<Movie>?>

suspend fun getEtag(page: Int): String?

}

interface Remote {

suspend fun getUpcomingMovies(page: Int?): Outcome<PagingReply<Movie>>
suspend fun getUpcomingMovies(etag: String? = null, page: Int?): Outcome<PagingReply<Movie>>

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package com.zsoltbertalan.flickslate.movies.data.db

import com.zsoltbertalan.flickslate.movies.data.api.NowPlayingMoviesDataSource
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.movies.data.db.model.NowPlayingMovieDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.NowPlayingMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toMovie
import com.zsoltbertalan.flickslate.movies.data.db.model.toNowPlayingMoviesDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toNowPlayingMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toPageData
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import io.realm.kotlin.Realm
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

Expand Down Expand Up @@ -62,6 +64,10 @@ class NowPlayingMoviesDao @Inject constructor(
}.flowOn(ioContext)
}

override suspend fun getEtag(page: Int): String = withContext(ioContext) {
return@withContext realm.query<NowPlayingMoviesPageDbo>("page = $0", page).first().find()?.etag ?: ""
}

private fun getPageData(page: Int): PageData? {
return realm.query(NowPlayingMoviesPageDbo::class, "page = $0", page).find()
.map { dbo -> dbo.toPageData() }.firstOrNull()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package com.zsoltbertalan.flickslate.movies.data.db

import com.zsoltbertalan.flickslate.movies.data.api.PopularMoviesDataSource
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.movies.data.db.model.PopularMovieDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.PopularMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toMovie
import com.zsoltbertalan.flickslate.movies.data.db.model.toPageData
import com.zsoltbertalan.flickslate.movies.data.db.model.toPopularMoviesDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toPopularMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import io.realm.kotlin.Realm
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

Expand Down Expand Up @@ -62,6 +64,10 @@ class PopularMoviesDao @Inject constructor(
}.flowOn(ioContext)
}

override suspend fun getEtag(page: Int): String? = withContext(ioContext) {
return@withContext realm.query<PopularMoviesPageDbo>("page = $0", page).first().find()?.etag
}

private fun getPageData(page: Int): PageData? {
return realm.query(PopularMoviesPageDbo::class, "page = $0", page).find()
.map { dbo -> dbo.toPageData() }.firstOrNull()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package com.zsoltbertalan.flickslate.movies.data.db

import com.zsoltbertalan.flickslate.movies.data.api.UpcomingMoviesDataSource
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.movies.data.db.model.UpcomingMovieDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.UpcomingMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toMovie
import com.zsoltbertalan.flickslate.movies.data.db.model.toPageData
import com.zsoltbertalan.flickslate.movies.data.db.model.toUpcomingMoviesDbo
import com.zsoltbertalan.flickslate.movies.data.db.model.toUpcomingMoviesPageDbo
import com.zsoltbertalan.flickslate.movies.domain.model.Movie
import com.zsoltbertalan.flickslate.shared.async.IoDispatcher
import com.zsoltbertalan.flickslate.shared.domain.model.PageData
import com.zsoltbertalan.flickslate.shared.domain.model.PagingReply
import com.zsoltbertalan.flickslate.shared.util.runCatchingUnit
import io.realm.kotlin.Realm
import io.realm.kotlin.UpdatePolicy
import io.realm.kotlin.ext.query
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

Expand Down Expand Up @@ -62,6 +64,10 @@ class UpcomingMoviesDao @Inject constructor(
}.flowOn(ioContext)
}

override suspend fun getEtag(page: Int): String? = withContext(ioContext) {
return@withContext realm.query<UpcomingMoviesPageDbo>("page = $0", page).first().find()?.etag
}

private fun getPageData(page: Int): PageData? {
return realm.query(UpcomingMoviesPageDbo::class, "page = $0", page).find()
.map { dbo -> dbo.toPageData() }.firstOrNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.zsoltbertalan.flickslate.movies.data.network.model.NowPlayingMoviesRe
import com.zsoltbertalan.flickslate.movies.data.network.model.UpcomingMoviesReplyDto
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Path
import retrofit2.http.Query

Expand All @@ -18,24 +19,28 @@ interface MoviesService {

@GET(URL_MOVIES_POPULAR)
suspend fun getPopularMovies(
@Header("If-None-Match") ifNoneMatch: String? = null,
@Query("language") language: String? = "en",
@Query("page") page: Int?
): Response<MoviesReplyDto>

@GET(URL_MOVIES_NOW_PLAYING)
suspend fun getNowPlayingMovies(
@Header("If-None-Match") ifNoneMatch: String? = null,
@Query("language") language: String? = "en",
@Query("page") page: Int?
): Response<NowPlayingMoviesReplyDto>

@GET(URL_MOVIES_UPCOMING)
suspend fun getUpcomingMovies(
@Header("If-None-Match") ifNoneMatch: String? = null,
@Query("language") language: String? = "en",
@Query("page") page: Int?
): Response<UpcomingMoviesReplyDto>

@GET(URL_MOVIE_DETAILS)
suspend fun getMovieDetails(
@Header("If-None-Match") ifNoneMatch: String? = null,
@Path("movie_id") movieId: Int,
): MovieDetailsDto

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ class NowPlayingRemoteDataSource @Inject constructor(
private val moviesService: MoviesService
) : NowPlayingMoviesDataSource.Remote {

override suspend fun getNowPlayingMovies(page: Int?): Outcome<PagingReply<Movie>> {
override suspend fun getNowPlayingMovies(etag: String?, page: Int?): Outcome<PagingReply<Movie>> {
return safeCallWithMetadata(
{ moviesService.getNowPlayingMovies(page = page) },
{ moviesService.getNowPlayingMovies(ifNoneMatch = etag, page = page) },
Response<NowPlayingMoviesReplyDto>::toMoviesReply
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ class PopularMoviesRemoteDataSource @Inject constructor(
private val moviesService: MoviesService
) : PopularMoviesDataSource.Remote {

override suspend fun getPopularMovies(page: Int?): Outcome<PagingReply<Movie>> {
override suspend fun getPopularMovies(etag: String?, page: Int?): Outcome<PagingReply<Movie>> {
return safeCallWithMetadata(
{ moviesService.getPopularMovies(page = page) },
{ moviesService.getPopularMovies(ifNoneMatch = etag, page = page) },
Response<MoviesReplyDto>::toMoviesReply
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ class UpcomingMoviesRemoteDataSource @Inject constructor(
private val moviesService: MoviesService
) : UpcomingMoviesDataSource.Remote {

override suspend fun getUpcomingMovies(page: Int?): Outcome<PagingReply<Movie>> {
override suspend fun getUpcomingMovies(etag: String?, page: Int?): Outcome<PagingReply<Movie>> {
return safeCallWithMetadata(
{ moviesService.getUpcomingMovies(page = page) },
{ moviesService.getUpcomingMovies(ifNoneMatch = etag, page = page) },
Response<UpcomingMoviesReplyDto>::toMoviesReply
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ class MoviesAccessor @Inject constructor(
override fun getPopularMovies(page: Int): Flow<Outcome<PagingReply<Movie>>> {
return fetchCacheThenRemote(
fetchFromLocal = { popularMoviesDataSource.getPopularMovies(page) },
makeNetworkRequest = { popularMoviesRemoteDataSource.getPopularMovies(page = page) },
makeNetworkRequest = {
val etag = popularMoviesDataSource.getEtag(page)
popularMoviesRemoteDataSource.getPopularMovies(etag = etag, page = page)
},
saveResponseData = { pagingReply ->
val moviesReply = pagingReply.pagingList
popularMoviesDataSource.insertPopularMoviesPageData(
Expand All @@ -54,7 +57,10 @@ class MoviesAccessor @Inject constructor(
override fun getUpcomingMovies(page: Int): Flow<Outcome<PagingReply<Movie>>> {
return fetchCacheThenRemote(
fetchFromLocal = { upcomingMoviesDataSource.getUpcomingMovies(page) },
makeNetworkRequest = { upcomingMoviesRemoteDataSource.getUpcomingMovies(page = page) },
makeNetworkRequest = {
val etag = upcomingMoviesDataSource.getEtag(page)
upcomingMoviesRemoteDataSource.getUpcomingMovies(etag = etag, page = page)
},
saveResponseData = { pagingReply ->
val moviesReply = pagingReply.pagingList
upcomingMoviesDataSource.insertUpcomingMoviesPageData(
Expand All @@ -68,7 +74,10 @@ class MoviesAccessor @Inject constructor(
override fun getNowPlayingMovies(page: Int): Flow<Outcome<PagingReply<Movie>>> {
return fetchCacheThenRemote(
fetchFromLocal = { nowPlayingMoviesDataSource.getNowPlayingMovies(page) },
makeNetworkRequest = { nowPlayingMoviesRemoteDataSource.getNowPlayingMovies(page = page) },
makeNetworkRequest = {
val etag = nowPlayingMoviesDataSource.getEtag(page)
nowPlayingMoviesRemoteDataSource.getNowPlayingMovies(etag = etag, page = page)
},
saveResponseData = { pagingReply ->
val moviesReply = pagingReply.pagingList
nowPlayingMoviesDataSource.insertNowPlayingMoviesPageData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,21 @@ interface SearchService {

@GET(URL_GENRE)
suspend fun getGenres(
@Header("If-None-Match") ifNoneMatch: String = "",
@Query("language") language: String? = "en",
@Header("If-None-Match") ifNoneMatch: String = ""
): Response<GenreReplyDto>

@GET(URL_MOVIES_SEARCH)
suspend fun searchMovies(
@Header("If-None-Match") ifNoneMatch: String = "",
@Query("language") language: String? = "en",
@Query("query") query: String,
@Query("page") page: Int?
): Response<MoviesReplyDto>

@GET(URL_DISCOVER_MOVIE)
suspend fun getGenreMovie(
@Header("If-None-Match") ifNoneMatch: String = "",
@Query("with_genres") withGenres: Int,
@Query("page") page: Int?,
): Response<MoviesReplyDto>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ interface TvDataSource {

fun getTv(page: Int): Flow<PagingReply<TvShow>?>

suspend fun getEtag(page: Int): String?

}

interface Remote {

suspend fun getTopRatedTv(page: Int?): Outcome<PagingReply<TvShow>>
suspend fun getTopRatedTv(etag: String? = null, page: Int?): Outcome<PagingReply<TvShow>>

}

Expand Down
Loading

0 comments on commit 2b5af1e

Please sign in to comment.