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 cd84a60..e08f7f5 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,22 +1,51 @@ package fr.iut.pm.movieapplication.api -import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO +import fr.iut.pm.movieapplication.api.dtos.MovieDTO +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 +import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query interface MovieApplicationAPI { + // Movie @GET("movie/popular") - fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY) : Call + suspend fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + + @GET("movie/now_playing") + suspend fun getNowPlayingMovies(@Query("api_key") apiKey : String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + + @GET("movie/upcoming") + suspend fun getUpcomingMovies(@Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + + @GET("movie/top_rated") + suspend fun getTopRatedMovies(@Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + + // Movie details + @GET("movie/{movie_id}") + suspend fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr") : Response + + + // TvShow + @GET("tv/popular") + suspend fun getPopularTvShows(@Query("api_key") apiKey : String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + @GET("tv/airing_today") + suspend fun getAiringTodayTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + @GET("tv/on_the_air") + suspend fun getTvOnTheAirTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr", @Query("page") page : Int = 1) : Response + @GET("tv/top_rated") + suspend fun getTopRatedTvShows(@Query("api_key") apiKey: String = API_KEY, @Query("language") language : String = "fr", @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 + suspend fun getTrending(@Path("media_type") mediaType : String = "all", @Path("time_window") timeWindow : String = "day", @Query("api_key") apiKey: String = API_KEY ) : Response + - @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) } \ No newline at end of file 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 new file mode 100644 index 0000000..2f1029f --- /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") +open class MediaResultDTO( + + @Json(name = "poster_path") + val posterPath : String?, + val adult : Boolean?, + val overview : String? = null, + @Json(name = "first_air_date") + val firstAirDate : String? = null, + @Json(name = "release_date") + val releaseDate : String? = null, + @Json(name = "origin_country") + val originCountry : List? = null, +// @Json(name = "genre_ids") +// val genreIds : List, + val id : Int, + @Json(name = "original_title") + val originalTitle : String? = null, + @Json(name = "original_language") + val originalLanguage : String, + val title : String? = null, + @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? = null, + @Json(name = "original_name") + val originalName : String? = null, + @Json(name = "media_type") + val mediaType : String? = null +) { + +} \ 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..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 @@ -1,44 +1,29 @@ 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, + 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, + @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/MovieDetailsDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt new file mode 100644 index 0000000..99dfb48 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDetailsDTO.kt @@ -0,0 +1,37 @@ +package fr.iut.pm.movieapplication.api.dtos + +import com.squareup.moshi.Json +import fr.iut.pm.movieapplication.model.Genre + +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 + @Json(name = "release_date") + val releaseDate: String, + val revenue: Int, + //spoken language + 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/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/TvShowDetailsDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDetailsDTO.kt new file mode 100644 index 0000000..bdee72e --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/TvShowDetailsDTO.kt @@ -0,0 +1,30 @@ +package fr.iut.pm.movieapplication.api.dtos + +import com.squareup.moshi.Json + +open class TvShowDetailsDTO( + + @Json(name = "poster_path") + open val posterPath: String?, + open val popularity: Double, + open val id: Int, + @Json(name = "backdrop_path") + 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/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/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..ef3a9a2 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/MediaResult.kt @@ -0,0 +1,21 @@ +package fr.iut.pm.movieapplication.model.media + +data class MediaResult( + + val posterPath: String? = null, + val adult: Boolean?, + val overview: String, + val releaseDate: String, + val originCountry: List? = null, +// val genreIds: List, + val id: Int, + val originalTitle: String, + val originalLanguage: String, + val title: String, + val backdropPath: String? = null, + val popularity: Double, + val voteCount: Int, + val voteAverage: Double, + 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..c03daae --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/Movie.kt @@ -0,0 +1,55 @@ +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 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 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 (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 (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 + 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 + voteAverage.hashCode() + return result + } +} \ 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..a9c63d9 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/movie/MovieDetails.kt @@ -0,0 +1,34 @@ +package fr.iut.pm.movieapplication.model.media.movie + +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/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..22a8bfd --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/media/tvshow/TvShow.kt @@ -0,0 +1,62 @@ +package fr.iut.pm.movieapplication.model.media.tvshow + +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/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/MediaRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt new file mode 100644 index 0000000..2b9b632 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MediaRepository.kt @@ -0,0 +1,71 @@ +package fr.iut.pm.movieapplication.repository + +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.utils.MediaResultMapper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class MediaRepository { + + suspend fun getTrends() : List = withContext(Dispatchers.IO) { + val listMediaResult : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getTrending() + if(response.isSuccessful) { + + val listMediaResultDTO = response.body()?.results + Log.d("Response",response.body().toString()) + listMediaResultDTO?.forEach { + + val mediaResult = MediaResultMapper.mapToMediaResult(it) + listMediaResult.add(mediaResult) + mediaResult.title?.let { it1 -> Log.d("Movie", it1) } + + } + } + else Log.d("ERROR FAILED", response.message()) + listMediaResult + } + + suspend fun getPopularMovies() : List = withContext(Dispatchers.IO) { + val listMediaResult : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getPopularMovies() + if(response.isSuccessful) { + + val listMediaResultDTO = response.body()?.results + Log.d("Response",response.body().toString()) + listMediaResultDTO?.forEach { + + val mediaResult = MediaResultMapper.mapToMediaResult(it) + listMediaResult.add(mediaResult) + mediaResult.title?.let { it1 -> Log.d("Movie", it1) } + + } + } + else Log.d("ERROR FAILED", response.message()) + listMediaResult + } + + suspend fun getPopularTvShows(): List = withContext(Dispatchers.IO) { + val listMediaResult : MutableList = mutableListOf() + + val response = RetrofitInstance.api.getPopularTvShows() + if(response.isSuccessful) { + + val listMediaResultDTO = response.body()?.results + Log.d("Response",response.body().toString()) + listMediaResultDTO?.forEach { + + val mediaResult = MediaResultMapper.mapToMediaResult(it) + listMediaResult.add(mediaResult) + mediaResult.title?.let { it1 -> Log.d("Movie", it1) } + + } + } + else Log.d("ERROR FAILED", response.message()) + listMediaResult + } +} \ 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..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,65 +2,104 @@ 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 retrofit2.Call -import retrofit2.Callback -import retrofit2.Response +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() { - - fun getPopularMovies(callback: (List) -> Unit ) { +class MovieRepository { + suspend fun getPopularMovies(page : Int = 1) : List = withContext(Dispatchers.IO) + { val listMovie : MutableList = mutableListOf() - RetrofitInstance.api.getPopularMovies().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 = Mapper.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!! + " " + movie.id) } + } + else Log.d("ERROR FAILED", response.message()) + listMovie + } - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) - } + suspend fun getNowPlayingMovies(page : Int = 1) : List = withContext(Dispatchers.IO) + { + + val listMovie : MutableList = mutableListOf() - }) + 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!!) + } + } + else Log.d("ERROR FAILED", response.message()) + listMovie } - fun getTrends(callback: (List) -> Unit) { + suspend fun getUpcomingMovies(page : Int = 1) : List = withContext(Dispatchers.IO) + { + 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 = Mapper.MapToMovie(it) - listMovie.add(movie) - movie.title?.let { it1 -> Log.d("Movie", it1) } - } - } - 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!!) } + } + else Log.d("ERROR FAILED", response.message()) + listMovie + } + + suspend fun getTopRatedMovies(page : Int = 1) : List = withContext(Dispatchers.IO) + { + + val listMovie : MutableList = mutableListOf() - override fun onFailure(call: Call, t: Throwable) { - Log.d("Error failure", t.message.toString()) + 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!!) } - }) + } + else Log.d("ERROR FAILED", response.message()) + 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 } + + } \ 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..58ccf1d --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/TvShowRepository.kt @@ -0,0 +1,89 @@ +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 getPopularTvShows(page : Int = 1 ) : List { + + val listMovie : MutableList = mutableListOf() + + 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() + 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 558a3c5..d741285 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,27 +5,18 @@ 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() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -42,31 +33,17 @@ class MainActivity : AppCompatActivity() { } R.id.movies_page -> { - loadFragments(MoviesFragment(this)) + loadFragments(MoviesFragment()) return@setOnItemSelectedListener true } R.id.series_page -> { - loadFragments(ShowsFragment(this)) + loadFragments(TvShowsFragment()) return@setOnItemSelectedListener true } 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 - // Remember that you should never show the action bar if the - // status bar is hidden, so hide that too if necessary. - actionBar?.hide() - } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -78,12 +55,13 @@ class MainActivity : AppCompatActivity() { searchView.setOnQueryTextListener( object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { - TODO("Not yet implemented") - return false + if(!query.isNullOrEmpty()) { + + } + return true; } 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/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/HomeItemAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt deleted file mode 100644 index 20acfe9..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt +++ /dev/null @@ -1,52 +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.api.config.GlobalImageConfig -import fr.iut.pm.movieapplication.model.Movie -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 - ) : 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): ViewHolder { - val view = LayoutInflater - .from(parent.context) - .inflate(layoutId, parent, false) - return ViewHolder(view) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val currentItem = list[position] - 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 - - } - - override fun getItemCount(): Int = list.size -} \ 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 new file mode 100644 index 0000000..ec130b5 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MediaAdapter.kt @@ -0,0 +1,40 @@ +package fr.iut.pm.movieapplication.ui.adapter + +import android.util.Log +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.ItemHorizontalHomePageBinding +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.ui.interfaces.MovieSelection +import fr.iut.pm.movieapplication.utils.Constants + +class MediaAdapter(private val listener : MovieSelection): ListAdapter(DiffUtilMediaCallback) { + + private object DiffUtilMediaCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: MediaResult, newItem: MediaResult) = oldItem.id == newItem.id + override fun areContentsTheSame(oldItem: MediaResult, newItem: MediaResult) = oldItem == newItem + } + + class ViewHolder(private val binding : ItemHorizontalHomePageBinding, listener: MovieSelection) + : RecyclerView.ViewHolder(binding.root) { + + val mediaResult : MediaResult? get() = binding.mediaResult + + fun bind(mediaResult : MediaResult) { + binding.mediaResult = mediaResult + val imgUri = mediaResult.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(ItemHorizontalHomePageBinding.inflate(LayoutInflater.from(parent.context)), listener) + 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/MovieAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt new file mode 100644 index 0000000..20d7e3f --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/MovieAdapter.kt @@ -0,0 +1,45 @@ +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.ItemMovieCategoryBinding +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.ui.dialog.MovieDialog +import fr.iut.pm.movieapplication.ui.interfaces.MovieSelection +import fr.iut.pm.movieapplication.utils.Constants + +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, listener: MovieSelection) : + RecyclerView.ViewHolder(binding.root) { + + val movie : Movie? get() = binding.movie + + init { + itemView.setOnClickListener { + listener.onMovieSelected(movie?.id ?: 0) + } + } + 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)), listener) + 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/SearchResultAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/SearchResultAdapter.kt new file mode 100644 index 0000000..81c2d51 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/SearchResultAdapter.kt @@ -0,0 +1,4 @@ +package fr.iut.pm.movieapplication.ui.adapter + +class SearchResultAdapter { +} \ 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/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/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index d321a90..a93adcb 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 @@ -5,41 +5,70 @@ import android.view.LayoutInflater import android.view.View 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 androidx.fragment.app.viewModels +import fr.iut.pm.movieapplication.databinding.FragmentHomeSectionsBinding 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.interfaces.MovieSelection import fr.iut.pm.movieapplication.ui.viewmodel.HomeSectionsVM class HomeSectionsFragment( private val context : MainActivity - ) : Fragment() { + ) : Fragment(), MovieSelection { - private lateinit var homeSectionsViewModel : HomeSectionsVM + private val homeSectionsVM by viewModels() - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_home_sections, container, false) + private val trendsAdapter = MediaAdapter(this) + private val popularMoviesAdapter = MediaAdapter(this) + private val popularTvShowsAdapter = MediaAdapter(this) - //get the trends RecyclerView - context.movieRepository.getTrends { - val homeTrendsRecyclerView = view?.findViewById(R.id.home_trends_recycler_view) - homeTrendsRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,it) - homeTrendsRecyclerView?.addItemDecoration(HomeItemDecoration()) + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?) + : View? { + + val binding = FragmentHomeSectionsBinding.inflate(inflater) + binding.homeSectionsVM = homeSectionsVM + binding.lifecycleOwner = viewLifecycleOwner + + with(binding.homeTrendsRecyclerView) { + adapter = trendsAdapter + addItemDecoration(HomeItemDecoration()) } - //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?.addItemDecoration(HomeItemDecoration()) + with(binding.homePopularMoviesRecyclerView) { + adapter = popularMoviesAdapter + 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?.addItemDecoration(HomeItemDecoration()) - return view + + with(binding.homePopularTvShowsRecyclerView) { + adapter = popularTvShowsAdapter + addItemDecoration(HomeItemDecoration()) + } + + + return binding.root + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + homeSectionsVM.getTrendsLiveData().observe(viewLifecycleOwner) { + trendsAdapter.submitList(it) + } + + homeSectionsVM.getPopularMoviesLiveData().observe(viewLifecycleOwner) { + popularMoviesAdapter.submitList(it) + } + + homeSectionsVM.getPopularTvShowsLiveData().observe(viewLifecycleOwner) { + popularTvShowsAdapter.submitList(it) + } + } + + override fun onMovieSelected(movieId: Int) { + TODO("Not yet implemented") } } \ 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 3623498..150badd 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,39 +4,76 @@ 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 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.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.databinding.FragmentMoviesBinding +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.ui.dialog.MovieDialog +import fr.iut.pm.movieapplication.ui.interfaces.MovieSelection 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 class MoviesFragment( - private val context : MainActivity -) : Fragment() { - - private val moviesVM: MoviesVM by viewModels{ MoviesVMFactory(repository = MovieRepository())} - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_movies, container, false) - - 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()) +) : Fragment(), MovieSelection { + + private val moviesVM by viewModels() + val moviesAdapter = MovieAdapter(this) + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = FragmentMoviesBinding.inflate(inflater) + binding.moviesVM = moviesVM + binding.lifecycleOwner = viewLifecycleOwner + + with(binding.moviesItemRecyclerView) { + adapter = moviesAdapter + } + + 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.categoryMovieSpinner) + { + 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<*>?) { + TODO("Not yet implemented") + } + + } + } + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + moviesVM.getMoviesLiveData().observe(viewLifecycleOwner) { + moviesAdapter.submitList(it) } + } - return view + override fun onMovieSelected(movieId: Int) { + val dialog = MovieDialog() + val args = Bundle() + args.putInt("movieId",movieId) + dialog.arguments = args + dialog.show(parentFragmentManager, "tag") } -} \ No newline at end of file +} diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/SearchResultFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/SearchResultFragment.kt new file mode 100644 index 0000000..2040680 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/SearchResultFragment.kt @@ -0,0 +1,23 @@ +package fr.iut.pm.movieapplication.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import fr.iut.pm.movieapplication.ui.viewmodel.SearchResultVM +import fr.iut.pm.movieapplication.ui.viewmodel.SearchResultVMFactory + +class SearchResultFragment : Fragment() { + + private val searchResultViewModel by viewModels { SearchResultVMFactory(arguments?.getString("query")!!) } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return super.onCreateView(inflater, container, savedInstanceState) + } +} \ 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/ShowsFragment.kt deleted file mode 100644 index b9f7feb..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt +++ /dev/null @@ -1,15 +0,0 @@ -package fr.iut.pm.movieapplication.ui.fragments - -import android.os.Bundle -import androidx.fragment.app.Fragment -import fr.iut.pm.movieapplication.ui.activity.MainActivity - -class ShowsFragment( - private val context : MainActivity -) : Fragment() { - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } -} \ No newline at end of file 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 new file mode 100644 index 0000000..fe13393 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/TvShowsFragment.kt @@ -0,0 +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( +) : Fragment() { + + + 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/interfaces/MovieSelection.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/interfaces/MovieSelection.kt new file mode 100644 index 0000000..a195ecb --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/interfaces/MovieSelection.kt @@ -0,0 +1,6 @@ +package fr.iut.pm.movieapplication.ui.interfaces + +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/viewmodel/HomeSectionsVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/HomeSectionsVM.kt index 0f0ae6b..c724078 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/HomeSectionsVM.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/HomeSectionsVM.kt @@ -1,4 +1,33 @@ package fr.iut.pm.movieapplication.ui.viewmodel -class HomeSectionsVM { +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import fr.iut.pm.movieapplication.model.media.MediaResult +import fr.iut.pm.movieapplication.repository.MediaRepository +import kotlinx.coroutines.launch + +class HomeSectionsVM : ViewModel() { + + private val repository = MediaRepository() + + private var _trendsLiveData : MutableLiveData> = MutableLiveData() + fun getTrendsLiveData() : MutableLiveData> = _trendsLiveData + + private var _popularMoviesLiveData : MutableLiveData> = MutableLiveData() + fun getPopularMoviesLiveData() : MutableLiveData> = _popularMoviesLiveData + + private var _popularTvShowsLiveData : MutableLiveData> = MutableLiveData() + fun getPopularTvShowsLiveData() : MutableLiveData> = _popularTvShowsLiveData + + + init { + viewModelScope.launch { + _trendsLiveData.postValue(repository.getTrends()) + _popularMoviesLiveData.postValue(repository.getPopularMovies()) + _popularTvShowsLiveData.postValue(repository.getPopularTvShows()) + } + } + + } \ No newline at end of file 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 67fb70d..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 @@ -1,37 +1,111 @@ 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 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 kotlinx.coroutines.CoroutineScope +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(private val repository: MovieRepository) : ViewModel() { +class MoviesVM() : ViewModel() { + /** + * The movie repository used to get our data + */ + private val repository = MovieRepository() - private val _popularMovies = MutableLiveData>() - val popularMovies : LiveData> = _popularMovies + /** + * The MutableLiveData + */ + private var _moviesLiveData : MutableLiveData> = MutableLiveData>() - init { - //loadData() + /** + * 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 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 + + if(lastVisibleItemPosition == totalItemCount -1) { + + ++currentPage + //1000 is the MAX_PAGE + if(currentPage <= MAX_PAGE) getMoreData(currentPage) + } + } } - suspend fun loadData() { - viewModelScope.launch { - repository.getPopularMovies { movies -> - _popularMovies.value = movies + + /** + * Currrent page where the data are obtained + */ + private var currentPage = 1 + + /** + * 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()) + repository.getMovieDetails(315162) } - }.join() + "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()) + } + } } -} - + /** + * 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 { + 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 { - override fun create(modelClass: Class): T { - return MoviesVM(repository) as T } } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/SearchResultVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/SearchResultVM.kt new file mode 100644 index 0000000..ea4d77c --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/SearchResultVM.kt @@ -0,0 +1,23 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +class SearchResultVM(private var query : String) : ViewModel() { + private var _queryLiveData : MutableLiveData = MutableLiveData() + fun getQueryLiveData() : LiveData = _queryLiveData + + init { + _queryLiveData.postValue(query) + } +} + +class SearchResultVMFactory(private var query : String) : ViewModelProvider.Factory +{ + override funcreate(modelClass:Class) : T + { + return SearchResultVM(query) as T + } +} \ No newline at end of file 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..383b73b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/TvShowVM.kt @@ -0,0 +1,43 @@ +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.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()) + } + } + } +} \ 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 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..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 @@ -3,8 +3,15 @@ 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 + const val MAX_PAGE = 1000 } } \ 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..242c62b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/MediaResultMapper.kt @@ -0,0 +1,103 @@ +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 { + + 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, + 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, + overview = mediaResultDTO.overview ?: "", + releaseDate = mediaResultDTO.releaseDate ?: mediaResultDTO.firstAirDate!! , + originCountry = mediaResultDTO.originCountry, +// 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, + 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, + mediaType = mediaResultDTO.mediaType + ) + } + + 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_home_sections.xml b/Sources/app/src/main/res/layout/fragment_home_sections.xml index 12275b5..891fe6d 100644 --- a/Sources/app/src/main/res/layout/fragment_home_sections.xml +++ b/Sources/app/src/main/res/layout/fragment_home_sections.xml @@ -1,69 +1,86 @@ + - + - + - + - + - + android:contentDescription="@string/section_nested_scroll_view"> - - - + > + + + + + + + + + + + + + + + - - - \ No newline at end of file + \ 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..85d6b50 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -1,14 +1,55 @@ - - + + + + + + + + + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/fragment_search_results.xml b/Sources/app/src/main/res/layout/fragment_search_results.xml new file mode 100644 index 0000000..b612533 --- /dev/null +++ b/Sources/app/src/main/res/layout/fragment_search_results.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/fragment_tv_shows.xml b/Sources/app/src/main/res/layout/fragment_tv_shows.xml new file mode 100644 index 0000000..550b066 --- /dev/null +++ b/Sources/app/src/main/res/layout/fragment_tv_shows.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/item_horizontal_home_page.xml b/Sources/app/src/main/res/layout/item_horizontal_home_page.xml index a98f4f9..86db216 100644 --- a/Sources/app/src/main/res/layout/item_horizontal_home_page.xml +++ b/Sources/app/src/main/res/layout/item_horizontal_home_page.xml @@ -1,45 +1,51 @@ - - - - - + + + + + + + + + app:cardCornerRadius="5dp"> + - - + - + + + - \ 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..9b7af0a --- /dev/null +++ b/Sources/app/src/main/res/layout/item_movie_category.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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..8f58121 --- /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/layout/item_vertical_fragment.xml b/Sources/app/src/main/res/layout/item_vertical_fragment.xml index 6c2d62a..3de6c1a 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"> - - - - - + + + + + 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..ee7df69 --- /dev/null +++ b/Sources/app/src/main/res/layout/movie_dialog.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + +