From ddc0f661e66dc3e03f3452ce196b64c75cf21062 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Thu, 2 Feb 2023 11:55:22 +0100 Subject: [PATCH 1/9] :construction: add tvdto and some requests tvdto not finished --- .../pm/movieapplication/api/MovieApplicationAPI.kt | 12 +++++++++++- .../fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index cd84a60..68b255c 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -1,5 +1,6 @@ package fr.iut.pm.movieapplication.api +import fr.iut.pm.movieapplication.api.dtos.MovieDTO import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO import fr.iut.pm.movieapplication.api.dtos.PopularDTO import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY @@ -13,10 +14,19 @@ interface MovieApplicationAPI { @GET("movie/popular") fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY) : Call + @GET("movie/top_rated") + fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY) : Call + + @GET("movie/upcoming") + fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY) : Call + @GET("trending/{media_type}/{time_window}") fun getTrending(@Path("media_type") mediaType : String = "all", @Path("time_window") timeWindow : String = "day", @Query("api_key") apiKey: String = API_KEY ) : Call @GET("movie/{movie_id") - fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Call + fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Call + + @GET("tv/{tv_id}") + fun getShowDetails(@Path("tv_id") tvId : Int, @Query("api_key") apiKey: String = API_KEY) } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt new file mode 100644 index 0000000..9e83997 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt @@ -0,0 +1,9 @@ +package fr.iut.pm.movieapplication.api.dtos + +import com.squareup.moshi.Json + +data class TvShowDTO( + @Json(name = "backdrop_path") + val backdropPath : String? +) { +} \ No newline at end of file From 5a6b157c4f776860159bb6d31719783dfa59adb7 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Thu, 2 Feb 2023 22:48:40 +0100 Subject: [PATCH 2/9] :construction: rebuild the dtos correctly --- .../api/MovieApplicationAPI.kt | 2 +- .../api/dtos/MediaResultDTO.kt | 42 +++++++++++ .../pm/movieapplication/api/dtos/MovieDTO.kt | 58 ++++++--------- .../api/dtos/MovieResultDTO.kt | 1 - .../movieapplication/api/dtos/PopularDTO.kt | 2 +- .../pm/movieapplication/api/dtos/TvShowDTO.kt | 29 +++++++- .../pm/movieapplication/data/dao/MovieDAO.kt | 6 +- .../fr/iut/pm/movieapplication/model/Movie.kt | 64 ---------------- .../iut/pm/movieapplication/model/Popular.kt | 3 +- .../model/media/MediaResult.kt | 24 ++++++ .../model/media/movie/Movie.kt | 22 ++++++ .../model/media/movie/MovieDetails.kt | 50 +++++++++++++ .../model/media/tvshow/TvShow.kt | 20 +++++ .../model/media/tvshow/TvShowDetails.kt | 4 + .../movieapplication/network/dtos/GenreDTO.kt | 7 -- .../repository/MovieRepository.kt | 22 +++--- .../repository/TVShowRepository.kt | 4 + .../ui/adapter/HomeItemAdapter.kt | 15 +++- .../ui/adapter/MovieAdapter.kt | 59 +++++++++++++++ .../ui/fragments/HomeSectionsFragment.kt | 5 +- .../ui/fragments/MoviesFragment.kt | 74 ++++++++++++++++--- .../movieapplication/ui/viewmodel/MoviesVM.kt | 16 +--- .../pm/movieapplication/utils/Constants.kt | 6 ++ .../iut/pm/movieapplication/utils/Mapper.kt | 36 --------- .../utils/MediaResultMapper.kt | 71 ++++++++++++++++++ .../src/main/res/layout/fragment_movies.xml | 2 +- .../res/layout/item_vertical_fragment.xml | 63 ++++++++-------- 27 files changed, 482 insertions(+), 225 deletions(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShowDetails.kt delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/GenreDTO.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index 68b255c..803183d 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -12,7 +12,7 @@ import retrofit2.http.Query interface MovieApplicationAPI { @GET("movie/popular") - fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY) : Call + fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call @GET("movie/top_rated") fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY) : Call diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt new file mode 100644 index 0000000..b428527 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -0,0 +1,42 @@ +package fr.iut.pm.movieapplication.api.dtos + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@Json(name = "results") +data class MediaResultDTO( + + @Json(name = "poster_path") + val posterPath : String, + val adult : Boolean, + val overview : String, + @Json(name = "first_air_date") + val firstAirDate : String?, + @Json(name = "release_date") + val releaseDate : String?, + @Json(name = "origin_country") + val originCountry : List?, + @Json(name = "genre_ids") + val genreIds : List, + val id : Int, + @Json(name = "original_title") + val originalTitle : String?, + @Json(name = "original_language") + val originalLanguage : String, + val title : String?, + @Json(name = "backdrop_path") + val backdropPath : String, + val popularity : Double, + @Json(name = "vote_count") + val voteCount : Int, + val video : Boolean?, + @Json(name = "vote_average") + val voteAverage : Double, + val name: String?, + @Json(name = "original_name") + val originalName : String?, + @Json(name = "media_type") + val mediaType : String +) { + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt index 83abc57..73f4017 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt @@ -1,44 +1,32 @@ package fr.iut.pm.movieapplication.api.dtos -import androidx.room.ColumnInfo -import androidx.room.Embedded -import androidx.room.PrimaryKey -import androidx.room.Relation import com.squareup.moshi.Json -import fr.iut.pm.movieapplication.model.Genre -import fr.iut.pm.movieapplication.model.ProductionCompany -import fr.iut.pm.movieapplication.model.ProductionCountry -import fr.iut.pm.movieapplication.network.dtos.GenreDTO -class MovieDTO ( - val adult: Boolean, - val budget: Int, - val genres: Array?, - val homepage: String?, - val id: Int, - @Json(name = "original_language") - val originalLanguage: String, - @Json(name = "original_title") - val originalTitle: String, - val overview: String?, - val popularity: Double, +open class MovieDTO ( @Json(name = "poster_path") - val posterPath: String?, - @Json(name = "production_countries") - val productionCountries: Array, + open val posterPath: String?, + open val adult: Boolean, + open val overview: String, @Json(name = "release_date") - val releaseDate: String, - val revenue: Int, - val runtime: Int?, - //var spokenLanguages : Array, - val status: String, - @Json(name = "tag_line") - val tagLine: String?, - val title: String, - @Json(name = "vote_average") - val voteAverage: Double, + open val releaseDate: String, + @Json(name = "genre_ids") + open val genreIds: List, + open val id: Int, + @Json(name = "original_title") + open val originalTitle: String, + @Json(name = "original_language") + open val originalLanguage: String, + open val title: String, + @Json(name = "backdrop_path") + open val backdropPath: String?, + open val popularity: Double, @Json(name = "vote_count") - val voteCount: Int, - val backdropPath: String? + open val voteCount: Int, + open val video : Boolean, + @Json(name = "vote_average") + open val voteAverage: Double + + ){ + } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt index 68acf5b..bc1c340 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt @@ -28,7 +28,6 @@ class MovieResultDTO( val popularity : Double?, @Json(name = "vote_count") val voteCount : Int?, - val video : Boolean?, @Json(name = "vote_average") val voteAverage : Double? diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt index baf6422..2db4407 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt @@ -9,7 +9,7 @@ class PopularDTO( @Json(name = "page") val page : Int, @Json(name = "results") - val results : List, + val results : List, @Json(name = "total_results") val totalResults : Int, @Json(name = "total_pages") diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt index 9e83997..be4247c 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt @@ -2,8 +2,29 @@ package fr.iut.pm.movieapplication.api.dtos import com.squareup.moshi.Json -data class TvShowDTO( +open class TvShowDTO( + + @Json(name = "poster_path") + open val posterPath: String?, + open val popularity: Double, + open val id: Int, @Json(name = "backdrop_path") - val backdropPath : String? -) { -} \ No newline at end of file + open val backdropPath: String?, + @Json(name = "vote_average") + open val voteAverage: Double, + open val overview: String, + @Json(name = "first_air_date") + open val firstAirDate: String, + @Json(name = "origin_country") + open val originCountry: List, + @Json(name = "genre_ids") + open val genreIds: List, + @Json(name = "original_language") + open val originalLanguage: String, + @Json(name = "vote_count") + open val voteCount: Int, + open val name: String, + @Json(name = "original_name") + open val originalName: String, + ) +{} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieDAO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieDAO.kt index cf78568..5efb718 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieDAO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieDAO.kt @@ -4,17 +4,17 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import kotlinx.coroutines.flow.Flow @Dao interface MovieDAO { @Query("SELECT * FROM movies_table ORDER BY original_title ASC") - fun getMovieByAlphabetizeMovie() : Flow> + fun getMovieByAlphabetizeMovie() : Flow> @Insert(onConflict = OnConflictStrategy.IGNORE) - suspend fun insert(movie : Movie) + suspend fun insert(movie : MovieDetails) @Query("DELETE FROM movies_table") suspend fun deleteAll() diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt deleted file mode 100644 index 1b8021b..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt +++ /dev/null @@ -1,64 +0,0 @@ -package fr.iut.pm.movieapplication.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "movies_table") -data class Movie( - @ColumnInfo(name = "adult") - val adult: Boolean, - @ColumnInfo(name = "budget") - val budget: Int?, - @ColumnInfo(name = "genres") - val genres: Array?, - @ColumnInfo(name = "homepage") - val homePage: String?, - @PrimaryKey - @ColumnInfo(name = "id") - val movieId: Int, - @ColumnInfo(name = "original_language") - val originalLanguage: String?, - @ColumnInfo(name = "original_title") - val originalTitle: String?, - val overview: String?, - val popularity: Double?, - @ColumnInfo(name = "poster_path") - val posterPath: String?, - val productionCompanies: Array?, - @ColumnInfo(name = "production_countries") - val productionCountries: Array?, - @ColumnInfo(name = "release_date") - val releaseDate: String?, - val revenue: Int?, - val runtime: Int?, - //var spokenLanguages : Array, - val status: String?, - @ColumnInfo(name = "tag_line") - val tagLine: String?, - val title: String?, - @ColumnInfo(name = "vote_average") - val voteAverage: Double?, - @ColumnInfo(name = "vote_count") - val voteCount: Int?, - val backdropPath: String? - - -) { - - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Movie - - if (movieId != other.movieId) return false - - return true - } - - override fun hashCode(): Int { - return movieId - } -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt index 256c611..c278e4d 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt @@ -2,13 +2,14 @@ package fr.iut.pm.movieapplication.model import androidx.room.ColumnInfo import androidx.room.Embedded +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails data class Popular( @ColumnInfo("page") val page : Int, @ColumnInfo("results") @Embedded - val results : List, + val results : List, val totalResults : Int, val totalPages : Int diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt new file mode 100644 index 0000000..d443566 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt @@ -0,0 +1,24 @@ +package fr.iut.pm.movieapplication.model.media + +data class MediaResult( + + val posterPath: String? = null, + val adult: Boolean, + val overview: String, + val firstAirDate: String? = null, + val releaseDate: String? = null, + val originCountry: List? = null, + val genreIds: List, + val id: Int, + val originalTitle: String? = null, + val originalLanguage: String, + val title: String?, + val backdropPath: String? = null, + val popularity: Double, + val voteCount: Int, + val voteAverage: Double, + val name: String? = null, + val originalName: String? = null, + val mediaType : String +) +{} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt new file mode 100644 index 0000000..1a5021b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt @@ -0,0 +1,22 @@ +package fr.iut.pm.movieapplication.model.media.movie + +open class Movie( + open val posterPath: String?, + open val adult: Boolean, + open val overview: String, + open val releaseDate: String, + open val genreIds: List, + open val id: Int, + open val originalTitle: String, + open val originalLanguage: String, + open val title: String?, + open val backdropPath: String?, + open val popularity: Double, + open val voteCount: Int, + open val video: Boolean?, + open val voteAverage: Double, +) +{ + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt new file mode 100644 index 0000000..c70e337 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt @@ -0,0 +1,50 @@ +package fr.iut.pm.movieapplication.model.media.movie + +import fr.iut.pm.movieapplication.model.ProductionCompany +import fr.iut.pm.movieapplication.model.ProductionCountry + + +data class MovieDetails( + + override val posterPath: String, + override val adult: Boolean, + override val overview: String, + override val releaseDate: String, + override val genreIds : List, + override val id: Int, + override val originalTitle: String, + override val originalLanguage: String, + override val title: String?, + override val backdropPath: String?, + override val popularity: Double, + override val voteCount: Int, + override val video: Boolean?, + override val voteAverage: Double, + val mediaType: String, + + val budget: Int?, + val homePage: String?, + val productionCompanies: Array?, + val productionCountries: Array?, + val revenue: Int?, + val runtime: Int?, + val status: String?, + val tagLine: String? + +) : Movie(posterPath, + adult, + overview, + releaseDate, + genreIds, + id, + originalTitle, + originalLanguage, + title, + backdropPath, + popularity, + voteCount, + video, + voteAverage) { + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt new file mode 100644 index 0000000..b9ac31a --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt @@ -0,0 +1,20 @@ +package fr.iut.pm.movieapplication.model.media.tvshow + +class TvShow( + val posterPath: String?, + val popularity: Double, + val id: Int, + val backdropPath: String, + val voteAverage: Double, + val overview: String, + val firstAirDate: String?, + val originCountry: List, + val genreIds: List, + val originalLanguage: String, + val voteCount: Int, + val name: String, + val originalName: String, + val mediaType: String = "tv", +) +{ +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShowDetails.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShowDetails.kt new file mode 100644 index 0000000..7a96534 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShowDetails.kt @@ -0,0 +1,4 @@ +package fr.iut.pm.movieapplication.model.media.tvshow + +class TvShowDetails { +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/GenreDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/GenreDTO.kt deleted file mode 100644 index 5405548..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/GenreDTO.kt +++ /dev/null @@ -1,7 +0,0 @@ -package fr.iut.pm.movieapplication.network.dtos - -data class GenreDTO( - private val id : Int, - private val name : String -) { -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt index c099d8e..8212a01 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -3,20 +3,20 @@ package fr.iut.pm.movieapplication.repository import android.util.Log import fr.iut.pm.movieapplication.api.RetrofitInstance import fr.iut.pm.movieapplication.api.dtos.PopularDTO -import fr.iut.pm.movieapplication.model.Movie -import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY -import fr.iut.pm.movieapplication.utils.Mapper +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.utils.MediaResultMapper import retrofit2.Call import retrofit2.Callback import retrofit2.Response class MovieRepository() { - fun getPopularMovies(callback: (List) -> Unit ) { + fun getPopularMovies(page : Int = 1 ,callback: (List) -> Unit ) { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getPopularMovies().enqueue(object : + RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { @@ -25,9 +25,9 @@ class MovieRepository() { val listMoviesDTO = popularDTO?.results listMoviesDTO?.forEach { - val movie = Mapper.MapToMovie(it) + val movie = MediaResultMapper.mapToMovie(it) listMovie.add(movie) - Log.d("Movie ", movie.title!!) + Log.d("Movie ", movie.title!! ) } } @@ -41,8 +41,8 @@ class MovieRepository() { }) } - fun getTrends(callback: (List) -> Unit) { - val listMovie : MutableList = mutableListOf() + fun getTrends(callback: (List) -> Unit) { + val listMovie : MutableList = mutableListOf() RetrofitInstance.api.getTrending().enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { @@ -50,7 +50,7 @@ class MovieRepository() { Log.d("Response",response.body().toString()) val popularDTO = response.body() popularDTO?.results?.forEach { - val movie = Mapper.MapToMovie(it) + val movie = MediaResultMapper.mapToMediaResult(it) listMovie.add(movie) movie.title?.let { it1 -> Log.d("Movie", it1) } } @@ -59,7 +59,7 @@ class MovieRepository() { } override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) + Log.d("Error failure", t.printStackTrace().toString()) } }) } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt new file mode 100644 index 0000000..b19f419 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt @@ -0,0 +1,4 @@ +package fr.iut.pm.movieapplication.repository + +class TVShowRepository { +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt index 20acfe9..bb5a305 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt @@ -11,14 +11,17 @@ import androidx.recyclerview.widget.RecyclerView import coil.load import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.api.config.GlobalImageConfig -import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.utils.Constants.Companion.IMG_URL class HomeItemAdapter( private val context: MainActivity, private val layoutId: Int, - private val list: List + private val list: List ) : RecyclerView.Adapter() { class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { @@ -39,13 +42,19 @@ class HomeItemAdapter( Log.d("SINGLETON", GlobalImageConfig.baseUrl) val imgUri = currentItem.posterPath?.let { (IMG_URL + it).toUri().buildUpon().scheme("https").build() - } Log.d("SINGLETON", imgUri.toString() ) holder.itemImage.load(imgUri) holder.itemName.text = currentItem.title holder.itemDate.text = currentItem.releaseDate + holder.itemView.setOnClickListener { + onItemClick(currentItem) + } + + } + private fun onItemClick(item : MediaResult) { + Log.d("item clicked", item.toString()) } override fun getItemCount(): Int = list.size diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt new file mode 100644 index 0000000..dc28e98 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -0,0 +1,59 @@ +package fr.iut.pm.movieapplication.ui.adapter + +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.net.toUri +import androidx.recyclerview.widget.RecyclerView +import coil.load +import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.api.config.GlobalImageConfig +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.ui.activity.MainActivity +import fr.iut.pm.movieapplication.utils.Constants + +class MovieAdapter( + private val context: MainActivity, + private val layoutId: Int, + private val list: List +) : RecyclerView.Adapter(){ + + class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { + val itemImage: ImageView = view.findViewById(R.id.item_image) + val itemName: TextView = view.findViewById(R.id.item_name) + val itemDate: TextView = view.findViewById(R.id.item_date) + } + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeItemAdapter.ViewHolder { + val view = LayoutInflater + .from(parent.context) + .inflate(layoutId, parent, false) + return HomeItemAdapter.ViewHolder(view) + } + + override fun getItemCount(): Int = list.size + + + override fun onBindViewHolder(holder: HomeItemAdapter.ViewHolder, position: Int) { + val currentItem = list[position] + Log.d("SINGLETON", GlobalImageConfig.baseUrl) + val imgUri = currentItem.posterPath?.let { + (Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build() + } + Log.d("SINGLETON", imgUri.toString() ) + holder.itemImage.load(imgUri) + holder.itemName.text = currentItem.title + holder.itemDate.text = currentItem.releaseDate + holder.itemView.setOnClickListener { + onItemClick(currentItem) + } + } + + private fun onItemClick(item : Movie) { + Log.d("item clicked", item.toString()) + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index d321a90..528981f 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt @@ -7,11 +7,10 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO -import fr.iut.pm.movieapplication.model.Movie import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import fr.iut.pm.movieapplication.ui.viewmodel.HomeSectionsVM class HomeSectionsFragment( @@ -33,7 +32,7 @@ class HomeSectionsFragment( //get the popularity RecyclerView context.movieRepository.getPopularMovies { val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) - homePopularityRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,it) + homePopularityRecyclerView?.adapter = MovieAdapter(context,R.layout.item_horizontal_home_page,it) homePopularityRecyclerView?.addItemDecoration(HomeItemDecoration()) } //get the free RecyclerView diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index 3623498..9c868c9 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -6,37 +6,89 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.api.RetrofitInstance -import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.ui.adapter.CategoryItemDecoration import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVMFactory -import fr.iut.pm.movieapplication.ui.viewmodel.viewModelFactory -import kotlinx.coroutines.launch +import fr.iut.pm.movieapplication.utils.Constants.Companion.PAGE_SIZE class MoviesFragment( private val context : MainActivity ) : Fragment() { + private var isLoading = false + private var isLastPage = false + private var currentPage = 1 + private var currentList : MutableList = mutableListOf() + private val moviesVM: MoviesVM by viewModels{ MoviesVMFactory(repository = MovieRepository())} + lateinit var moviesRecyclerView : RecyclerView override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_movies, container, false) + // Get the RecyclerView + moviesRecyclerView = view.findViewById(R.id.movies_item_recycler_view) + + // Initialized the data inside our RecyclerView context.movieRepository.getPopularMovies { listMovies -> - val moviesRecyclerView = view?.findViewById(R.id.movies_item_recycler_view) - moviesRecyclerView?.adapter = HomeItemAdapter(context, R.layout.item_vertical_fragment, listMovies) - moviesRecyclerView ?. layoutManager = GridLayoutManager (context, 2) - moviesRecyclerView?.addItemDecoration(CategoryItemDecoration()) + currentList.addAll(0,listMovies) + moviesRecyclerView.adapter = MovieAdapter(context, R.layout.item_vertical_fragment, currentList) + moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) + } + + // Create the ScrollListener + val scrollListener = object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + + val layoutManager = moviesRecyclerView.layoutManager as GridLayoutManager + val visibleItemCount = layoutManager.childCount + val totalItemCount = layoutManager.itemCount + val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition() + + // If we are not already loading data and it's not the last page + if(!isLoading && !isLastPage) { + if(visibleItemCount + firstVisibleItemPosition >= totalItemCount + && firstVisibleItemPosition >= 0 + && totalItemCount >= PAGE_SIZE + ) { + loadMoreMovies() + } + } + } } + // Add the ScrollLister created before to our RecyclerView + moviesRecyclerView.addOnScrollListener(scrollListener) + return view } + + /** + * Method to load data when the user reaches the bottom of the view + */ + private fun loadMoreMovies() { + isLoading = true + currentPage += 1 + + if(currentPage == 1000) isLastPage = true + + val start = currentList.size + context.movieRepository.getPopularMovies(currentPage) { listMovies -> + + currentList.addAll(start, listMovies) + moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + + } + + isLoading = false + } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt index 67fb70d..8548868 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -1,28 +1,18 @@ package fr.iut.pm.movieapplication.ui.viewmodel import androidx.lifecycle.* -import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO -import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.repository.MovieRepository -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class MoviesVM(private val repository: MovieRepository) : ViewModel() { - private val _popularMovies = MutableLiveData>() - val popularMovies : LiveData> = _popularMovies + private val _popularMovies = MutableLiveData>() + val popularMovies : LiveData> = _popularMovies init { //loadData() } - suspend fun loadData() { - viewModelScope.launch { - repository.getPopularMovies { movies -> - _popularMovies.value = movies - } - }.join() - - } } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt index 4081cf5..3bc70c1 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt @@ -3,8 +3,14 @@ package fr.iut.pm.movieapplication.utils class Constants { companion object { + + //API const val BASE_URL = "https://api.themoviedb.org/3/" const val IMG_URL = "https://image.tmdb.org/t/p/w500" const val API_KEY = "8f14a279249638d7f247d0d7298b21b4" + + + //VIEW PAGINATION + const val PAGE_SIZE = 20 } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt deleted file mode 100644 index 9c91be0..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt +++ /dev/null @@ -1,36 +0,0 @@ -package fr.iut.pm.movieapplication.utils - -import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO -import fr.iut.pm.movieapplication.model.Movie - -object Mapper { - - fun MapToMovie( movieDTO : MovieResultDTO) : Movie { - return Movie( - adult = movieDTO.adult, - posterPath = movieDTO.posterPath, - overview = movieDTO.overview, - releaseDate = movieDTO.releaseDate, - movieId = movieDTO.id, - originalTitle = movieDTO.originalTitle, - originalLanguage = movieDTO.originalLanguage, - title = movieDTO.title, - backdropPath = movieDTO.backdropPath, - popularity = movieDTO.popularity, - voteCount = movieDTO.voteCount, - voteAverage = movieDTO.voteAverage, - budget = null, - genres = null, - homePage = null, - productionCompanies = null, - productionCountries = null, - revenue = null, - runtime = null, - status = null, - tagLine = null - - ) - } - - -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt new file mode 100644 index 0000000..3b3bca8 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -0,0 +1,71 @@ +package fr.iut.pm.movieapplication.utils + +import fr.iut.pm.movieapplication.api.dtos.MediaResultDTO +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow + +object MediaResultMapper { + + fun mapToTvShow(mediaResultDTO: MediaResultDTO): TvShow { + return TvShow( + posterPath = mediaResultDTO.posterPath, + popularity = mediaResultDTO.popularity, + id = mediaResultDTO.id, + backdropPath = mediaResultDTO.backdropPath!!, + voteAverage = mediaResultDTO.voteAverage, + overview = mediaResultDTO.overview, + firstAirDate = mediaResultDTO.firstAirDate, + originCountry = mediaResultDTO.originCountry!!, + genreIds = mediaResultDTO.genreIds, + originalLanguage = mediaResultDTO.originalLanguage, + voteCount = mediaResultDTO.voteCount, + name = mediaResultDTO.name!!, + originalName = mediaResultDTO.originalName!! + ) + } + + fun mapToMovie(mediaResultDTO: MediaResultDTO): Movie { + return Movie( + posterPath = mediaResultDTO.posterPath, + adult = mediaResultDTO.adult == false, + overview = mediaResultDTO.overview, + releaseDate = mediaResultDTO.releaseDate!!, + genreIds = mediaResultDTO.genreIds, + id = mediaResultDTO.id, + originalTitle = mediaResultDTO.originalTitle!!, + originalLanguage = mediaResultDTO.originalLanguage, + title = mediaResultDTO.title, + backdropPath = mediaResultDTO.backdropPath, + popularity = mediaResultDTO.popularity, + voteCount = mediaResultDTO.voteCount, + video = mediaResultDTO.video, + voteAverage = mediaResultDTO.voteAverage + ) + } + + fun mapToMediaResult(mediaResultDTO: MediaResultDTO) : MediaResult { + return MediaResult( + posterPath = mediaResultDTO.posterPath, + adult = mediaResultDTO.adult == false, + overview = mediaResultDTO.overview, + firstAirDate = mediaResultDTO.firstAirDate, + releaseDate = mediaResultDTO.releaseDate, + originCountry = mediaResultDTO.originCountry, + genreIds = mediaResultDTO.genreIds, + id = mediaResultDTO.id, + originalTitle = mediaResultDTO.originalTitle, + originalLanguage = mediaResultDTO.originalLanguage, + title = mediaResultDTO.title, + backdropPath = mediaResultDTO.backdropPath, + popularity = mediaResultDTO.popularity, + voteCount = mediaResultDTO.voteCount, + voteAverage = mediaResultDTO.voteAverage, + name = mediaResultDTO.name, + originalName = mediaResultDTO.originalName, + mediaType = mediaResultDTO.mediaType + ) + } + + +} \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index 4094d47..bda7cfc 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -7,7 +7,7 @@ diff --git a/Sources/app/src/main/res/layout/item_vertical_fragment.xml b/Sources/app/src/main/res/layout/item_vertical_fragment.xml index 6c2d62a..ef3a88c 100644 --- a/Sources/app/src/main/res/layout/item_vertical_fragment.xml +++ b/Sources/app/src/main/res/layout/item_vertical_fragment.xml @@ -1,46 +1,49 @@ + android:layout_height="match_parent" + android:layout_marginStart="4dp" + android:layout_marginLeft="4dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="4dp" + android:layout_marginRight="4dp" + android:layout_marginBottom="8dp" + app:cardCornerRadius="10dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - - - - - + + + + + From fc371bf386b8175f965d95b57ad9c9dc3d53db2d Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Fri, 3 Feb 2023 20:41:27 +0100 Subject: [PATCH 3/9] :construction: add some requests Get the most popular movie Get the top rated movie Get the upcoming movie Get the movie now playing --- .../api/MovieApplicationAPI.kt | 17 ++- .../api/dtos/MediaResultDTO.kt | 2 +- .../model/media/MediaResult.kt | 2 +- .../repository/MediaRepository.kt | 36 ++++++ .../repository/MovieRepository.kt | 84 +++++++++++-- .../repository/TVShowRepository.kt | 39 ++++++ .../ui/activity/MainActivity.kt | 14 +-- .../{MovieAdapter.kt => CategoryAdapter.kt} | 45 ++++--- .../{HomeItemAdapter.kt => MediaAdapter.kt} | 26 ++-- .../ui/fragments/HomeSectionsFragment.kt | 12 +- .../ui/fragments/MoviesFragment.kt | 112 +++++++++++++++--- .../{ShowsFragment.kt => TvShowsFragment.kt} | 2 +- .../utils/MediaResultMapper.kt | 4 +- .../src/main/res/layout/fragment_movies.xml | 12 ++ .../src/main/res/layout/fragment_tv_shows.xml | 13 ++ Sources/app/src/main/res/values/strings.xml | 8 ++ 16 files changed, 357 insertions(+), 71 deletions(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt rename Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/{MovieAdapter.kt => CategoryAdapter.kt} (50%) rename Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/{HomeItemAdapter.kt => MediaAdapter.kt} (78%) rename Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/{ShowsFragment.kt => TvShowsFragment.kt} (93%) create mode 100644 Sources/app/src/main/res/layout/fragment_tv_shows.xml diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index 803183d..09619f8 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -11,14 +11,25 @@ import retrofit2.http.Query interface MovieApplicationAPI { + // Movie @GET("movie/popular") fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call - @GET("movie/top_rated") - fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY) : Call + @GET("movie/now_playing") + fun getNowPlayingMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call @GET("movie/upcoming") - fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY) : Call + fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Call + + @GET("movie/top_rated") + fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Call + + + + // TvShow + @GET + fun getPopularTvShow(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call + @GET("trending/{media_type}/{time_window}") fun getTrending(@Path("media_type") mediaType : String = "all", @Path("time_window") timeWindow : String = "day", @Query("api_key") apiKey: String = API_KEY ) : Call diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt index b428527..7973820 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -36,7 +36,7 @@ data class MediaResultDTO( @Json(name = "original_name") val originalName : String?, @Json(name = "media_type") - val mediaType : String + val mediaType : String? ) { } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt index d443566..73834d0 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt @@ -19,6 +19,6 @@ data class MediaResult( val voteAverage: Double, val name: String? = null, val originalName: String? = null, - val mediaType : String + val mediaType: String? ) {} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt new file mode 100644 index 0000000..d4f9501 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt @@ -0,0 +1,36 @@ +package fr.iut.pm.movieapplication.repository + +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.api.dtos.PopularDTO +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.utils.MediaResultMapper +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class MediaRepository { + + fun getTrends(callback: (List) -> Unit) { + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getTrending().enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if(response.isSuccessful) { + Log.d("Response",response.body().toString()) + val popularDTO = response.body() + popularDTO?.results?.forEach { + val movie = MediaResultMapper.mapToMediaResult(it) + listMovie.add(movie) + movie.title?.let { it1 -> Log.d("Movie", it1) } + } + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.printStackTrace().toString()) + } + }) + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt index 8212a01..495a223 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -41,26 +41,92 @@ class MovieRepository() { }) } - fun getTrends(callback: (List) -> Unit) { - val listMovie : MutableList = mutableListOf() + fun getNowPlayingMovies(page : Int = 1, callback: (List) -> Unit) { - RetrofitInstance.api.getTrending().enqueue(object : Callback { + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getNowPlayingMovies(page = page).enqueue(object : + Callback { override fun onResponse(call: Call, response: Response) { - if(response.isSuccessful) { - Log.d("Response",response.body().toString()) + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) val popularDTO = response.body() - popularDTO?.results?.forEach { - val movie = MediaResultMapper.mapToMediaResult(it) + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + + val movie = MediaResultMapper.mapToMovie(it) listMovie.add(movie) - movie.title?.let { it1 -> Log.d("Movie", it1) } + Log.d("Movie ", movie.title!! ) } + } callback(listMovie) } override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.printStackTrace().toString()) + Log.d("Error failure", t.message.toString()) } + }) } + + fun getUpcomingMovies(page : Int = 1, callback: (List) -> Unit) { + + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getUpcomingMovies(page = page).enqueue(object : + Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!! ) + } + + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.message.toString()) + } + + }) + } + + fun getTopRatedMovies(page : Int = 1, callback: (List) -> Unit) { + + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getTopRatedMovies(page = page).enqueue(object : + Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!! ) + } + + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.message.toString()) + } + + }) + } + + } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt index b19f419..2515701 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt @@ -1,4 +1,43 @@ package fr.iut.pm.movieapplication.repository +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.api.dtos.PopularDTO +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow +import fr.iut.pm.movieapplication.utils.MediaResultMapper +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + class TVShowRepository { + + fun getPopularTvShow(page : Int = 1 ,callback: (List) -> Unit ) { + + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : + Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + + val tvShow = MediaResultMapper.mapToTvShow(it) + listMovie.add(tvShow) + Log.d("Movie ", tvShow.name ) + } + + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.message.toString()) + } + + }) + } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index 558a3c5..3648708 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt @@ -5,26 +5,20 @@ import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.Menu import android.view.View -import android.widget.SearchView.OnQueryTextListener import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import com.google.android.material.bottomnavigation.BottomNavigationView import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.api.RetrofitInstance -import fr.iut.pm.movieapplication.api.config.GlobalImageConfig +import fr.iut.pm.movieapplication.repository.MediaRepository import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.fragments.HomeSectionsFragment import fr.iut.pm.movieapplication.ui.fragments.MoviesFragment -import fr.iut.pm.movieapplication.ui.fragments.ShowsFragment -import fr.iut.pm.movieapplication.utils.Constants -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import retrofit2.awaitResponse +import fr.iut.pm.movieapplication.ui.fragments.TvShowsFragment class MainActivity : AppCompatActivity() { val movieRepository : MovieRepository = MovieRepository() + val mediaRepository : MediaRepository = MediaRepository() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -47,7 +41,7 @@ class MainActivity : AppCompatActivity() { } R.id.series_page -> { - loadFragments(ShowsFragment(this)) + loadFragments(TvShowsFragment(this)) return@setOnItemSelectedListener true } else -> false diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt similarity index 50% rename from Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt rename to Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt index dc28e98..050a2ae 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt @@ -10,16 +10,16 @@ import androidx.core.net.toUri import androidx.recyclerview.widget.RecyclerView import coil.load import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.api.config.GlobalImageConfig import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.utils.Constants +import fr.iut.pm.movieapplication.utils.Constants.Companion.IMG_URL -class MovieAdapter( +class CategoryAdapter( private val context: MainActivity, private val layoutId: Int, - private val list: List -) : RecyclerView.Adapter(){ + private val list: List +) : RecyclerView.Adapter(){ class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { val itemImage: ImageView = view.findViewById(R.id.item_image) @@ -28,29 +28,40 @@ class MovieAdapter( } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeItemAdapter.ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaAdapter.ViewHolder { val view = LayoutInflater .from(parent.context) .inflate(layoutId, parent, false) - return HomeItemAdapter.ViewHolder(view) + return MediaAdapter.ViewHolder(view) } override fun getItemCount(): Int = list.size - override fun onBindViewHolder(holder: HomeItemAdapter.ViewHolder, position: Int) { + override fun onBindViewHolder(holder: MediaAdapter.ViewHolder, position: Int) { val currentItem = list[position] - Log.d("SINGLETON", GlobalImageConfig.baseUrl) - val imgUri = currentItem.posterPath?.let { - (Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build() + if(currentItem != null) { + + when(currentItem!!::class.java) { + Movie::class.java -> bindMovie(holder, currentItem as Movie) + TvShow::class.java -> bindTvShow(holder, currentItem as TvShow) + } + } - Log.d("SINGLETON", imgUri.toString() ) + } + + private fun bindTvShow(holder: MediaAdapter.ViewHolder, tvShow: TvShow) { + val imgUri = tvShow.posterPath?.let { (IMG_URL+it).toUri().buildUpon().scheme("https").build() } holder.itemImage.load(imgUri) - holder.itemName.text = currentItem.title - holder.itemDate.text = currentItem.releaseDate - holder.itemView.setOnClickListener { - onItemClick(currentItem) - } + holder.itemName.text = tvShow.name + holder.itemDate.text = tvShow.firstAirDate + } + + private fun bindMovie(holder: MediaAdapter.ViewHolder, movie: Movie) { + val imgUri = movie.posterPath?.let { (IMG_URL+it).toUri().buildUpon().scheme("https").build() } + holder.itemImage.load(imgUri) + holder.itemName.text = movie.title + holder.itemDate.text = movie.releaseDate } private fun onItemClick(item : Movie) { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt similarity index 78% rename from Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt rename to Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt index bb5a305..d3c6be9 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt @@ -12,17 +12,14 @@ import coil.load import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.api.config.GlobalImageConfig import fr.iut.pm.movieapplication.model.media.MediaResult -import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.model.media.movie.MovieDetails -import fr.iut.pm.movieapplication.model.media.tvshow.TvShow import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.utils.Constants.Companion.IMG_URL -class HomeItemAdapter( +class MediaAdapter( private val context: MainActivity, private val layoutId: Int, private val list: List - ) : RecyclerView.Adapter() { + ) : RecyclerView.Adapter() { class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { val itemImage: ImageView = view.findViewById(R.id.item_image) @@ -38,21 +35,36 @@ class HomeItemAdapter( } override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val currentItem = list[position] + when(currentItem.mediaType) { + "movie" -> bindMovie(holder, currentItem) + "tv" -> bindTvShow(holder, currentItem) + } Log.d("SINGLETON", GlobalImageConfig.baseUrl) val imgUri = currentItem.posterPath?.let { (IMG_URL + it).toUri().buildUpon().scheme("https").build() } Log.d("SINGLETON", imgUri.toString() ) holder.itemImage.load(imgUri) - holder.itemName.text = currentItem.title - holder.itemDate.text = currentItem.releaseDate + holder.itemView.setOnClickListener { onItemClick(currentItem) } } + // If the item is a Movie + private fun bindMovie(holder: ViewHolder, currentItem: MediaResult) { + holder.itemName.text = currentItem.title + holder.itemDate.text = currentItem.releaseDate + } + // If the item is a TvShow + private fun bindTvShow(holder: ViewHolder, currentItem: MediaResult) { + holder.itemName.text = currentItem.name + holder.itemDate.text = currentItem.firstAirDate + } + private fun onItemClick(item : MediaResult) { Log.d("item clicked", item.toString()) } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index 528981f..d27bc09 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt @@ -8,9 +8,9 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter +import fr.iut.pm.movieapplication.ui.adapter.MediaAdapter import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration -import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.ui.adapter.CategoryAdapter import fr.iut.pm.movieapplication.ui.viewmodel.HomeSectionsVM class HomeSectionsFragment( @@ -23,21 +23,21 @@ class HomeSectionsFragment( val view = inflater.inflate(R.layout.fragment_home_sections, container, false) //get the trends RecyclerView - context.movieRepository.getTrends { + context.mediaRepository.getTrends { val homeTrendsRecyclerView = view?.findViewById(R.id.home_trends_recycler_view) - homeTrendsRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,it) + homeTrendsRecyclerView?.adapter = MediaAdapter(context,R.layout.item_horizontal_home_page,it) homeTrendsRecyclerView?.addItemDecoration(HomeItemDecoration()) } //get the popularity RecyclerView context.movieRepository.getPopularMovies { val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) - homePopularityRecyclerView?.adapter = MovieAdapter(context,R.layout.item_horizontal_home_page,it) + homePopularityRecyclerView?.adapter = CategoryAdapter(context,R.layout.item_horizontal_home_page,it) homePopularityRecyclerView?.addItemDecoration(HomeItemDecoration()) } //get the free RecyclerView val homeFreeRecyclerView = view?.findViewById(R.id.home_free_recycler_view) - homeFreeRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) + homeFreeRecyclerView?.adapter = MediaAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) homeFreeRecyclerView?.addItemDecoration(HomeItemDecoration()) return view } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index 9c868c9..87fbca2 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -4,18 +4,18 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Spinner import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.model.media.MediaResult import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter -import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.ui.adapter.CategoryAdapter import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVMFactory import fr.iut.pm.movieapplication.utils.Constants.Companion.PAGE_SIZE @@ -31,6 +31,8 @@ class MoviesFragment( private val moviesVM: MoviesVM by viewModels{ MoviesVMFactory(repository = MovieRepository())} lateinit var moviesRecyclerView : RecyclerView + lateinit var spinner: Spinner + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_movies, container, false) @@ -38,11 +40,7 @@ class MoviesFragment( moviesRecyclerView = view.findViewById(R.id.movies_item_recycler_view) // Initialized the data inside our RecyclerView - context.movieRepository.getPopularMovies { listMovies -> - currentList.addAll(0,listMovies) - moviesRecyclerView.adapter = MovieAdapter(context, R.layout.item_vertical_fragment, currentList) - moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) - } + // Create the ScrollListener val scrollListener = object : RecyclerView.OnScrollListener() { @@ -69,9 +67,73 @@ class MoviesFragment( // Add the ScrollLister created before to our RecyclerView moviesRecyclerView.addOnScrollListener(scrollListener) + spinner = view.findViewById(R.id.category_spinner) + configSpinner(spinner) return view } + private fun configSpinner(spinner: Spinner) { + ArrayAdapter.createFromResource( + context, + R.array.movie_filter, + android.R.layout.simple_spinner_item + ).also { adapter -> + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + + spinner.adapter = adapter + } + + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + when(position) { + 0 -> { + currentList.clear() + context.movieRepository.getPopularMovies { listMovies -> + currentList.addAll(0,listMovies) + moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) + moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) + } + } + 1 -> { + currentList.clear() + context.movieRepository.getNowPlayingMovies { movies: List -> + currentList.addAll(0,movies) + moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) + moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) + + } + } + 2 -> { + currentList.clear() + context.movieRepository.getUpcomingMovies { movies: List -> + currentList.addAll(0,movies) + moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) + moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) + } + } + 3 -> { + currentList.clear() + context.movieRepository.getTopRatedMovies { movies -> + currentList.addAll(0,movies) + moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) + moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) + } + } + } + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + + } + + } + } + /** * Method to load data when the user reaches the bottom of the view */ @@ -82,13 +144,35 @@ class MoviesFragment( if(currentPage == 1000) isLastPage = true val start = currentList.size - context.movieRepository.getPopularMovies(currentPage) { listMovies -> - - currentList.addAll(start, listMovies) - moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + when(spinner.selectedItemPosition) { + 0 -> { + context.movieRepository.getPopularMovies(currentPage) { listMovies -> + currentList.addAll(start, listMovies) + moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + } + } + 1 -> { + context.movieRepository.getNowPlayingMovies(currentPage) { listMovies -> + currentList.addAll(start, listMovies) + moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + } + } + 2 -> { + context.movieRepository.getUpcomingMovies(currentPage) { listMovies -> + currentList.addAll(start, listMovies) + moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + } + } + 3 -> { + context.movieRepository.getTopRatedMovies(currentPage) { listMovies -> + currentList.addAll(start, listMovies) + moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) + } + } } + isLoading = false } -} \ No newline at end of file +} diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt similarity index 93% rename from Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt rename to Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt index b9f7feb..4aba7f2 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt @@ -4,7 +4,7 @@ import android.os.Bundle import androidx.fragment.app.Fragment import fr.iut.pm.movieapplication.ui.activity.MainActivity -class ShowsFragment( +class TvShowsFragment( private val context : MainActivity ) : Fragment() { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt index 3b3bca8..9948f10 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -28,7 +28,7 @@ object MediaResultMapper { fun mapToMovie(mediaResultDTO: MediaResultDTO): Movie { return Movie( posterPath = mediaResultDTO.posterPath, - adult = mediaResultDTO.adult == false, + adult = !mediaResultDTO.adult, overview = mediaResultDTO.overview, releaseDate = mediaResultDTO.releaseDate!!, genreIds = mediaResultDTO.genreIds, @@ -47,7 +47,7 @@ object MediaResultMapper { fun mapToMediaResult(mediaResultDTO: MediaResultDTO) : MediaResult { return MediaResult( posterPath = mediaResultDTO.posterPath, - adult = mediaResultDTO.adult == false, + adult = !mediaResultDTO.adult, overview = mediaResultDTO.overview, firstAirDate = mediaResultDTO.firstAirDate, releaseDate = mediaResultDTO.releaseDate, diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index bda7cfc..7a243ca 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -2,8 +2,20 @@ + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/values/strings.xml b/Sources/app/src/main/res/values/strings.xml index 260cd67..6280e15 100644 --- a/Sources/app/src/main/res/values/strings.xml +++ b/Sources/app/src/main/res/values/strings.xml @@ -13,5 +13,13 @@ Populaires Gratuits section_nested_scroll_view + + + + Populaires + Du moment + À venir + Les mieux notés + \ No newline at end of file From e29247f3ce41ee566961134f55d50605b04b7d66 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Sun, 5 Feb 2023 01:34:03 +0100 Subject: [PATCH 4/9] :construction: add data binding and view model Data are now binded on the view --- Sources/app/build.gradle | 12 +- .../api/MovieApplicationAPI.kt | 9 +- .../api/dtos/MediaResultDTO.kt | 4 +- .../model/media/MediaResult.kt | 9 +- .../model/media/movie/Movie.kt | 39 ++++ .../repository/MovieRepository.kt | 149 ++++++--------- .../repository/TVShowRepository.kt | 56 +++--- .../ui/activity/MainActivity.kt | 2 +- .../ui/adapter/CategoryAdapter.kt | 70 ------- .../ui/adapter/MediaAdapter.kt | 14 +- .../ui/adapter/MovieAdapter.kt | 47 +++++ .../ui/fragments/HomeSectionsFragment.kt | 11 +- .../ui/fragments/MoviesFragment.kt | 172 ++++-------------- .../movieapplication/ui/viewmodel/MoviesVM.kt | 86 ++++++++- .../utils/MediaResultMapper.kt | 11 +- .../src/main/res/layout/fragment_movies.xml | 74 +++++--- .../main/res/layout/item_movie_category.xml | 67 +++++++ 17 files changed, 429 insertions(+), 403 deletions(-) delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt create mode 100644 Sources/app/src/main/res/layout/item_movie_category.xml diff --git a/Sources/app/build.gradle b/Sources/app/build.gradle index 6940713..cd5b0a7 100644 --- a/Sources/app/build.gradle +++ b/Sources/app/build.gradle @@ -36,13 +36,17 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + dataBinding true + } } dependencies { + implementation 'androidx.core:core-ktx:1.9.0' implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" - implementation 'androidx.core:core-ktx:1.9.0' + implementation "androidx.fragment:fragment-ktx:1.5.5" // Room components @@ -53,7 +57,7 @@ dependencies { // Lifecycle components implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-common-java8:$rootProject.lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$rootProject.lifecycleVersion" // Kotlin components implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" @@ -69,13 +73,11 @@ dependencies { // Moshi implementation "com.squareup.moshi:moshi-kotlin:1.13.0" - //GSON - //implementation 'com.squareup.retrofit2:converter-gson:2.1.0' // Retrofit implementation "com.squareup.retrofit2:retrofit:2.9.0" // Retrofit with Scalar Converter - //implementation "com.squareup.retrofit2:converter-scalars:2.9.0" + implementation "com.squareup.retrofit2:converter-scalars:2.9.0" // Retrofit with Moshi Converter implementation "com.squareup.retrofit2:converter-moshi:2.9.0" diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index 09619f8..13efeba 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -5,6 +5,7 @@ import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO import fr.iut.pm.movieapplication.api.dtos.PopularDTO import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY import retrofit2.Call +import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query @@ -13,16 +14,16 @@ interface MovieApplicationAPI { // Movie @GET("movie/popular") - fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call + suspend fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Response @GET("movie/now_playing") - fun getNowPlayingMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call + suspend fun getNowPlayingMovies(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Response @GET("movie/upcoming") - fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Call + suspend fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response @GET("movie/top_rated") - fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Call + suspend fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt index 7973820..b9b56af 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -7,7 +7,7 @@ import com.squareup.moshi.JsonClass data class MediaResultDTO( @Json(name = "poster_path") - val posterPath : String, + val posterPath : String?, val adult : Boolean, val overview : String, @Json(name = "first_air_date") @@ -25,7 +25,7 @@ data class MediaResultDTO( val originalLanguage : String, val title : String?, @Json(name = "backdrop_path") - val backdropPath : String, + val backdropPath : String?, val popularity : Double, @Json(name = "vote_count") val voteCount : Int, diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt index 73834d0..fbe2ce4 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt @@ -5,20 +5,17 @@ data class MediaResult( val posterPath: String? = null, val adult: Boolean, val overview: String, - val firstAirDate: String? = null, - val releaseDate: String? = null, + val releaseDate: String, val originCountry: List? = null, val genreIds: List, val id: Int, - val originalTitle: String? = null, + val originalTitle: String, val originalLanguage: String, - val title: String?, + val title: String, val backdropPath: String? = null, val popularity: Double, val voteCount: Int, val voteAverage: Double, - val name: String? = null, - val originalName: String? = null, val mediaType: String? ) {} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt index 1a5021b..32ac156 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt @@ -17,6 +17,45 @@ open class Movie( open val voteAverage: Double, ) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as Movie + if (posterPath != other.posterPath) return false + if (adult != other.adult) return false + if (overview != other.overview) return false + if (releaseDate != other.releaseDate) return false + if (genreIds != other.genreIds) return false + if (id != other.id) return false + if (originalTitle != other.originalTitle) return false + if (originalLanguage != other.originalLanguage) return false + if (title != other.title) return false + if (backdropPath != other.backdropPath) return false + if (popularity != other.popularity) return false + if (voteCount != other.voteCount) return false + if (video != other.video) return false + if (voteAverage != other.voteAverage) return false + + return true + } + + override fun hashCode(): Int { + var result = posterPath?.hashCode() ?: 0 + result = 31 * result + adult.hashCode() + result = 31 * result + overview.hashCode() + result = 31 * result + releaseDate.hashCode() + result = 31 * result + genreIds.hashCode() + result = 31 * result + id + result = 31 * result + originalTitle.hashCode() + result = 31 * result + originalLanguage.hashCode() + result = 31 * result + (title?.hashCode() ?: 0) + result = 31 * result + (backdropPath?.hashCode() ?: 0) + result = 31 * result + popularity.hashCode() + result = 31 * result + voteCount + result = 31 * result + (video?.hashCode() ?: 0) + result = 31 * result + voteAverage.hashCode() + return result + } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt index 495a223..e327a64 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -1,131 +1,88 @@ package fr.iut.pm.movieapplication.repository import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.liveData import fr.iut.pm.movieapplication.api.RetrofitInstance import fr.iut.pm.movieapplication.api.dtos.PopularDTO import fr.iut.pm.movieapplication.model.media.MediaResult import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.utils.MediaResultMapper -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +import kotlinx.coroutines.Dispatchers -class MovieRepository() { +class MovieRepository { - fun getPopularMovies(page : Int = 1 ,callback: (List) -> Unit ) { + suspend fun getPopularMovies(page : Int = 1) : List + { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : - Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - Log.d("List :", response.body().toString()) - val popularDTO = response.body() - val listMoviesDTO = popularDTO?.results - listMoviesDTO?.forEach { - - val movie = MediaResultMapper.mapToMovie(it) - listMovie.add(movie) - Log.d("Movie ", movie.title!! ) - } - - } - callback(listMovie) + val response = RetrofitInstance.api.getPopularMovies(page = page) + if(response.isSuccessful) { + val listMediaResultDTO = response.body()?.results + listMediaResultDTO?.forEach { + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!!) } - - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } - - }) + } + else Log.d("ERROR FAILED", response.message()) + return listMovie } - fun getNowPlayingMovies(page : Int = 1, callback: (List) -> Unit) { + suspend fun getNowPlayingMovies(page : Int = 1) : List + { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getNowPlayingMovies(page = page).enqueue(object : - Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - Log.d("List :", response.body().toString()) - val popularDTO = response.body() - val listMoviesDTO = popularDTO?.results - listMoviesDTO?.forEach { - - val movie = MediaResultMapper.mapToMovie(it) - listMovie.add(movie) - Log.d("Movie ", movie.title!! ) - } - - } - callback(listMovie) + val response = RetrofitInstance.api.getNowPlayingMovies(page = page) + if(response.isSuccessful) { + val listMediaResultDTO = response.body()?.results + listMediaResultDTO?.forEach { + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!!) } - - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } - - }) + } + else Log.d("ERROR FAILED", response.message()) + return listMovie } - fun getUpcomingMovies(page : Int = 1, callback: (List) -> Unit) { + suspend fun getUpcomingMovies(page : Int = 1) : List + { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getUpcomingMovies(page = page).enqueue(object : - Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - Log.d("List :", response.body().toString()) - val popularDTO = response.body() - val listMoviesDTO = popularDTO?.results - listMoviesDTO?.forEach { - - val movie = MediaResultMapper.mapToMovie(it) - listMovie.add(movie) - Log.d("Movie ", movie.title!! ) - } - - } - callback(listMovie) + val response = RetrofitInstance.api.getUpcomingMovies(page = page) + if(response.isSuccessful) { + val listMediaResultDTO = response.body()?.results + listMediaResultDTO?.forEach { + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!!) } - - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } - - }) + } + else Log.d("ERROR FAILED", response.message()) + return listMovie } - fun getTopRatedMovies(page : Int = 1, callback: (List) -> Unit) { + suspend fun getTopRatedMovies(page : Int = 1) : List + { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getTopRatedMovies(page = page).enqueue(object : - Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - Log.d("List :", response.body().toString()) - val popularDTO = response.body() - val listMoviesDTO = popularDTO?.results - listMoviesDTO?.forEach { - - val movie = MediaResultMapper.mapToMovie(it) - listMovie.add(movie) - Log.d("Movie ", movie.title!! ) - } - - } - callback(listMovie) + val response = RetrofitInstance.api.getTopRatedMovies(page = page) + if(response.isSuccessful) { + val listMediaResultDTO = response.body()?.results + listMediaResultDTO?.forEach { + val movie = MediaResultMapper.mapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!!) } - - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } - - }) + } + else Log.d("ERROR FAILED", response.message()) + return listMovie } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt index 2515701..f2c1d4a 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt @@ -12,32 +12,32 @@ import retrofit2.Response class TVShowRepository { - fun getPopularTvShow(page : Int = 1 ,callback: (List) -> Unit ) { - - val listMovie : MutableList = mutableListOf() - - RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : - Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - Log.d("List :", response.body().toString()) - val popularDTO = response.body() - val listMoviesDTO = popularDTO?.results - listMoviesDTO?.forEach { - - val tvShow = MediaResultMapper.mapToTvShow(it) - listMovie.add(tvShow) - Log.d("Movie ", tvShow.name ) - } - - } - callback(listMovie) - } - - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } - - }) - } +// fun getPopularTvShow(page : Int = 1 ,callback: (List) -> Unit ) { +// +// val listMovie : MutableList = mutableListOf() +// +// RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : +// Callback { +// override fun onResponse(call: Call, response: Response) { +// if (response.isSuccessful) { +// Log.d("List :", response.body().toString()) +// val popularDTO = response.body() +// val listMoviesDTO = popularDTO?.results +// listMoviesDTO?.forEach { +// +// val tvShow = MediaResultMapper.mapToTvShow(it) +// listMovie.add(tvShow) +// Log.d("Movie ", tvShow.name ) +// } +// +// } +// callback(listMovie) +// } +// +// override fun onFailure(call: Call, t: Throwable) { +// Log.d("Error failure", t.message.toString()) +// } +// +// }) +// } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index 3648708..4e6e7db 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt @@ -36,7 +36,7 @@ class MainActivity : AppCompatActivity() { } R.id.movies_page -> { - loadFragments(MoviesFragment(this)) + loadFragments(MoviesFragment()) return@setOnItemSelectedListener true } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt deleted file mode 100644 index 050a2ae..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryAdapter.kt +++ /dev/null @@ -1,70 +0,0 @@ -package fr.iut.pm.movieapplication.ui.adapter - -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.core.net.toUri -import androidx.recyclerview.widget.RecyclerView -import coil.load -import fr.iut.pm.movieapplication.R -import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.model.media.tvshow.TvShow -import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.utils.Constants.Companion.IMG_URL - -class CategoryAdapter( - private val context: MainActivity, - private val layoutId: Int, - private val list: List -) : RecyclerView.Adapter(){ - - class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { - val itemImage: ImageView = view.findViewById(R.id.item_image) - val itemName: TextView = view.findViewById(R.id.item_name) - val itemDate: TextView = view.findViewById(R.id.item_date) - } - - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaAdapter.ViewHolder { - val view = LayoutInflater - .from(parent.context) - .inflate(layoutId, parent, false) - return MediaAdapter.ViewHolder(view) - } - - override fun getItemCount(): Int = list.size - - - override fun onBindViewHolder(holder: MediaAdapter.ViewHolder, position: Int) { - val currentItem = list[position] - if(currentItem != null) { - - when(currentItem!!::class.java) { - Movie::class.java -> bindMovie(holder, currentItem as Movie) - TvShow::class.java -> bindTvShow(holder, currentItem as TvShow) - } - - } - } - - private fun bindTvShow(holder: MediaAdapter.ViewHolder, tvShow: TvShow) { - val imgUri = tvShow.posterPath?.let { (IMG_URL+it).toUri().buildUpon().scheme("https").build() } - holder.itemImage.load(imgUri) - holder.itemName.text = tvShow.name - holder.itemDate.text = tvShow.firstAirDate - } - - private fun bindMovie(holder: MediaAdapter.ViewHolder, movie: Movie) { - val imgUri = movie.posterPath?.let { (IMG_URL+it).toUri().buildUpon().scheme("https").build() } - holder.itemImage.load(imgUri) - holder.itemName.text = movie.title - holder.itemDate.text = movie.releaseDate - } - - private fun onItemClick(item : Movie) { - Log.d("item clicked", item.toString()) - } -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt index d3c6be9..bfa49cd 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt @@ -37,11 +37,8 @@ class MediaAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val currentItem = list[position] - when(currentItem.mediaType) { - "movie" -> bindMovie(holder, currentItem) - "tv" -> bindTvShow(holder, currentItem) - } - Log.d("SINGLETON", GlobalImageConfig.baseUrl) + bindItem(holder, currentItem) + val imgUri = currentItem.posterPath?.let { (IMG_URL + it).toUri().buildUpon().scheme("https").build() } @@ -55,15 +52,10 @@ class MediaAdapter( } // If the item is a Movie - private fun bindMovie(holder: ViewHolder, currentItem: MediaResult) { + private fun bindItem(holder: ViewHolder, currentItem: MediaResult) { holder.itemName.text = currentItem.title holder.itemDate.text = currentItem.releaseDate } - // If the item is a TvShow - private fun bindTvShow(holder: ViewHolder, currentItem: MediaResult) { - holder.itemName.text = currentItem.name - holder.itemDate.text = currentItem.firstAirDate - } private fun onItemClick(item : MediaResult) { Log.d("item clicked", item.toString()) diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt new file mode 100644 index 0000000..d798661 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -0,0 +1,47 @@ +package fr.iut.pm.movieapplication.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.net.toUri +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import coil.load +import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.databinding.ItemMovieCategoryBinding +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.utils.Constants + +class MovieAdapter : ListAdapter(DiffUtilDogCallback) { + + private object DiffUtilDogCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Movie, newItem: Movie) = oldItem.id == newItem.id + override fun areContentsTheSame(oldItem: Movie, newItem: Movie) = oldItem == newItem + } + + class ViewHolder(private val binding : ItemMovieCategoryBinding) : + RecyclerView.ViewHolder(binding.root) { + + val movie : Movie? get() = binding.movie + + init { + itemView.setOnClickListener {} + } + + fun bind(movie : Movie) { + binding.movie = movie + val imgUri = movie.posterPath?.let { (Constants.IMG_URL +it).toUri().buildUpon().scheme("https").build() } + binding.itemImage.load(imgUri) + binding.executePendingBindings() + } + + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = + ViewHolder(ItemMovieCategoryBinding.inflate(LayoutInflater.from(parent.context))) + + override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(getItem(position)) +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index d27bc09..f58178f 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt @@ -10,7 +10,6 @@ import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.ui.adapter.MediaAdapter import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration -import fr.iut.pm.movieapplication.ui.adapter.CategoryAdapter import fr.iut.pm.movieapplication.ui.viewmodel.HomeSectionsVM class HomeSectionsFragment( @@ -30,11 +29,11 @@ class HomeSectionsFragment( } //get the popularity RecyclerView - context.movieRepository.getPopularMovies { - val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) - homePopularityRecyclerView?.adapter = CategoryAdapter(context,R.layout.item_horizontal_home_page,it) - homePopularityRecyclerView?.addItemDecoration(HomeItemDecoration()) - } +// context.movieRepository.getPopularMovies { +// val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) +// homePopularityRecyclerView?.adapter = CategoryAdapter(context,R.layout.item_horizontal_home_page,it) +// homePopularityRecyclerView?.addItemDecoration(HomeItemDecoration()) +// } //get the free RecyclerView val homeFreeRecyclerView = view?.findViewById(R.id.home_free_recycler_view) homeFreeRecyclerView?.adapter = MediaAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index 87fbca2..9e80f2b 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -1,6 +1,7 @@ package fr.iut.pm.movieapplication.ui.fragments import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,19 +10,17 @@ import android.widget.ArrayAdapter import android.widget.Spinner import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.databinding.FragmentMoviesBinding import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.repository.MovieRepository -import fr.iut.pm.movieapplication.ui.activity.MainActivity -import fr.iut.pm.movieapplication.ui.adapter.CategoryAdapter +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM -import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVMFactory import fr.iut.pm.movieapplication.utils.Constants.Companion.PAGE_SIZE class MoviesFragment( - private val context : MainActivity ) : Fragment() { private var isLoading = false @@ -29,150 +28,53 @@ class MoviesFragment( private var currentPage = 1 private var currentList : MutableList = mutableListOf() - private val moviesVM: MoviesVM by viewModels{ MoviesVMFactory(repository = MovieRepository())} - lateinit var moviesRecyclerView : RecyclerView - lateinit var spinner: Spinner - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_movies, container, false) - - // Get the RecyclerView - moviesRecyclerView = view.findViewById(R.id.movies_item_recycler_view) + private val moviesVM by viewModels() - // Initialized the data inside our RecyclerView + lateinit var spinner: Spinner - // Create the ScrollListener - val scrollListener = object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - super.onScrolled(recyclerView, dx, dy) - - val layoutManager = moviesRecyclerView.layoutManager as GridLayoutManager - val visibleItemCount = layoutManager.childCount - val totalItemCount = layoutManager.itemCount - val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = FragmentMoviesBinding.inflate(inflater) + binding.moviesVM = moviesVM + binding.lifecycleOwner = viewLifecycleOwner + + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.movie_filter, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - // If we are not already loading data and it's not the last page - if(!isLoading && !isLastPage) { - if(visibleItemCount + firstVisibleItemPosition >= totalItemCount - && firstVisibleItemPosition >= 0 - && totalItemCount >= PAGE_SIZE + with(binding.categorySpinner) + { + this.adapter = adapter + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long ) { - loadMoreMovies() + moviesVM.getDataFilter(selectedItem.toString()) } - } - } - } - // Add the ScrollLister created before to our RecyclerView - moviesRecyclerView.addOnScrollListener(scrollListener) - spinner = view.findViewById(R.id.category_spinner) - configSpinner(spinner) - return view - } - - private fun configSpinner(spinner: Spinner) { - ArrayAdapter.createFromResource( - context, - R.array.movie_filter, - android.R.layout.simple_spinner_item - ).also { adapter -> - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - - spinner.adapter = adapter - } - - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - when(position) { - 0 -> { - currentList.clear() - context.movieRepository.getPopularMovies { listMovies -> - currentList.addAll(0,listMovies) - moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) - moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) - } - } - 1 -> { - currentList.clear() - context.movieRepository.getNowPlayingMovies { movies: List -> - currentList.addAll(0,movies) - moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) - moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) - - } - } - 2 -> { - currentList.clear() - context.movieRepository.getUpcomingMovies { movies: List -> - currentList.addAll(0,movies) - moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) - moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) - } - } - 3 -> { - currentList.clear() - context.movieRepository.getTopRatedMovies { movies -> - currentList.addAll(0,movies) - moviesRecyclerView.adapter = CategoryAdapter(context, R.layout.item_vertical_fragment, currentList) - moviesRecyclerView.layoutManager = GridLayoutManager (context, 3) - } - } + override fun onNothingSelected(parent: AdapterView<*>?) { + TODO("Not yet implemented") } - } - - override fun onNothingSelected(parent: AdapterView<*>?) { } - } + return binding.root } - /** - * Method to load data when the user reaches the bottom of the view - */ - private fun loadMoreMovies() { - isLoading = true - currentPage += 1 - - if(currentPage == 1000) isLastPage = true - - val start = currentList.size - - when(spinner.selectedItemPosition) { - 0 -> { - context.movieRepository.getPopularMovies(currentPage) { listMovies -> - currentList.addAll(start, listMovies) - moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) - } - } - 1 -> { - context.movieRepository.getNowPlayingMovies(currentPage) { listMovies -> - currentList.addAll(start, listMovies) - moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) - } - } - 2 -> { - context.movieRepository.getUpcomingMovies(currentPage) { listMovies -> - currentList.addAll(start, listMovies) - moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) - } - } - 3 -> { - context.movieRepository.getTopRatedMovies(currentPage) { listMovies -> - currentList.addAll(start, listMovies) - moviesRecyclerView.adapter?.notifyItemRangeChanged(start, listMovies.size) - } - } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + moviesVM.getMoviesLiveData().observe(viewLifecycleOwner) { + moviesVM.moviesAdapter.submitList(it) } - - - isLoading = false } } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt index 8548868..84bbc25 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -1,27 +1,93 @@ package fr.iut.pm.movieapplication.ui.viewmodel import androidx.lifecycle.* -import fr.iut.pm.movieapplication.model.media.movie.MovieDetails +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.repository.MovieRepository +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import kotlinx.coroutines.launch -class MoviesVM(private val repository: MovieRepository) : ViewModel() { +class MoviesVM() : ViewModel() { + //Movie repository + private val repository = MovieRepository() + //Live data + private var _moviesLiveData : MutableLiveData> = MutableLiveData>() + fun getMoviesLiveData() : LiveData> = _moviesLiveData - private val _popularMovies = MutableLiveData>() - val popularMovies : LiveData> = _popularMovies + private var currentFilter = "" + val moviesAdapter = MovieAdapter() + val scrollListener = object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + val layoutManager = recyclerView.layoutManager as GridLayoutManager + val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition() + val totalItemCount = layoutManager.itemCount - init { - //loadData() + if(lastVisibleItemPosition == totalItemCount -1) { + + ++currentPage + getMoreData(currentPage) + } + } } + + private var currentPage = 1 + + + fun getDataFilter(filter : String) { + + //_moviesLiveData.value = mutableListOf() + currentFilter = filter + currentPage = 1 + + when(currentFilter) { + "Populaires" -> viewModelScope.launch { + _moviesLiveData.postValue(repository.getPopularMovies()) + } + "Du moment" -> viewModelScope.launch { + _moviesLiveData.postValue(repository.getNowPlayingMovies()) + } + "À venir" -> viewModelScope.launch { + _moviesLiveData.postValue(repository.getUpcomingMovies()) + } + "Les mieux notés" -> viewModelScope.launch { + _moviesLiveData.postValue(repository.getTopRatedMovies()) + } + } + + } + + fun getMoreData(page : Int = 1) { + var movies : List + when(currentFilter) { + "Populaires" -> viewModelScope.launch { + movies = _moviesLiveData.value?.plus(repository.getPopularMovies(page)) ?: listOf() + _moviesLiveData.postValue(movies) + } + "Du moment" -> viewModelScope.launch { + movies = _moviesLiveData.value?.plus(repository.getNowPlayingMovies(page)) ?: listOf() + _moviesLiveData.postValue(movies) + } + "À venir" -> viewModelScope.launch { + movies = _moviesLiveData.value?.plus(repository.getUpcomingMovies(page)) ?: listOf() + _moviesLiveData.postValue(movies) + } + "Les mieux notés" -> viewModelScope.launch { + movies = _moviesLiveData.value?.plus(repository.getTopRatedMovies(page)) ?: listOf() + _moviesLiveData.postValue(movies) + } + } + + } + } -class MoviesVMFactory( - private val repository: MovieRepository - ) : ViewModelProvider.Factory { +class MoviesVMFactory : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { - return MoviesVM(repository) as T + return MoviesVM() as T } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt index 9948f10..c15a018 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -30,7 +30,7 @@ object MediaResultMapper { posterPath = mediaResultDTO.posterPath, adult = !mediaResultDTO.adult, overview = mediaResultDTO.overview, - releaseDate = mediaResultDTO.releaseDate!!, + releaseDate = mediaResultDTO.releaseDate ?: "", genreIds = mediaResultDTO.genreIds, id = mediaResultDTO.id, originalTitle = mediaResultDTO.originalTitle!!, @@ -49,20 +49,17 @@ object MediaResultMapper { posterPath = mediaResultDTO.posterPath, adult = !mediaResultDTO.adult, overview = mediaResultDTO.overview, - firstAirDate = mediaResultDTO.firstAirDate, - releaseDate = mediaResultDTO.releaseDate, + releaseDate = mediaResultDTO.releaseDate ?: mediaResultDTO.firstAirDate!! , originCountry = mediaResultDTO.originCountry, genreIds = mediaResultDTO.genreIds, id = mediaResultDTO.id, - originalTitle = mediaResultDTO.originalTitle, + originalTitle = mediaResultDTO.originalTitle ?: mediaResultDTO.originalName!!, //if it's not a movie also it's a tvshow originalLanguage = mediaResultDTO.originalLanguage, - title = mediaResultDTO.title, + title = mediaResultDTO.title ?: mediaResultDTO.name!!, //if it's not a movie also it's a tvshow backdropPath = mediaResultDTO.backdropPath, popularity = mediaResultDTO.popularity, voteCount = mediaResultDTO.voteCount, voteAverage = mediaResultDTO.voteAverage, - name = mediaResultDTO.name, - originalName = mediaResultDTO.originalName, mediaType = mediaResultDTO.mediaType ) } diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index 7a243ca..a3d0e0f 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -1,26 +1,56 @@ - - - - + + + + + + + + + android:orientation="vertical"> + + + + + + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/item_movie_category.xml b/Sources/app/src/main/res/layout/item_movie_category.xml new file mode 100644 index 0000000..784f1f9 --- /dev/null +++ b/Sources/app/src/main/res/layout/item_movie_category.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 635a458cadebbae094dc5ff2b6c91e41132de286 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Sun, 5 Feb 2023 01:57:52 +0100 Subject: [PATCH 5/9] :recycler: refactor and clean the code --- .../repository/MovieRepository.kt | 6 --- .../ui/activity/MainActivity.kt | 9 +--- .../ui/adapter/CategoryItemDecoration.kt | 12 ----- .../ui/adapter/MovieAdapter.kt | 4 -- .../ui/fragments/MoviesFragment.kt | 52 +++++++------------ .../movieapplication/ui/viewmodel/MoviesVM.kt | 47 ++++++++++------- .../ui/viewmodel/ViewModelFactory.kt | 9 ---- 7 files changed, 48 insertions(+), 91 deletions(-) delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryItemDecoration.kt delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt index e327a64..4e471ae 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -1,15 +1,9 @@ package fr.iut.pm.movieapplication.repository import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.liveData import fr.iut.pm.movieapplication.api.RetrofitInstance -import fr.iut.pm.movieapplication.api.dtos.PopularDTO -import fr.iut.pm.movieapplication.model.media.MediaResult import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.utils.MediaResultMapper -import kotlinx.coroutines.Dispatchers class MovieRepository { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index 4e6e7db..30f886a 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt @@ -17,7 +17,6 @@ import fr.iut.pm.movieapplication.ui.fragments.TvShowsFragment class MainActivity : AppCompatActivity() { - val movieRepository : MovieRepository = MovieRepository() val mediaRepository : MediaRepository = MediaRepository() override fun onCreate(savedInstanceState: Bundle?) { @@ -47,13 +46,7 @@ class MainActivity : AppCompatActivity() { else -> false } } - /* - //Trends fragment injected in main activity - val transaction = supportFragmentManager.beginTransaction() - transaction.replace(R.id.fragment_container, HomeSectionsFragment()) - transaction.addToBackStack(null) - transaction.commit() - */ + if(Build.VERSION.SDK_INT < 33) { // Hide the status bar. window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryItemDecoration.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryItemDecoration.kt deleted file mode 100644 index fe08862..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/CategoryItemDecoration.kt +++ /dev/null @@ -1,12 +0,0 @@ -package fr.iut.pm.movieapplication.ui.adapter - -import android.graphics.Rect -import android.view.View -import androidx.recyclerview.widget.RecyclerView - -class CategoryItemDecoration : RecyclerView.ItemDecoration() { - - override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { - outRect.bottom = 50 - } -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt index d798661..e19e4e0 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -1,16 +1,12 @@ package fr.iut.pm.movieapplication.ui.adapter import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView import androidx.core.net.toUri import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import coil.load -import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.databinding.ItemMovieCategoryBinding import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.utils.Constants diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index 9e80f2b..c4573f5 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -1,38 +1,22 @@ package fr.iut.pm.movieapplication.ui.fragments import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter -import android.widget.Spinner import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.databinding.FragmentMoviesBinding -import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM -import fr.iut.pm.movieapplication.utils.Constants.Companion.PAGE_SIZE class MoviesFragment( ) : Fragment() { - private var isLoading = false - private var isLastPage = false - private var currentPage = 1 - private var currentList : MutableList = mutableListOf() - private val moviesVM by viewModels() - - lateinit var spinner: Spinner - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -41,25 +25,25 @@ class MoviesFragment( binding.moviesVM = moviesVM binding.lifecycleOwner = viewLifecycleOwner - val adapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.movie_filter, - android.R.layout.simple_spinner_item - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.movie_filter, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - with(binding.categorySpinner) - { - this.adapter = adapter - onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - moviesVM.getDataFilter(selectedItem.toString()) - } + with(binding.categorySpinner) + { + this.adapter = adapter + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + moviesVM.getData(selectedItem.toString()) + } override fun onNothingSelected(parent: AdapterView<*>?) { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt index 84bbc25..126f2b3 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -9,14 +9,31 @@ import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter import kotlinx.coroutines.launch class MoviesVM() : ViewModel() { - //Movie repository + /** + * The movie repository used to get our data + */ private val repository = MovieRepository() - //Live data + + /** + * The MutableLiveData + */ private var _moviesLiveData : MutableLiveData> = MutableLiveData>() + + /** + * Getter of the LiveData + */ fun getMoviesLiveData() : LiveData> = _moviesLiveData + /** + * The current data filter + */ private var currentFilter = "" + + /** + * The adapter of the RecyclerView (set on the RecyclerView in the view) + */ val moviesAdapter = MovieAdapter() + val scrollListener = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { val layoutManager = recyclerView.layoutManager as GridLayoutManager @@ -33,13 +50,13 @@ class MoviesVM() : ViewModel() { private var currentPage = 1 - - fun getDataFilter(filter : String) { - - //_moviesLiveData.value = mutableListOf() + /** + * Get the data with a given filter + * @param filter filter applied to get data + */ + fun getData(filter : String) { currentFilter = filter currentPage = 1 - when(currentFilter) { "Populaires" -> viewModelScope.launch { _moviesLiveData.postValue(repository.getPopularMovies()) @@ -57,7 +74,11 @@ class MoviesVM() : ViewModel() { } - fun getMoreData(page : Int = 1) { + /** + * Get more data with the actual filter + * @param page page from which the data are obtained + */ + private fun getMoreData(page : Int = 1) { var movies : List when(currentFilter) { "Populaires" -> viewModelScope.launch { @@ -80,14 +101,4 @@ class MoviesVM() : ViewModel() { } -} - - - -class MoviesVMFactory : ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - return MoviesVM() as T - } - } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt deleted file mode 100644 index d9d7bcc..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fr.iut.pm.movieapplication.ui.viewmodel - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider - -inline fun viewModelFactory(crossinline f: () -> VM) = - object : ViewModelProvider.Factory { - override fun create(modelClass: Class): T = f() as T - } \ No newline at end of file From 724e6cb75c47a1074b54003b869408cd066b5e5b Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Sun, 5 Feb 2023 21:18:27 +0100 Subject: [PATCH 6/9] :construction: add the tv show request and display the data in the tvshow cateogry --- .../api/MovieApplicationAPI.kt | 4 +- .../api/dtos/MediaResultDTO.kt | 2 +- .../model/media/tvshow/TvShow.kt | 72 +++++++++++++++---- .../repository/TVShowRepository.kt | 43 ----------- .../repository/TvShowRepository.kt | 29 ++++++++ .../ui/activity/MainActivity.kt | 2 +- .../ui/adapter/MovieAdapter.kt | 5 +- .../ui/adapter/TvShowAdapter.kt | 48 +++++++++++++ .../ui/fragments/MoviesFragment.kt | 2 +- .../ui/fragments/TvShowsFragment.kt | 59 ++++++++++++++- .../movieapplication/ui/viewmodel/MoviesVM.kt | 8 ++- .../movieapplication/ui/viewmodel/TvShowVM.kt | 34 +++++++++ .../pm/movieapplication/utils/Constants.kt | 1 + .../utils/MediaResultMapper.kt | 6 +- .../src/main/res/layout/fragment_movies.xml | 2 +- .../src/main/res/layout/fragment_tv_shows.xml | 48 ++++++++++--- .../main/res/layout/item_tv_show_category.xml | 67 +++++++++++++++++ Sources/app/src/main/res/values/strings.xml | 7 ++ 18 files changed, 358 insertions(+), 81 deletions(-) delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/TvShowAdapter.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt create mode 100644 Sources/app/src/main/res/layout/item_tv_show_category.xml diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index 13efeba..5b9350a 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -28,8 +28,8 @@ interface MovieApplicationAPI { // TvShow - @GET - fun getPopularTvShow(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Call + @GET("tv/popular") + suspend fun getPopularTvShow(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Response @GET("trending/{media_type}/{time_window}") diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt index b9b56af..2a979af 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -8,7 +8,7 @@ data class MediaResultDTO( @Json(name = "poster_path") val posterPath : String?, - val adult : Boolean, + val adult : Boolean?, val overview : String, @Json(name = "first_air_date") val firstAirDate : String?, diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt index b9ac31a..0b698dc 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt @@ -1,20 +1,62 @@ package fr.iut.pm.movieapplication.model.media.tvshow -class TvShow( - val posterPath: String?, - val popularity: Double, - val id: Int, - val backdropPath: String, - val voteAverage: Double, - val overview: String, - val firstAirDate: String?, - val originCountry: List, - val genreIds: List, - val originalLanguage: String, - val voteCount: Int, - val name: String, - val originalName: String, - val mediaType: String = "tv", +open class TvShow( + open val posterPath: String?, + open val popularity: Double, + open val id: Int, + open val backdropPath: String, + open val voteAverage: Double, + open val overview: String, + open val firstAirDate: String?, + open val originCountry: List, + open val genreIds: List, + open val originalLanguage: String, + open val voteCount: Int, + open val name: String, + open val originalName: String, + open val mediaType: String = "tv", ) { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TvShow + + if (posterPath != other.posterPath) return false + if (popularity != other.popularity) return false + if (id != other.id) return false + if (backdropPath != other.backdropPath) return false + if (voteAverage != other.voteAverage) return false + if (overview != other.overview) return false + if (firstAirDate != other.firstAirDate) return false + if (originCountry != other.originCountry) return false + if (genreIds != other.genreIds) return false + if (originalLanguage != other.originalLanguage) return false + if (voteCount != other.voteCount) return false + if (name != other.name) return false + if (originalName != other.originalName) return false + if (mediaType != other.mediaType) return false + + return true + } + + override fun hashCode(): Int { + var result = posterPath?.hashCode() ?: 0 + result = 31 * result + popularity.hashCode() + result = 31 * result + id + result = 31 * result + backdropPath.hashCode() + result = 31 * result + voteAverage.hashCode() + result = 31 * result + overview.hashCode() + result = 31 * result + (firstAirDate?.hashCode() ?: 0) + result = 31 * result + originCountry.hashCode() + result = 31 * result + genreIds.hashCode() + result = 31 * result + originalLanguage.hashCode() + result = 31 * result + voteCount + result = 31 * result + name.hashCode() + result = 31 * result + originalName.hashCode() + result = 31 * result + mediaType.hashCode() + return result + } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt deleted file mode 100644 index f2c1d4a..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TVShowRepository.kt +++ /dev/null @@ -1,43 +0,0 @@ -package fr.iut.pm.movieapplication.repository - -import android.util.Log -import fr.iut.pm.movieapplication.api.RetrofitInstance -import fr.iut.pm.movieapplication.api.dtos.PopularDTO -import fr.iut.pm.movieapplication.model.media.movie.Movie -import fr.iut.pm.movieapplication.model.media.tvshow.TvShow -import fr.iut.pm.movieapplication.utils.MediaResultMapper -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response - -class TVShowRepository { - -// fun getPopularTvShow(page : Int = 1 ,callback: (List) -> Unit ) { -// -// val listMovie : MutableList = mutableListOf() -// -// RetrofitInstance.api.getPopularMovies(page = page).enqueue(object : -// Callback { -// override fun onResponse(call: Call, response: Response) { -// if (response.isSuccessful) { -// Log.d("List :", response.body().toString()) -// val popularDTO = response.body() -// val listMoviesDTO = popularDTO?.results -// listMoviesDTO?.forEach { -// -// val tvShow = MediaResultMapper.mapToTvShow(it) -// listMovie.add(tvShow) -// Log.d("Movie ", tvShow.name ) -// } -// -// } -// callback(listMovie) -// } -// -// override fun onFailure(call: Call, t: Throwable) { -// Log.d("Error failure", t.message.toString()) -// } -// -// }) -// } -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt new file mode 100644 index 0000000..01e2e10 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt @@ -0,0 +1,29 @@ +package fr.iut.pm.movieapplication.repository + +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow +import fr.iut.pm.movieapplication.utils.MediaResultMapper + +class TvShowRepository { + + suspend fun getPopularTvShow(page : Int = 1 ) : List { + + val listMovie : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getPopularTvShow(page = page) + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + val tvShow = MediaResultMapper.mapToTvShow(it) + listMovie.add(tvShow) + Log.d("Movie ", tvShow.name ) + } + } + else Log.d("Error failure", response.message()) + + return listMovie + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index 30f886a..b27c2aa 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt @@ -40,7 +40,7 @@ class MainActivity : AppCompatActivity() { } R.id.series_page -> { - loadFragments(TvShowsFragment(this)) + loadFragments(TvShowsFragment()) return@setOnItemSelectedListener true } else -> false diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt index e19e4e0..24eed09 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -11,9 +11,9 @@ import fr.iut.pm.movieapplication.databinding.ItemMovieCategoryBinding import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.utils.Constants -class MovieAdapter : ListAdapter(DiffUtilDogCallback) { +class MovieAdapter() : ListAdapter(DiffUtilMovieCallback) { - private object DiffUtilDogCallback : DiffUtil.ItemCallback() { + private object DiffUtilMovieCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Movie, newItem: Movie) = oldItem.id == newItem.id override fun areContentsTheSame(oldItem: Movie, newItem: Movie) = oldItem == newItem } @@ -40,4 +40,5 @@ class MovieAdapter : ListAdapter(DiffUtilDogCall ViewHolder(ItemMovieCategoryBinding.inflate(LayoutInflater.from(parent.context))) override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(getItem(position)) + } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/TvShowAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/TvShowAdapter.kt new file mode 100644 index 0000000..e139b65 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/TvShowAdapter.kt @@ -0,0 +1,48 @@ +package fr.iut.pm.movieapplication.ui.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.net.toUri +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import coil.load +import fr.iut.pm.movieapplication.databinding.ItemTvShowCategoryBinding +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow +import fr.iut.pm.movieapplication.utils.Constants + +class TvShowAdapter() : ListAdapter(DiffUtilTvShowCallback) { + + + private object DiffUtilTvShowCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: TvShow, newItem: TvShow) = oldItem.id == newItem.id + + override fun areContentsTheSame(oldItem: TvShow, newItem: TvShow) = oldItem == newItem + } + + + class ViewHolder(private val binding : ItemTvShowCategoryBinding) + : RecyclerView.ViewHolder(binding.root){ + + val tvShow : TvShow? get() = binding.tvShow + + init { + itemView.setOnClickListener {} + } + + fun bind(tvShow : TvShow) { + binding.tvShow = tvShow + val imgUri = tvShow.posterPath?.let { (Constants.IMG_URL +it).toUri().buildUpon().scheme("https").build() } + binding.itemImage.load(imgUri) + binding.executePendingBindings() + } + + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TvShowAdapter.ViewHolder = + TvShowAdapter.ViewHolder(ItemTvShowCategoryBinding.inflate(LayoutInflater.from(parent.context))) + + override fun onBindViewHolder(holder: TvShowAdapter.ViewHolder, position: Int) = holder.bind(getItem(position)) + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index c4573f5..c0326ac 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -32,7 +32,7 @@ class MoviesFragment( ) adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - with(binding.categorySpinner) + with(binding.categoryMovieSpinner) { this.adapter = adapter onItemSelectedListener = object : AdapterView.OnItemSelectedListener { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt index 4aba7f2..fe13393 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt @@ -1,15 +1,68 @@ package fr.iut.pm.movieapplication.ui.fragments import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.databinding.FragmentTvShowsBinding import fr.iut.pm.movieapplication.ui.activity.MainActivity +import fr.iut.pm.movieapplication.ui.viewmodel.TvShowVM class TvShowsFragment( - private val context : MainActivity ) : Fragment() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + private val tvShowVM by viewModels() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?) + : View { + val binding = FragmentTvShowsBinding.inflate(inflater) + + binding.tvShowVM = tvShowVM + binding.lifecycleOwner = viewLifecycleOwner + + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.tv_show_filter, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + + with(binding.categoryTvShowSpinner) + { + this.adapter = adapter + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + tvShowVM.getData(selectedItem.toString()) + } + + + override fun onNothingSelected(parent: AdapterView<*>?) { + TODO("Not yet implemented") + } + + } + } + + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + tvShowVM.getTvShowLiveData().observe(viewLifecycleOwner) { + tvShowVM.tvShowAdapter.submitList(it) + } } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt index 126f2b3..69cf7cd 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -6,6 +6,8 @@ import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.utils.Constants.Companion.MAX_PAGE +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class MoviesVM() : ViewModel() { @@ -43,11 +45,15 @@ class MoviesVM() : ViewModel() { if(lastVisibleItemPosition == totalItemCount -1) { ++currentPage - getMoreData(currentPage) + //1000 is the MAX_PAGE + if(currentPage <= MAX_PAGE) getMoreData(currentPage) } } } + /** + * Currrent page where the data are obtained + */ private var currentPage = 1 /** diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt new file mode 100644 index 0000000..33b1c4b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt @@ -0,0 +1,34 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import fr.iut.pm.movieapplication.model.media.tvshow.TvShow +import fr.iut.pm.movieapplication.repository.TvShowRepository +import fr.iut.pm.movieapplication.ui.adapter.TvShowAdapter +import kotlinx.coroutines.launch + +class TvShowVM : ViewModel() { + + private val tvShowRepository = TvShowRepository() + + private var tvShowLiveData : MutableLiveData> = MutableLiveData>() + fun getTvShowLiveData() : LiveData> = tvShowLiveData + + private var currentFilter : String = "" + val tvShowAdapter = TvShowAdapter() + + private var currentPage = 1 + + fun getData(filter : String) { + + currentFilter = filter + currentPage = 1 + when(currentFilter) { + "Populaires" -> viewModelScope.launch { + tvShowLiveData.postValue(tvShowRepository.getPopularTvShow()) + } + } + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt index 3bc70c1..37e050b 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt @@ -12,5 +12,6 @@ class Constants { //VIEW PAGINATION const val PAGE_SIZE = 20 + const val MAX_PAGE = 1000 } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt index c15a018..0b58a33 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -12,7 +12,7 @@ object MediaResultMapper { posterPath = mediaResultDTO.posterPath, popularity = mediaResultDTO.popularity, id = mediaResultDTO.id, - backdropPath = mediaResultDTO.backdropPath!!, + backdropPath = mediaResultDTO.backdropPath ?: "", voteAverage = mediaResultDTO.voteAverage, overview = mediaResultDTO.overview, firstAirDate = mediaResultDTO.firstAirDate, @@ -28,7 +28,7 @@ object MediaResultMapper { fun mapToMovie(mediaResultDTO: MediaResultDTO): Movie { return Movie( posterPath = mediaResultDTO.posterPath, - adult = !mediaResultDTO.adult, + adult = mediaResultDTO.adult!!, overview = mediaResultDTO.overview, releaseDate = mediaResultDTO.releaseDate ?: "", genreIds = mediaResultDTO.genreIds, @@ -47,7 +47,7 @@ object MediaResultMapper { fun mapToMediaResult(mediaResultDTO: MediaResultDTO) : MediaResult { return MediaResult( posterPath = mediaResultDTO.posterPath, - adult = !mediaResultDTO.adult, + adult = mediaResultDTO.adult!!, overview = mediaResultDTO.overview, releaseDate = mediaResultDTO.releaseDate ?: mediaResultDTO.firstAirDate!! , originCountry = mediaResultDTO.originCountry, diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index a3d0e0f..7016eed 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -20,7 +20,7 @@ - + - + + + + + + + + android:orientation="vertical"> + + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/item_tv_show_category.xml b/Sources/app/src/main/res/layout/item_tv_show_category.xml new file mode 100644 index 0000000..188f2fb --- /dev/null +++ b/Sources/app/src/main/res/layout/item_tv_show_category.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/values/strings.xml b/Sources/app/src/main/res/values/strings.xml index 6280e15..79bb1d8 100644 --- a/Sources/app/src/main/res/values/strings.xml +++ b/Sources/app/src/main/res/values/strings.xml @@ -22,4 +22,11 @@ Les mieux notés + + Populaires + Diffusées aujourd\'hui + En cours de diffusion + Les mieux notées + + \ No newline at end of file From 76130b935844d54ca3638a80d3e8f320846f6e37 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Mon, 6 Feb 2023 19:56:43 +0100 Subject: [PATCH 7/9] :construction: prepare class for the movie details request --- .../api/MovieApplicationAPI.kt | 15 +++-- .../pm/movieapplication/api/dtos/GenreDTO.kt | 8 +++ .../api/dtos/MediaResultDTO.kt | 24 +++---- .../api/dtos/MovieDetailsDTO.kt | 48 ++++++++++++++ .../{TvShowDTO.kt => TvShowDetailsDTO.kt} | 2 +- .../model/media/MediaResult.kt | 2 +- .../model/media/movie/Movie.kt | 12 ++-- .../model/media/movie/MovieDetails.kt | 8 +-- .../model/media/tvshow/TvShow.kt | 6 +- .../repository/TvShowRepository.kt | 64 ++++++++++++++++++- .../movieapplication/ui/viewmodel/TvShowVM.kt | 11 +++- .../utils/MediaResultMapper.kt | 14 ++-- Sources/app/src/main/res/values/arrays.xml | 2 + Sources/app/src/main/res/values/strings.xml | 4 +- 14 files changed, 177 insertions(+), 43 deletions(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/GenreDTO.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt rename Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/{TvShowDTO.kt => TvShowDetailsDTO.kt} (96%) create mode 100644 Sources/app/src/main/res/values/arrays.xml diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index 5b9350a..a8d2bd0 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -1,7 +1,7 @@ package fr.iut.pm.movieapplication.api import fr.iut.pm.movieapplication.api.dtos.MovieDTO -import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO +import fr.iut.pm.movieapplication.api.dtos.MovieDetailsDTO import fr.iut.pm.movieapplication.api.dtos.PopularDTO import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY import retrofit2.Call @@ -25,18 +25,25 @@ interface MovieApplicationAPI { @GET("movie/top_rated") suspend fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response + // Movie details + @GET("movie/{movie_id}") + fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Response // TvShow @GET("tv/popular") - suspend fun getPopularTvShow(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Response + suspend fun getPopularTvShows(@Query("api_key") apiKey : String = API_KEY, @Query("page") page : Int = 1) : Response + @GET("tv/airing_today") + suspend fun getAiringTodayTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response + @GET("tv/on_the_air") + suspend fun getTvOnTheAirTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response + @GET("tv/top_rated") + suspend fun getTopRatedTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("page") page : Int = 1) : Response @GET("trending/{media_type}/{time_window}") fun getTrending(@Path("media_type") mediaType : String = "all", @Path("time_window") timeWindow : String = "day", @Query("api_key") apiKey: String = API_KEY ) : Call - @GET("movie/{movie_id") - fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Call @GET("tv/{tv_id}") fun getShowDetails(@Path("tv_id") tvId : Int, @Query("api_key") apiKey: String = API_KEY) diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/GenreDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/GenreDTO.kt new file mode 100644 index 0000000..8bbdaa4 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/GenreDTO.kt @@ -0,0 +1,8 @@ +package fr.iut.pm.movieapplication.api.dtos + +data class GenreDTO( + val id : Int, + val name : String +) { + +} diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt index 2a979af..a56948c 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -4,23 +4,23 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @Json(name = "results") -data class MediaResultDTO( +open class MediaResultDTO( @Json(name = "poster_path") val posterPath : String?, val adult : Boolean?, - val overview : String, + val overview : String? = null, @Json(name = "first_air_date") - val firstAirDate : String?, + val firstAirDate : String? = null, @Json(name = "release_date") - val releaseDate : String?, + val releaseDate : String? = null, @Json(name = "origin_country") - val originCountry : List?, - @Json(name = "genre_ids") - val genreIds : List, + val originCountry : List? = null, +// @Json(name = "genre_ids") +// val genreIds : List, val id : Int, @Json(name = "original_title") - val originalTitle : String?, + val originalTitle : String? = null, @Json(name = "original_language") val originalLanguage : String, val title : String?, @@ -29,14 +29,14 @@ data class MediaResultDTO( val popularity : Double, @Json(name = "vote_count") val voteCount : Int, - val video : Boolean?, + //val video : Boolean?, @Json(name = "vote_average") val voteAverage : Double, - val name: String?, + val name: String? = null, @Json(name = "original_name") - val originalName : String?, + val originalName : String? = null, @Json(name = "media_type") - val mediaType : String? + val mediaType : String? = null ) { } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt new file mode 100644 index 0000000..4fc1dae --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt @@ -0,0 +1,48 @@ +package fr.iut.pm.movieapplication.api.dtos + +import fr.iut.pm.movieapplication.model.Genre + +class MovieDetailsDTO( + + adult : Boolean?, + backdropPath : String?, + val budget : Int, + val genres : List, + val homepage : String?, + id : Int, + originalLanguage : String, + originalTitle : String, + overview : String?, + popularity : Double, + posterPath : String?, + //prod companies + //prod countries + releaseDate : String?, + val revenue : Int, + //spoken language + val status : String, + title : String, + voteAverage : Double, + voteCount : Int + + + +) : MediaResultDTO( + adult = adult, + backdropPath = backdropPath, + id = id, + originalLanguage = originalLanguage, + originalTitle = originalTitle, + overview = overview, + popularity = popularity, + posterPath = posterPath, + releaseDate = releaseDate, + title = title, + voteAverage = voteAverage, + voteCount = voteCount, +) { + + + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDetailsDTO.kt similarity index 96% rename from Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt rename to Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDetailsDTO.kt index be4247c..bdee72e 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDetailsDTO.kt @@ -2,7 +2,7 @@ package fr.iut.pm.movieapplication.api.dtos import com.squareup.moshi.Json -open class TvShowDTO( +open class TvShowDetailsDTO( @Json(name = "poster_path") open val posterPath: String?, diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt index fbe2ce4..d9c8594 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt @@ -7,7 +7,7 @@ data class MediaResult( val overview: String, val releaseDate: String, val originCountry: List? = null, - val genreIds: List, +// val genreIds: List, val id: Int, val originalTitle: String, val originalLanguage: String, diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt index 32ac156..ad61088 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt @@ -5,7 +5,7 @@ open class Movie( open val adult: Boolean, open val overview: String, open val releaseDate: String, - open val genreIds: List, +// open val genreIds: List, open val id: Int, open val originalTitle: String, open val originalLanguage: String, @@ -13,8 +13,8 @@ open class Movie( open val backdropPath: String?, open val popularity: Double, open val voteCount: Int, - open val video: Boolean?, - open val voteAverage: Double, + //open val video: Boolean?, + open val voteAverage: Double ) { override fun equals(other: Any?): Boolean { @@ -27,7 +27,7 @@ open class Movie( if (adult != other.adult) return false if (overview != other.overview) return false if (releaseDate != other.releaseDate) return false - if (genreIds != other.genreIds) return false +// if (genreIds != other.genreIds) return false if (id != other.id) return false if (originalTitle != other.originalTitle) return false if (originalLanguage != other.originalLanguage) return false @@ -35,7 +35,6 @@ open class Movie( if (backdropPath != other.backdropPath) return false if (popularity != other.popularity) return false if (voteCount != other.voteCount) return false - if (video != other.video) return false if (voteAverage != other.voteAverage) return false return true @@ -46,7 +45,7 @@ open class Movie( result = 31 * result + adult.hashCode() result = 31 * result + overview.hashCode() result = 31 * result + releaseDate.hashCode() - result = 31 * result + genreIds.hashCode() +// result = 31 * result + genreIds.hashCode() result = 31 * result + id result = 31 * result + originalTitle.hashCode() result = 31 * result + originalLanguage.hashCode() @@ -54,7 +53,6 @@ open class Movie( result = 31 * result + (backdropPath?.hashCode() ?: 0) result = 31 * result + popularity.hashCode() result = 31 * result + voteCount - result = 31 * result + (video?.hashCode() ?: 0) result = 31 * result + voteAverage.hashCode() return result } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt index c70e337..ab5a9e2 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt @@ -10,7 +10,7 @@ data class MovieDetails( override val adult: Boolean, override val overview: String, override val releaseDate: String, - override val genreIds : List, +// override val genreIds : List, override val id: Int, override val originalTitle: String, override val originalLanguage: String, @@ -18,7 +18,7 @@ data class MovieDetails( override val backdropPath: String?, override val popularity: Double, override val voteCount: Int, - override val video: Boolean?, +// override val video: Boolean?, override val voteAverage: Double, val mediaType: String, @@ -35,7 +35,7 @@ data class MovieDetails( adult, overview, releaseDate, - genreIds, +// genreIds, id, originalTitle, originalLanguage, @@ -43,7 +43,7 @@ data class MovieDetails( backdropPath, popularity, voteCount, - video, +// video, voteAverage) { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt index 0b698dc..22a8bfd 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt @@ -9,7 +9,7 @@ open class TvShow( open val overview: String, open val firstAirDate: String?, open val originCountry: List, - open val genreIds: List, +// open val genreIds: List, open val originalLanguage: String, open val voteCount: Int, open val name: String, @@ -32,7 +32,7 @@ open class TvShow( if (overview != other.overview) return false if (firstAirDate != other.firstAirDate) return false if (originCountry != other.originCountry) return false - if (genreIds != other.genreIds) return false +// if (genreIds != other.genreIds) return false if (originalLanguage != other.originalLanguage) return false if (voteCount != other.voteCount) return false if (name != other.name) return false @@ -51,7 +51,7 @@ open class TvShow( result = 31 * result + overview.hashCode() result = 31 * result + (firstAirDate?.hashCode() ?: 0) result = 31 * result + originCountry.hashCode() - result = 31 * result + genreIds.hashCode() +// result = 31 * result + genreIds.hashCode() result = 31 * result + originalLanguage.hashCode() result = 31 * result + voteCount result = 31 * result + name.hashCode() diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt index 01e2e10..58ccf1d 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt @@ -7,11 +7,71 @@ import fr.iut.pm.movieapplication.utils.MediaResultMapper class TvShowRepository { - suspend fun getPopularTvShow(page : Int = 1 ) : List { + suspend fun getPopularTvShows(page : Int = 1 ) : List { val listMovie : MutableList = mutableListOf() - val response = RetrofitInstance.api.getPopularTvShow(page = page) + val response = RetrofitInstance.api.getPopularTvShows(page = page) + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + val tvShow = MediaResultMapper.mapToTvShow(it) + listMovie.add(tvShow) + Log.d("Movie ", tvShow.name ) + } + } + else Log.d("Error failure", response.message()) + + return listMovie + } + + suspend fun getAiringTodayTvShows(page : Int = 1 ) : List { + + val listMovie : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getAiringTodayTvShows(page = page) + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + val tvShow = MediaResultMapper.mapToTvShow(it) + listMovie.add(tvShow) + Log.d("Movie ", tvShow.name ) + } + } + else Log.d("Error failure", response.message()) + + return listMovie + } + + suspend fun getTvOnTheAirTvShows(page : Int = 1 ) : List { + + val listMovie : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getTvOnTheAirTvShows(page = page) + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + val tvShow = MediaResultMapper.mapToTvShow(it) + listMovie.add(tvShow) + Log.d("Movie ", tvShow.name ) + } + } + else Log.d("Error failure", response.message()) + + return listMovie + } + + suspend fun getTopRatedTvShows(page : Int = 1 ) : List { + + val listMovie : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getTopRatedTvShows(page = page) if (response.isSuccessful) { Log.d("List :", response.body().toString()) val popularDTO = response.body() diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt index 33b1c4b..383b73b 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt @@ -27,7 +27,16 @@ class TvShowVM : ViewModel() { currentPage = 1 when(currentFilter) { "Populaires" -> viewModelScope.launch { - tvShowLiveData.postValue(tvShowRepository.getPopularTvShow()) + tvShowLiveData.postValue(tvShowRepository.getPopularTvShows()) + } + "Diffusées aujourd\'hui" -> viewModelScope.launch { + tvShowLiveData.postValue(tvShowRepository.getAiringTodayTvShows()) + } + "En cours de diffusion" -> viewModelScope.launch { + tvShowLiveData.postValue(tvShowRepository.getTvOnTheAirTvShows()) + } + "Les mieux notées" -> viewModelScope.launch { + tvShowLiveData.postValue(tvShowRepository.getTopRatedTvShows()) } } } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt index 0b58a33..0b8bd7f 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -14,10 +14,10 @@ object MediaResultMapper { id = mediaResultDTO.id, backdropPath = mediaResultDTO.backdropPath ?: "", voteAverage = mediaResultDTO.voteAverage, - overview = mediaResultDTO.overview, + overview = mediaResultDTO.overview ?: "", firstAirDate = mediaResultDTO.firstAirDate, originCountry = mediaResultDTO.originCountry!!, - genreIds = mediaResultDTO.genreIds, +// genreIds = mediaResultDTO.genreIds, originalLanguage = mediaResultDTO.originalLanguage, voteCount = mediaResultDTO.voteCount, name = mediaResultDTO.name!!, @@ -29,9 +29,9 @@ object MediaResultMapper { return Movie( posterPath = mediaResultDTO.posterPath, adult = mediaResultDTO.adult!!, - overview = mediaResultDTO.overview, + overview = mediaResultDTO.overview ?: "", releaseDate = mediaResultDTO.releaseDate ?: "", - genreIds = mediaResultDTO.genreIds, +// genreIds = mediaResultDTO.genreIds, id = mediaResultDTO.id, originalTitle = mediaResultDTO.originalTitle!!, originalLanguage = mediaResultDTO.originalLanguage, @@ -39,7 +39,7 @@ object MediaResultMapper { backdropPath = mediaResultDTO.backdropPath, popularity = mediaResultDTO.popularity, voteCount = mediaResultDTO.voteCount, - video = mediaResultDTO.video, + //video = mediaResultDTO.video, voteAverage = mediaResultDTO.voteAverage ) } @@ -48,10 +48,10 @@ object MediaResultMapper { return MediaResult( posterPath = mediaResultDTO.posterPath, adult = mediaResultDTO.adult!!, - overview = mediaResultDTO.overview, + overview = mediaResultDTO.overview ?: "", releaseDate = mediaResultDTO.releaseDate ?: mediaResultDTO.firstAirDate!! , originCountry = mediaResultDTO.originCountry, - genreIds = mediaResultDTO.genreIds, +// genreIds = mediaResultDTO.genreIds, id = mediaResultDTO.id, originalTitle = mediaResultDTO.originalTitle ?: mediaResultDTO.originalName!!, //if it's not a movie also it's a tvshow originalLanguage = mediaResultDTO.originalLanguage, diff --git a/Sources/app/src/main/res/values/arrays.xml b/Sources/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..a6b3dae --- /dev/null +++ b/Sources/app/src/main/res/values/arrays.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Sources/app/src/main/res/values/strings.xml b/Sources/app/src/main/res/values/strings.xml index 79bb1d8..c8587f9 100644 --- a/Sources/app/src/main/res/values/strings.xml +++ b/Sources/app/src/main/res/values/strings.xml @@ -13,7 +13,9 @@ Populaires Gratuits section_nested_scroll_view - + + + Populaires From 797ce00665acfb53cb2aaed80b49e856e034b837 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Tue, 7 Feb 2023 02:00:50 +0100 Subject: [PATCH 8/9] :construction: some requests implemented need to had coroutines now to improve perf --- .../api/MovieApplicationAPI.kt | 2 +- .../api/dtos/MediaResultDTO.kt | 4 +- .../pm/movieapplication/api/dtos/MovieDTO.kt | 5 +- .../api/dtos/MovieDetailsDTO.kt | 71 ++++++-------- .../fr/iut/pm/movieapplication/model/Genre.kt | 13 +-- .../model/media/movie/Movie.kt | 12 +-- .../model/media/movie/MovieDetails.kt | 74 ++++++--------- .../repository/MovieRepository.kt | 42 +++++++-- .../ui/activity/MainActivity.kt | 2 - .../ui/adapter/MovieAdapter.kt | 14 ++- .../movieapplication/ui/dialog/MovieDialog.kt | 42 +++++++++ .../ui/fragments/MoviesFragment.kt | 20 +++- .../ui/viewmodel/MoviesDialogVM.kt | 29 ++++++ .../movieapplication/ui/viewmodel/MoviesVM.kt | 3 +- .../utils/MediaResultMapper.kt | 35 +++++++ .../pm/movieapplication/utils/MovieMapper.kt | 48 ++++++++++ .../app/src/main/res/drawable/ic_close.xml | 5 + .../src/main/res/layout/fragment_movies.xml | 1 - .../app/src/main/res/layout/movie_dialog.xml | 94 +++++++++++++++++++ 19 files changed, 383 insertions(+), 133 deletions(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/dialog/MovieDialog.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesDialogVM.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MovieMapper.kt create mode 100644 Sources/app/src/main/res/drawable/ic_close.xml create mode 100644 Sources/app/src/main/res/layout/movie_dialog.xml diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt index a8d2bd0..8617fdd 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/MovieApplicationAPI.kt @@ -27,7 +27,7 @@ interface MovieApplicationAPI { // Movie details @GET("movie/{movie_id}") - fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Response + suspend fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Response // TvShow diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt index a56948c..d5348c1 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MediaResultDTO.kt @@ -20,10 +20,10 @@ open class MediaResultDTO( // val genreIds : List, val id : Int, @Json(name = "original_title") - val originalTitle : String? = null, + val originalTitle : String = "", @Json(name = "original_language") val originalLanguage : String, - val title : String?, + val title : String = "", @Json(name = "backdrop_path") val backdropPath : String?, val popularity : Double, diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt index 73f4017..d7cf509 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt @@ -6,11 +6,9 @@ open class MovieDTO ( @Json(name = "poster_path") open val posterPath: String?, open val adult: Boolean, - open val overview: String, + open val overview: String?, @Json(name = "release_date") open val releaseDate: String, - @Json(name = "genre_ids") - open val genreIds: List, open val id: Int, @Json(name = "original_title") open val originalTitle: String, @@ -22,7 +20,6 @@ open class MovieDTO ( open val popularity: Double, @Json(name = "vote_count") open val voteCount: Int, - open val video : Boolean, @Json(name = "vote_average") open val voteAverage: Double diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt index 4fc1dae..99dfb48 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt @@ -1,48 +1,37 @@ package fr.iut.pm.movieapplication.api.dtos +import com.squareup.moshi.Json import fr.iut.pm.movieapplication.model.Genre -class MovieDetailsDTO( - - adult : Boolean?, - backdropPath : String?, - val budget : Int, - val genres : List, - val homepage : String?, - id : Int, - originalLanguage : String, - originalTitle : String, - overview : String?, - popularity : Double, - posterPath : String?, +data class MovieDetailsDTO( + + val adult: Boolean, + @Json(name = "backdrop_path") + val backdropPath: String?, + val budget: Int, + val genres: List, + val homepage: String?, + val id: Int, + @Json(name = "original_language") + val originalLanguage: String, + @Json(name = "original_title") + val originalTitle: String, + val overview: String?, + val popularity: Double, + @Json(name = "poster_path") + val posterPath: String?, //prod companies //prod countries - releaseDate : String?, - val revenue : Int, + @Json(name = "release_date") + val releaseDate: String, + val revenue: Int, //spoken language - val status : String, - title : String, - voteAverage : Double, - voteCount : Int - - - -) : MediaResultDTO( - adult = adult, - backdropPath = backdropPath, - id = id, - originalLanguage = originalLanguage, - originalTitle = originalTitle, - overview = overview, - popularity = popularity, - posterPath = posterPath, - releaseDate = releaseDate, - title = title, - voteAverage = voteAverage, - voteCount = voteCount, -) { - - - - -} \ No newline at end of file + val status: String, + val title: String, + @Json(name = "vote_average") + val voteAverage: Double, + @Json(name = "vote_count") + val voteCount: Int + +) +{} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Genre.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Genre.kt index 62c322d..f0a8111 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Genre.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Genre.kt @@ -1,16 +1,7 @@ package fr.iut.pm.movieapplication.model - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "genre_table") data class Genre( - @PrimaryKey - @ColumnInfo(name = "id") - var id : Int, - @ColumnInfo(name = "name") - var name : String + val id : Int, + val name : String ) { override fun equals(other: Any?): Boolean { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt index ad61088..c03daae 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt @@ -2,18 +2,16 @@ package fr.iut.pm.movieapplication.model.media.movie open class Movie( open val posterPath: String?, - open val adult: Boolean, - open val overview: String, - open val releaseDate: String, -// open val genreIds: List, + open val adult: Boolean?, + open val overview: String?, + open val releaseDate: String?, open val id: Int, open val originalTitle: String, open val originalLanguage: String, - open val title: String?, + open val title: String, open val backdropPath: String?, open val popularity: Double, open val voteCount: Int, - //open val video: Boolean?, open val voteAverage: Double ) { @@ -27,7 +25,6 @@ open class Movie( if (adult != other.adult) return false if (overview != other.overview) return false if (releaseDate != other.releaseDate) return false -// if (genreIds != other.genreIds) return false if (id != other.id) return false if (originalTitle != other.originalTitle) return false if (originalLanguage != other.originalLanguage) return false @@ -45,7 +42,6 @@ open class Movie( result = 31 * result + adult.hashCode() result = 31 * result + overview.hashCode() result = 31 * result + releaseDate.hashCode() -// result = 31 * result + genreIds.hashCode() result = 31 * result + id result = 31 * result + originalTitle.hashCode() result = 31 * result + originalLanguage.hashCode() diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt index ab5a9e2..a9c63d9 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt @@ -1,50 +1,34 @@ package fr.iut.pm.movieapplication.model.media.movie -import fr.iut.pm.movieapplication.model.ProductionCompany -import fr.iut.pm.movieapplication.model.ProductionCountry - - -data class MovieDetails( - - override val posterPath: String, - override val adult: Boolean, - override val overview: String, - override val releaseDate: String, -// override val genreIds : List, - override val id: Int, - override val originalTitle: String, - override val originalLanguage: String, - override val title: String?, - override val backdropPath: String?, - override val popularity: Double, - override val voteCount: Int, -// override val video: Boolean?, - override val voteAverage: Double, - val mediaType: String, - - val budget: Int?, - val homePage: String?, - val productionCompanies: Array?, - val productionCountries: Array?, - val revenue: Int?, - val runtime: Int?, - val status: String?, - val tagLine: String? - -) : Movie(posterPath, - adult, - overview, - releaseDate, -// genreIds, - id, - originalTitle, - originalLanguage, - title, - backdropPath, - popularity, - voteCount, -// video, - voteAverage) { +import fr.iut.pm.movieapplication.model.Genre + + +class MovieDetails( + + adult : Boolean?, + backdropPath : String?, + val budget : Int, + val genres : List, + val homepage : String?, + id : Int, + originalLanguage : String, + originalTitle : String, + overview : String?, + popularity : Double, + posterPath : String?, + //prod companies + //prod countries + releaseDate : String?, + val revenue : Int, + //spoken language + val status : String, + title : String, + voteAverage : Double, + voteCount : Int + +) : Movie(posterPath, adult, overview, releaseDate, id, originalTitle, originalLanguage, + title, backdropPath, popularity, voteCount, voteAverage) +{ } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt index 4e471ae..a42cbd3 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -2,12 +2,16 @@ package fr.iut.pm.movieapplication.repository import android.util.Log import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.api.dtos.MovieDetailsDTO import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.utils.MediaResultMapper +import fr.iut.pm.movieapplication.utils.MovieMapper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext class MovieRepository { - - suspend fun getPopularMovies(page : Int = 1) : List + suspend fun getPopularMovies(page : Int = 1) : List = withContext(Dispatchers.IO) { val listMovie : MutableList = mutableListOf() @@ -18,14 +22,14 @@ class MovieRepository { listMediaResultDTO?.forEach { val movie = MediaResultMapper.mapToMovie(it) listMovie.add(movie) - Log.d("Movie ", movie.title!!) + Log.d("Movie ", movie.title!! + " " + movie.id) } } else Log.d("ERROR FAILED", response.message()) - return listMovie + listMovie } - suspend fun getNowPlayingMovies(page : Int = 1) : List + suspend fun getNowPlayingMovies(page : Int = 1) : List = withContext(Dispatchers.IO) { val listMovie : MutableList = mutableListOf() @@ -40,10 +44,10 @@ class MovieRepository { } } else Log.d("ERROR FAILED", response.message()) - return listMovie + listMovie } - suspend fun getUpcomingMovies(page : Int = 1) : List + suspend fun getUpcomingMovies(page : Int = 1) : List = withContext(Dispatchers.IO) { val listMovie : MutableList = mutableListOf() @@ -58,10 +62,10 @@ class MovieRepository { } } else Log.d("ERROR FAILED", response.message()) - return listMovie + listMovie } - suspend fun getTopRatedMovies(page : Int = 1) : List + suspend fun getTopRatedMovies(page : Int = 1) : List = withContext(Dispatchers.IO) { val listMovie : MutableList = mutableListOf() @@ -76,7 +80,25 @@ class MovieRepository { } } else Log.d("ERROR FAILED", response.message()) - return listMovie + listMovie + } + + suspend fun getMovieDetails(id : Int) : MovieDetails? + { + var movieDetails : MovieDetails? = null + + val response = RetrofitInstance.api.getMovieDetails(id) + if(response.isSuccessful && response.body() != null) { + + Log.d("SUCCESS", response.body().toString()) + movieDetails = MovieMapper.mapToMovieDetails(response.body()!!) + Log.d("Movie details",movieDetails.toString()) + } + else Log.d("ERROR FAILED", response.toString()) + + + + return movieDetails } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index b27c2aa..fa38ab8 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt @@ -65,12 +65,10 @@ class MainActivity : AppCompatActivity() { searchView.setOnQueryTextListener( object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { - TODO("Not yet implemented") return false } override fun onQueryTextChange(newText: String?): Boolean { - TODO("Not yet implemented") return false } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt index 24eed09..2c8da88 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -9,22 +9,25 @@ import androidx.recyclerview.widget.RecyclerView import coil.load import fr.iut.pm.movieapplication.databinding.ItemMovieCategoryBinding import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.ui.dialog.MovieDialog import fr.iut.pm.movieapplication.utils.Constants -class MovieAdapter() : ListAdapter(DiffUtilMovieCallback) { +class MovieAdapter(private val listener : MovieSelection) : ListAdapter(DiffUtilMovieCallback) { private object DiffUtilMovieCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: Movie, newItem: Movie) = oldItem.id == newItem.id override fun areContentsTheSame(oldItem: Movie, newItem: Movie) = oldItem == newItem } - class ViewHolder(private val binding : ItemMovieCategoryBinding) : + class ViewHolder(private val binding : ItemMovieCategoryBinding, listener: MovieSelection) : RecyclerView.ViewHolder(binding.root) { val movie : Movie? get() = binding.movie init { - itemView.setOnClickListener {} + itemView.setOnClickListener { + listener.onMovieSelected(movie?.id ?: 0) + } } fun bind(movie : Movie) { @@ -37,8 +40,11 @@ class MovieAdapter() : ListAdapter(DiffUtilMovie } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = - ViewHolder(ItemMovieCategoryBinding.inflate(LayoutInflater.from(parent.context))) + ViewHolder(ItemMovieCategoryBinding.inflate(LayoutInflater.from(parent.context, )), listener) override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(getItem(position)) + interface MovieSelection { + fun onMovieSelected(movieId : Int) + } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/dialog/MovieDialog.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/dialog/MovieDialog.kt new file mode 100644 index 0000000..5847821 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/dialog/MovieDialog.kt @@ -0,0 +1,42 @@ +package fr.iut.pm.movieapplication.ui.dialog + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.net.toUri +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.viewModels +import coil.load +import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.databinding.MovieDialogBinding +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesDialogVM +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesDialogVMFactory +import fr.iut.pm.movieapplication.utils.Constants + +class MovieDialog : DialogFragment() { + + val moviesDialogVM by viewModels { MoviesDialogVMFactory(arguments?.getInt("movieId") ?: 0) } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val binding = MovieDialogBinding.inflate(inflater) + binding.lifecycleOwner = viewLifecycleOwner + binding.closeItem.setOnClickListener { dismiss() } + moviesDialogVM.getMovieDetailLiveData().observe(viewLifecycleOwner) { + binding.movieDetails = it + binding.detailsImage.load(it.posterPath?.let { it -> + (Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build() + }) + } + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index c0326ac..cf2181f 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt @@ -10,13 +10,15 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.databinding.FragmentMoviesBinding +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.ui.dialog.MovieDialog import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM class MoviesFragment( -) : Fragment() { +) : Fragment(), MovieAdapter.MovieSelection { private val moviesVM by viewModels() - + val moviesAdapter = MovieAdapter(this) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -25,6 +27,10 @@ class MoviesFragment( binding.moviesVM = moviesVM binding.lifecycleOwner = viewLifecycleOwner + with(binding.moviesItemRecyclerView) { + adapter = moviesAdapter + } + val adapter = ArrayAdapter.createFromResource( requireContext(), R.array.movie_filter, @@ -58,7 +64,15 @@ class MoviesFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) moviesVM.getMoviesLiveData().observe(viewLifecycleOwner) { - moviesVM.moviesAdapter.submitList(it) + moviesAdapter.submitList(it) } } + + override fun onMovieSelected(movieId: Int) { + val dialog = MovieDialog() + val args = Bundle() + args.putInt("movieId",movieId) + dialog.arguments = args + dialog.show(parentFragmentManager, "tag") + } } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesDialogVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesDialogVM.kt new file mode 100644 index 0000000..b39350f --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesDialogVM.kt @@ -0,0 +1,29 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.* +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails +import fr.iut.pm.movieapplication.repository.MovieRepository +import kotlinx.coroutines.launch + +class MoviesDialogVM(private val movieId : Int) : ViewModel() { + + private val repository = MovieRepository() + + private var _movieDetailsLiveData : MutableLiveData = MutableLiveData() + fun getMovieDetailLiveData() : LiveData = _movieDetailsLiveData + + init { + viewModelScope.launch { + if(movieId != 0) _movieDetailsLiveData.postValue(repository.getMovieDetails(movieId)) + } + } + +} + +class MoviesDialogVMFactory(private val movieId : Int) : ViewModelProvider.Factory +{ + override funcreate(modelClass:Class) : T + { + return MoviesDialogVM(movieId) as T + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt index 69cf7cd..8c6da20 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -34,7 +34,7 @@ class MoviesVM() : ViewModel() { /** * The adapter of the RecyclerView (set on the RecyclerView in the view) */ - val moviesAdapter = MovieAdapter() + val scrollListener = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { @@ -66,6 +66,7 @@ class MoviesVM() : ViewModel() { when(currentFilter) { "Populaires" -> viewModelScope.launch { _moviesLiveData.postValue(repository.getPopularMovies()) + repository.getMovieDetails(315162) } "Du moment" -> viewModelScope.launch { _moviesLiveData.postValue(repository.getNowPlayingMovies()) diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt index 0b8bd7f..02b8f6c 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -1,8 +1,12 @@ package fr.iut.pm.movieapplication.utils +import fr.iut.pm.movieapplication.api.dtos.GenreDTO import fr.iut.pm.movieapplication.api.dtos.MediaResultDTO +import fr.iut.pm.movieapplication.api.dtos.MovieDetailsDTO +import fr.iut.pm.movieapplication.model.Genre import fr.iut.pm.movieapplication.model.media.MediaResult import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.model.media.tvshow.TvShow object MediaResultMapper { @@ -64,5 +68,36 @@ object MediaResultMapper { ) } + fun mapToMovieDetails(movieDetailsDTO: MovieDetailsDTO?): MovieDetails? { + if(movieDetailsDTO == null) return null + return MovieDetails( + posterPath = movieDetailsDTO.posterPath, + adult = movieDetailsDTO.adult!!, + overview = movieDetailsDTO.overview ?: "", + releaseDate = movieDetailsDTO.releaseDate ?: "", + id = movieDetailsDTO.id, + originalTitle = movieDetailsDTO.originalTitle!!, + originalLanguage = movieDetailsDTO.originalLanguage, + title = movieDetailsDTO.title, + backdropPath = movieDetailsDTO.backdropPath, + popularity = movieDetailsDTO.popularity, + voteCount = movieDetailsDTO.voteCount, + voteAverage = movieDetailsDTO.voteAverage, + budget = movieDetailsDTO.budget, + genres = movieDetailsDTO.genres.map { mapGenreDTOToGenre(it) }, + homepage = movieDetailsDTO.homepage, + revenue = movieDetailsDTO.revenue, + status = movieDetailsDTO.status + ) + + } + + fun mapGenreDTOToGenre(genreDTO : GenreDTO) : Genre { + return Genre( + name = genreDTO.name, + id = genreDTO.id + ) + } + } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MovieMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MovieMapper.kt new file mode 100644 index 0000000..0801222 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MovieMapper.kt @@ -0,0 +1,48 @@ +package fr.iut.pm.movieapplication.utils + +import fr.iut.pm.movieapplication.api.dtos.MovieDTO +import fr.iut.pm.movieapplication.api.dtos.MovieDetailsDTO +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails + +object MovieMapper { + + fun mapToMovie(movieDTO : MovieDTO) : Movie { + return Movie( + posterPath = movieDTO.posterPath, + adult = movieDTO.adult, + overview = movieDTO.overview, + releaseDate = movieDTO.releaseDate, + id = movieDTO.id, + originalTitle = movieDTO.originalTitle, + originalLanguage = movieDTO.originalLanguage, + title = movieDTO.title, + backdropPath = movieDTO.backdropPath, + popularity = movieDTO.popularity, + voteCount = movieDTO.voteCount, + voteAverage = movieDTO.voteAverage + ) + } + + fun mapToMovieDetails(movieDetailsDTO: MovieDetailsDTO ) : MovieDetails { + return MovieDetails( + posterPath = movieDetailsDTO.posterPath, + adult = movieDetailsDTO.adult!!, + overview = movieDetailsDTO.overview ?: "", + releaseDate = movieDetailsDTO.releaseDate ?: "", + id = movieDetailsDTO.id, + originalTitle = movieDetailsDTO.originalTitle, + originalLanguage = movieDetailsDTO.originalLanguage, + title = movieDetailsDTO.title, + backdropPath = movieDetailsDTO.backdropPath, + popularity = movieDetailsDTO.popularity, + voteCount = movieDetailsDTO.voteCount, + voteAverage = movieDetailsDTO.voteAverage, + budget = movieDetailsDTO.budget, + genres = movieDetailsDTO.genres.map { MediaResultMapper.mapGenreDTOToGenre(it) }, + homepage = movieDetailsDTO.homepage, + revenue = movieDetailsDTO.revenue, + status = movieDetailsDTO.status + ) + } +} \ No newline at end of file diff --git a/Sources/app/src/main/res/drawable/ic_close.xml b/Sources/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000..844b6b6 --- /dev/null +++ b/Sources/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,5 @@ + + + diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index 7016eed..85d6b50 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -45,7 +45,6 @@ android:layout_marginBottom="@dimen/default_margin" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:spanCount="3" - android:adapter="@{moviesVM.moviesAdapter}" app:onScrollListener = "@{moviesVM.scrollListener}" tools:listitem="@layout/item_movie_category" diff --git a/Sources/app/src/main/res/layout/movie_dialog.xml b/Sources/app/src/main/res/layout/movie_dialog.xml new file mode 100644 index 0000000..f487839 --- /dev/null +++ b/Sources/app/src/main/res/layout/movie_dialog.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + +