🚧 add the room database

develop
Jordan ARTZET 2 years ago
parent 10646b7c38
commit d0768d2704

@ -45,14 +45,15 @@ dependencies {
implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.core:core-ktx:1.9.0'
implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion" implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
implementation "androidx.activity:activity-ktx:$rootProject.activityVersion"
implementation "androidx.fragment:fragment-ktx:1.5.5" 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 // Room components
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
implementation "androidx.room:room-ktx:$rootProject.roomVersion" implementation "androidx.room:room-ktx:$rootProject.roomVersion"
kapt "androidx.room:room-compiler:$rootProject.roomVersion" kapt "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
// Lifecycle components // Lifecycle components
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion"
@ -68,17 +69,14 @@ dependencies {
implementation "io.coil-kt:coil:1.1.1" implementation "io.coil-kt:coil:1.1.1"
// UI // UI
implementation "androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion"
implementation "com.google.android.material:material:$rootProject.materialVersion"
// Moshi // Moshi
implementation "com.squareup.moshi:moshi-kotlin:1.13.0" implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
// Retrofit // Retrofit & Moshi
implementation "com.squareup.retrofit2:retrofit:2.9.0" 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" implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
// Testing // Testing

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".MovieApplication"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
@ -13,7 +14,7 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MovieApplication" android:theme="@style/Theme.MovieApplication"
tools:targetApi="31"> tools:targetApi="33">
<activity <activity
android:name=".ui.activity.MainActivity" android:name=".ui.activity.MainActivity"
android:exported="true"> android:exported="true">

@ -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)
}
}

@ -24,7 +24,7 @@ data class MovieDetailsDTO(
//prod countries //prod countries
@Json(name = "release_date") @Json(name = "release_date")
val releaseDate: String, val releaseDate: String,
val revenue: Int, val revenue: Long,
//spoken language //spoken language
val status: String, val status: String,
val title: String, val title: String,

@ -1,23 +1,51 @@
package fr.iut.pm.movieapplication.data.dao package fr.iut.pm.movieapplication.data.dao
import androidx.room.Dao import androidx.room.*
import androidx.room.Insert import fr.iut.pm.movieapplication.data.entities.*
import androidx.room.OnConflictStrategy
import androidx.room.Query
import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.model.media.movie.MovieDetails
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface MovieDAO { interface MovieDAO {
@Query("SELECT * FROM movies_table ORDER BY original_title ASC")
fun getMovieByAlphabetizeMovie() : Flow<List<MovieDetails>>
@Insert(onConflict = OnConflictStrategy.IGNORE) @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") @Transaction
suspend fun deleteAll() @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) }
)
}
}

@ -19,7 +19,7 @@ class MovieDetails(
//prod companies //prod companies
//prod countries //prod countries
releaseDate : String?, releaseDate : String?,
val revenue : Int, val revenue : Long,
//spoken language //spoken language
val status : String, val status : String,
title : String, title : String,

@ -2,7 +2,6 @@ package fr.iut.pm.movieapplication.repository
import android.util.Log import android.util.Log
import fr.iut.pm.movieapplication.api.RetrofitInstance 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.Movie
import fr.iut.pm.movieapplication.model.media.movie.MovieDetails import fr.iut.pm.movieapplication.model.media.movie.MovieDetails
import fr.iut.pm.movieapplication.utils.MediaResultMapper 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.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class MovieRepository { class MovieAPIRepository {
suspend fun getPopularMovies(page : Int = 1) : List<Movie> = withContext(Dispatchers.IO) suspend fun getPopularMovies(page : Int = 1) : List<Movie> = withContext(Dispatchers.IO)
{ {

@ -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
}
}

@ -1,16 +1,13 @@
package fr.iut.pm.movieapplication.ui.activity package fr.iut.pm.movieapplication.ui.activity
import android.os.Build
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.View
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import fr.iut.pm.movieapplication.R import fr.iut.pm.movieapplication.R
import fr.iut.pm.movieapplication.repository.MediaRepository import fr.iut.pm.movieapplication.ui.fragments.FavoritesFragment
import fr.iut.pm.movieapplication.repository.MovieRepository
import fr.iut.pm.movieapplication.ui.fragments.HomeSectionsFragment import fr.iut.pm.movieapplication.ui.fragments.HomeSectionsFragment
import fr.iut.pm.movieapplication.ui.fragments.MoviesFragment import fr.iut.pm.movieapplication.ui.fragments.MoviesFragment
import fr.iut.pm.movieapplication.ui.fragments.TvShowsFragment import fr.iut.pm.movieapplication.ui.fragments.TvShowsFragment
@ -41,6 +38,10 @@ class MainActivity : AppCompatActivity() {
loadFragments(TvShowsFragment()) loadFragments(TvShowsFragment())
return@setOnItemSelectedListener true return@setOnItemSelectedListener true
} }
R.id.favorites_page -> {
loadFragments(FavoritesFragment())
return@setOnItemSelectedListener true
}
else -> false else -> false
} }
} }

@ -31,6 +31,11 @@ class MovieDialog : DialogFragment() {
(Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build() (Constants.IMG_URL + it).toUri().buildUpon().scheme("https").build()
}) })
} }
binding.registerMovieDetailsButton.setOnClickListener {
moviesDialogVM.register(binding.movieDetails!!)
}
return binding.root return binding.root
} }

@ -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()
}
}
}

@ -1,13 +1,18 @@
package fr.iut.pm.movieapplication.ui.viewmodel package fr.iut.pm.movieapplication.ui.viewmodel
import androidx.lifecycle.* 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.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 import kotlinx.coroutines.launch
class MoviesDialogVM(private val movieId : Int) : ViewModel() { 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<MovieDetails> = MutableLiveData() private var _movieDetailsLiveData : MutableLiveData<MovieDetails> = MutableLiveData()
fun getMovieDetailLiveData() : LiveData<MovieDetails> = _movieDetailsLiveData fun getMovieDetailLiveData() : LiveData<MovieDetails> = _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 class MoviesDialogVMFactory(private val movieId : Int) : ViewModelProvider.Factory

@ -4,17 +4,15 @@ import androidx.lifecycle.*
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import fr.iut.pm.movieapplication.model.media.movie.Movie import fr.iut.pm.movieapplication.model.media.movie.Movie
import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.repository.MovieAPIRepository
import fr.iut.pm.movieapplication.ui.adapter.MovieAdapter
import fr.iut.pm.movieapplication.utils.Constants.Companion.MAX_PAGE import fr.iut.pm.movieapplication.utils.Constants.Companion.MAX_PAGE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class MoviesVM() : ViewModel() { class MoviesVM() : ViewModel() {
/** /**
* The movie repository used to get our data * The movie repository used to get our data
*/ */
private val repository = MovieRepository() private val repository = MovieAPIRepository()
/** /**
* The MutableLiveData * The MutableLiveData

@ -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>

@ -60,16 +60,15 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="@{movieDetails.overview.length() > 150 ? movieDetails.overview.substring(0, 150) + `...` : movieDetails.overview}" android:text="@{movieDetails.overview.length() > 150 ? movieDetails.overview.substring(0, 150) + `...` : movieDetails.overview}"
android:textAlignment="center" 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_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/details_image" app:layout_constraintStart_toEndOf="@+id/details_image"
app:layout_constraintTop_toBottomOf="@+id/details_image" /> app:layout_constraintTop_toBottomOf="@+id/details_image" />
<Button <Button
android:id="@+id/button" android:id="@+id/register_movie_details_button"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"

@ -14,7 +14,7 @@
android:icon="@drawable/ic_tv_shows" android:icon="@drawable/ic_tv_shows"
android:title="@string/bottom_series_item" /> android:title="@string/bottom_series_item" />
<item <item
android:id="@+id/artist_page" android:id="@+id/favorites_page"
android:icon="@drawable/ic_baseline_star_border_24" android:icon="@drawable/ic_baseline_star_border_24"
android:title="@string/bottom_artist_item" /> android:title="@string/bottom_favorite_item" />
</menu> </menu>

@ -14,7 +14,7 @@
android:icon="@drawable/ic_tv_shows" android:icon="@drawable/ic_tv_shows"
android:title="@string/bottom_series_item" /> android:title="@string/bottom_series_item" />
<item <item
android:id="@+id/artist_page" android:id="@+id/favorites_page"
android:icon="@drawable/ic_baseline_star_border_24" android:icon="@drawable/ic_baseline_star_border_24"
android:title="@string/bottom_artist_item" /> android:title="@string/bottom_favorite_item" />
</menu> </menu>

@ -4,7 +4,7 @@
<string name="bottom_home_item">Accueil</string> <string name="bottom_home_item">Accueil</string>
<string name="bottom_movies_item">Films</string> <string name="bottom_movies_item">Films</string>
<string name="bottom_series_item">Séries</string> <string name="bottom_series_item">Séries</string>
<string name="bottom_artist_item">Artistes</string> <string name="bottom_favorite_item">Favoris</string>
<!-- Home page --> <!-- Home page -->
<string name="home_page_title">Bienvenue,</string> <string name="home_page_title">Bienvenue,</string>

@ -7,7 +7,7 @@ plugins {
ext { ext {
activityVersion = '1.6.1' activityVersion = '1.6.1'
appCompatVersion = '1.6.0' appCompatVersion = '1.6.1'
constraintLayoutVersion = '2.1.4' constraintLayoutVersion = '2.1.4'
coreTestingVersion = '2.1.0' coreTestingVersion = '2.1.0'
coroutines = '1.6.4' coroutines = '1.6.4'

Loading…
Cancel
Save