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.
Unfortunately it crashes due to a sqldelight bug. Must upgrade to 2.0.0 alpha cashapp/sqldelight#2434
- Loading branch information
1 parent
9a8eae6
commit 258c452
Showing
3 changed files
with
98 additions
and
66 deletions.
There are no files selected for viewing
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 AS Int | ||
); | ||
|
||
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; |
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
95 changes: 67 additions & 28 deletions
95
...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,87 @@ | ||
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 com.squareup.sqldelight.android.paging3.QueryPagingSource | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
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, | ||
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<Long, Movie>() { | ||
override suspend fun load( | ||
loadType: LoadType, | ||
state: PagingState<Long, Movie>, | ||
): MediatorResult { | ||
return try { | ||
|
||
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 loadKey: Int? = 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 | ||
} | ||
} | ||
|
||
println("RemoteMediator.load:\nloadType: $loadType\nstate :$state\nloadKey: $loadKey") | ||
|
||
val movies = httpApi.trendingMovies(page = loadKey ?: 1) | ||
val nextKey = 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(nextKey) | ||
} | ||
} | ||
} | ||
|
||
MediatorResult.Success(endOfPaginationReached = nextKey == null) | ||
} catch (e: RuntimeException) { | ||
return MediatorResult.Error(e) | ||
} | ||
} | ||
} |