diff --git a/Sources/app/build.gradle b/Sources/app/build.gradle index 3440a82..c53bb1e 100644 --- a/Sources/app/build.gradle +++ b/Sources/app/build.gradle @@ -42,6 +42,8 @@ dependencies { 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 implementation "androidx.room:room-ktx:$rootProject.roomVersion" @@ -62,6 +64,15 @@ dependencies { 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 + 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 testImplementation "junit:junit:$rootProject.junitVersion" androidTestImplementation "androidx.arch.core:core-testing:$rootProject.coreTestingVersion" diff --git a/Sources/app/src/main/AndroidManifest.xml b/Sources/app/src/main/AndroidManifest.xml index a4559cd..be3f5d0 100644 --- a/Sources/app/src/main/AndroidManifest.xml +++ b/Sources/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/RetrofitInstance.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/RetrofitInstance.kt new file mode 100644 index 0000000..740a00e --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/RetrofitInstance.kt @@ -0,0 +1,27 @@ +package fr.iut.pm.movieapplication.api + +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import fr.iut.pm.movieapplication.utils.Constants.Companion.BASE_URL +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory + +private val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + + +object RetrofitInstance { + + private val retrofit by lazy { + Retrofit.Builder() + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .baseUrl(BASE_URL) + .build() + } + + val api : MovieApplicationAPI by lazy { + retrofit.create(MovieApplicationAPI::class.java) + } +} \ 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 bd50cd9..cf78568 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,6 +1,8 @@ package fr.iut.pm.movieapplication.data.dao import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import fr.iut.pm.movieapplication.model.Movie import kotlinx.coroutines.flow.Flow @@ -11,5 +13,11 @@ interface MovieDAO { @Query("SELECT * FROM movies_table ORDER BY original_title ASC") fun getMovieByAlphabetizeMovie() : Flow> + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insert(movie : Movie) + + @Query("DELETE FROM movies_table") + suspend fun deleteAll() + } \ 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 new file mode 100644 index 0000000..c0eaec1 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/data/dao/MovieEntity.kt @@ -0,0 +1,9 @@ +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/model/Popular.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt new file mode 100644 index 0000000..256c611 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Popular.kt @@ -0,0 +1,17 @@ +package fr.iut.pm.movieapplication.model + +import androidx.room.ColumnInfo +import androidx.room.Embedded + +data class Popular( + @ColumnInfo("page") + val page : Int, + @ColumnInfo("results") + @Embedded + val results : List, + val totalResults : Int, + val totalPages : Int + +){ + +} \ 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 new file mode 100644 index 0000000..5405548 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/GenreDTO.kt @@ -0,0 +1,7 @@ +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/network/dtos/MovieDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/MovieDTO.kt new file mode 100644 index 0000000..839f4be --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/MovieDTO.kt @@ -0,0 +1,25 @@ +package fr.iut.pm.movieapplication.network.dtos + +import com.squareup.moshi.Json + +data class MovieDTO( + @Json(name = "poster_path") + val posterPath : String?, + val adult : Boolean, + val overview : String?, + @Json(name = "release_date") + val releaseDate : String, + @Json(name = "genre_ids") + val genreIds : List, + val id : Int, + @Json(name = "original_title") + val originalTitle : String, + @Json(name = "original_language") + val originalLanguage : String, + val title : String + + +) { + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/PopularDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/PopularDTO.kt new file mode 100644 index 0000000..8d82f1c --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/network/dtos/PopularDTO.kt @@ -0,0 +1,12 @@ +package fr.iut.pm.movieapplication.network.dtos + +import com.squareup.moshi.Json + +data class PopularDTO( + val page : Int, + val results : List, + @Json(name = "total_pages") + val totalPages : Int, + @Json(name = "total_results") + val totalResults : Int +) {} \ 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 new file mode 100644 index 0000000..3574a71 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -0,0 +1,15 @@ +package fr.iut.pm.movieapplication.repository + +import fr.iut.pm.movieapplication.data.dao.MovieDAO +import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.network.dtos.MovieDTO +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.transform + +class MovieRepository() { + + suspend fun getPopularMovies() : List{ + return PopularRepository().getPopular()!!.results + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..94c8f3c --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt @@ -0,0 +1,33 @@ +package fr.iut.pm.movieapplication.repository + +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.network.dtos.PopularDTO +import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY +import kotlinx.coroutines.flow.Flow +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class PopularRepository() { + + suspend fun getPopular(): PopularDTO? { + + lateinit var popularDTO : PopularDTO + RetrofitInstance.api.getPopularMovies(API_KEY).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("RESPONSE ::", response.body()?.page.toString()) + popularDTO = response.body()!! + } + } + + override fun onFailure(call: Call, t: Throwable) { + TODO("Not yet implemented") + } + + + }) + return popularDTO + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt index 2e6f389..8fcc367 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/adapter/HomeItemAdapter.kt @@ -6,11 +6,13 @@ import android.view.ViewGroup import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.network.dtos.MovieDTO import fr.iut.pm.movieapplication.ui.activity.MainActivity class HomeItemAdapter( private val context : MainActivity, - private val layoutId : Int + private val layoutId : Int, + private val list : List ) : RecyclerView.Adapter() { class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { @@ -23,7 +25,9 @@ class HomeItemAdapter( return ViewHolder(view) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) {} + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val currentItem = list?.get(position) + } - override fun getItemCount(): Int = 5 + 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/fragments/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index 4e47377..4b9a081 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt @@ -7,30 +7,33 @@ 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.network.dtos.MovieDTO +import fr.iut.pm.movieapplication.network.dtos.PopularDTO import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration +import fr.iut.pm.movieapplication.ui.viewmodel.HomeSectionsVM -class HomeSectionsFragment( - private val context : MainActivity -) : Fragment() { +class HomeSectionsFragment(private val context : MainActivity) : Fragment() { + + private lateinit var homeSectionsViewModel : HomeSectionsVM override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_home_sections, container, false) //get the trends RecyclerView val homeTrendsRecyclerView = view?.findViewById(R.id.home_trends_recycler_view) - homeTrendsRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page) + homeTrendsRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) homeTrendsRecyclerView?.addItemDecoration(HomeItemDecoration()) //get the popularity RecyclerView val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) - homePopularityRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page) + homePopularityRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) homePopularityRecyclerView?.addItemDecoration(HomeItemDecoration()) //get the free RecyclerView val homeFreeRecyclerView = view?.findViewById(R.id.home_free_recycler_view) - homeFreeRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page) + homeFreeRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,ArrayList()) homeFreeRecyclerView?.addItemDecoration(HomeItemDecoration()) return view } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/MoviesFragment.kt index 648ac51..5cee8de 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 @@ -5,13 +5,25 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.viewModelFactory import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.data.dao.MovieDAO +import fr.iut.pm.movieapplication.network.dtos.MovieDTO +import fr.iut.pm.movieapplication.network.dtos.PopularDTO +import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.ui.adapter.CategoryItemDecoration import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVMFactory +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.runBlocking class MoviesFragment( private val context : MainActivity @@ -20,10 +32,15 @@ class MoviesFragment( override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_movies, container, false) + val viewModel by viewModels { + MoviesVMFactory(MovieRepository()) + } + - //get the recycler view val moviesRecyclerView = view?.findViewById(R.id.movies_item_recycler_view) - moviesRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_vertical_fragment) + + moviesRecyclerView?.adapter = HomeItemAdapter(context, R.layout.item_vertical_fragment,viewModel.popularMovies.value!!) + moviesRecyclerView?.layoutManager = GridLayoutManager(context, 2) moviesRecyclerView?.addItemDecoration(CategoryItemDecoration()) 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 new file mode 100644 index 0000000..0f0ae6b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/HomeSectionsVM.kt @@ -0,0 +1,4 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +class HomeSectionsVM { +} \ 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 new file mode 100644 index 0000000..5772d1e --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -0,0 +1,46 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import fr.iut.pm.movieapplication.network.dtos.MovieDTO +import fr.iut.pm.movieapplication.repository.MovieRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class MoviesVM(private val repository: MovieRepository) : ViewModel() { + + private val _popularMovies = MutableLiveData>() + val popularMovies : MutableLiveData> = _popularMovies + + init { + getPopularMovies() + } + + + private fun getPopularMovies() { + viewModelScope.launch { + try { + _popularMovies.value = repository.getPopularMovies()} + catch (e : Exception) { + e.stackTrace + } + + } + } + +} + +class MoviesVMFactory( + private val repository: MovieRepository + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + if (modelClass.isAssignableFrom(MoviesVM::class.java)) { + return MoviesVM(repository) as T + } + throw java.lang.IllegalArgumentException("Unknown ViewModel class") + } + +} \ 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 new file mode 100644 index 0000000..a992963 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt @@ -0,0 +1,9 @@ +package fr.iut.pm.movieapplication.utils + +class Constants { + + companion object { + const val BASE_URL = "https://api.themoviedb.org/3/" + const val API_KEY = "8f14a279249638d7f247d0d7298b21b4" + } +} \ 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 a07abbd..9427bc7 100644 --- a/Sources/app/src/main/res/layout/item_vertical_fragment.xml +++ b/Sources/app/src/main/res/layout/item_vertical_fragment.xml @@ -24,6 +24,7 @@ android:background="@color/black" />