From d0768d270419e1605774f2630815c87e15fdd660 Mon Sep 17 00:00:00 2001 From: Jordan Artzet Date: Sun, 12 Feb 2023 21:07:08 +0100 Subject: [PATCH] :construction: add the room database --- Sources/app/build.gradle | 14 ++- Sources/app/src/main/AndroidManifest.xml | 3 +- .../pm/movieapplication/MovieApplication.kt | 12 +++ .../api/dtos/MovieDetailsDTO.kt | 2 +- .../pm/movieapplication/data/dao/MovieDAO.kt | 48 +++++++--- .../movieapplication/data/dao/MovieEntity.kt | 9 -- .../data/database/MovieDataBase.kt | 60 +++++++++++++ .../data/entities/GenreEntity.kt | 12 +++ .../data/entities/MovieDetailsEntity.kt | 19 ++++ .../data/entities/MovieDetailsGenreEntity.kt | 17 ++++ .../data/entities/MovieDetailsWithGenres.kt | 15 ++++ .../data/entities/MovieEntity.kt | 23 +++++ .../data/mapper/GenreLocalMapper.kt | 25 ++++++ .../data/mapper/MovieLocalMapper.kt | 87 +++++++++++++++++++ .../model/media/movie/MovieDetails.kt | 2 +- ...vieRepository.kt => MovieAPIRepository.kt} | 3 +- .../repository/PopularRepository.kt | 16 ---- .../repository/local/MovieLocalRepository.kt | 36 ++++++++ .../ui/activity/MainActivity.kt | 9 +- .../movieapplication/ui/dialog/MovieDialog.kt | 5 ++ .../ui/fragments/FavoritesFragment.kt | 52 +++++++++++ .../ui/viewmodel/FavoritesVM.kt | 30 +++++++ .../ui/viewmodel/MoviesDialogVM.kt | 14 ++- .../movieapplication/ui/viewmodel/MoviesVM.kt | 6 +- .../layout/fragment_favorites_category.xml | 38 ++++++++ .../app/src/main/res/layout/movie_dialog.xml | 5 +- .../res/menu-v26/bottom_navigation_menu.xml | 4 +- .../main/res/menu/bottom_navigation_menu.xml | 4 +- Sources/app/src/main/res/values/strings.xml | 2 +- Sources/build.gradle | 2 +- 30 files changed, 507 insertions(+), 67 deletions(-) create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/MovieApplication.kt delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieEntity.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/database/MovieDataBase.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/GenreEntity.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsEntity.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsGenreEntity.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsWithGenres.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieEntity.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/GenreLocalMapper.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/MovieLocalMapper.kt rename Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/{MovieRepository.kt => MovieAPIRepository.kt} (97%) delete mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/local/MovieLocalRepository.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/FavoritesFragment.kt create mode 100644 Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/FavoritesVM.kt create mode 100644 Sources/app/src/main/res/layout/fragment_favorites_category.xml diff --git a/Sources/app/build.gradle b/Sources/app/build.gradle index cd5b0a7..d8696c7 100644 --- a/Sources/app/build.gradle +++ b/Sources/app/build.gradle @@ -45,14 +45,15 @@ dependencies { implementation 'androidx.core:core-ktx:1.9.0' implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" - implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" - implementation "androidx.fragment:fragment-ktx:1.5.5" + implementation "androidx.activity:activity-ktx:$rootProject.activityVersion" + implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion" + implementation "com.google.android.material:material:$rootProject.materialVersion" // Room components + implementation "androidx.room:room-runtime:$rootProject.roomVersion" implementation "androidx.room:room-ktx:$rootProject.roomVersion" kapt "androidx.room:room-compiler:$rootProject.roomVersion" - androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion" // Lifecycle components implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" @@ -68,17 +69,14 @@ dependencies { implementation "io.coil-kt:coil:1.1.1" // UI - implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion" - implementation "com.google.android.material:material:$rootProject.materialVersion" + // Moshi implementation "com.squareup.moshi:moshi-kotlin:1.13.0" - // Retrofit + // Retrofit & Moshi implementation "com.squareup.retrofit2:retrofit:2.9.0" - // Retrofit with Scalar Converter implementation "com.squareup.retrofit2:converter-scalars:2.9.0" - // Retrofit with Moshi Converter implementation "com.squareup.retrofit2:converter-moshi:2.9.0" // Testing diff --git a/Sources/app/src/main/AndroidManifest.xml b/Sources/app/src/main/AndroidManifest.xml index be3f5d0..6d1f5dd 100644 --- a/Sources/app/src/main/AndroidManifest.xml +++ b/Sources/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + tools:targetApi="33"> diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/MovieApplication.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/MovieApplication.kt new file mode 100644 index 0000000..9e750db --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/MovieApplication.kt @@ -0,0 +1,12 @@ +package fr.iut.pm.movieapplication + +import android.app.Application +import androidx.room.Room +import fr.iut.pm.movieapplication.data.database.MovieDataBase + +class MovieApplication : Application() { + override fun onCreate() { + super.onCreate() + MovieDataBase.initialize(this) + } +} \ 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 index 99dfb48..248dbab 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 @@ -24,7 +24,7 @@ data class MovieDetailsDTO( //prod countries @Json(name = "release_date") val releaseDate: String, - val revenue: Int, + val revenue: Long, //spoken language val status: String, val title: String, 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 5efb718..81525c7 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 @@ -1,23 +1,51 @@ package fr.iut.pm.movieapplication.data.dao -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query +import androidx.room.* +import fr.iut.pm.movieapplication.data.entities.* 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> - @Insert(onConflict = OnConflictStrategy.IGNORE) - suspend fun insert(movie : MovieDetails) + suspend fun insert(movieEntity : MovieEntity) + + @Query("SELECT * FROM movies_table") + suspend fun getAllMovies() : List + + @Query("SELECT * FROM movies_details_table") + suspend fun getAllMoviesDetails() : List + + @Query("SELECT * FROM movies_table WHERE id = :id") + fun getMovieById(id : Int) : MovieEntity + + //delete a movie + @Query("DELETE FROM movies_table WHERE id = :id") + suspend fun deleteMovieById(id : Int) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertMovieDetails(movieDetailsEntity: MovieDetailsEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertGenres(genres : List) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertMovieDetailsGenres(movieDetailsGenresEntity : List) + + @Transaction + suspend fun insertMovieDetailsWithGenres(movieDetailsWithGenres : MovieDetailsWithGenres) { + insertMovieDetails(movieDetailsWithGenres.movieDetails) + insertGenres(movieDetailsWithGenres.genres) + val movieDetailsGenres = movieDetailsWithGenres.genres.map { + MovieDetailsGenreEntity(movieDetailsWithGenres.movieDetails.movieId, it.genreId) + } + insertMovieDetailsGenres(movieDetailsGenres) + } - @Query("DELETE FROM movies_table") - suspend fun deleteAll() + @Transaction + @Query("SELECT * FROM movies_details_table WHERE movie_id = :movieId") + suspend fun getMovieDetailsWithGenresById(movieId: Int): MovieDetailsWithGenres } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieEntity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieEntity.kt deleted file mode 100644 index c0eaec1..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieEntity.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fr.iut.pm.movieapplication.data.dao - -import androidx.room.Entity - -@Entity("movies_table") -class MovieEntity { - - -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/database/MovieDataBase.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/database/MovieDataBase.kt new file mode 100644 index 0000000..5e8aaa2 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/database/MovieDataBase.kt @@ -0,0 +1,60 @@ +package fr.iut.pm.movieapplication.data.database + +import android.app.Application +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import fr.iut.pm.movieapplication.MovieApplication +import fr.iut.pm.movieapplication.data.dao.MovieDAO +import fr.iut.pm.movieapplication.data.entities.GenreEntity +import fr.iut.pm.movieapplication.data.entities.MovieDetailsEntity +import fr.iut.pm.movieapplication.data.entities.MovieDetailsGenreEntity +import fr.iut.pm.movieapplication.data.entities.MovieEntity + + +const val MOVIE_DB_NAME = "movies.db" + +@Database( entities = [MovieEntity::class, MovieDetailsEntity::class, GenreEntity::class, MovieDetailsGenreEntity::class], version = 3) +abstract class MovieDataBase : RoomDatabase() +{ + abstract fun movieDAO() : MovieDAO + + companion object + { + private lateinit var application : Application + + @Volatile + private var instance : MovieDataBase? = null + + fun getInstance() : MovieDataBase + { + if (::application.isInitialized) { + if (instance == null) + synchronized(this) + { + if (instance == null) + instance = Room.databaseBuilder( + application.applicationContext, + MovieDataBase::class.java, + MOVIE_DB_NAME + ) + .fallbackToDestructiveMigration() + .build() + } + return instance!! + } + else + throw RuntimeException("the database must be first initialized") + } + + @Synchronized + fun initialize(app : MovieApplication) + { + if (::application.isInitialized) + throw RuntimeException("the database must not be initialized twice") + + application = app + } + } +} + diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/GenreEntity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/GenreEntity.kt new file mode 100644 index 0000000..e6b9788 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/GenreEntity.kt @@ -0,0 +1,12 @@ +package fr.iut.pm.movieapplication.data.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "genres_table") +data class GenreEntity( + @PrimaryKey @ColumnInfo("genre_id") val genreId : Int, + val name : String +) { +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsEntity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsEntity.kt new file mode 100644 index 0000000..269c273 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsEntity.kt @@ -0,0 +1,19 @@ +package fr.iut.pm.movieapplication.data.entities + +import androidx.room.* +import fr.iut.pm.movieapplication.model.Genre + + +@Entity(tableName = "movies_details_table") +data class MovieDetailsEntity( + @PrimaryKey @ColumnInfo("movie_id") val movieId : Int, + @Embedded val movie : MovieEntity, + val budget : Int, + val homepage : String?, + val revenue : Long, + val status : String + //Future attributes to add +) { + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsGenreEntity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsGenreEntity.kt new file mode 100644 index 0000000..538f94c --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsGenreEntity.kt @@ -0,0 +1,17 @@ +package fr.iut.pm.movieapplication.data.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey + +@Entity(tableName = "movie_details_genre", + primaryKeys = ["movie_id", "genre_id"], + foreignKeys = [ + ForeignKey(entity = MovieDetailsEntity::class, parentColumns = ["movie_id"], childColumns = ["movie_id"]), + ForeignKey(entity = GenreEntity::class, parentColumns = ["genre_id"], childColumns = ["genre_id"]) + ] +) +data class MovieDetailsGenreEntity( + @ColumnInfo("movie_id") val movieId : Int, + @ColumnInfo("genre_id") val genreId : Int +) \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsWithGenres.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsWithGenres.kt new file mode 100644 index 0000000..cf15e8e --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieDetailsWithGenres.kt @@ -0,0 +1,15 @@ +package fr.iut.pm.movieapplication.data.entities + +import androidx.room.Embedded +import androidx.room.Junction +import androidx.room.Relation + +data class MovieDetailsWithGenres( + @Embedded val movieDetails: MovieDetailsEntity, + @Relation( + parentColumn = "movie_id", + entityColumn = "genre_id", + associateBy = Junction(MovieDetailsGenreEntity::class) + ) + val genres: List +) \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieEntity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieEntity.kt new file mode 100644 index 0000000..217bd5a --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/entities/MovieEntity.kt @@ -0,0 +1,23 @@ +package fr.iut.pm.movieapplication.data.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "movies_table") +data class MovieEntity( + @PrimaryKey val id: Int, + val title: String, + val overview: String?, + @ColumnInfo("poster_path") val posterPath: String?, + @ColumnInfo("backdrop_path") val backdropPath: String?, + @ColumnInfo("release_date") val releaseDate: String, + @ColumnInfo("vote_average") val voteAverage: Double, + @ColumnInfo("vote_count") val voteCount: Int, + val popularity: Double, + @ColumnInfo("original_language") val originalLanguage: String, + @ColumnInfo("original_title") val originalTitle: String, + val adult: Boolean, + @ColumnInfo("is_favorite") val isFavorite: Boolean +) { +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/GenreLocalMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/GenreLocalMapper.kt new file mode 100644 index 0000000..64355b1 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/GenreLocalMapper.kt @@ -0,0 +1,25 @@ +package fr.iut.pm.movieapplication.data.mapper + +import fr.iut.pm.movieapplication.data.entities.GenreEntity +import fr.iut.pm.movieapplication.model.Genre + +object GenreLocalMapper { + + fun mapToGenreEntity(genre : Genre) : GenreEntity { + return GenreEntity( + genreId = genre.id, + name = genre.name + ) + } + + fun mapToGenreEntities(genres : List) : List { + return genres.map { mapToGenreEntity(it) } + } + + fun mapToGenre(genreEntity : GenreEntity) : Genre { + return Genre( + id = genreEntity.genreId, + name = genreEntity.name + ) + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/MovieLocalMapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/MovieLocalMapper.kt new file mode 100644 index 0000000..fdd5d9a --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/mapper/MovieLocalMapper.kt @@ -0,0 +1,87 @@ +package fr.iut.pm.movieapplication.data.mapper + +import fr.iut.pm.movieapplication.data.entities.MovieDetailsEntity +import fr.iut.pm.movieapplication.data.entities.MovieDetailsWithGenres +import fr.iut.pm.movieapplication.data.entities.MovieEntity +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails + +object MovieLocalMapper { + + fun mapToMovie(movieEntity : MovieEntity) : Movie { + return Movie( + posterPath = movieEntity.posterPath, + adult = movieEntity.adult, + overview = movieEntity.overview, + releaseDate = movieEntity.releaseDate, + id = movieEntity.id, + originalTitle = movieEntity.originalTitle, + originalLanguage = movieEntity.originalLanguage, + title = movieEntity.title, + backdropPath = movieEntity.backdropPath, + popularity = movieEntity.popularity, + voteCount = movieEntity.voteCount, + voteAverage = movieEntity.voteAverage + ) + } + + + + fun mapToMovieEntity(movie : Movie) : MovieEntity { + return MovieEntity( + posterPath = movie.posterPath, + adult = movie.adult!!, + overview = movie.overview, + releaseDate = movie.releaseDate!!, + id = movie.id, + originalTitle = movie.originalTitle, + originalLanguage = movie.originalLanguage, + title = movie.title, + backdropPath = movie.backdropPath , + popularity = movie.popularity, + voteCount = movie.voteCount, + voteAverage = movie.voteAverage, + isFavorite = false + ) + } + + fun mapToMovieDetailsEntity(movieDetails : MovieDetails) : MovieDetailsEntity { + return MovieDetailsEntity( + movieId = movieDetails.id, + movie = mapToMovieEntity(movieDetails), + budget = movieDetails.budget, + homepage = movieDetails.homepage, + revenue = movieDetails.revenue, + status = movieDetails.status + ) + } + + fun mapToMovieDetailsWithGenres(movieDetails: MovieDetails) : MovieDetailsWithGenres { + return MovieDetailsWithGenres( + movieDetails = mapToMovieDetailsEntity(movieDetails), + genres = movieDetails.genres.map { GenreLocalMapper.mapToGenreEntity(it) } + ) + } + + fun mapToMovieDetails(movieDetailsWithGenres: MovieDetailsWithGenres) : MovieDetails { + return MovieDetails( + id = movieDetailsWithGenres.movieDetails.movieId, + posterPath = movieDetailsWithGenres.movieDetails.movie.posterPath, + adult = movieDetailsWithGenres.movieDetails.movie.adult, + overview = movieDetailsWithGenres.movieDetails.movie.overview, + releaseDate = movieDetailsWithGenres.movieDetails.movie.releaseDate, + originalTitle = movieDetailsWithGenres.movieDetails.movie.originalTitle, + originalLanguage = movieDetailsWithGenres.movieDetails.movie.originalLanguage, + title = movieDetailsWithGenres.movieDetails.movie.title, + backdropPath = movieDetailsWithGenres.movieDetails.movie.backdropPath, + popularity = movieDetailsWithGenres.movieDetails.movie.popularity, + voteCount = movieDetailsWithGenres.movieDetails.movie.voteCount, + voteAverage = movieDetailsWithGenres.movieDetails.movie.voteAverage, + budget = movieDetailsWithGenres.movieDetails.budget, + homepage = movieDetailsWithGenres.movieDetails.homepage, + revenue = movieDetailsWithGenres.movieDetails.revenue, + status = movieDetailsWithGenres.movieDetails.status, + genres = movieDetailsWithGenres.genres.map { GenreLocalMapper.mapToGenre(it) } + ) + } +} \ 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 index a9c63d9..7bb297f 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 @@ -19,7 +19,7 @@ class MovieDetails( //prod companies //prod countries releaseDate : String?, - val revenue : Int, + val revenue : Long, //spoken language val status : String, title : String, 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/MovieAPIRepository.kt similarity index 97% rename from Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt rename to Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieAPIRepository.kt index a42cbd3..2ca77aa 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/MovieAPIRepository.kt @@ -2,7 +2,6 @@ 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 @@ -10,7 +9,7 @@ import fr.iut.pm.movieapplication.utils.MovieMapper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -class MovieRepository { +class MovieAPIRepository { suspend fun getPopularMovies(page : Int = 1) : List = withContext(Dispatchers.IO) { diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt deleted file mode 100644 index 6c8a645..0000000 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt +++ /dev/null @@ -1,16 +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.utils.Constants.Companion.API_KEY -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response - -class PopularRepository() { - - suspend fun getPopular(): PopularDTO? { - throw NoSuchMethodError() - } -} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/local/MovieLocalRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/local/MovieLocalRepository.kt new file mode 100644 index 0000000..e6c5cbb --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/local/MovieLocalRepository.kt @@ -0,0 +1,36 @@ +package fr.iut.pm.movieapplication.repository.local + +import android.util.Log +import fr.iut.pm.movieapplication.data.dao.MovieDAO +import fr.iut.pm.movieapplication.data.mapper.MovieLocalMapper +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.model.media.movie.MovieDetails +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class MovieLocalRepository(private val movieDAO: MovieDAO) { + + suspend fun insertMovie(movie : Movie) = withContext(Dispatchers.IO) { + movieDAO.insert(MovieLocalMapper.mapToMovieEntity(movie)) + } + + suspend fun insertMovieDetails(movieDetails : MovieDetails) = withContext(Dispatchers.IO) { + Log.i("MovieLocalRepository", "INSERT MOVIE DETAILS") + movieDAO.insertMovieDetailsWithGenres(MovieLocalMapper.mapToMovieDetailsWithGenres(movieDetails)) + } + + suspend fun getMovieDetailsById(id : Int) : MovieDetails { + return MovieLocalMapper.mapToMovieDetails(movieDAO.getMovieDetailsWithGenresById(id)) + } + + suspend fun getAllMovies() : List = withContext(Dispatchers.IO) { + val listMovie : MutableList = mutableListOf() + val listMoviesEntities = movieDAO.getAllMoviesDetails() + + listMoviesEntities.forEach { movieEntity -> + listMovie.add(MovieLocalMapper.mapToMovie(movieEntity.movie)) + } + + 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 d741285..426b00b 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 @@ -1,16 +1,13 @@ package fr.iut.pm.movieapplication.ui.activity -import android.os.Build import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.Menu -import android.view.View 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.repository.MediaRepository -import fr.iut.pm.movieapplication.repository.MovieRepository +import fr.iut.pm.movieapplication.ui.fragments.FavoritesFragment import fr.iut.pm.movieapplication.ui.fragments.HomeSectionsFragment import fr.iut.pm.movieapplication.ui.fragments.MoviesFragment import fr.iut.pm.movieapplication.ui.fragments.TvShowsFragment @@ -41,6 +38,10 @@ class MainActivity : AppCompatActivity() { loadFragments(TvShowsFragment()) return@setOnItemSelectedListener true } + R.id.favorites_page -> { + loadFragments(FavoritesFragment()) + return@setOnItemSelectedListener true + } else -> false } } 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 index 5847821..ea5f0b1 100644 --- 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 @@ -31,6 +31,11 @@ class MovieDialog : DialogFragment() { (Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build() }) } + + binding.registerMovieDetailsButton.setOnClickListener { + moviesDialogVM.register(binding.movieDetails!!) + } + return binding.root } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/FavoritesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/FavoritesFragment.kt new file mode 100644 index 0000000..97aed80 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/FavoritesFragment.kt @@ -0,0 +1,52 @@ +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.databinding.FragmentFavoritesCategoryBinding +import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter +import fr.iut.pm.movieapplication.ui.interfaces.MovieSelection +import fr.iut.pm.movieapplication.ui.viewmodel.FavoritesVM + +class FavoritesFragment : Fragment(), MovieSelection { + + private val favoritesVM by viewModels() + + private val movieAdapter = MovieAdapter(this); + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding = FragmentFavoritesCategoryBinding.inflate(inflater) + + binding.favoritesVM = favoritesVM + binding.lifecycleOwner = viewLifecycleOwner + + with(binding.moviesItemRecyclerView) { + this.adapter = movieAdapter + } + + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + favoritesVM.getFavoritesLiveData().observe(viewLifecycleOwner) { + movieAdapter.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/viewmodel/FavoritesVM.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/FavoritesVM.kt new file mode 100644 index 0000000..5667f7d --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/FavoritesVM.kt @@ -0,0 +1,30 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import fr.iut.pm.movieapplication.data.database.MovieDataBase +import fr.iut.pm.movieapplication.model.media.movie.Movie +import fr.iut.pm.movieapplication.repository.local.MovieLocalRepository +import kotlinx.coroutines.launch + +class FavoritesVM : ViewModel() { + + private val repository = MovieLocalRepository(MovieDataBase.getInstance().movieDAO()) + + private var _favoritesLiveData : MutableLiveData> = MutableLiveData() + + fun getFavoritesLiveData() : MutableLiveData> = _favoritesLiveData + + + init { + //with dispatchers.IO + viewModelScope.launch{ + _favoritesLiveData.value = repository.getAllMovies() + } + + + + } + +} \ 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 index b39350f..ea482ef 100644 --- 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 @@ -1,13 +1,18 @@ package fr.iut.pm.movieapplication.ui.viewmodel import androidx.lifecycle.* +import fr.iut.pm.movieapplication.data.database.MovieDataBase import fr.iut.pm.movieapplication.model.media.movie.MovieDetails -import fr.iut.pm.movieapplication.repository.MovieRepository +import fr.iut.pm.movieapplication.repository.MovieAPIRepository +import fr.iut.pm.movieapplication.repository.local.MovieLocalRepository import kotlinx.coroutines.launch class MoviesDialogVM(private val movieId : Int) : ViewModel() { - private val repository = MovieRepository() + private val repository = MovieAPIRepository() + + private val movieLocalRepository = MovieLocalRepository( + MovieDataBase.getInstance().movieDAO()) private var _movieDetailsLiveData : MutableLiveData = MutableLiveData() fun getMovieDetailLiveData() : LiveData = _movieDetailsLiveData @@ -18,6 +23,11 @@ class MoviesDialogVM(private val movieId : Int) : ViewModel() { } } + fun register(movieDetails: MovieDetails) = viewModelScope.launch { + + movieLocalRepository.insertMovieDetails(movieDetails) + } + } class MoviesDialogVMFactory(private val movieId : Int) : ViewModelProvider.Factory 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 8c6da20..23ce2cb 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 @@ -4,17 +4,15 @@ import androidx.lifecycle.* 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 fr.iut.pm.movieapplication.repository.MovieAPIRepository import fr.iut.pm.movieapplication.utils.Constants.Companion.MAX_PAGE -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class MoviesVM() : ViewModel() { /** * The movie repository used to get our data */ - private val repository = MovieRepository() + private val repository = MovieAPIRepository() /** * The MutableLiveData diff --git a/Sources/app/src/main/res/layout/fragment_favorites_category.xml b/Sources/app/src/main/res/layout/fragment_favorites_category.xml new file mode 100644 index 0000000..424be29 --- /dev/null +++ b/Sources/app/src/main/res/layout/fragment_favorites_category.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/movie_dialog.xml b/Sources/app/src/main/res/layout/movie_dialog.xml index ee7df69..c8d5dbc 100644 --- a/Sources/app/src/main/res/layout/movie_dialog.xml +++ b/Sources/app/src/main/res/layout/movie_dialog.xml @@ -60,16 +60,15 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" android:text="@{movieDetails.overview.length() > 150 ? movieDetails.overview.substring(0, 150) + `...` : movieDetails.overview}" android:textAlignment="center" - app:layout_constraintBottom_toTopOf="@+id/button" + app:layout_constraintBottom_toTopOf="@+id/register_movie_details_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/details_image" app:layout_constraintTop_toBottomOf="@+id/details_image" />