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