generated from julioromano/skeleton-android
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Uses RemoteMediator to page the movie list from the database while fetching new data from the network. - Upgrades SQLDelight to 2.0.0-alpha05 to fix cashapp/sqldelight#2434
- Loading branch information
1 parent
9a8eae6
commit d98a5fa
Showing
8 changed files
with
113 additions
and
78 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
database/fake/src/main/kotlin/net/marcoromano/mooviez/database/DatabaseFake.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 22 additions & 32 deletions
54
database/public/src/main/sqldelight/net/marcoromano/mooviez/database/Movie.sq
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,32 @@ | ||
CREATE TABLE Movie ( | ||
id INTEGER PRIMARY KEY NOT NULL, | ||
position INTEGER PRIMARY KEY NOT NULL, | ||
id INTEGER NOT NULL, | ||
title TEXT NOT NULL, | ||
poster_path TEXT NOT NULL, | ||
overview TEXT NOT NULL, | ||
vote_average REAL NOT NULL | ||
vote_average REAL NOT NULL, | ||
release_date TEXT NOT NULL | ||
); | ||
|
||
getMovies: | ||
SELECT | ||
id, | ||
title, | ||
poster_path, | ||
overview, | ||
vote_average | ||
FROM Movie | ||
; | ||
CREATE TABLE MoviePage ( | ||
id INTEGER PRIMARY KEY NOT NULL, | ||
next_page INTEGER | ||
); | ||
|
||
getMovie: | ||
SELECT | ||
id, | ||
title, | ||
poster_path, | ||
overview, | ||
vote_average | ||
insertMovie: | ||
INSERT OR REPLACE INTO Movie VALUES ?; | ||
|
||
countMovies: | ||
SELECT count(*) FROM Movie; | ||
|
||
movies: | ||
SELECT * | ||
FROM Movie | ||
WHERE id = ? | ||
; | ||
ORDER BY position ASC | ||
LIMIT :limit OFFSET :offset; | ||
|
||
insertMovie: | ||
INSERT OR REPLACE INTO Movie ( | ||
id, | ||
title, | ||
poster_path, | ||
overview, | ||
vote_average | ||
) | ||
VALUES (?,?,?,?,?) | ||
; | ||
insertNextPage: | ||
INSERT OR REPLACE INTO MoviePage(id, next_page) VALUES (0, ?); | ||
|
||
deleteMovies: | ||
DELETE FROM Movie; | ||
nextPage: | ||
SELECT next_page FROM MoviePage WHERE id == 0; |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 66 additions & 28 deletions
94
...in/net/marcoromano/mooviez/trending/widgets/trending/TrendingLazyVerticalGridViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,86 @@ | ||
package net.marcoromano.mooviez.trending.widgets.trending | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.paging.ExperimentalPagingApi | ||
import androidx.paging.LoadType | ||
import androidx.paging.Pager | ||
import androidx.paging.PagingConfig | ||
import androidx.paging.PagingSource | ||
import androidx.paging.PagingState | ||
import androidx.paging.RemoteMediator | ||
import app.cash.sqldelight.paging3.QueryPagingSource | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import kotlinx.coroutines.Dispatchers | ||
import net.marcoromano.mooviez.database.Database | ||
import net.marcoromano.mooviez.database.Movie | ||
import net.marcoromano.mooviez.httpapi.HttpApi | ||
import net.marcoromano.mooviez.httpapi.TrendingMovies | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
internal class TrendingLazyVerticalGridViewModel @Inject constructor( | ||
private val httpApi: HttpApi, | ||
httpApi: HttpApi, | ||
private val database: Database, | ||
) : ViewModel() { | ||
val pager = Pager(PagingConfig(pageSize = 20)) { // 20 comes from tmdb api docs | ||
NetworkPagingSource(httpApi) | ||
@OptIn(ExperimentalPagingApi::class) | ||
val pager = Pager( | ||
config = PagingConfig(pageSize = 20), // 20 comes from tmdb api docs | ||
remoteMediator = Mediator(httpApi = httpApi, database = database), | ||
) { | ||
QueryPagingSource( | ||
countQuery = database.movieQueries.countMovies(), | ||
transacter = database.movieQueries, | ||
context = Dispatchers.IO, | ||
queryProvider = database.movieQueries::movies, | ||
) | ||
}.flow | ||
} | ||
|
||
private class NetworkPagingSource( | ||
@OptIn(ExperimentalPagingApi::class) | ||
private class Mediator( | ||
private val httpApi: HttpApi, | ||
) : PagingSource<Int, TrendingMovies.Movie>() { | ||
override fun getRefreshKey(state: PagingState<Int, TrendingMovies.Movie>): Int? { | ||
return state.anchorPosition?.let { anchorPosition -> | ||
val anchorPage = state.closestPageToPosition(anchorPosition) | ||
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1) | ||
} | ||
} | ||
private val database: Database, | ||
) : RemoteMediator<Int, Movie>() { | ||
override suspend fun load( | ||
loadType: LoadType, | ||
state: PagingState<Int, Movie>, | ||
): MediatorResult { | ||
return try { | ||
val loadPage: Long? = when (loadType) { | ||
LoadType.REFRESH -> null | ||
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true) | ||
LoadType.APPEND -> { | ||
val remoteKey = database.movieQueries.nextPage().executeAsOne() | ||
if (remoteKey.next_page == null) { | ||
return MediatorResult.Success(endOfPaginationReached = true) | ||
} | ||
remoteKey.next_page | ||
} | ||
} | ||
|
||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TrendingMovies.Movie> { | ||
return runCatching { | ||
httpApi.trendingMovies(page = params.key ?: 1) | ||
}.fold( | ||
{ | ||
LoadResult.Page( | ||
data = it.results, | ||
prevKey = if (it.page > 1) it.page - 1 else null, | ||
nextKey = if (it.page < it.total_pages) it.page + 1 else null, | ||
) | ||
}, | ||
{ | ||
LoadResult.Error(it) | ||
}, | ||
) | ||
val movies = httpApi.trendingMovies(page = loadPage?.toInt() ?: 1) | ||
val nextPage = if (movies.page < movies.total_pages) movies.page + 1 else null | ||
|
||
database.movieQueries.apply { | ||
transaction { | ||
movies.results.forEachIndexed { i, movie -> | ||
insertMovie( | ||
Movie( | ||
position = (movies.page - 1) * 20L + i, | ||
id = movie.id, | ||
title = movie.title, | ||
poster_path = movie.poster_path, | ||
overview = movie.overview, | ||
vote_average = movie.vote_average, | ||
release_date = movie.release_date, | ||
), | ||
) | ||
insertNextPage(nextPage?.toLong()) | ||
} | ||
} | ||
} | ||
|
||
MediatorResult.Success(endOfPaginationReached = nextPage == null) | ||
} catch (e: RuntimeException) { | ||
return MediatorResult.Error(e) | ||
} | ||
} | ||
} |