diff --git a/Sources/app/build.gradle b/Sources/app/build.gradle index 3440a82..6940713 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" @@ -58,10 +60,25 @@ dependencies { api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutines" api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines" + //Coil + 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" + //GSON + //implementation 'com.squareup.retrofit2:converter-gson:2.1.0' + + // Retrofit + implementation "com.squareup.retrofit2:retrofit:2.9.0" + // Retrofit with Scalar Converter + //implementation "com.squareup.retrofit2:converter-scalars:2.9.0" + // 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 @@ + + + + @GET("trending/{media_type}/{time_window}") + fun getTrending(@Path("media_type") mediaType : String = "all", @Path("time_window") timeWindow : String = "day", @Query("api_key") apiKey: String = API_KEY ) : Call + + @GET("movie/{movie_id") + fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Call + +} \ 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..1ade6b0 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/RetrofitInstance.kt @@ -0,0 +1,23 @@ +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 + + + +object RetrofitInstance { + + private val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + private val retrofit = Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + + val api: MovieApplicationAPI = retrofit.create(MovieApplicationAPI::class.java) +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/config/GlobalImageConfig.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/config/GlobalImageConfig.kt new file mode 100644 index 0000000..74063eb --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/config/GlobalImageConfig.kt @@ -0,0 +1,51 @@ +package fr.iut.pm.movieapplication.api.config + +import android.util.Log +import com.squareup.moshi.Json + + +object GlobalImageConfig { + @Json(name = "base_url") + private var _baseUrl : String = "" + val baseUrl : String = _baseUrl + @Json(name = "secure_base_url") + private var _secureBaseUrl : String = "" + val secureBaseUrl = _secureBaseUrl + @Json(name = "backdrop_sizes") + private var backdropSizes : List = listOf() + @Json(name = "logo_sizes") + private var logoSizes : List = listOf() + @Json(name = "poster_sizes") + private var posterSizes : List = listOf() + @Json(name = "profile_sizes") + private var profilSizes : List = listOf() + @Json(name = "still_sizes") + private var stillSizes : List = listOf() + + fun updateConfig(config: ImageConfig) { + Log.d("BASE URL IMAGE", baseUrl) + _baseUrl = config.baseUrl + _secureBaseUrl = config.secureBaseUrl + posterSizes = config.posterSizes + backdropSizes = config.backdropSizes + } + +} + +data class ImageConfig( + + @Json(name = "images.base_url") + val baseUrl : String, + @Json(name = "images.secure_base_url") + val secureBaseUrl : String, + @Json(name = "images.backdrop_sizes") + val backdropSizes : List, + @Json(name = "images.logo_sizes") + val logoSizes : List, + @Json(name = "images.poster_sizes") + val posterSizes : List, + @Json(name = "images.profile_sizes") + val profileSizes : List, + @Json(name = "images.still_sizes") + val stillSizes : List +) \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt new file mode 100644 index 0000000..83abc57 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieDTO.kt @@ -0,0 +1,44 @@ +package fr.iut.pm.movieapplication.api.dtos + +import androidx.room.ColumnInfo +import androidx.room.Embedded +import androidx.room.PrimaryKey +import androidx.room.Relation +import com.squareup.moshi.Json +import fr.iut.pm.movieapplication.model.Genre +import fr.iut.pm.movieapplication.model.ProductionCompany +import fr.iut.pm.movieapplication.model.ProductionCountry +import fr.iut.pm.movieapplication.network.dtos.GenreDTO + +class MovieDTO ( + val adult: Boolean, + val budget: Int, + val genres: Array?, + val homepage: String?, + val id: Int, + @Json(name = "original_language") + val originalLanguage: String, + @Json(name = "original_title") + val originalTitle: String, + val overview: String?, + val popularity: Double, + @Json(name = "poster_path") + val posterPath: String?, + @Json(name = "production_countries") + val productionCountries: Array, + @Json(name = "release_date") + val releaseDate: String, + val revenue: Int, + val runtime: Int?, + //var spokenLanguages : Array, + val status: String, + @Json(name = "tag_line") + val tagLine: String?, + val title: String, + @Json(name = "vote_average") + val voteAverage: Double, + @Json(name = "vote_count") + val voteCount: Int, + val backdropPath: String? +){ +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt new file mode 100644 index 0000000..68acf5b --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/MovieResultDTO.kt @@ -0,0 +1,40 @@ +package fr.iut.pm.movieapplication.api.dtos + + +import com.squareup.moshi.Json + +class MovieResultDTO( + @Json(name = "poster_path") + val posterPath : String?, + @Json(name = "adult") + val adult : Boolean, + @Json(name = "overview") + val overview : String, + @Json(name = "release_date") + val releaseDate : String?, + @Json(name = "genre_ids") + val genreIds : List?, + @Json(name = "id") + val id : Int, + @Json(name = "original_title") + val originalTitle : String?, + @Json(name = "original_language") + val originalLanguage : String?, + @Json(name = "title") + val title : String?, + @Json(name = "backdrop_path") + val backdropPath : String?, + @Json(name = "popularity") + val popularity : Double?, + @Json(name = "vote_count") + val voteCount : Int?, + val video : Boolean?, + @Json(name = "vote_average") + val voteAverage : Double? + + + +) { + + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt new file mode 100644 index 0000000..baf6422 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/api/dtos/PopularDTO.kt @@ -0,0 +1,18 @@ +package fr.iut.pm.movieapplication.api.dtos + + +import com.squareup.moshi.Json + + + +class PopularDTO( + @Json(name = "page") + val page : Int, + @Json(name = "results") + val results : List, + @Json(name = "total_results") + val totalResults : Int, + @Json(name = "total_pages") + val totalPages : Int + +) {} \ 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/Movie.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt index 6269f00..1b8021b 100644 --- a/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/model/Movie.kt @@ -1,57 +1,50 @@ package fr.iut.pm.movieapplication.model import androidx.room.ColumnInfo -import androidx.room.Embedded import androidx.room.Entity import androidx.room.PrimaryKey -import androidx.room.Relation -import java.util.Date @Entity(tableName = "movies_table") data class Movie( @ColumnInfo(name = "adult") val adult: Boolean, @ColumnInfo(name = "budget") - val budget: Int, + val budget: Int?, @ColumnInfo(name = "genres") - val genres: Array, + val genres: Array?, @ColumnInfo(name = "homepage") val homePage: String?, @PrimaryKey @ColumnInfo(name = "id") val movieId: Int, @ColumnInfo(name = "original_language") - val originalLanguage: String, + val originalLanguage: String?, @ColumnInfo(name = "original_title") - val originalTitle: String, + val originalTitle: String?, val overview: String?, - val popularity: Int, + val popularity: Double?, @ColumnInfo(name = "poster_path") - val posterPath : String?, - @Embedded - val productionCompanies: Array, - @Relation( - parentColumn = "movieId", - entityColumn = "" - ) + val posterPath: String?, + val productionCompanies: Array?, @ColumnInfo(name = "production_countries") - val productionCountries: Array, + val productionCountries: Array?, @ColumnInfo(name = "release_date") - val releaseDate: Date, - val revenue: Int, + val releaseDate: String?, + val revenue: Int?, val runtime: Int?, //var spokenLanguages : Array, - val status: String, + val status: String?, @ColumnInfo(name = "tag_line") val tagLine: String?, - val title: String, + val title: String?, @ColumnInfo(name = "vote_average") - val voteAverage: Number, + val voteAverage: Double?, @ColumnInfo(name = "vote_count") - val voteCount : Int + val voteCount: Int?, + val backdropPath: String? - ) { +) { override fun equals(other: Any?): Boolean { 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/repository/MovieRepository.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt new file mode 100644 index 0000000..c099d8e --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/MovieRepository.kt @@ -0,0 +1,66 @@ +package fr.iut.pm.movieapplication.repository + +import android.util.Log +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.api.dtos.PopularDTO +import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY +import fr.iut.pm.movieapplication.utils.Mapper +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class MovieRepository() { + + fun getPopularMovies(callback: (List) -> Unit ) { + + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getPopularMovies().enqueue(object : + Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("List :", response.body().toString()) + val popularDTO = response.body() + val listMoviesDTO = popularDTO?.results + listMoviesDTO?.forEach { + + val movie = Mapper.MapToMovie(it) + listMovie.add(movie) + Log.d("Movie ", movie.title!!) + } + + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.message.toString()) + } + + }) + } + + fun getTrends(callback: (List) -> Unit) { + val listMovie : MutableList = mutableListOf() + + RetrofitInstance.api.getTrending().enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if(response.isSuccessful) { + Log.d("Response",response.body().toString()) + val popularDTO = response.body() + popularDTO?.results?.forEach { + val movie = Mapper.MapToMovie(it) + listMovie.add(movie) + movie.title?.let { it1 -> Log.d("Movie", it1) } + } + } + callback(listMovie) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.d("Error failure", t.message.toString()) + } + }) + } +} \ 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..6c8a645 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/repository/PopularRepository.kt @@ -0,0 +1,16 @@ +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/ui/activity/MainActivity.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/activity/MainActivity.kt index 1410f0f..558a3c5 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 @@ -3,14 +3,29 @@ 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 android.widget.SearchView.OnQueryTextListener +import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import com.google.android.material.bottomnavigation.BottomNavigationView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.api.config.GlobalImageConfig +import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.fragments.HomeSectionsFragment import fr.iut.pm.movieapplication.ui.fragments.MoviesFragment +import fr.iut.pm.movieapplication.ui.fragments.ShowsFragment +import fr.iut.pm.movieapplication.utils.Constants +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import retrofit2.awaitResponse class MainActivity : AppCompatActivity() { + + val movieRepository : MovieRepository = MovieRepository() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -30,6 +45,11 @@ class MainActivity : AppCompatActivity() { loadFragments(MoviesFragment(this)) return@setOnItemSelectedListener true } + + R.id.series_page -> { + loadFragments(ShowsFragment(this)) + return@setOnItemSelectedListener true + } else -> false } } @@ -47,11 +67,29 @@ class MainActivity : AppCompatActivity() { // status bar is hidden, so hide that too if necessary. actionBar?.hide() } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.app_menu, menu) + val searchItem = menu?.findItem(R.id.search_bar) + val searchView : SearchView = searchItem?.actionView as SearchView + searchView.setOnQueryTextListener( object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + TODO("Not yet implemented") + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + TODO("Not yet implemented") + return false + } + }) + return true } private fun loadFragments(fragment: Fragment) { 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..20acfe9 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 @@ -1,19 +1,30 @@ package fr.iut.pm.movieapplication.ui.adapter +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView +import android.widget.TextView +import androidx.core.net.toUri import androidx.recyclerview.widget.RecyclerView +import coil.load import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.api.config.GlobalImageConfig +import fr.iut.pm.movieapplication.model.Movie import fr.iut.pm.movieapplication.ui.activity.MainActivity +import fr.iut.pm.movieapplication.utils.Constants.Companion.IMG_URL class HomeItemAdapter( - private val context : MainActivity, - private val layoutId : Int + private val context: MainActivity, + private val layoutId: Int, + private val list: List ) : RecyclerView.Adapter() { class ViewHolder(view : View) : RecyclerView.ViewHolder(view) { + val itemImage: ImageView = view.findViewById(R.id.item_image) + val itemName: TextView = view.findViewById(R.id.item_name) + val itemDate: TextView = view.findViewById(R.id.item_date) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { @@ -23,7 +34,19 @@ class HomeItemAdapter( return ViewHolder(view) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) {} + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val currentItem = list[position] + Log.d("SINGLETON", GlobalImageConfig.baseUrl) + val imgUri = currentItem.posterPath?.let { + (IMG_URL + it).toUri().buildUpon().scheme("https").build() - override fun getItemCount(): Int = 5 + } + Log.d("SINGLETON", imgUri.toString() ) + holder.itemImage.load(imgUri) + holder.itemName.text = currentItem.title + holder.itemDate.text = currentItem.releaseDate + + } + + override fun getItemCount(): Int = list.size } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/HomeSectionsFragment.kt index 4e47377..d321a90 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,38 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO +import fr.iut.pm.movieapplication.model.Movie import 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() { + ) : 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 + context.movieRepository.getTrends { 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,it) homeTrendsRecyclerView?.addItemDecoration(HomeItemDecoration()) + } //get the popularity RecyclerView + context.movieRepository.getPopularMovies { val homePopularityRecyclerView = view?.findViewById(R.id.home_popularity_recycler_view) - homePopularityRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page) + homePopularityRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_horizontal_home_page,it) 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..3623498 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,28 +5,37 @@ 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.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import fr.iut.pm.movieapplication.R +import fr.iut.pm.movieapplication.api.RetrofitInstance +import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.repository.MovieRepository import fr.iut.pm.movieapplication.ui.activity.MainActivity import fr.iut.pm.movieapplication.ui.adapter.CategoryItemDecoration import fr.iut.pm.movieapplication.ui.adapter.HomeItemAdapter -import fr.iut.pm.movieapplication.ui.adapter.HomeItemDecoration +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVM +import fr.iut.pm.movieapplication.ui.viewmodel.MoviesVMFactory +import fr.iut.pm.movieapplication.ui.viewmodel.viewModelFactory +import kotlinx.coroutines.launch class MoviesFragment( private val context : MainActivity ) : Fragment() { - + private val moviesVM: MoviesVM by viewModels{ MoviesVMFactory(repository = MovieRepository())} override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_movies, container, false) - //get the recycler view - val moviesRecyclerView = view?.findViewById(R.id.movies_item_recycler_view) - moviesRecyclerView?.adapter = HomeItemAdapter(context,R.layout.item_vertical_fragment) - moviesRecyclerView?.layoutManager = GridLayoutManager(context, 2) - moviesRecyclerView?.addItemDecoration(CategoryItemDecoration()) - + context.movieRepository.getPopularMovies { listMovies -> + val moviesRecyclerView = view?.findViewById(R.id.movies_item_recycler_view) + moviesRecyclerView?.adapter = HomeItemAdapter(context, R.layout.item_vertical_fragment, listMovies) + moviesRecyclerView ?. layoutManager = GridLayoutManager (context, 2) + moviesRecyclerView?.addItemDecoration(CategoryItemDecoration()) + } return view } diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt new file mode 100644 index 0000000..b9f7feb --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/fragments/ShowsFragment.kt @@ -0,0 +1,15 @@ +package fr.iut.pm.movieapplication.ui.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import fr.iut.pm.movieapplication.ui.activity.MainActivity + +class ShowsFragment( + private val context : MainActivity +) : Fragment() { + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/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..67fb70d --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/MoviesVM.kt @@ -0,0 +1,37 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.* +import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO +import fr.iut.pm.movieapplication.model.Movie +import fr.iut.pm.movieapplication.repository.MovieRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +class MoviesVM(private val repository: MovieRepository) : ViewModel() { + + private val _popularMovies = MutableLiveData>() + val popularMovies : LiveData> = _popularMovies + + init { + //loadData() + } + suspend fun loadData() { + viewModelScope.launch { + repository.getPopularMovies { movies -> + _popularMovies.value = movies + } + }.join() + + } +} + + + +class MoviesVMFactory( + private val repository: MovieRepository + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return MoviesVM(repository) as T + } + +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt new file mode 100644 index 0000000..d9d7bcc --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/ui/viewmodel/ViewModelFactory.kt @@ -0,0 +1,9 @@ +package fr.iut.pm.movieapplication.ui.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider + +inline fun viewModelFactory(crossinline f: () -> VM) = + object : ViewModelProvider.Factory { + override fun create(modelClass: Class): T = f() as T + } \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt new file mode 100644 index 0000000..4081cf5 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Constants.kt @@ -0,0 +1,10 @@ +package fr.iut.pm.movieapplication.utils + +class Constants { + + companion object { + const val BASE_URL = "https://api.themoviedb.org/3/" + const val IMG_URL = "https://image.tmdb.org/t/p/w500" + const val API_KEY = "8f14a279249638d7f247d0d7298b21b4" + } +} \ No newline at end of file diff --git a/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt new file mode 100644 index 0000000..9c91be0 --- /dev/null +++ b/Sources/app/src/main/java/fr/iut/pm/movieapplication/utils/Mapper.kt @@ -0,0 +1,36 @@ +package fr.iut.pm.movieapplication.utils + +import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO +import fr.iut.pm.movieapplication.model.Movie + +object Mapper { + + fun MapToMovie( movieDTO : MovieResultDTO) : Movie { + return Movie( + adult = movieDTO.adult, + posterPath = movieDTO.posterPath, + overview = movieDTO.overview, + releaseDate = movieDTO.releaseDate, + movieId = movieDTO.id, + originalTitle = movieDTO.originalTitle, + originalLanguage = movieDTO.originalLanguage, + title = movieDTO.title, + backdropPath = movieDTO.backdropPath, + popularity = movieDTO.popularity, + voteCount = movieDTO.voteCount, + voteAverage = movieDTO.voteAverage, + budget = null, + genres = null, + homePage = null, + productionCompanies = null, + productionCountries = null, + revenue = null, + runtime = null, + status = null, + tagLine = null + + ) + } + + +} \ No newline at end of file diff --git a/Sources/app/src/main/res/drawable/item_selector.xml b/Sources/app/src/main/res/drawable/item_selector.xml new file mode 100644 index 0000000..1666c03 --- /dev/null +++ b/Sources/app/src/main/res/drawable/item_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/font/source_sans_pro.ttf b/Sources/app/src/main/res/font/source_sans_pro.ttf new file mode 100644 index 0000000..6791613 Binary files /dev/null and b/Sources/app/src/main/res/font/source_sans_pro.ttf differ diff --git a/Sources/app/src/main/res/layout/activity_main.xml b/Sources/app/src/main/res/layout/activity_main.xml index d0fbc8a..b98f75d 100644 --- a/Sources/app/src/main/res/layout/activity_main.xml +++ b/Sources/app/src/main/res/layout/activity_main.xml @@ -11,7 +11,7 @@ android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginBottom="75dp" + android:layout_marginBottom="55dp" app:layout_constraintBottom_toTopOf="@+id/navigation_view" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -20,10 +20,14 @@ \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/fragment_home_sections.xml b/Sources/app/src/main/res/layout/fragment_home_sections.xml index 6c2afed..12275b5 100644 --- a/Sources/app/src/main/res/layout/fragment_home_sections.xml +++ b/Sources/app/src/main/res/layout/fragment_home_sections.xml @@ -12,48 +12,58 @@ android:layout_height="wrap_content" > - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/fragment_movies.xml b/Sources/app/src/main/res/layout/fragment_movies.xml index 8b0c3d2..4094d47 100644 --- a/Sources/app/src/main/res/layout/fragment_movies.xml +++ b/Sources/app/src/main/res/layout/fragment_movies.xml @@ -8,6 +8,7 @@ android:id="@+id/movies_item_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/default_margin" /> \ No newline at end of file diff --git a/Sources/app/src/main/res/layout/item_horizontal_home_page.xml b/Sources/app/src/main/res/layout/item_horizontal_home_page.xml index d7dc465..a98f4f9 100644 --- a/Sources/app/src/main/res/layout/item_horizontal_home_page.xml +++ b/Sources/app/src/main/res/layout/item_horizontal_home_page.xml @@ -4,19 +4,20 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="150dp" - android:layout_height="match_parent" > + android:layout_height="match_parent" + android:layout_marginTop="10dp"> + app:layout_constraintTop_toBottomOf="@+id/item_name" /> \ 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..6c2d62a 100644 --- a/Sources/app/src/main/res/layout/item_vertical_fragment.xml +++ b/Sources/app/src/main/res/layout/item_vertical_fragment.xml @@ -2,7 +2,7 @@ + android:layout_height="wrap_content"> @@ -19,22 +20,24 @@ android:orientation="vertical"> diff --git a/Sources/app/src/main/res/menu-v26/bottom_navigation_menu.xml b/Sources/app/src/main/res/menu-v26/bottom_navigation_menu.xml index 675901b..26edad9 100644 --- a/Sources/app/src/main/res/menu-v26/bottom_navigation_menu.xml +++ b/Sources/app/src/main/res/menu-v26/bottom_navigation_menu.xml @@ -3,21 +3,18 @@ + android:title="@string/bottom_home_item" /> + android:title="@string/bottom_movies_item" /> + android:title="@string/bottom_series_item" /> + android:icon="@drawable/ic_baseline_star_border_24" + android:title="@string/bottom_artist_item" /> \ No newline at end of file diff --git a/Sources/app/src/main/res/menu/app_menu.xml b/Sources/app/src/main/res/menu/app_menu.xml new file mode 100644 index 0000000..340dd81 --- /dev/null +++ b/Sources/app/src/main/res/menu/app_menu.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/Sources/app/src/main/res/menu/bottom_navigation_menu.xml b/Sources/app/src/main/res/menu/bottom_navigation_menu.xml index 675901b..26edad9 100644 --- a/Sources/app/src/main/res/menu/bottom_navigation_menu.xml +++ b/Sources/app/src/main/res/menu/bottom_navigation_menu.xml @@ -3,21 +3,18 @@ + android:title="@string/bottom_home_item" /> + android:title="@string/bottom_movies_item" /> + android:title="@string/bottom_series_item" /> + android:icon="@drawable/ic_baseline_star_border_24" + android:title="@string/bottom_artist_item" /> \ No newline at end of file diff --git a/Sources/app/src/main/res/values-night/themes.xml b/Sources/app/src/main/res/values-night/themes.xml index 9817c27..aaa9e8e 100644 --- a/Sources/app/src/main/res/values-night/themes.xml +++ b/Sources/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/build.gradle b/Sources/build.gradle index f8c3a46..ad7fa55 100644 --- a/Sources/build.gradle +++ b/Sources/build.gradle @@ -12,7 +12,7 @@ ext { coreTestingVersion = '2.1.0' coroutines = '1.6.4' lifecycleVersion = '2.5.1' - materialVersion = '1.7.0' + materialVersion = '1.8.0' roomVersion = '2.5.0' kotlin_version = '1.7.20' // testing