diff --git a/README.md b/README.md index 22cdf90..9f7ae4f 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Movie World app using [The Movie DB](https://www.themoviedb.org) built with jetp

- - - + + +

# Main Features diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/ApiService.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/ApiService.kt index a4ad6af..72eef3f 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/ApiService.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/ApiService.kt @@ -1,43 +1,46 @@ package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote import com.piashcse.hilt_mvvm_compose_movie.BuildConfig -import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModel +import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModelMovie +import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModelTvSeries import com.piashcse.hilt_mvvm_compose_movie.data.model.Genres +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.ArtistDetail import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.MovieDetail +import com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail.TvSeriesDetail import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query interface ApiService { @GET("movie/now_playing") - suspend fun nowPlayingMovieList( + suspend fun nowPlayingMovies( @Query("page") page: Int, @Query("with_genres") genreId: String?, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): BaseModelMovie @GET("movie/popular") - suspend fun popularMovieList( + suspend fun popularMovies( @Query("page") page: Int, @Query("with_genres") genreId: String?, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): BaseModelMovie @GET("movie/top_rated") - suspend fun topRatedMovieList( + suspend fun topRatedMovies( @Query("page") page: Int, @Query("with_genres") genreId: String?, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): BaseModelMovie @GET("movie/upcoming") - suspend fun upcomingMovieList( + suspend fun upcomingMovies( @Query("page") page: Int, @Query("with_genres") genreId: String?, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): BaseModelMovie @GET("movie/{movieId}") suspend fun movieDetail( @@ -46,14 +49,13 @@ interface ApiService { @GET("movie/{movieId}/recommendations") suspend fun recommendedMovie( - @Path("movieId") movieId: Int, - @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + @Path("movieId") movieId: Int, @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelMovie @GET("search/movie?page=1&include_adult=false") - suspend fun search( + suspend fun searchMovie( @Query("query") searchKey: String, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): SearchBaseModel @GET("genre/movie/list") suspend fun genreList(@Query("api_key") api_key: String = BuildConfig.API_KEY): Genres @@ -63,7 +65,7 @@ interface ApiService { @Query("page") page: Int, @Query("with_genres") genreId: String, @Query("api_key") api_key: String = BuildConfig.API_KEY - ): BaseModel + ): BaseModelMovie @GET("movie/{movieId}/credits") suspend fun movieCredit( @@ -74,4 +76,53 @@ interface ApiService { suspend fun artistDetail( @Path("personId") personId: Int, @Query("api_key") api_key: String = BuildConfig.API_KEY ): ArtistDetail + + @GET("tv/airing_today") + suspend fun airingTodayTvSeries( + @Query("page") page: Int, + @Query("with_genres") genreId: String?, + @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelTvSeries + + @GET("tv/on_the_air") + suspend fun onTheAirTvSeries( + @Query("page") page: Int, + @Query("with_genres") genreId: String?, + @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelTvSeries + + @GET("tv/popular") + suspend fun popularTvSeries( + @Query("page") page: Int, + @Query("with_genres") genreId: String?, + @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelTvSeries + + @GET("tv/top_rated") + suspend fun topRatedTvSeries( + @Query("page") page: Int, + @Query("with_genres") genreId: String?, + @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelTvSeries + + @GET("tv/{seriesId}") + suspend fun tvSeriesDetail( + @Path("seriesId") seriesId: Int, @Query("api_key") api_key: String = BuildConfig.API_KEY + ): TvSeriesDetail + + @GET("tv/{seriesId}/recommendations") + suspend fun recommendedTvSeries( + @Path("seriesId") seriesId: Int, @Query("api_key") api_key: String = BuildConfig.API_KEY + ): BaseModelTvSeries + + @GET("tv/{seriesId}/credits") + suspend fun tvSeriesCredit( + @Path("seriesId") seriesId: Int, @Query("api_key") api_key: String = BuildConfig.API_KEY + ): Artist + + @GET("search/tv?page=1&include_adult=false") + suspend fun searchTvSeries( + @Query("query") searchKey: String, + @Query("api_key") api_key: String = BuildConfig.API_KEY + ): SearchBaseModel } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/GenrePagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/GenrePagingDataSource.kt similarity index 98% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/GenrePagingDataSource.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/GenrePagingDataSource.kt index 9c8a990..47ba4d8 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/GenrePagingDataSource.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/GenrePagingDataSource.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource import androidx.paging.PagingSource import androidx.paging.PagingState diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/PopularPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/NowPlayingMoviePagingDataSource.kt similarity index 85% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/PopularPagingDataSource.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/NowPlayingMoviePagingDataSource.kt index c6bb039..6e5e507 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/PopularPagingDataSource.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/NowPlayingMoviePagingDataSource.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie import androidx.paging.PagingSource import androidx.paging.PagingState @@ -9,7 +9,7 @@ import timber.log.Timber import java.io.IOException import javax.inject.Inject -class PopularPagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : +class NowPlayingMoviePagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : PagingSource() { override fun getRefreshKey(state: PagingState): Int? { @@ -19,7 +19,7 @@ class PopularPagingDataSource @Inject constructor(private val apiService: ApiSer override suspend fun load(params: LoadParams): LoadResult { return try { val nextPage = params.key ?: 1 - val movieList = apiService.popularMovieList(nextPage, genreId) + val movieList = apiService.nowPlayingMovies(nextPage, genreId) LoadResult.Page( data = movieList.results, prevKey = if (nextPage == 1) null else nextPage - 1, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/NowPlayingPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/PopularMoviePagingDataSource.kt similarity index 85% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/NowPlayingPagingDataSource.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/PopularMoviePagingDataSource.kt index 2d68d60..d8ea334 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/NowPlayingPagingDataSource.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/PopularMoviePagingDataSource.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie import androidx.paging.PagingSource import androidx.paging.PagingState @@ -9,7 +9,7 @@ import timber.log.Timber import java.io.IOException import javax.inject.Inject -class NowPlayingPagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : +class PopularMoviePagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : PagingSource() { override fun getRefreshKey(state: PagingState): Int? { @@ -19,7 +19,7 @@ class NowPlayingPagingDataSource @Inject constructor(private val apiService: Api override suspend fun load(params: LoadParams): LoadResult { return try { val nextPage = params.key ?: 1 - val movieList = apiService.nowPlayingMovieList(nextPage, genreId) + val movieList = apiService.popularMovies(nextPage, genreId) LoadResult.Page( data = movieList.results, prevKey = if (nextPage == 1) null else nextPage - 1, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/TopRatedPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/TopRatedMoviePagingDataSource.kt similarity index 84% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/TopRatedPagingDataSource.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/TopRatedMoviePagingDataSource.kt index 9a4af7e..e26b7b0 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/TopRatedPagingDataSource.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/TopRatedMoviePagingDataSource.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie import androidx.paging.PagingSource import androidx.paging.PagingState @@ -9,7 +9,7 @@ import timber.log.Timber import java.io.IOException import javax.inject.Inject -class TopRatedPagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : +class TopRatedMoviePagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : PagingSource() { override fun getRefreshKey(state: PagingState): Int? { @@ -19,7 +19,7 @@ class TopRatedPagingDataSource @Inject constructor(private val apiService: ApiSe override suspend fun load(params: LoadParams): LoadResult { return try { val nextPage = params.key ?: 1 - val movieList = apiService.topRatedMovieList(nextPage, genreId) + val movieList = apiService.topRatedMovies(nextPage, genreId) LoadResult.Page( data = movieList.results, prevKey = if (nextPage == 1) null else nextPage - 1, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/UpcomingPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/UpcomingMoviePagingDataSource.kt similarity index 84% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/UpcomingPagingDataSource.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/UpcomingMoviePagingDataSource.kt index bedc872..d7e2e5e 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging/UpcomingPagingDataSource.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/movie/UpcomingMoviePagingDataSource.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie import androidx.paging.PagingSource import androidx.paging.PagingState @@ -9,7 +9,7 @@ import timber.log.Timber import java.io.IOException import javax.inject.Inject -class UpcomingPagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : +class UpcomingMoviePagingDataSource @Inject constructor(private val apiService: ApiService, private val genreId:String?) : PagingSource() { override fun getRefreshKey(state: PagingState): Int? { @@ -19,7 +19,7 @@ class UpcomingPagingDataSource @Inject constructor(private val apiService: ApiSe override suspend fun load(params: LoadParams): LoadResult { return try { val nextPage = params.key ?: 1 - val movieList = apiService.upcomingMovieList(nextPage, genreId) + val movieList = apiService.upcomingMovies(nextPage, genreId) LoadResult.Page( data = movieList.results, prevKey = if (nextPage == 1) null else nextPage - 1, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/AiringTodayTvSeriesPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/AiringTodayTvSeriesPagingDataSource.kt new file mode 100644 index 0000000..3fed2df --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/AiringTodayTvSeriesPagingDataSource.kt @@ -0,0 +1,39 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import retrofit2.HttpException +import timber.log.Timber +import java.io.IOException +import javax.inject.Inject + +class AiringTodayTvSeriesPagingDataSource @Inject constructor( + private val apiService: ApiService, + private val genreId: String? +) : + PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition + } + + override suspend fun load(params: LoadParams): LoadResult { + return try { + val nextPage = params.key ?: 1 + val movieList = apiService.airingTodayTvSeries(nextPage, genreId) + LoadResult.Page( + data = movieList.results, + prevKey = if (nextPage == 1) null else nextPage - 1, + nextKey = if (movieList.results.isNotEmpty()) movieList.page + 1 else null + ) + } catch (exception: IOException) { + Timber.e("exception ${exception.message}") + return LoadResult.Error(exception) + } catch (httpException: HttpException) { + Timber.e("httpException ${httpException.message}") + return LoadResult.Error(httpException) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/OnTheAirTvSeriesPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/OnTheAirTvSeriesPagingDataSource.kt new file mode 100644 index 0000000..d1f63c2 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/OnTheAirTvSeriesPagingDataSource.kt @@ -0,0 +1,39 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import retrofit2.HttpException +import timber.log.Timber +import java.io.IOException +import javax.inject.Inject + +class OnTheAirTvSeriesPagingDataSource @Inject constructor( + private val apiService: ApiService, + private val genreId: String? +) : + PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition + } + + override suspend fun load(params: LoadParams): LoadResult { + return try { + val nextPage = params.key ?: 1 + val movieList = apiService.onTheAirTvSeries(nextPage, genreId) + LoadResult.Page( + data = movieList.results, + prevKey = if (nextPage == 1) null else nextPage - 1, + nextKey = if (movieList.results.isNotEmpty()) movieList.page + 1 else null + ) + } catch (exception: IOException) { + Timber.e("exception ${exception.message}") + return LoadResult.Error(exception) + } catch (httpException: HttpException) { + Timber.e("httpException ${httpException.message}") + return LoadResult.Error(httpException) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/PopularTvSeriesPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/PopularTvSeriesPagingDataSource.kt new file mode 100644 index 0000000..74002b5 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/PopularTvSeriesPagingDataSource.kt @@ -0,0 +1,39 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import retrofit2.HttpException +import timber.log.Timber +import java.io.IOException +import javax.inject.Inject + +class PopularTvSeriesPagingDataSource @Inject constructor( + private val apiService: ApiService, + private val genreId: String? +) : + PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition + } + + override suspend fun load(params: LoadParams): LoadResult { + return try { + val nextPage = params.key ?: 1 + val movieList = apiService.popularTvSeries(nextPage, genreId) + LoadResult.Page( + data = movieList.results, + prevKey = if (nextPage == 1) null else nextPage - 1, + nextKey = if (movieList.results.isNotEmpty()) movieList.page + 1 else null + ) + } catch (exception: IOException) { + Timber.e("exception ${exception.message}") + return LoadResult.Error(exception) + } catch (httpException: HttpException) { + Timber.e("httpException ${httpException.message}") + return LoadResult.Error(httpException) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/TopRatedTvSeriesPagingDataSource.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/TopRatedTvSeriesPagingDataSource.kt new file mode 100644 index 0000000..ed61e50 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/datasource/remote/paging_datasource/tv_series/TopRatedTvSeriesPagingDataSource.kt @@ -0,0 +1,39 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import retrofit2.HttpException +import timber.log.Timber +import java.io.IOException +import javax.inject.Inject + +class TopRatedTvSeriesPagingDataSource @Inject constructor( + private val apiService: ApiService, + private val genreId: String? +) : + PagingSource() { + + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition + } + + override suspend fun load(params: LoadParams): LoadResult { + return try { + val nextPage = params.key ?: 1 + val movieList = apiService.topRatedTvSeries(nextPage, genreId) + LoadResult.Page( + data = movieList.results, + prevKey = if (nextPage == 1) null else nextPage - 1, + nextKey = if (movieList.results.isNotEmpty()) movieList.page + 1 else null + ) + } catch (exception: IOException) { + Timber.e("exception ${exception.message}") + return LoadResult.Error(exception) + } catch (httpException: HttpException) { + Timber.e("httpException ${httpException.message}") + return LoadResult.Error(httpException) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelMovie.kt similarity index 92% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelMovie.kt index c146728..67f8f06 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelMovie.kt @@ -3,7 +3,7 @@ package com.piashcse.hilt_mvvm_compose_movie.data.model import com.google.gson.annotations.SerializedName -data class BaseModel( +data class BaseModelMovie( @SerializedName("page") val page: Int, @SerializedName("results") diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelTvSeries.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelTvSeries.kt new file mode 100644 index 0000000..23cb13f --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/BaseModelTvSeries.kt @@ -0,0 +1,15 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model + + +import com.google.gson.annotations.SerializedName + +data class BaseModelTvSeries( + @SerializedName("page") + val page: Int, + @SerializedName("results") + val results: List, + @SerializedName("total_pages") + val totalPages: Int, + @SerializedName("total_results") + val totalResults: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/SearchBaseModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/SearchBaseModel.kt new file mode 100644 index 0000000..69d757c --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/SearchBaseModel.kt @@ -0,0 +1,29 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model + +import com.google.gson.annotations.SerializedName + +data class SearchBaseModel( + @SerializedName("page") + val page: Int, + @SerializedName("results") + val results: List, + @SerializedName("total_pages") + val totalPages: Int, + @SerializedName("total_results") + val totalResults: Int +) + +data class SearchItem( + @SerializedName("backdrop_path") + val backdropPath: String?, + @SerializedName("id") + val id: Int, + @SerializedName("poster_path") + val posterPath: String?, + @SerializedName("title") + val title: String?, + @SerializedName("vote_average") + val voteAverage: Double?, + @SerializedName("release_date") + val releaseDate: String?, +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/TvSeriesItem.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/TvSeriesItem.kt new file mode 100644 index 0000000..441c39d --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/TvSeriesItem.kt @@ -0,0 +1,35 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model + + +import com.google.gson.annotations.SerializedName + +data class TvSeriesItem( + @SerializedName("adult") + val adult: Boolean, + @SerializedName("backdrop_path") + val backdropPath: String?, + @SerializedName("first_air_date") + val firstAirDate: String, + @SerializedName("genre_ids") + val genreIds: List, + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String, + @SerializedName("origin_country") + val originCountry: List, + @SerializedName("original_language") + val originalLanguage: String, + @SerializedName("original_name") + val originalName: String, + @SerializedName("overview") + val overview: String, + @SerializedName("popularity") + val popularity: Double, + @SerializedName("poster_path") + val posterPath: String, + @SerializedName("vote_average") + val voteAverage: Double, + @SerializedName("vote_count") + val voteCount: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/CreatedBy.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/CreatedBy.kt new file mode 100644 index 0000000..900edc3 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/CreatedBy.kt @@ -0,0 +1,19 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail + + +import com.google.gson.annotations.SerializedName + +data class CreatedBy( + @SerializedName("credit_id") + val creditId: String, + @SerializedName("gender") + val gender: Int, + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String, + @SerializedName("original_name") + val originalName: String, + @SerializedName("profile_path") + val profilePath: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Genre.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Genre.kt new file mode 100644 index 0000000..3ce13b4 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Genre.kt @@ -0,0 +1,9 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail + +import com.google.gson.annotations.SerializedName +data class Genre( + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/LastEpisodeToAir.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/LastEpisodeToAir.kt new file mode 100644 index 0000000..8bac9d2 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/LastEpisodeToAir.kt @@ -0,0 +1,32 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail + +import com.google.gson.annotations.SerializedName + +data class LastEpisodeToAir( + @SerializedName("air_date") + val airDate: String, + @SerializedName("episode_number") + val episodeNumber: Int, + @SerializedName("episode_type") + val episodeType: String, + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String, + @SerializedName("overview") + val overview: String, + @SerializedName("production_code") + val productionCode: String, + @SerializedName("runtime") + val runtime: Double?, + @SerializedName("season_number") + val seasonNumber: Int, + @SerializedName("show_id") + val showId: Int, + @SerializedName("still_path") + val stillPath: String?, + @SerializedName("vote_average") + val voteAverage: Double, + @SerializedName("vote_count") + val voteCount: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Network.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Network.kt new file mode 100644 index 0000000..92741a6 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Network.kt @@ -0,0 +1,12 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail +import com.google.gson.annotations.SerializedName +data class Network( + @SerializedName("id") + val id: Int, + @SerializedName("logo_path") + val logoPath: String?, + @SerializedName("name") + val name: String, + @SerializedName("origin_country") + val originCountry: String +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/NextEpisodeToAir.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/NextEpisodeToAir.kt new file mode 100644 index 0000000..7f49c1a --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/NextEpisodeToAir.kt @@ -0,0 +1,31 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail +import com.google.gson.annotations.SerializedName + +data class NextEpisodeToAir( + @SerializedName("air_date") + val airDate: String, + @SerializedName("episode_number") + val episodeNumber: Int, + @SerializedName("episode_type") + val episodeType: String, + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String, + @SerializedName("overview") + val overview: String, + @SerializedName("production_code") + val productionCode: String, + @SerializedName("runtime") + val runtime: Double?, + @SerializedName("season_number") + val seasonNumber: Int, + @SerializedName("show_id") + val showId: Int, + @SerializedName("still_path") + val stillPath: String?, + @SerializedName("vote_average") + val voteAverage: Double, + @SerializedName("vote_count") + val voteCount: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCompany.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCompany.kt new file mode 100644 index 0000000..9f9c59c --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCompany.kt @@ -0,0 +1,14 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail + +import com.google.gson.annotations.SerializedName + +data class ProductionCompany( + @SerializedName("id") + val id: Int, + @SerializedName("logo_path") + val logoPath: String?, + @SerializedName("name") + val name: String, + @SerializedName("origin_country") + val originCountry: String +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCountry.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCountry.kt new file mode 100644 index 0000000..79bc9cb --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/ProductionCountry.kt @@ -0,0 +1,9 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail +import com.google.gson.annotations.SerializedName + +data class ProductionCountry( + @SerializedName("iso_3166_1") + val iso31661: String, + @SerializedName("name") + val name: String +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Season.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Season.kt new file mode 100644 index 0000000..2afd62e --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/Season.kt @@ -0,0 +1,21 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail +import com.google.gson.annotations.SerializedName + +data class Season( + @SerializedName("air_date") + val airDate: String?, + @SerializedName("episode_count") + val episodeCount: Int, + @SerializedName("id") + val id: Int, + @SerializedName("name") + val name: String, + @SerializedName("overview") + val overview: String, + @SerializedName("poster_path") + val posterPath: String?, + @SerializedName("season_number") + val seasonNumber: Int, + @SerializedName("vote_average") + val voteAverage: Double +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/SpokenLanguage.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/SpokenLanguage.kt new file mode 100644 index 0000000..a9da281 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/SpokenLanguage.kt @@ -0,0 +1,11 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail + +import com.google.gson.annotations.SerializedName +data class SpokenLanguage( + @SerializedName("english_name") + val englishName: String, + @SerializedName("iso_639_1") + val iso6391: String, + @SerializedName("name") + val name: String +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/TvSeriesDetail.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/TvSeriesDetail.kt new file mode 100644 index 0000000..461718d --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/model/tv_series_detail/TvSeriesDetail.kt @@ -0,0 +1,68 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail +import com.google.gson.annotations.SerializedName +data class TvSeriesDetail( + @SerializedName("adult") + val adult: Boolean, + @SerializedName("backdrop_path") + val backdropPath: String, + @SerializedName("created_by") + val createdBy: List, + @SerializedName("episode_run_time") + val episodeRunTime: List, + @SerializedName("first_air_date") + val firstAirDate: String, + @SerializedName("genres") + val genres: List, + @SerializedName("homepage") + val homepage: String, + @SerializedName("id") + val id: Int, + @SerializedName("in_production") + val inProduction: Boolean, + @SerializedName("languages") + val languages: List, + @SerializedName("last_air_date") + val lastAirDate: String?, + @SerializedName("last_episode_to_air") + val lastEpisodeToAir: LastEpisodeToAir?, + @SerializedName("name") + val name: String, + @SerializedName("networks") + val networks: List, + @SerializedName("next_episode_to_air") + val nextEpisodeToAir: NextEpisodeToAir?, + @SerializedName("number_of_episodes") + val numberOfEpisodes: Int, + @SerializedName("number_of_seasons") + val numberOfSeasons: Int, + @SerializedName("origin_country") + val originCountry: List, + @SerializedName("original_language") + val originalLanguage: String, + @SerializedName("original_name") + val originalName: String, + @SerializedName("overview") + val overview: String, + @SerializedName("popularity") + val popularity: Double, + @SerializedName("poster_path") + val posterPath: String, + @SerializedName("production_companies") + val productionCompanies: List, + @SerializedName("production_countries") + val productionCountries: List, + @SerializedName("seasons") + val seasons: List, + @SerializedName("spoken_languages") + val spokenLanguages: List, + @SerializedName("status") + val status: String, + @SerializedName("tagline") + val tagline: String, + @SerializedName("type") + val type: String, + @SerializedName("vote_average") + val voteAverage: Double, + @SerializedName("vote_count") + val voteCount: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepository.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepository.kt index cfb2e2a..f62e0e1 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepository.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepository.kt @@ -4,14 +4,14 @@ import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService -import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging.GenrePagingDataSource -import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging.NowPlayingPagingDataSource -import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging.PopularPagingDataSource -import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging.TopRatedPagingDataSource -import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging.UpcomingPagingDataSource -import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModel +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.GenrePagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie.NowPlayingMoviePagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie.PopularMoviePagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie.TopRatedMoviePagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.movie.UpcomingMoviePagingDataSource import com.piashcse.hilt_mvvm_compose_movie.data.model.Genres import com.piashcse.hilt_mvvm_compose_movie.data.model.MovieItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.ArtistDetail import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.MovieDetail @@ -47,10 +47,10 @@ class MovieRepository @Inject constructor( } - override suspend fun search(searchKey: String): Flow> = flow { + override suspend fun movieSearch(searchKey: String): Flow> = flow { emit(DataState.Loading) try { - val searchResult = apiService.search(searchKey) + val searchResult = apiService.searchMovie(searchKey) emit(DataState.Success(searchResult)) } catch (e: Exception) { @@ -91,29 +91,29 @@ class MovieRepository @Inject constructor( } } - override fun nowPlayingPagingDataSource(genreId: String?): Flow> = Pager( - pagingSourceFactory = { NowPlayingPagingDataSource(apiService, genreId) }, - config = PagingConfig(pageSize = 1) + override fun nowPlayingMoviePagingDataSource(genreId: String?): Flow> = Pager( + pagingSourceFactory = { NowPlayingMoviePagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) ).flow - override fun popularPagingDataSource(genreId: String?): Flow> = Pager( - pagingSourceFactory = { PopularPagingDataSource(apiService, genreId) }, - config = PagingConfig(pageSize = 1) + override fun popularMoviePagingDataSource(genreId: String?): Flow> = Pager( + pagingSourceFactory = { PopularMoviePagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) ).flow - override fun topRatedPagingDataSource(genreId: String?): Flow> = Pager( - pagingSourceFactory = { TopRatedPagingDataSource(apiService, genreId) }, - config = PagingConfig(pageSize = 1) + override fun topRatedMoviePagingDataSource(genreId: String?): Flow> = Pager( + pagingSourceFactory = { TopRatedMoviePagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) ).flow - override fun upcomingPagingDataSource(genreId: String?): Flow> = Pager( - pagingSourceFactory = { UpcomingPagingDataSource(apiService, genreId) }, - config = PagingConfig(pageSize = 1) + override fun upcomingMoviePagingDataSource(genreId: String?): Flow> = Pager( + pagingSourceFactory = { UpcomingMoviePagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) ).flow override fun genrePagingDataSource(genreId: String): Flow> = Pager( pagingSourceFactory = { GenrePagingDataSource(apiService, genreId) }, - config = PagingConfig(pageSize = 1) + config = PagingConfig(pageSize = 20) ).flow } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepositoryInterface.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepositoryInterface.kt index 263c142..f8a1efc 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepositoryInterface.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/MovieRepositoryInterface.kt @@ -1,9 +1,9 @@ package com.piashcse.hilt_mvvm_compose_movie.data.repository import androidx.paging.PagingData -import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModel import com.piashcse.hilt_mvvm_compose_movie.data.model.Genres import com.piashcse.hilt_mvvm_compose_movie.data.model.MovieItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.ArtistDetail import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.MovieDetail @@ -13,13 +13,13 @@ import kotlinx.coroutines.flow.Flow interface MovieRepositoryInterface { suspend fun movieDetail(movieId: Int): Flow> suspend fun recommendedMovie(movieId: Int): Flow>> - suspend fun search(searchKey: String): Flow> + suspend fun movieSearch(searchKey: String): Flow> suspend fun genreList(): Flow> suspend fun movieCredit(movieId: Int): Flow> suspend fun artistDetail(personId: Int): Flow> - fun nowPlayingPagingDataSource(genreId: String?): Flow> - fun popularPagingDataSource(genreId: String?): Flow> - fun topRatedPagingDataSource(genreId: String?): Flow> - fun upcomingPagingDataSource(genreId: String?): Flow> + fun nowPlayingMoviePagingDataSource(genreId: String?): Flow> + fun popularMoviePagingDataSource(genreId: String?): Flow> + fun topRatedMoviePagingDataSource(genreId: String?): Flow> + fun upcomingMoviePagingDataSource(genreId: String?): Flow> fun genrePagingDataSource(genreId: String): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepository.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepository.kt new file mode 100644 index 0000000..7bb9c2b --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepository.kt @@ -0,0 +1,90 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.repository + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series.AiringTodayTvSeriesPagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series.OnTheAirTvSeriesPagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series.PopularTvSeriesPagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.paging_datasource.tv_series.TopRatedTvSeriesPagingDataSource +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist +import com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail.TvSeriesDetail +import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class TvSeriesRepository @Inject constructor( + private val apiService: ApiService +) : TvSeriesRepositoryInterFace { + override fun airingTodayTvSeriesPagingDataSource(genreId: String?): Flow> = + Pager( + pagingSourceFactory = { AiringTodayTvSeriesPagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) + ).flow + + override fun onTheAirTvSeriesPagingDataSource(genreId: String?): Flow> = + Pager( + pagingSourceFactory = { OnTheAirTvSeriesPagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) + ).flow + + override fun popularTvSeriesPagingDataSource(genreId: String?): Flow> = + Pager( + pagingSourceFactory = { PopularTvSeriesPagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) + ).flow + + override fun topRatedTvSeriesPagingDataSource(genreId: String?): Flow> = + Pager( + pagingSourceFactory = { TopRatedTvSeriesPagingDataSource(apiService, genreId) }, + config = PagingConfig(pageSize = 20) + ).flow + + override suspend fun searchTvSeries(searchKey: String): Flow> = flow { + emit(DataState.Loading) + try { + val searchResult = apiService.searchTvSeries(searchKey) + emit(DataState.Success(searchResult)) + + } catch (e: Exception) { + emit(DataState.Error(e)) + } + } + + override suspend fun tvSeriesDetail(seriesId: Int): Flow> = flow { + emit(DataState.Loading) + try { + val apiResponse = apiService.tvSeriesDetail(seriesId) + emit(DataState.Success(apiResponse)) + + } catch (e: Exception) { + emit(DataState.Error(e)) + } + } + + override suspend fun recommendedTvSeries(seriesId: Int): Flow>> = flow { + emit(DataState.Loading) + try { + val apiResponse = apiService.recommendedTvSeries(seriesId) + emit(DataState.Success(apiResponse.results)) + + } catch (e: Exception) { + emit(DataState.Error(e)) + } + } + + override suspend fun artistDetail(personId: Int): Flow> = flow { + emit(DataState.Loading) + try { + val apiResponse = apiService.tvSeriesCredit(personId) + emit(DataState.Success(apiResponse)) + + } catch (e: Exception) { + emit(DataState.Error(e)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepositoryInterFace.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepositoryInterFace.kt new file mode 100644 index 0000000..b06fde3 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/data/repository/TvSeriesRepositoryInterFace.kt @@ -0,0 +1,20 @@ +package com.piashcse.hilt_mvvm_compose_movie.data.repository + +import androidx.paging.PagingData +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist +import com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail.TvSeriesDetail +import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState +import kotlinx.coroutines.flow.Flow + +interface TvSeriesRepositoryInterFace { + fun airingTodayTvSeriesPagingDataSource(genreId: String?): Flow> + fun onTheAirTvSeriesPagingDataSource(genreId: String?): Flow> + fun popularTvSeriesPagingDataSource(genreId: String?): Flow> + fun topRatedTvSeriesPagingDataSource(genreId: String?): Flow> + suspend fun searchTvSeries(searchKey: String): Flow> + suspend fun tvSeriesDetail(seriesId: Int): Flow> + suspend fun recommendedTvSeries(seriesId: Int): Flow>> + suspend fun artistDetail(personId: Int): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/di/RepositoryModule.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/di/RepositoryModule.kt index fcf6c6d..ad7fc38 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/di/RepositoryModule.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/di/RepositoryModule.kt @@ -2,6 +2,7 @@ package com.piashcse.hilt_mvvm_compose_movie.di import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiService import com.piashcse.hilt_mvvm_compose_movie.data.repository.MovieRepository +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -23,5 +24,17 @@ object RepositoryModule { apiService ) } + /** + * Provides RemoteDataRepository for access api service method + */ + @Singleton + @Provides + fun provideTvSeriesRepository( + apiService: ApiService, + ): TvSeriesRepository { + return TvSeriesRepository( + apiService + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavGraph.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavGraph.kt index 96a9497..7c282ca 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavGraph.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavGraph.kt @@ -2,7 +2,6 @@ package com.piashcse.hilt_mvvm_compose_movie.navigation import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.navigation.NavController import androidx.navigation.NavHostController @@ -13,39 +12,44 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.navArgument import com.piashcse.hilt_mvvm_compose_movie.R import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.artistdetail.ArtistDetail -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.nowplaying.NowPlaying -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.popular.Popular -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.toprated.TopRated -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.upcoming.Upcoming +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.artist_detail.ArtistDetail import com.piashcse.hilt_mvvm_compose_movie.ui.screens.genre.GenreScreen -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.moviedetail.MovieDetail +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.movie_detail.MovieDetail +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.nowplaying.NowPlayingMovie +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.popular.PopularMovie +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.toprated.TopRatedMovie +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.upcoming.UpcomingMovie +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.airing_today.AiringTodayTvSeries +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.on_the_air.OnTheAirTvSeries +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.popular.PopularTvSeries +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.top_rated.TopRatedTvSeries +import com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.tv_series_detail.TvSeriesDetail @Composable fun Navigation( - navController: NavHostController, modifier: Modifier, genres: ArrayList? = null, + navController: NavHostController, page: Int, genres: ArrayList? = null, ) { - NavHost(navController, startDestination = Screen.Home.route, modifier) { - composable(Screen.Home.route) { - NowPlaying( + NavHost(navController, startDestination = initialScreen(page)) { + composable(Screen.NowPlaying.route) { + NowPlayingMovie( navController = navController, genres ) } composable(Screen.Popular.route) { - Popular( + PopularMovie( navController = navController, genres ) } composable(Screen.TopRated.route) { - TopRated( + TopRatedMovie( navController = navController, genres ) } composable(Screen.Upcoming.route) { - Upcoming( + UpcomingMovie( navController = navController, genres ) @@ -91,6 +95,52 @@ fun Navigation( ) } } + composable(Screen.AiringTodayTvSeries.route) { + AiringTodayTvSeries( + navController = navController, + genres + ) + } + composable(Screen.OnTheAirTvSeries.route) { + OnTheAirTvSeries( + navController = navController, + genres + ) + } + composable(Screen.PopularTvSeries.route) { + PopularTvSeries( + navController = navController, + genres + ) + } + composable(Screen.TopRatedTvSeries.route) { + TopRatedTvSeries( + navController = navController, + genres + ) + } + composable( + Screen.TvSeriesDetail.route.plus(Screen.TvSeriesDetail.objectPath), + arguments = listOf(navArgument(Screen.TvSeriesDetail.objectName) { + type = NavType.IntType + }) + ) { + label = stringResource(R.string.tv_series_detail) + val movieId = it.arguments?.getInt(Screen.TvSeriesDetail.objectName) + movieId?.let { + TvSeriesDetail( + navController = navController, movieId + ) + } + } + } +} + +fun initialScreen(page:Int): String { + return if (page == 0) { + Screen.NowPlaying.route + } else { + Screen.AiringTodayTvSeries.route } } @@ -98,10 +148,10 @@ fun Navigation( fun navigationTitle(navController: NavController): String { return when (currentRoute(navController)) { Screen.MovieDetail.route -> stringResource(id = R.string.movie_detail) + Screen.TvSeriesDetail.route -> stringResource(id = R.string.tv_series_detail) Screen.ArtistDetail.route -> stringResource(id = R.string.artist_detail) - Screen.Login.route -> stringResource(id = R.string.login) else -> { - "" + stringResource(R.string.app_name) } } } diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavigationScreen.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavigationScreen.kt index 4bd4480..33e343e 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavigationScreen.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/navigation/NavigationScreen.kt @@ -4,8 +4,10 @@ import androidx.annotation.StringRes import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.KeyboardArrowDown +import androidx.compose.material.icons.filled.LiveTv import androidx.compose.material.icons.filled.Star import androidx.compose.material.icons.filled.Timeline import androidx.compose.material3.Icon @@ -16,7 +18,7 @@ import com.piashcse.hilt_mvvm_compose_movie.R sealed class Screen( val route: String, - @StringRes val title: Int = R.string.app_title, + @StringRes val title: Int = R.string.app_name, val navIcon: (@Composable () -> Unit) = { Icon( Icons.Filled.Home, contentDescription = "home" @@ -25,22 +27,28 @@ sealed class Screen( val objectName: String = "", val objectPath: String = "" ) { - object Login : Screen("login_screen") - object Home : Screen("home_screen") - object Popular : Screen("popular_screen") - object TopRated : Screen("top_rated_screen") - object Upcoming : Screen("upcoming_screen") + object NowPlaying : Screen("now_playing_movie") + object Popular : Screen("popular_movie") + object TopRated : Screen("top_rated_movie") + object Upcoming : Screen("upcoming_movie") + object AiringTodayTvSeries : Screen("airing_today_tv_series") + object OnTheAirTvSeries : Screen("on_the_air_tv_series") + object PopularTvSeries : Screen("popular_tv_series") + object TopRatedTvSeries : Screen("top_rated_tv_series") object NavigationDrawer : Screen("navigation_drawer", objectName = "genreId", objectPath = "/{genreId}") object MovieDetail : Screen("movie_detail_screen", objectName = "movieItem", objectPath = "/{movieItem}") + object TvSeriesDetail : + Screen("tv_series_detail_screen", objectName = "tvSeriesItem", objectPath = "/{tvSeriesItem}") + object ArtistDetail : Screen("artist_detail_screen", objectName = "artistId", objectPath = "/{artistId}") // Bottom Navigation - object HomeNav : Screen("home_screen", title = R.string.home, navIcon = { + object NowPlayingNav : Screen("now_playing_movie", title = R.string.now_playing, navIcon = { Icon( Icons.Filled.Home, contentDescription = "search", @@ -50,7 +58,7 @@ sealed class Screen( ) }) - object PopularNav : Screen("popular_screen", title = R.string.popular, navIcon = { + object PopularNav : Screen("popular_movie", title = R.string.popular, navIcon = { Icon( Icons.Filled.Timeline, contentDescription = "search", @@ -60,7 +68,7 @@ sealed class Screen( ) }) - object TopRatedNav : Screen("top_rated_screen", title = R.string.top_rate, navIcon = { + object TopRatedNav : Screen("top_rated_movie", title = R.string.top_rated, navIcon = { Icon( Icons.Filled.Star, contentDescription = "search", @@ -70,7 +78,7 @@ sealed class Screen( ) }) - object UpcomingNav : Screen("upcoming_screen", title = R.string.up_coming, navIcon = { + object UpcomingNav : Screen("upcoming_movie", title = R.string.up_coming, navIcon = { Icon( Icons.Filled.KeyboardArrowDown, contentDescription = "search", @@ -79,4 +87,40 @@ sealed class Screen( .offset(x = 10.dp) ) }) + object AiringTodayTvSeriesNav : Screen("airing_today_tv_series", title = R.string.airing_today, navIcon = { + Icon( + Icons.Filled.LiveTv, + contentDescription = "Home", + modifier = Modifier + .padding(end = 16.dp) + .offset(x = 10.dp) + ) + }) + object OnTheAirTvSeriesNav : Screen("on_the_air_tv_series", title = R.string.on_the_air, navIcon = { + Icon( + Icons.Filled.Timeline, + contentDescription = "Timeline", + modifier = Modifier + .padding(end = 16.dp) + .offset(x = 10.dp) + ) + }) + object PopularTvSeriesNav : Screen("popular_tv_series", title = R.string.popular, navIcon = { + Icon( + Icons.Filled.Favorite, + contentDescription = "Star", + modifier = Modifier + .padding(end = 16.dp) + .offset(x = 10.dp) + ) + }) + object TopRatedTvSeriesNav : Screen("top_rated_tv_series", title = R.string.top_rated, navIcon = { + Icon( + Icons.Filled.Star, + contentDescription = "KeyboardArrowDown", + modifier = Modifier + .padding(end = 16.dp) + .offset(x = 10.dp) + ) + }) } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/ExistAlertDiaglog.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/ExistAlertDiaglog.kt index c8b05b5..b34c97f 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/ExistAlertDiaglog.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/ExistAlertDiaglog.kt @@ -20,7 +20,7 @@ import com.piashcse.hilt_mvvm_compose_movie.navigation.currentRoute @Composable fun ExitAlertDialog(navController: NavController, cancel: (isOpen: Boolean) -> Unit, ok: () -> Unit) { val openDialog = remember { mutableStateOf(true) } - if (currentRoute(navController = navController) == Screen.Home.route && openDialog.value) { + if (currentRoute(navController = navController) == Screen.NowPlaying.route && openDialog.value) { AlertDialog( onDismissRequest = { }, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/MovieItem.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/MovieItem.kt index df9cc53..b4bf703 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/MovieItem.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/MovieItem.kt @@ -34,9 +34,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController -import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiURL import com.piashcse.hilt_mvvm_compose_movie.data.model.MovieItem import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre @@ -56,12 +54,11 @@ import com.skydoves.landscapist.coil.CoilImage import com.skydoves.landscapist.components.rememberImageComponent import com.skydoves.landscapist.placeholder.shimmer.Shimmer import com.skydoves.landscapist.placeholder.shimmer.ShimmerPlugin -import kotlinx.coroutines.flow.Flow @Composable fun MovieItemList( navController: NavController, - movies: Flow>, + moviesItems: LazyPagingItems, genres: ArrayList? = null, selectedName: Genre?, onclick: (genreId: Genre?) -> Unit @@ -69,9 +66,9 @@ fun MovieItemList( val activity = (LocalContext.current as? Activity) val progressBar = remember { mutableStateOf(false) } val openDialog = remember { mutableStateOf(false) } - val moviesItems: LazyPagingItems = movies.collectAsLazyPagingItems() + //val moviesItems: LazyPagingItems = movies.collectAsLazyPagingItems() - BackHandler(enabled = (currentRoute(navController) == Screen.Home.route)) { + BackHandler(enabled = (currentRoute(navController) == Screen.NowPlaying.route)) { openDialog.value = true } Column(modifier = Modifier.background(DefaultBackgroundColor)) { diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchBar.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchBar.kt index 2cfd7e4..a332b14 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchBar.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchBar.kt @@ -31,7 +31,7 @@ import kotlinx.coroutines.FlowPreview @OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) @Composable -fun SearchBar(isAppBarVisible:MutableState, viewModel: MainViewModel){ +fun SearchBar(isAppBarVisible:MutableState, viewModel: MainViewModel, activeTab: Int){ var text by remember { mutableStateOf("") } val focusRequester = FocusRequester() BackHandler(isAppBarVisible.value.not()) { @@ -51,7 +51,11 @@ fun SearchBar(isAppBarVisible:MutableState, viewModel: MainViewModel){ ), onValueChange = { text = it - viewModel.searchApi(it) + if (activeTab == 0 ){ + viewModel.searchMovie(it) + }else{ + viewModel.searchTvSeries(it) + } }, //shape = RoundedCornerShape(8.dp), singleLine = true, diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchUI.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchUI.kt index a57ded6..10c5e6a 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchUI.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/component/SearchUI.kt @@ -26,12 +26,14 @@ import androidx.compose.ui.unit.sp import androidx.navigation.NavController import com.piashcse.hilt_mvvm_compose_movie.R import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiURL -import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModel +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel import com.piashcse.hilt_mvvm_compose_movie.navigation.Screen import com.piashcse.hilt_mvvm_compose_movie.ui.theme.DefaultBackgroundColor import com.piashcse.hilt_mvvm_compose_movie.ui.theme.FontColor import com.piashcse.hilt_mvvm_compose_movie.ui.theme.SecondaryFontColor import com.piashcse.hilt_mvvm_compose_movie.ui.theme.cornerRadius +import com.piashcse.hilt_mvvm_compose_movie.utils.ACTIVE_MOVIE_TAB +import com.piashcse.hilt_mvvm_compose_movie.utils.ACTIVE_TV_SERIES_TAB import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState import com.piashcse.hilt_mvvm_compose_movie.utils.roundTo import com.skydoves.landscapist.ImageOptions @@ -42,9 +44,15 @@ import com.skydoves.landscapist.placeholder.shimmer.Shimmer import com.skydoves.landscapist.placeholder.shimmer.ShimmerPlugin @Composable -fun SearchUI(navController:NavController, searchData: MutableState?>, itemClick:()->Unit) { +fun SearchUI( + navController: NavController, + searchData: MutableState?>, + activeTab: Int, + itemClick: () -> Unit +) { LazyColumn( - modifier = Modifier.padding(top = 60.dp) + modifier = Modifier + .padding(top = 48.dp) .fillMaxWidth() .heightIn(0.dp, 350.dp) // define max height .clip(RoundedCornerShape(bottomStart = 15.dp, bottomEnd = 15.dp)) @@ -53,23 +61,32 @@ fun SearchUI(navController:NavController, searchData: MutableState) { + if (it is DataState.Success) { items(items = it.data.results, itemContent = { item -> Row(modifier = Modifier - .padding(bottom = 8.dp, start = 8.dp , end = 8.dp) + .padding(bottom = 8.dp, start = 8.dp, end = 8.dp) .clickable { itemClick.invoke() - navController.navigate( - Screen.MovieDetail.route.plus( - "/${item.id}" + if (activeTab == ACTIVE_MOVIE_TAB){ + navController.navigate( + Screen.MovieDetail.route.plus( + "/${item.id}" + ) ) - ) + }else if (activeTab == ACTIVE_TV_SERIES_TAB){ + navController.navigate( + Screen.TvSeriesDetail.route.plus( + "/${item.id}" + ) + ) + } }) { CoilImage( modifier = Modifier .height(100.dp) - .width(80.dp).cornerRadius(8), - imageModel = { ApiURL.IMAGE_URL.plus(item.backdropPath) }, + .width(80.dp) + .cornerRadius(8), + imageModel = { ApiURL.IMAGE_URL.plus(item.backdropPath) }, imageOptions = ImageOptions( contentScale = ContentScale.Crop, alignment = Alignment.Center, @@ -80,15 +97,17 @@ fun SearchUI(navController:NavController, searchData: MutableState , + genres: ArrayList? = null, + selectedName: Genre?, + onclick: (genreId: Genre?) -> Unit +) { + val activity = (LocalContext.current as? Activity) + val progressBar = remember { mutableStateOf(false) } + val openDialog = remember { mutableStateOf(false) } + + BackHandler(enabled = (currentRoute(navController) == Screen.NowPlaying.route)) { + openDialog.value = true + } + Column(modifier = Modifier.background(DefaultBackgroundColor)) { + genres?.let { + LazyRow( + modifier = Modifier + .padding(top = 8.dp, bottom = 8.dp, start = 9.dp, end = 9.dp) + .fillMaxWidth() + ) { + items(genres) { item -> + SelectableGenreChipTv( + selected = item.name === selectedName?.name, + genre = item.name, + onclick = { + onclick(item) + } + ) + } + } + } + CircularIndeterminateProgressBar(isDisplayed = progressBar.value, 0.4f) + LazyVerticalGrid(columns = GridCells.Fixed(2), + modifier = Modifier + .padding(start = 5.dp, end = 5.dp) + .conditional(genres == null) { + padding(top = 8.dp) + }, + content = { + items(tvSeries) { item -> + item?.let { + MovieItemViewTV(item, navController) + } + } + }) + } + if (openDialog.value) { + ExitAlertDialog(navController, { + openDialog.value = it + }, { + activity?.finish() + }) + + } + tvSeries.pagingLoadingState { + progressBar.value = it + } +} + + +@Composable +fun MovieItemViewTV(item: TvSeriesItem, navController: NavController) { + Column(modifier = Modifier.padding(start = 5.dp, end = 5.dp, top = 0.dp, bottom = 10.dp)) { + CoilImage( + modifier = Modifier + .size(250.dp) + .cornerRadius(10) + .clickable { + navController.navigate(Screen.TvSeriesDetail.route.plus("/${item.id}")) + }, + imageModel = { ApiURL.IMAGE_URL.plus(item.posterPath) }, + imageOptions = ImageOptions( + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + contentDescription = "Movie item", + colorFilter = null, + ), + component = rememberImageComponent { + +CircularRevealPlugin( + duration = 800 + ) + +ShimmerPlugin(shimmer = Shimmer.Flash( + baseColor = SecondaryFontColor, + highlightColor = DefaultBackgroundColor + )) + }, + ) + } +} + +@Composable +fun SelectableGenreChipTv( + selected: Boolean, + genre: String, + onclick: () -> Unit +) { + + val animateChipBackgroundColor by animateColorAsState( + targetValue = if (selected) Purple500 else Purple200, + animationSpec = tween( + durationMillis = 50, + delayMillis = 0, + easing = LinearOutSlowInEasing + ) + ) + Box( + modifier = Modifier + .padding(end = 8.dp) + .cornerRadius(16) + .background( + color = animateChipBackgroundColor + ) + .height(32.dp) + .widthIn(min = 80.dp) + .padding(horizontal = 8.dp) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { + onclick() + } + ) { + Text( + text = genre, + fontSize = 14.sp, + fontWeight = FontWeight.Light, + textAlign = TextAlign.Center, + modifier = Modifier.align(Alignment.Center), + color = Color.White.copy(alpha = 0.80F) + ) + } +} + + + diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetail.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetail.kt similarity index 98% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetail.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetail.kt index 1eb59c8..092a96e 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetail.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetail.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.artistdetail +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.artist_detail import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetailViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetailViewModel.kt similarity index 95% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetailViewModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetailViewModel.kt index 3d62aa1..3b19097 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artistdetail/ArtistDetailViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/artist_detail/ArtistDetailViewModel.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.artistdetail +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.artist_detail import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/drawer/NavigationDrawer.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/drawer/NavigationDrawer.kt deleted file mode 100644 index 9c1ec56..0000000 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/drawer/NavigationDrawer.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.drawer - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Movie -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.navigation.NavController -import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre -import com.piashcse.hilt_mvvm_compose_movie.navigation.Screen -import com.piashcse.hilt_mvvm_compose_movie.navigation.currentRoute - -@Composable -fun DrawerUI( - navController: NavController, - genres: List, - closeDrawer: (genreName: String) -> Unit -) { - LazyColumn( - modifier = Modifier - .fillMaxHeight() - ) { - items(items = genres, itemContent = { item -> - DrawerItem( - item = item, - selected = currentRoute(navController) == "", - onItemClick = { - navController.navigate(Screen.NavigationDrawer.route.plus("/${it.id}")) { - launchSingleTop = true - } - // Close drawer - closeDrawer(it.name) - }) - }) - } -} - -@Composable -fun DrawerItem(item: Genre, selected: Boolean, onItemClick: (Genre) -> Unit) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .clickable(onClick = { onItemClick(item) }) - .height(45.dp) - .padding(start = 10.dp) - ) { - Icon( - Icons.Outlined.Movie, "", modifier = Modifier - .height(24.dp) - .width(24.dp) - ) - Spacer(modifier = Modifier.width(7.dp)) - Text( - text = item.name, - fontSize = 18.sp - ) - } -} diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/genre/GenreScreen.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/genre/GenreScreen.kt index 8badc56..df5d446 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/genre/GenreScreen.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/genre/GenreScreen.kt @@ -3,6 +3,7 @@ package com.piashcse.hilt_mvvm_compose_movie.ui.screens.genre import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.ui.component.MovieItemList @Composable @@ -13,10 +14,10 @@ fun GenreScreen( val genreViewModel = hiltViewModel() MovieItemList( navController = navController, - movies = genreViewModel.moviesByGenre(genreId), + moviesItems = genreViewModel.moviesByGenre(genreId).collectAsLazyPagingItems(), null, null - ){ + ) { } } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainScreen.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainScreen.kt index 2f33418..763929a 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainScreen.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainScreen.kt @@ -1,30 +1,32 @@ package com.piashcse.hilt_mvvm_compose_movie.ui.screens.mainscreen +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Search import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.DrawerValue import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalDrawerSheet -import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Snackbar +import androidx.compose.material3.Tab +import androidx.compose.material3.TabRow +import androidx.compose.material3.TabRowDefaults +import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -39,6 +41,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.piashcse.hilt_mvvm_compose_movie.R import com.piashcse.hilt_mvvm_compose_movie.data.model.Genres @@ -46,12 +49,14 @@ import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre import com.piashcse.hilt_mvvm_compose_movie.navigation.Navigation import com.piashcse.hilt_mvvm_compose_movie.navigation.Screen import com.piashcse.hilt_mvvm_compose_movie.navigation.currentRoute +import com.piashcse.hilt_mvvm_compose_movie.navigation.navigationTitle import com.piashcse.hilt_mvvm_compose_movie.ui.component.CircularIndeterminateProgressBar import com.piashcse.hilt_mvvm_compose_movie.ui.component.SearchBar import com.piashcse.hilt_mvvm_compose_movie.ui.component.SearchUI -import com.piashcse.hilt_mvvm_compose_movie.ui.screens.drawer.DrawerUI import com.piashcse.hilt_mvvm_compose_movie.ui.theme.FloatingActionBackground import com.piashcse.hilt_mvvm_compose_movie.ui.theme.cornerRadius +import com.piashcse.hilt_mvvm_compose_movie.utils.ACTIVE_MOVIE_TAB +import com.piashcse.hilt_mvvm_compose_movie.utils.ACTIVE_TV_SERIES_TAB import com.piashcse.hilt_mvvm_compose_movie.utils.AppConstant import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState import com.piashcse.hilt_mvvm_compose_movie.utils.networkconnection.ConnectionState @@ -66,156 +71,146 @@ import kotlinx.coroutines.launch fun MainScreen() { val mainViewModel = hiltViewModel() val navController = rememberNavController() - val scope = rememberCoroutineScope() val isAppBarVisible = remember { mutableStateOf(true) } val searchProgressBar = remember { mutableStateOf(false) } val genreName = remember { mutableStateOf("") } - val genreList = remember { mutableStateOf(arrayListOf()) } - // internet connection + var genreList = remember { mutableListOf() } val connection by connectivityState() val isConnected = connection === ConnectionState.Available val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) - val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) + val pagerState = rememberPagerState { + 2 + } // genre api call for first time - LaunchedEffect(key1 = 0) { + LaunchedEffect(Unit) { mainViewModel.genreList() } if (mainViewModel.genres.value is DataState.Success) { - genreList.value = + genreList = (mainViewModel.genres.value as DataState.Success).data.genres as ArrayList // All first value as all - if (genreList.value.first().name != AppConstant.DEFAULT_GENRE_ITEM) genreList.value.add( + if (genreList.first().name != AppConstant.DEFAULT_GENRE_ITEM) genreList.add( 0, Genre(null, AppConstant.DEFAULT_GENRE_ITEM) ) } - ModalNavigationDrawer( - drawerState = drawerState, drawerContent = { - ModalDrawerSheet( - modifier = Modifier - .padding(0.dp, 0.dp, 100.dp, 0.dp) - .fillMaxHeight() - ) { - DrawerUI(navController, genreList.value as List) { - genreName.value = it - scope.launch { - drawerState.apply { - if (isClosed) open() else close() - } - } - } - } - }, gesturesEnabled = true - ) { - Scaffold(topBar = { - if (!isAppBarVisible.value) { - SearchBar(isAppBarVisible, mainViewModel) - } else CenterAlignedTopAppBar( - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer, - titleContentColor = MaterialTheme.colorScheme.primary, - ), - title = { - Text( - if (currentRoute(navController) == Screen.NavigationDrawer.route) genreName.value - else stringResource(R.string.app_title), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = Color.White - ) - }, - navigationIcon = { - when (currentRoute(navController)) { - Screen.Home.route, Screen.Popular.route, Screen.TopRated.route, Screen.Upcoming.route -> { - IconButton(onClick = { - scope.launch { - drawerState.apply { - if (isClosed) open() else close() - } - } - }) { - Icon( - imageVector = Icons.Filled.Menu, - contentDescription = "Localized description", - tint = Color.White - ) - } - } - else -> { - IconButton(onClick = { navController.popBackStack() }) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Localized description", - tint = Color.White - ) - } + Scaffold(topBar = { + if (!isAppBarVisible.value) { + SearchBar(isAppBarVisible, mainViewModel, pagerState.currentPage) + } else CenterAlignedTopAppBar( + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer, + titleContentColor = MaterialTheme.colorScheme.primary, + ), + title = { + Text( + text = navigationTitle(navController), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = Color.White + ) + }, + navigationIcon = { + when (currentRoute(navController)) { + Screen.MovieDetail.route, Screen.ArtistDetail.route, Screen.TvSeriesDetail.route -> { + IconButton(onClick = { navController.popBackStack() }) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Localized description", + tint = Color.White + ) } } - }, - scrollBehavior = scrollBehavior, - ) - }, floatingActionButton = { - when (currentRoute(navController)) { - Screen.Home.route, Screen.Popular.route, Screen.TopRated.route, Screen.Upcoming.route -> { - FloatingActionButton( - modifier = Modifier.cornerRadius(30), - containerColor = FloatingActionBackground, - onClick = { - isAppBarVisible.value = false - }, - ) { - Icon(Icons.Filled.Search, "", tint = Color.White) - } } - } - }, bottomBar = { - when (currentRoute(navController)) { - Screen.Home.route, Screen.Popular.route, Screen.TopRated.route, Screen.Upcoming.route -> { - BottomNavigationUI(navController) - } - } - }, snackbarHost = { - if (isConnected.not()) { - Snackbar( - action = {}, modifier = Modifier.padding(8.dp) + }, + scrollBehavior = scrollBehavior, + ) + }, floatingActionButton = { + when (currentRoute(navController)) { + Screen.NowPlaying.route, Screen.Popular.route, Screen.TopRated.route, Screen.Upcoming.route, + Screen.AiringTodayTvSeries.route, Screen.OnTheAirTvSeriesNav.route, Screen.PopularTvSeries.route, Screen.TopRatedTvSeries.route -> { + FloatingActionButton( + modifier = Modifier.cornerRadius(30), + containerColor = FloatingActionBackground, + onClick = { + isAppBarVisible.value = false + }, ) { - Text(text = stringResource(R.string.there_is_no_internet)) + Icon(Icons.Filled.Search, "", tint = Color.White) } } - }) { - Box( - modifier = Modifier.fillMaxWidth() + } + }, bottomBar = { + when (currentRoute(navController)) { + Screen.NowPlaying.route, Screen.Popular.route, Screen.TopRated.route, Screen.Upcoming.route, + Screen.AiringTodayTvSeries.route, Screen.OnTheAirTvSeriesNav.route, + Screen.PopularTvSeries.route, Screen.TopRatedTvSeries.route -> { + BottomNavigationUI(navController, pagerState) + } + } + }, snackbarHost = { + if (isConnected.not()) { + Snackbar( + action = {}, modifier = Modifier.padding(8.dp) ) { - Navigation(navController, Modifier.padding(it), genreList.value) - Column { - CircularIndeterminateProgressBar(isDisplayed = searchProgressBar.value, 0.1f) - if (isAppBarVisible.value.not()) { - SearchUI(navController, mainViewModel.searchData) { - isAppBarVisible.value = true - } + Text(text = stringResource(R.string.there_is_no_internet)) + } + } + }) { + Box(Modifier.padding(it)) { + TabScreen( + navController, + pagerState, + genreList as ArrayList? + ) + CircularIndeterminateProgressBar(isDisplayed = searchProgressBar.value, 0.1f) + if (isAppBarVisible.value.not()) { + if (pagerState.currentPage == ACTIVE_MOVIE_TAB) { + SearchUI(navController, mainViewModel.movieSearchData, pagerState.currentPage) { + isAppBarVisible.value = true + } + mainViewModel.movieSearchData.pagingLoadingState { + searchProgressBar.value = it + } + } else if (pagerState.currentPage == ACTIVE_TV_SERIES_TAB){ + SearchUI( + navController, + mainViewModel.tvSeriesSearchData, + pagerState.currentPage + ) { + isAppBarVisible.value = true + } + mainViewModel.tvSeriesSearchData.pagingLoadingState { + searchProgressBar.value = it } } - } - mainViewModel.searchData.pagingLoadingState { - searchProgressBar.value = it + } } } - } @Composable -fun BottomNavigationUI(navController: NavController) { +fun BottomNavigationUI(navController: NavController, pagerState: PagerState) { NavigationBar { - val items = listOf( - Screen.HomeNav, - Screen.PopularNav, - Screen.TopRatedNav, - Screen.UpcomingNav, - ) + val items = if (pagerState.currentPage == 0) { + listOf( + Screen.NowPlayingNav, + Screen.PopularNav, + Screen.TopRatedNav, + Screen.UpcomingNav, + ) + } else { + listOf( + Screen.AiringTodayTvSeriesNav, + Screen.OnTheAirTvSeriesNav, + Screen.PopularTvSeriesNav, + Screen.TopRatedTvSeriesNav, + ) + } items.forEachIndexed { index, item -> NavigationBarItem(icon = item.navIcon, label = { Text(text = stringResource(id = item.title)) }, @@ -239,4 +234,48 @@ fun BottomNavigationUI(navController: NavController) { }) } } -} \ No newline at end of file +} + +@Composable +fun TabScreen( + navigator: NavHostController, + pagerState: PagerState, + genres: ArrayList? = null, +) { + val coroutineScope = rememberCoroutineScope() + val tabs = listOf(stringResource(R.string.movie), stringResource(R.string.tv_series)) + + Column { + TabRow( + modifier = Modifier.background(Color.White), + selectedTabIndex = pagerState.currentPage, + indicator = { tabPositions -> + TabRowDefaults.PrimaryIndicator( + Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]), + color = MaterialTheme.colorScheme.primary + ) + } + ) { + tabs.forEachIndexed { index, title -> + Tab( + selected = pagerState.currentPage == index, + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(index) + } + }, + text = { + Text( + title, + color = if (pagerState.currentPage == index) MaterialTheme.colorScheme.primary else Color.Gray + ) + }) + } + } + HorizontalPager( + state = pagerState, modifier = Modifier.fillMaxSize() + ) { page -> + Navigation(navigator, page, genres) + } + } +} diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainViewModel.kt index fcb2736..bf56063 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/mainscreen/MainViewModel.kt @@ -4,9 +4,10 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.piashcse.hilt_mvvm_compose_movie.data.model.BaseModel import com.piashcse.hilt_mvvm_compose_movie.data.model.Genres +import com.piashcse.hilt_mvvm_compose_movie.data.model.SearchBaseModel import com.piashcse.hilt_mvvm_compose_movie.data.repository.MovieRepository +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -23,20 +24,21 @@ import timber.log.Timber import javax.inject.Inject @HiltViewModel -class MainViewModel @Inject constructor(private val repo: MovieRepository) : ViewModel() { +class MainViewModel @Inject constructor(private val movieRepo: MovieRepository, private val tvSeriesRepo: TvSeriesRepository) : ViewModel() { val genres: MutableState?> = mutableStateOf(null) - val searchData: MutableState?> = mutableStateOf(null) + val movieSearchData: MutableState?> = mutableStateOf(null) + val tvSeriesSearchData: MutableState?> = mutableStateOf(null) fun genreList() { viewModelScope.launch { - repo.genreList().onEach { + movieRepo.genreList().onEach { genres.value = it }.launchIn(viewModelScope) } } @ExperimentalCoroutinesApi @FlowPreview - fun searchApi(searchKey: String) { + fun searchMovie(searchKey: String) { viewModelScope.launch { flowOf(searchKey).debounce(300) .filter { @@ -44,13 +46,33 @@ class MainViewModel @Inject constructor(private val repo: MovieRepository) : Vie } .distinctUntilChanged() .flatMapLatest { - repo.search(it) + movieRepo.movieSearch(it) }.collect { if (it is DataState.Success){ it.data Timber.e(" data ${it.data.totalPages}") } - searchData.value = it + movieSearchData.value = it + } + } + } + @ExperimentalCoroutinesApi + @FlowPreview + fun searchTvSeries(searchKey: String) { + viewModelScope.launch { + flowOf(searchKey).debounce(300) + .filter { + it.trim().isEmpty().not() + } + .distinctUntilChanged() + .flatMapLatest { + tvSeriesRepo.searchTvSeries(it) + }.collect { + if (it is DataState.Success){ + it.data + Timber.e(" data ${it.data.totalPages}") + } + tvSeriesSearchData.value = it } } } diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/moviedetail/MovieDetail.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetail.kt similarity index 99% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/moviedetail/MovieDetail.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetail.kt index 6255e16..87861f9 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/moviedetail/MovieDetail.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetail.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.moviedetail +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.movie_detail import androidx.compose.foundation.background import androidx.compose.foundation.clickable diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetailViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetailViewModel.kt new file mode 100644 index 0000000..7fab15e --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/movie_detail/MovieDetailViewModel.kt @@ -0,0 +1,94 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.movie_detail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.piashcse.hilt_mvvm_compose_movie.data.model.MovieItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.MovieDetail +import com.piashcse.hilt_mvvm_compose_movie.data.repository.MovieRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class MovieDetailViewModel @Inject constructor(private val repo: MovieRepository) : ViewModel() { + private val _movieDetail = MutableStateFlow(null) + val movieDetail get() = _movieDetail.asStateFlow() + + private val _recommendedMovie = MutableStateFlow>(arrayListOf()) + val recommendedMovie get() = _recommendedMovie.asStateFlow() + + private val _movieCredit = MutableStateFlow(null) + val movieCredit get() = _movieCredit.asStateFlow() + + private val _isLoading = MutableStateFlow(false) + val isLoading get() = _isLoading.asStateFlow() + + fun movieDetail(movieId: Int) { + viewModelScope.launch { + repo.movieDetail(movieId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _movieDetail.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } + + fun recommendedMovie(movieId: Int) { + viewModelScope.launch { + repo.recommendedMovie(movieId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _recommendedMovie.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } + + fun movieCredit(movieId: Int) { + viewModelScope.launch { + repo.movieCredit(movieId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _movieCredit.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlaying.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovie.kt similarity index 71% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlaying.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovie.kt index a992220..0d9e1f3 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlaying.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovie.kt @@ -1,21 +1,22 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.nowplaying +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.nowplaying import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre import com.piashcse.hilt_mvvm_compose_movie.ui.component.MovieItemList @Composable -fun NowPlaying( +fun NowPlayingMovie( navController: NavController, genres: ArrayList? = null, ) { - val nowPlayViewModel = hiltViewModel() + val nowPlayViewModel = hiltViewModel() MovieItemList( navController = navController, - movies = nowPlayViewModel.nowPlayingMovies, + moviesItems = nowPlayViewModel.nowPlayingMovies.collectAsLazyPagingItems(), genres = genres, selectedName = nowPlayViewModel.selectedGenre.value ){ diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlayingViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovieViewModel.kt similarity index 81% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlayingViewModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovieViewModel.kt index 23053e4..a254e33 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/nowplaying/NowPlayingViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/nowplaying/NowPlayingMovieViewModel.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.nowplaying +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.nowplaying import androidx.compose.runtime.MutableState @@ -18,14 +18,14 @@ import kotlinx.coroutines.flow.flatMapLatest import javax.inject.Inject @HiltViewModel -class NowPlayingViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { +class NowPlayingMovieViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { var selectedGenre: MutableState = mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) val filterData = MutableStateFlow(null) @OptIn(ExperimentalCoroutinesApi::class) val nowPlayingMovies = filterData.flatMapLatest { - repo.nowPlayingPagingDataSource(it?.genreId) + repo.nowPlayingMoviePagingDataSource(it?.genreId) }.cachedIn(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/Popular.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovie.kt similarity index 71% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/Popular.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovie.kt index e6348c0..d67548e 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/Popular.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovie.kt @@ -1,21 +1,22 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.popular +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.popular import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre import com.piashcse.hilt_mvvm_compose_movie.ui.component.MovieItemList @Composable -fun Popular( +fun PopularMovie( navController: NavController, genres: ArrayList? = null, ) { - val popularViewModel = hiltViewModel() + val popularViewModel = hiltViewModel() MovieItemList( navController = navController, - movies = popularViewModel.popularMovies, + moviesItems = popularViewModel.popularMovies.collectAsLazyPagingItems(), genres = genres, selectedName = popularViewModel.selectedGenre.value ){ diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/PopularViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovieViewModel.kt similarity index 82% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/PopularViewModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovieViewModel.kt index 199c22a..8c6fa07 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/popular/PopularViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/popular/PopularMovieViewModel.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.popular +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.popular import androidx.compose.runtime.MutableState @@ -17,13 +17,13 @@ import kotlinx.coroutines.flow.flatMapLatest import javax.inject.Inject @HiltViewModel -class PopularViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { +class PopularMovieViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { var selectedGenre: MutableState = mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) val filterData = MutableStateFlow(null) @OptIn(ExperimentalCoroutinesApi::class) val popularMovies = filterData.flatMapLatest { - repo.popularPagingDataSource(it?.genreId) + repo.popularMoviePagingDataSource(it?.genreId) }.cachedIn(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRated.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovie.kt similarity index 71% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRated.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovie.kt index 06b6593..155818d 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRated.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovie.kt @@ -1,21 +1,22 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.toprated +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.toprated import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre import com.piashcse.hilt_mvvm_compose_movie.ui.component.MovieItemList @Composable -fun TopRated( +fun TopRatedMovie( navController: NavController, genres: ArrayList? = null, ) { - val topRatedViewModel = hiltViewModel() + val topRatedViewModel = hiltViewModel() MovieItemList( navController = navController, - movies = topRatedViewModel.topRatedMovies, + moviesItems = topRatedViewModel.topRatedMovies.collectAsLazyPagingItems(), genres = genres, selectedName = topRatedViewModel.selectedGenre.value ){ diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRatedViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovieViewModel.kt similarity index 82% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRatedViewModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovieViewModel.kt index 7774760..0bec0f0 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/toprated/TopRatedViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/toprated/TopRatedMovieViewModel.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.toprated +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.toprated import androidx.compose.runtime.MutableState @@ -17,13 +17,13 @@ import kotlinx.coroutines.flow.flatMapLatest import javax.inject.Inject @HiltViewModel -class TopRatedViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { +class TopRatedMovieViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { var selectedGenre: MutableState = mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) val filterData = MutableStateFlow(null) @OptIn(ExperimentalCoroutinesApi::class) val topRatedMovies = filterData.flatMapLatest { - repo.topRatedPagingDataSource(it?.genreId) + repo.topRatedMoviePagingDataSource(it?.genreId) }.cachedIn(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComing.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovie.kt similarity index 71% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComing.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovie.kt index a5ae775..6570cd8 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComing.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovie.kt @@ -1,22 +1,23 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.upcoming +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.upcoming import androidx.compose.runtime.Composable import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre import com.piashcse.hilt_mvvm_compose_movie.ui.component.MovieItemList @Composable -fun Upcoming( +fun UpcomingMovie( navController: NavController, genres: ArrayList? = null, ) { - val upComingViewModel = hiltViewModel() + val upComingViewModel = hiltViewModel() MovieItemList( navController = navController, - movies = upComingViewModel.upcomingMovies, + moviesItems = upComingViewModel.upcomingMovies.collectAsLazyPagingItems(), genres = genres, selectedName = upComingViewModel.selectedGenre.value ) { diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComingViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovieViewModel.kt similarity index 82% rename from app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComingViewModel.kt rename to app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovieViewModel.kt index a2cd52c..30ac9a5 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/bottomnavigation/upcoming/UpComingViewModel.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/movies/upcoming/UpComingMovieViewModel.kt @@ -1,4 +1,4 @@ -package com.piashcse.hilt_mvvm_compose_movie.ui.screens.bottomnavigation.upcoming +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.movies.upcoming import androidx.compose.runtime.MutableState @@ -17,13 +17,13 @@ import kotlinx.coroutines.flow.flatMapLatest import javax.inject.Inject @HiltViewModel -class UpComingViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { +class UpComingMovieViewModel @Inject constructor(val repo: MovieRepository) : ViewModel() { var selectedGenre: MutableState = mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) val filterData = MutableStateFlow(null) @OptIn(ExperimentalCoroutinesApi::class) val upcomingMovies = filterData.flatMapLatest { - repo.upcomingPagingDataSource(it?.genreId) + repo.upcomingMoviePagingDataSource(it?.genreId) }.cachedIn(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeries.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeries.kt new file mode 100644 index 0000000..7c36aad --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeries.kt @@ -0,0 +1,28 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.airing_today + +import androidx.compose.runtime.Composable +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.ui.component.TvSeriesItem + +@Composable +fun AiringTodayTvSeries( + navController: NavController, + genres: ArrayList? = null, +) { + val airingTodayViewModel = hiltViewModel() + TvSeriesItem ( + navController = navController, + tvSeries = airingTodayViewModel.airingTodayTvSeries.collectAsLazyPagingItems(), + genres = genres, + selectedName = airingTodayViewModel.selectedGenre.value + ){ + airingTodayViewModel.filterData.value = GenreId(it?.id.toString()) + it?.let { + airingTodayViewModel.selectedGenre.value = it + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeriesViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeriesViewModel.kt new file mode 100644 index 0000000..76137b7 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/airing_today/AiringTodayTvSeriesViewModel.kt @@ -0,0 +1,30 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.airing_today + + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.AppConstant +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import javax.inject.Inject + +@HiltViewModel +class AiringTodayTvSeriesViewModel @Inject constructor(val repo: TvSeriesRepository) : ViewModel() { + var selectedGenre: MutableState = + mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) + val filterData = MutableStateFlow(null) + + @OptIn(ExperimentalCoroutinesApi::class) + val airingTodayTvSeries = filterData.flatMapLatest { + repo.airingTodayTvSeriesPagingDataSource(it?.genreId) + }.cachedIn(viewModelScope) + +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeries.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeries.kt new file mode 100644 index 0000000..b2d7847 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeries.kt @@ -0,0 +1,28 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.on_the_air + +import androidx.compose.runtime.Composable +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.ui.component.TvSeriesItem + +@Composable +fun OnTheAirTvSeries( + navController: NavController, + genres: ArrayList? = null, +) { + val onTheAirViewViewModel = hiltViewModel() + TvSeriesItem ( + navController = navController, + tvSeries = onTheAirViewViewModel.onTheAirTvSeries.collectAsLazyPagingItems(), + genres = genres, + selectedName = onTheAirViewViewModel.selectedGenre.value + ){ + onTheAirViewViewModel.filterData.value = GenreId(it?.id.toString()) + it?.let { + onTheAirViewViewModel.selectedGenre.value = it + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeriesViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeriesViewModel.kt new file mode 100644 index 0000000..1cc9c07 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/on_the_air/OnTheAirTvSeriesViewModel.kt @@ -0,0 +1,30 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.on_the_air + + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.AppConstant +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import javax.inject.Inject + +@HiltViewModel +class OnTheAirTvSeriesViewModel @Inject constructor(val repo: TvSeriesRepository) : ViewModel() { + var selectedGenre: MutableState = + mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) + val filterData = MutableStateFlow(null) + + @OptIn(ExperimentalCoroutinesApi::class) + val onTheAirTvSeries = filterData.flatMapLatest { + repo.onTheAirTvSeriesPagingDataSource(it?.genreId) + }.cachedIn(viewModelScope) + +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeries.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeries.kt new file mode 100644 index 0000000..553c396 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeries.kt @@ -0,0 +1,28 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.popular + +import androidx.compose.runtime.Composable +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.ui.component.TvSeriesItem + +@Composable +fun PopularTvSeries( + navController: NavController, + genres: ArrayList? = null, +) { + val popularViewViewModel = hiltViewModel() + TvSeriesItem ( + navController = navController, + tvSeries = popularViewViewModel.popularTvSeries.collectAsLazyPagingItems(), + genres = genres, + selectedName = popularViewViewModel.selectedGenre.value + ){ + popularViewViewModel.filterData.value = GenreId(it?.id.toString()) + it?.let { + popularViewViewModel.selectedGenre.value = it + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeriesViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeriesViewModel.kt new file mode 100644 index 0000000..bf8883c --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/popular/PopularTvSeriesViewModel.kt @@ -0,0 +1,30 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.popular + + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.AppConstant +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import javax.inject.Inject + +@HiltViewModel +class PopularTvSeriesViewModel @Inject constructor(val repo: TvSeriesRepository) : ViewModel() { + var selectedGenre: MutableState = + mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) + val filterData = MutableStateFlow(null) + + @OptIn(ExperimentalCoroutinesApi::class) + val popularTvSeries = filterData.flatMapLatest { + repo.popularTvSeriesPagingDataSource(it?.genreId) + }.cachedIn(viewModelScope) + +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeries.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeries.kt new file mode 100644 index 0000000..edb90a8 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeries.kt @@ -0,0 +1,28 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.top_rated + +import androidx.compose.runtime.Composable +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import androidx.paging.compose.collectAsLazyPagingItems +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.ui.component.TvSeriesItem + +@Composable +fun TopRatedTvSeries( + navController: NavController, + genres: ArrayList? = null, +) { + val topRatedViewViewModel = hiltViewModel() + TvSeriesItem ( + navController = navController, + tvSeries = topRatedViewViewModel.topRatedTvSeries.collectAsLazyPagingItems(), + genres = genres, + selectedName = topRatedViewViewModel.selectedGenre.value + ){ + topRatedViewViewModel.filterData.value = GenreId(it?.id.toString()) + it?.let { + topRatedViewViewModel.selectedGenre.value = it + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeriesViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeriesViewModel.kt new file mode 100644 index 0000000..f5e1a2f --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/top_rated/TopRatedTvSeriesViewModel.kt @@ -0,0 +1,30 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.top_rated + + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.paging.cachedIn +import com.piashcse.hilt_mvvm_compose_movie.data.model.GenreId +import com.piashcse.hilt_mvvm_compose_movie.data.model.moviedetail.Genre +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.AppConstant +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import javax.inject.Inject + +@HiltViewModel +class TopRatedTvSeriesViewModel @Inject constructor(val repo: TvSeriesRepository) : ViewModel() { + var selectedGenre: MutableState = + mutableStateOf(Genre(null, AppConstant.DEFAULT_GENRE_ITEM)) + val filterData = MutableStateFlow(null) + + @OptIn(ExperimentalCoroutinesApi::class) + val topRatedTvSeries = filterData.flatMapLatest { + repo.topRatedTvSeriesPagingDataSource(it?.genreId) + }.cachedIn(viewModelScope) + +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetail.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetail.kt new file mode 100644 index 0000000..8e40b2a --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetail.kt @@ -0,0 +1,281 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.tv_series_detail + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.piashcse.hilt_mvvm_compose_movie.R +import com.piashcse.hilt_mvvm_compose_movie.data.datasource.remote.ApiURL +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Cast +import com.piashcse.hilt_mvvm_compose_movie.navigation.Screen +import com.piashcse.hilt_mvvm_compose_movie.ui.component.CircularIndeterminateProgressBar +import com.piashcse.hilt_mvvm_compose_movie.ui.component.ExpandingText +import com.piashcse.hilt_mvvm_compose_movie.ui.component.text.SubtitlePrimary +import com.piashcse.hilt_mvvm_compose_movie.ui.component.text.SubtitleSecondary +import com.piashcse.hilt_mvvm_compose_movie.ui.theme.DefaultBackgroundColor +import com.piashcse.hilt_mvvm_compose_movie.ui.theme.FontColor +import com.piashcse.hilt_mvvm_compose_movie.ui.theme.SecondaryFontColor +import com.piashcse.hilt_mvvm_compose_movie.ui.theme.cornerRadius +import com.piashcse.hilt_mvvm_compose_movie.utils.roundTo +import com.skydoves.landscapist.ImageOptions +import com.skydoves.landscapist.animation.circular.CircularRevealPlugin +import com.skydoves.landscapist.coil.CoilImage +import com.skydoves.landscapist.components.rememberImageComponent +import com.skydoves.landscapist.placeholder.shimmer.Shimmer +import com.skydoves.landscapist.placeholder.shimmer.ShimmerPlugin + +@Composable +fun TvSeriesDetail(navController: NavController, tvSeriesId: Int) { + val viewModel = hiltViewModel() + val isLoading by viewModel.isLoading.collectAsState() + val tvSeriesDetail by viewModel.tvSeriesDetail.collectAsState() + val recommendTvSeries by viewModel.recommendedTvSeries.collectAsState() + val tvSeriesCredit by viewModel.tvSeriesCredit.collectAsState() + + LaunchedEffect(Unit) { + viewModel.tvSeriesDetail(tvSeriesId) + viewModel.recommendedTvSeries(tvSeriesId) + viewModel.tvSeriesCredit(tvSeriesId) + } + + Column( + modifier = Modifier + .fillMaxSize() + .background( + DefaultBackgroundColor + ) + ) { + CircularIndeterminateProgressBar(isDisplayed = isLoading, 0.4f) + tvSeriesDetail?.let { it -> + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + CoilImage( + modifier = Modifier + .fillMaxWidth() + .height(300.dp), + imageModel = { ApiURL.IMAGE_URL.plus(it.posterPath) }, + imageOptions = ImageOptions( + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + contentDescription = "Movie detail", + colorFilter = null, + ), + component = rememberImageComponent { + +CircularRevealPlugin( + duration = 800 + ) + +ShimmerPlugin( + shimmer = Shimmer.Flash( + baseColor = SecondaryFontColor, + highlightColor = DefaultBackgroundColor + ) + ) + }, + ) + Column( + modifier = Modifier + .fillMaxSize() + .padding(start = 10.dp, end = 10.dp) + ) { + Text( + text = it.name, + modifier = Modifier.padding(top = 10.dp), + color = FontColor, + fontSize = 30.sp, + fontWeight = FontWeight.W700, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 10.dp, top = 10.dp) + ) { + + Column(Modifier.weight(1f)) { + SubtitlePrimary( + text = it.originalLanguage, + ) + SubtitleSecondary( + text = stringResource(R.string.language) + ) + } + Column(Modifier.weight(1f)) { + SubtitlePrimary( + text = it.voteAverage.roundTo(1).toString(), + ) + SubtitleSecondary( + text = stringResource(R.string.rating) + ) + } + Column(Modifier.weight(1f)) { + SubtitlePrimary( + text = it.numberOfEpisodes.toString() + ) + SubtitleSecondary( + text = stringResource(R.string.number_of_episodes) + ) + } + Column(Modifier.weight(1f)) { + SubtitlePrimary( + text = it.firstAirDate + ) + SubtitleSecondary( + text = stringResource(R.string.release_date) + ) + } + } + Text( + text = stringResource(R.string.description), + color = FontColor, + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold + ) + ExpandingText(text = it.overview) + RecommendedTvSeries(navController, recommendTvSeries) + tvSeriesCredit?.let { + ArtistAndCrew(navController, it.cast) + } + } + } + } + } +} + +@Preview(name = "MovieDetail", showBackground = true) +@Composable +fun Preview() { + // TvSeriesDetail(null, MovieItem()) +} + +@Composable +fun RecommendedTvSeries(navController: NavController?, recommendedTvSeries: List) { + Column(modifier = Modifier.padding(bottom = 10.dp)) { + Text( + text = stringResource(R.string.similar), + color = FontColor, + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold + ) + LazyRow(modifier = Modifier.fillMaxHeight()) { + items(recommendedTvSeries, itemContent = { item -> + Column( + modifier = Modifier.padding( + start = 0.dp, end = 8.dp, top = 5.dp, bottom = 5.dp + ) + ) { + CoilImage( + modifier = Modifier + .height(190.dp) + .width(140.dp) + .cornerRadius(10) + .clickable { + navController?.navigate( + Screen.TvSeriesDetail.route.plus( + "/${item.id}" + ) + ) + }, + imageModel = { ApiURL.IMAGE_URL.plus(item.posterPath) }, + imageOptions = ImageOptions( + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + contentDescription = "similar movie", + colorFilter = null, + ), + component = rememberImageComponent { + // shows a shimmering effect when loading an image. + +CircularRevealPlugin( + duration = 800 + ) + }, + ) + } + }) + } + } +} + +@Composable +fun ArtistAndCrew(navController: NavController?, cast: List) { + Column(modifier = Modifier.padding(bottom = 10.dp)) { + Text( + text = stringResource(R.string.cast), + color = FontColor, + fontSize = 17.sp, + fontWeight = FontWeight.SemiBold + ) + LazyRow(modifier = Modifier.fillMaxHeight()) { + items(cast, itemContent = { item -> + Column( + modifier = Modifier.padding( + start = 0.dp, end = 10.dp, top = 5.dp, bottom = 5.dp + ), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + CoilImage( + modifier = Modifier + .padding(bottom = 5.dp) + .height(80.dp) + .width(80.dp) + .cornerRadius(40) + .clickable { + navController?.navigate( + Screen.ArtistDetail.route.plus( + "/${item.id}" + ) + ) + }, + imageModel = { ApiURL.IMAGE_URL.plus(item.profilePath) }, + imageOptions = ImageOptions( + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + contentDescription = "artist and crew", + colorFilter = null, + ), + component = rememberImageComponent { + +CircularRevealPlugin( + duration = 800 + ) + +ShimmerPlugin( + shimmer = Shimmer.Flash( + baseColor = SecondaryFontColor, + highlightColor = DefaultBackgroundColor + ) + ) + }, + ) + SubtitleSecondary(text = item.name) + } + }) + } + } +} diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetailViewModel.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetailViewModel.kt new file mode 100644 index 0000000..5a22d51 --- /dev/null +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/ui/screens/tv_series/tv_series_detail/TvSeriesDetailViewModel.kt @@ -0,0 +1,94 @@ +package com.piashcse.hilt_mvvm_compose_movie.ui.screens.tv_series.tv_series_detail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.piashcse.hilt_mvvm_compose_movie.data.model.TvSeriesItem +import com.piashcse.hilt_mvvm_compose_movie.data.model.artist.Artist +import com.piashcse.hilt_mvvm_compose_movie.data.model.tv_series_detail.TvSeriesDetail +import com.piashcse.hilt_mvvm_compose_movie.data.repository.TvSeriesRepository +import com.piashcse.hilt_mvvm_compose_movie.utils.network.DataState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class TvSeriesDetailViewModel @Inject constructor(private val repo: TvSeriesRepository) : ViewModel() { + private val _tvSeriesDetail = MutableStateFlow(null) + val tvSeriesDetail get() = _tvSeriesDetail.asStateFlow() + + private val _recommendedTvSeries= MutableStateFlow>(arrayListOf()) + val recommendedTvSeries get() = _recommendedTvSeries.asStateFlow() + + private val _tvSeriesCredit = MutableStateFlow(null) + val tvSeriesCredit get() = _tvSeriesCredit.asStateFlow() + + private val _isLoading = MutableStateFlow(false) + val isLoading get() = _isLoading.asStateFlow() + + fun tvSeriesDetail(seriesId: Int) { + viewModelScope.launch { + repo.tvSeriesDetail(seriesId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _tvSeriesDetail.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } + + fun recommendedTvSeries(tvSeriesId: Int) { + viewModelScope.launch { + repo.recommendedTvSeries(tvSeriesId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _recommendedTvSeries.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } + + fun tvSeriesCredit(movieId: Int) { + viewModelScope.launch { + repo.artistDetail(movieId).onEach { + when (it) { + is DataState.Loading -> { + _isLoading.value = true + } + + is DataState.Success -> { + _tvSeriesCredit.value = it.data + _isLoading.value = false + } + + is DataState.Error -> { + _isLoading.value = false + } + } + }.launchIn(viewModelScope) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/utils/AppConstant.kt b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/utils/AppConstant.kt index 801212a..1e3807f 100644 --- a/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/utils/AppConstant.kt +++ b/app/src/main/java/com/piashcse/hilt_mvvm_compose_movie/utils/AppConstant.kt @@ -3,4 +3,6 @@ package com.piashcse.hilt_mvvm_compose_movie.utils object AppConstant { const val MINIMIZED_MAX_LINES = 2 const val DEFAULT_GENRE_ITEM = "All" -} \ No newline at end of file +} +const val ACTIVE_MOVIE_TAB = 0 +const val ACTIVE_TV_SERIES_TAB = 1 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5f35478..709df8d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,17 +1,22 @@ Movie World - Movie World Title - Home + Movie + Tv Series + NowPlaying Popular - Top rated + Top rated Up coming + Airing today + On the air + Number of episodes Description Release Date Rating Language Duration Movie Detail + TV Series Detail Similar Cast Screen one diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index caefec6..a410d36 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.6.1" +agp = "8.7.0" kotlin = "2.0.20" coreKtx = "1.13.1" junit = "4.13.2" @@ -22,7 +22,7 @@ navigationCompose = "2.8.2" hiltNavigationCompose = "1.2.0" navigationRuntimeKtx = "2.8.2" hiltVersion = "2.52" -kspVersion = "2.0.20-1.0.24" +kspVersion = "2.0.20-1.0.25" composeBom = "2024.09.03" composeVersin = "1.7.3" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 70ae351..6a1144e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Sep 06 00:16:32 BDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/screenshots/1728491749751.PNG b/screenshots/1728491749751.PNG new file mode 100644 index 0000000..153bbb4 Binary files /dev/null and b/screenshots/1728491749751.PNG differ diff --git a/screenshots/1728491749752.PNG b/screenshots/1728491749752.PNG new file mode 100644 index 0000000..2254925 Binary files /dev/null and b/screenshots/1728491749752.PNG differ diff --git a/screenshots/1728491749753.PNG b/screenshots/1728491749753.PNG new file mode 100644 index 0000000..2f01a63 Binary files /dev/null and b/screenshots/1728491749753.PNG differ diff --git a/screenshots/Screenshot_20220420_021842.png b/screenshots/Screenshot_20220420_021842.png deleted file mode 100755 index ec27613..0000000 Binary files a/screenshots/Screenshot_20220420_021842.png and /dev/null differ diff --git a/screenshots/Screenshot_20220420_022455.png b/screenshots/Screenshot_20220420_022455.png deleted file mode 100755 index a430917..0000000 Binary files a/screenshots/Screenshot_20220420_022455.png and /dev/null differ diff --git a/screenshots/Screenshot_20220420_022546.png b/screenshots/Screenshot_20220420_022546.png deleted file mode 100755 index 16aa92b..0000000 Binary files a/screenshots/Screenshot_20220420_022546.png and /dev/null differ