parent
10646b7c38
commit
d0768d2704
@ -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)
|
||||
}
|
||||
}
|
@ -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<List<MovieDetails>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(movie : MovieDetails)
|
||||
suspend fun insert(movieEntity : MovieEntity)
|
||||
|
||||
@Query("SELECT * FROM movies_table")
|
||||
suspend fun getAllMovies() : List<MovieEntity>
|
||||
|
||||
@Query("SELECT * FROM movies_details_table")
|
||||
suspend fun getAllMoviesDetails() : List<MovieDetailsEntity>
|
||||
|
||||
@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<GenreEntity>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertMovieDetailsGenres(movieDetailsGenresEntity : List<MovieDetailsGenreEntity>)
|
||||
|
||||
@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
|
||||
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package fr.iut.pm.movieapplication.data.dao
|
||||
|
||||
import androidx.room.Entity
|
||||
|
||||
@Entity("movies_table")
|
||||
class MovieEntity {
|
||||
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
) {
|
||||
}
|
@ -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
|
||||
) {
|
||||
|
||||
|
||||
}
|
@ -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
|
||||
)
|
@ -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<GenreEntity>
|
||||
)
|
@ -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
|
||||
) {
|
||||
}
|
@ -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<Genre>) : List<GenreEntity> {
|
||||
return genres.map { mapToGenreEntity(it) }
|
||||
}
|
||||
|
||||
fun mapToGenre(genreEntity : GenreEntity) : Genre {
|
||||
return Genre(
|
||||
id = genreEntity.genreId,
|
||||
name = genreEntity.name
|
||||
)
|
||||
}
|
||||
}
|
@ -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) }
|
||||
)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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<Movie> = withContext(Dispatchers.IO) {
|
||||
val listMovie : MutableList<Movie> = mutableListOf()
|
||||
val listMoviesEntities = movieDAO.getAllMoviesDetails()
|
||||
|
||||
listMoviesEntities.forEach { movieEntity ->
|
||||
listMovie.add(MovieLocalMapper.mapToMovie(movieEntity.movie))
|
||||
}
|
||||
|
||||
listMovie
|
||||
}
|
||||
}
|
@ -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<FavoritesVM>()
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
@ -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<List<Movie>> = MutableLiveData()
|
||||
|
||||
fun getFavoritesLiveData() : MutableLiveData<List<Movie>> = _favoritesLiveData
|
||||
|
||||
|
||||
init {
|
||||
//with dispatchers.IO
|
||||
viewModelScope.launch{
|
||||
_favoritesLiveData.value = repository.getAllMovies()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
||||
<data>
|
||||
|
||||
<import type="android.view.View" />
|
||||
|
||||
<variable
|
||||
name="favoritesVM"
|
||||
type="fr.iut.pm.movieapplication.ui.viewmodel.FavoritesVM" />
|
||||
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/movies_item_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/default_margin"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="3"
|
||||
tools:listitem="@layout/item_movie_category"
|
||||
|
||||
/>
|
||||
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
Loading…
Reference in new issue