From 7ef38802be18545cfaf68f00cdfefc66fa81ce59 Mon Sep 17 00:00:00 2001 From: Satyajit Mishra <55646021+smish-hash@users.noreply.github.com> Date: Tue, 10 Jan 2023 14:35:25 +0530 Subject: [PATCH 1/2] Get bookmarked items state from db --- .../java/com/smish/abda/data/db/MovieDao.kt | 3 +++ .../com/smish/abda/data/model/movie/Search.kt | 6 ++++++ .../data/repository/MovieRepositoryImpl.kt | 4 ++++ .../datasource/MovieLocalDataSource.kt | 1 + .../MovieLocalDataSourceImpl.kt | 4 ++++ .../abda/domain/repository/MovieRepository.kt | 2 ++ .../domain/usecase/GetBookmarkedMovies.kt | 4 ++++ .../abda/ui/movieList/components/MovieList.kt | 5 ++++- .../ui/movieList/components/MovieListItem.kt | 20 +++++++++++++++---- .../movieList/components/MovieListScreen.kt | 6 ++++++ .../abda/ui/viewmodel/MoviesViewmodel.kt | 6 ++++++ 11 files changed, 56 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/smish/abda/data/db/MovieDao.kt b/app/src/main/java/com/smish/abda/data/db/MovieDao.kt index 7c3c4ca..9d01478 100644 --- a/app/src/main/java/com/smish/abda/data/db/MovieDao.kt +++ b/app/src/main/java/com/smish/abda/data/db/MovieDao.kt @@ -22,4 +22,7 @@ interface MovieDao { @Query("DELETE FROM movies") suspend fun deleteAll() + + @Query("SELECT imdbID FROM movies") + fun getSavedMoviesIds(): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/data/model/movie/Search.kt b/app/src/main/java/com/smish/abda/data/model/movie/Search.kt index c868248..6fc101f 100644 --- a/app/src/main/java/com/smish/abda/data/model/movie/Search.kt +++ b/app/src/main/java/com/smish/abda/data/model/movie/Search.kt @@ -1,6 +1,7 @@ package com.smish.abda.data.model.movie +import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.google.gson.annotations.SerializedName @@ -8,14 +9,19 @@ import com.google.gson.annotations.SerializedName @Entity(tableName = "movies") data class Search( @PrimaryKey + @ColumnInfo(name = "imdbID") @SerializedName("imdbID") val imdbID: String, + @SerializedName("Poster") val poster: String, + @SerializedName("Title") val title: String, + @SerializedName("Type") val type: String, + @SerializedName("Year") val year: String ) diff --git a/app/src/main/java/com/smish/abda/data/repository/MovieRepositoryImpl.kt b/app/src/main/java/com/smish/abda/data/repository/MovieRepositoryImpl.kt index d0a021b..dbe6363 100644 --- a/app/src/main/java/com/smish/abda/data/repository/MovieRepositoryImpl.kt +++ b/app/src/main/java/com/smish/abda/data/repository/MovieRepositoryImpl.kt @@ -53,4 +53,8 @@ class MovieRepositoryImpl( override fun getBookmarkedMovies(): Flow> { return movieLocalDataSource.getSavedMoviesFromDB() } + + override fun getSavedMoviesIds(): Flow> { + return movieLocalDataSource.getSavedMoviesIdsFromDB() + } } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/data/repository/datasource/MovieLocalDataSource.kt b/app/src/main/java/com/smish/abda/data/repository/datasource/MovieLocalDataSource.kt index c661e8e..656712f 100644 --- a/app/src/main/java/com/smish/abda/data/repository/datasource/MovieLocalDataSource.kt +++ b/app/src/main/java/com/smish/abda/data/repository/datasource/MovieLocalDataSource.kt @@ -7,5 +7,6 @@ interface MovieLocalDataSource { /*defining functions to interact with the db*/ suspend fun saveMovieToDB(movie: Search) fun getSavedMoviesFromDB(): Flow> + fun getSavedMoviesIdsFromDB(): Flow> suspend fun deleteMovieFromDB(imdbID: String) } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/data/repository/datasourceimpl/MovieLocalDataSourceImpl.kt b/app/src/main/java/com/smish/abda/data/repository/datasourceimpl/MovieLocalDataSourceImpl.kt index 825ba63..427ac01 100644 --- a/app/src/main/java/com/smish/abda/data/repository/datasourceimpl/MovieLocalDataSourceImpl.kt +++ b/app/src/main/java/com/smish/abda/data/repository/datasourceimpl/MovieLocalDataSourceImpl.kt @@ -16,6 +16,10 @@ class MovieLocalDataSourceImpl( return movieDao.getAllSavedMovies() } + override fun getSavedMoviesIdsFromDB(): Flow> { + return movieDao.getSavedMoviesIds() + } + override suspend fun deleteMovieFromDB(imdbID: String) { return movieDao.delete(imdbID) } diff --git a/app/src/main/java/com/smish/abda/domain/repository/MovieRepository.kt b/app/src/main/java/com/smish/abda/domain/repository/MovieRepository.kt index 1943d00..4e06043 100644 --- a/app/src/main/java/com/smish/abda/domain/repository/MovieRepository.kt +++ b/app/src/main/java/com/smish/abda/domain/repository/MovieRepository.kt @@ -17,4 +17,6 @@ interface MovieRepository { // to get data from db as a flow. // asynchronous data stream in the viewmodel, collect it and emit it as live data. fun getBookmarkedMovies(): Flow> + + fun getSavedMoviesIds(): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/domain/usecase/GetBookmarkedMovies.kt b/app/src/main/java/com/smish/abda/domain/usecase/GetBookmarkedMovies.kt index 586e365..d002b6d 100644 --- a/app/src/main/java/com/smish/abda/domain/usecase/GetBookmarkedMovies.kt +++ b/app/src/main/java/com/smish/abda/domain/usecase/GetBookmarkedMovies.kt @@ -8,4 +8,8 @@ class GetBookmarkedMovies(private val movieRepository: MovieRepository) { fun getBookmarkedMovies(): Flow> { return movieRepository.getBookmarkedMovies() } + + fun getSavedMoviesIds(): Flow> { + return movieRepository.getSavedMoviesIds() + } } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt index b1d9dd7..2367c79 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -19,7 +20,7 @@ import com.smish.abda.data.model.movie.Search @Composable fun MovieList( movies: LazyPagingItems, - modifier: Modifier = Modifier, + savedList: List, onMovieClick: (Search) -> Unit, onBookmarkClick: (isChecked: Boolean, movie: Search) -> Unit ) { @@ -57,11 +58,13 @@ fun MovieList( } }*/ LazyColumn( + state = rememberLazyListState(), modifier = Modifier.fillMaxSize() ) { items(movies) { movie -> if (movie != null) { val (isChecked, setChecked) = remember { mutableStateOf(false) } + if (savedList.contains(movie.imdbID)) setChecked(true) else setChecked(false) MovieListItem( movie = movie, onMovieClick = { diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt index e52551f..febf449 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt @@ -53,6 +53,14 @@ fun MovieListItem( // Crop, Fit, Inside, FillHeight, FillWidth, None contentScale = ContentScale.Crop ) + // for preview + /*Box( + modifier = Modifier + .height(150.dp) + .width(135.dp) + .background(color = Color.Cyan) + ) { + }*/ } IconToggleButton( @@ -88,16 +96,20 @@ fun MovieListItem( } } -@Preview(showBackground = true, showSystemUi = true) +@Preview(showBackground = true, showSystemUi = false) @Composable fun PreviewMovieListItem() { - val (isChecked, setChecked) = remember { mutableStateOf(false) } AbdaTheme { + val (isChecked, setChecked) = remember { mutableStateOf(false) } MovieListItem( - Search("123", "fdowbi", "Smishra", "movie", "2021"), + Search("123", + "https://www.google.com/imgres?imgurl=https%3A%2F%2Fmiro.medium.com%2Fmax%2F1024%2F1*zEs8abcQCFrwGeXrVcQ3cg.png&imgrefurl=https%3A%2F%2Fproandroiddev.com%2Fpaging-3-easier-way-to-pagination-part-1-584cad1f4f61&tbnid=Kaq9xtR0nHndYM&vet=12ahUKEwiYibfDv7z8AhW6i9gFHZofA9YQMygAegUIARC7AQ..i&docid=8Dlf-i8q9nZ3nM&w=1024&h=512&q=where%20to%20add%20paging%203%20in%20android&ved=2ahUKEwiYibfDv7z8AhW6i9gFHZofA9YQMygAegUIARC7AQ", + "Smishra", + "movie", + "2021"), onMovieClick = {}, isChecked, - onBookmarkClick = { setChecked(!isChecked) } + onBookmarkClick = {setChecked(!isChecked)} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt index b70c9e7..29cbf0a 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt @@ -1,5 +1,6 @@ package com.smish.abda.ui.movieList.components +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow @@ -12,6 +13,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Search import androidx.compose.runtime.* +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -57,6 +59,9 @@ fun MovieListScreen( mutableStateOf(false) } + val savedList by viewmodel.getSavedMoviesIds().observeAsState() + Log.d("saved", "MovieListScreen: $savedList") + val movieList = viewmodel.getPagingMovies().collectAsLazyPagingItems() ModalBottomSheetLayout( sheetState = bottomSheetModalState, @@ -123,6 +128,7 @@ fun MovieListScreen( MovieList( movies = movieList, + savedList = savedList ?: emptyList(), onMovieClick = { showModalSheet.value = !showModalSheet.value viewmodel.getMovieDetails(it.imdbID) diff --git a/app/src/main/java/com/smish/abda/ui/viewmodel/MoviesViewmodel.kt b/app/src/main/java/com/smish/abda/ui/viewmodel/MoviesViewmodel.kt index d6a6364..d09dcf4 100644 --- a/app/src/main/java/com/smish/abda/ui/viewmodel/MoviesViewmodel.kt +++ b/app/src/main/java/com/smish/abda/ui/viewmodel/MoviesViewmodel.kt @@ -121,4 +121,10 @@ class MoviesViewmodel @Inject constructor( emit(it) } } + + fun getSavedMoviesIds() = liveData { + getBookmarkedMovies.getSavedMoviesIds().collect{ + emit(it) + } + } } \ No newline at end of file From a0a3c8ea4ebbf32725e687ffd367212506bede49 Mon Sep 17 00:00:00 2001 From: Satyajit Mishra <55646021+smish-hash@users.noreply.github.com> Date: Tue, 10 Jan 2023 17:05:26 +0530 Subject: [PATCH 2/2] Save bookmark state on recomposition --- .../com/smish/abda/data/model/movie/Search.kt | 11 ++++- .../components/MovieBookmarkItem.kt | 8 +--- .../abda/ui/movieList/components/MovieList.kt | 48 ++++++++++++++----- .../ui/movieList/components/MovieListItem.kt | 24 +++++----- .../movieList/components/MovieListScreen.kt | 31 +----------- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/com/smish/abda/data/model/movie/Search.kt b/app/src/main/java/com/smish/abda/data/model/movie/Search.kt index 6fc101f..83f630a 100644 --- a/app/src/main/java/com/smish/abda/data/model/movie/Search.kt +++ b/app/src/main/java/com/smish/abda/data/model/movie/Search.kt @@ -23,8 +23,15 @@ data class Search( val type: String, @SerializedName("Year") - val year: String -) + val year: String, + + @ColumnInfo(name = "isBookmarked") + var isBookmarked: Boolean +) { + fun toggle() { + isBookmarked = !isBookmarked + } +} // since all are type string here, we do not create any type converter for room db else we would have needed one. /* diff --git a/app/src/main/java/com/smish/abda/ui/movieBookmark/components/MovieBookmarkItem.kt b/app/src/main/java/com/smish/abda/ui/movieBookmark/components/MovieBookmarkItem.kt index 773a930..3b15671 100644 --- a/app/src/main/java/com/smish/abda/ui/movieBookmark/components/MovieBookmarkItem.kt +++ b/app/src/main/java/com/smish/abda/ui/movieBookmark/components/MovieBookmarkItem.kt @@ -4,13 +4,9 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Favorite -import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale @@ -37,7 +33,7 @@ fun MovieBookmarkItem( .padding(12.dp) .wrapContentSize() ) { - Box() { + Box { Card( shape = RoundedCornerShape(12.dp), backgroundColor = MaterialTheme.colors.background, @@ -78,7 +74,7 @@ fun PreviewMovieListItem() { val (isChecked, setChecked) = remember { mutableStateOf(false) } AbdaTheme { MovieBookmarkItem( - Search("123", "fdowbi", "Smishra", "movie", "2021"), + Search("123", "fdowbi", "Smishra", "movie", "2021", false), onMovieClick = {} ) } diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt index 2367c79..16542d3 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieList.kt @@ -3,18 +3,16 @@ package com.smish.abda.ui.movieList.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.paging.LoadState import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.items import com.smish.abda.data.model.movie.Search @Composable @@ -22,7 +20,7 @@ fun MovieList( movies: LazyPagingItems, savedList: List, onMovieClick: (Search) -> Unit, - onBookmarkClick: (isChecked: Boolean, movie: Search) -> Unit + onBookmarkClick: (movie: Search) -> Unit ) { when (movies.loadState.refresh) { LoadState.Loading -> { @@ -57,28 +55,54 @@ fun MovieList( } } }*/ - LazyColumn( + /*LazyColumn( state = rememberLazyListState(), modifier = Modifier.fillMaxSize() ) { items(movies) { movie -> if (movie != null) { - val (isChecked, setChecked) = remember { mutableStateOf(false) } - if (savedList.contains(movie.imdbID)) setChecked(true) else setChecked(false) +// val (isChecked, setChecked) = remember { mutableStateOf(false) } + if (savedList.contains(movie.imdbID)) movie.isBookmarked = true MovieListItem( movie = movie, onMovieClick = { // call the movie detail api and trigger the bottom sheet onMovieClick(movie) }, - isChecked, onBookmarkClick = { - setChecked(!isChecked) - onBookmarkClick(isChecked, movie) +// setChecked(!isChecked) + movie.toggle() + onBookmarkClick(movie) } ) } } + }*/ + + LazyVerticalGrid( + modifier = Modifier.fillMaxSize(), + columns = GridCells.Adaptive(minSize = 135.dp) + ) { + items(movies.itemCount) { index -> + movies[index].let { movie -> + if (movie != null) { +// val (isChecked, setChecked) = remember { mutableStateOf(false) } + if (savedList.contains(movie.imdbID)) movie.isBookmarked = true + MovieListItem( + movie = movie, + onMovieClick = { + // call the movie detail api and trigger the bottom sheet + onMovieClick(movie) + }, + onBookmarkClick = { +// setChecked(!isChecked) + movie.toggle() + onBookmarkClick(movie) + } + ) + } + } + } } } } diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt index febf449..fda11dc 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListItem.kt @@ -8,8 +8,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -26,7 +24,7 @@ import com.smish.abda.ui.theme.AbdaTheme fun MovieListItem( movie: Search, onMovieClick: (Search) -> Unit, - isChecked: Boolean, +// isChecked: Boolean, onBookmarkClick: () -> Unit ) { Surface( @@ -39,7 +37,7 @@ fun MovieListItem( .padding(12.dp) .wrapContentSize() ) { - Box() { + Box { Card( shape = RoundedCornerShape(12.dp), backgroundColor = MaterialTheme.colors.background, @@ -64,15 +62,15 @@ fun MovieListItem( } IconToggleButton( - checked = isChecked, onCheckedChange = { onBookmarkClick() }, + checked = movie.isBookmarked, onCheckedChange = { onBookmarkClick() }, modifier = Modifier .align(Alignment.TopEnd) .padding(2.dp) ) { Icon( - imageVector = if (isChecked) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder, + imageVector = if (movie.isBookmarked) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder, contentDescription = "bookmark", - tint = if (isChecked) Color.Red else Color.White, + tint = if (movie.isBookmarked) Color.Red else Color.White, modifier = Modifier.size(24.dp) ) } @@ -100,16 +98,18 @@ fun MovieListItem( @Composable fun PreviewMovieListItem() { AbdaTheme { - val (isChecked, setChecked) = remember { mutableStateOf(false) } +// val (isChecked, setChecked) = remember { mutableStateOf(false) } MovieListItem( - Search("123", + Search( + "123", "https://www.google.com/imgres?imgurl=https%3A%2F%2Fmiro.medium.com%2Fmax%2F1024%2F1*zEs8abcQCFrwGeXrVcQ3cg.png&imgrefurl=https%3A%2F%2Fproandroiddev.com%2Fpaging-3-easier-way-to-pagination-part-1-584cad1f4f61&tbnid=Kaq9xtR0nHndYM&vet=12ahUKEwiYibfDv7z8AhW6i9gFHZofA9YQMygAegUIARC7AQ..i&docid=8Dlf-i8q9nZ3nM&w=1024&h=512&q=where%20to%20add%20paging%203%20in%20android&ved=2ahUKEwiYibfDv7z8AhW6i9gFHZofA9YQMygAegUIARC7AQ", "Smishra", "movie", - "2021"), + "2021", + false + ), onMovieClick = {}, - isChecked, - onBookmarkClick = {setChecked(!isChecked)} + onBookmarkClick = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt index 29cbf0a..aeedb52 100644 --- a/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt +++ b/app/src/main/java/com/smish/abda/ui/movieList/components/MovieListScreen.kt @@ -133,40 +133,13 @@ fun MovieListScreen( showModalSheet.value = !showModalSheet.value viewmodel.getMovieDetails(it.imdbID) }, - onBookmarkClick = { isChecked, movie -> - if (!isChecked) + onBookmarkClick = { movie -> + if (!movie.isBookmarked) viewmodel.bookmarkMovie(movie) else viewmodel.removeMovie(movie) } ) - - /*LazyVerticalGrid( - modifier = Modifier.fillMaxSize(), - columns = GridCells.Adaptive(minSize = 135.dp) - ) { - items(movieList) { movie -> - if (movie != null) { - val (isChecked, setChecked) = remember { mutableStateOf(false) } - MovieListItem( - movie = movie, - onMovieClick = { - // call the movie detail api and trigger the bottom sheet - showModalSheet.value = !showModalSheet.value - viewmodel.getMovieDetails(movie.imdbID) - }, - isChecked, - onBookmarkClick = { - setChecked(!isChecked) - if (!isChecked) - viewmodel.bookmarkMovie(movie) - else - viewmodel.removeMovie(movie) - } - ) - } - } - }*/ } /*if (state.error.isNotBlank()) {