Skip to content

Commit

Permalink
Basic implementation
Browse files Browse the repository at this point in the history
Unfortunately it crashes due to a sqldelight bug. Must upgrade to 2.0.0 alpha

cashapp/sqldelight#2434
  • Loading branch information
julioromano committed Mar 16, 2023
1 parent 0cc6eae commit 5924bc4
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 66 deletions.
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;
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import net.marcoromano.mooviez.httpapi.TrendingMovies
import net.marcoromano.mooviez.database.Movie
import net.marcoromano.mooviez.widgets.UserScore

@Composable
Expand All @@ -59,7 +59,7 @@ internal fun TrendingLazyVerticalGrid(
private fun TrendingLazyVerticalGrid(
columns: GridCells,
modifier: Modifier,
pager: Flow<PagingData<TrendingMovies.Movie>>,
pager: Flow<PagingData<Movie>>,
onMovieClick: (id: Long) -> Unit,
) {
val trendingPagingData = pager.collectAsLazyPagingItems()
Expand All @@ -86,7 +86,7 @@ private fun TrendingLazyVerticalGrid(

@Composable
private fun Movie(
movie: TrendingMovies.Movie,
movie: Movie,
navToDetail: (id: Long) -> Unit,
) {
Column(
Expand Down Expand Up @@ -142,7 +142,8 @@ private fun Movie(
@Composable
private fun PreviewMovie() {
Movie(
movie = TrendingMovies.Movie(
movie = Movie(
position = 0,
id = 0,
title = "A very long title that must be wrapped in multiple lines",
poster_path = "https://dummyimage.com/500x750/000/fff.jpg",
Expand All @@ -163,15 +164,17 @@ private fun PreviewTrending() {
pager = flowOf(
PagingData.from(
listOf(
TrendingMovies.Movie(
Movie(
position = 0,
id = 0,
title = "A very long title that must be wrapped in multiple lines",
poster_path = "https://dummyimage.com/500x750/000/fff.jpg",
overview = "Once upon a time...",
vote_average = 1.2,
release_date = "2022-02-03",
),
TrendingMovies.Movie(
Movie(
position = 0,
id = 0,
title = "A very long title that must be wrapped in multiple lines",
poster_path = "https://dummyimage.com/500x750/000/fff.jpg",
Expand Down
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)
}
}
}

0 comments on commit 5924bc4

Please sign in to comment.