Merge branch 'features/retrofit/1' into develop

develop
Jordan ARTZET 2 years ago
commit 96e30ea2a5

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

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"

@ -0,0 +1,22 @@
package fr.iut.pm.movieapplication.api
import fr.iut.pm.movieapplication.api.dtos.MovieResultDTO
import fr.iut.pm.movieapplication.api.dtos.PopularDTO
import fr.iut.pm.movieapplication.utils.Constants.Companion.API_KEY
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface MovieApplicationAPI {
@GET("movie/popular")
fun getPopularMovies(@Query("api_key") apiKey : String = API_KEY) : Call<PopularDTO>
@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<PopularDTO>
@GET("movie/{movie_id")
fun getMovieDetails(@Path("movie_id") movieId : Int, @Query("api_key") apiKey: String = API_KEY) : Call<MovieResultDTO>
}

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

@ -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<String> = listOf()
@Json(name = "logo_sizes")
private var logoSizes : List<String> = listOf()
@Json(name = "poster_sizes")
private var posterSizes : List<String> = listOf()
@Json(name = "profile_sizes")
private var profilSizes : List<String> = listOf()
@Json(name = "still_sizes")
private var stillSizes : List<String> = 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<String>,
@Json(name = "images.logo_sizes")
val logoSizes : List<String>,
@Json(name = "images.poster_sizes")
val posterSizes : List<String>,
@Json(name = "images.profile_sizes")
val profileSizes : List<String>,
@Json(name = "images.still_sizes")
val stillSizes : List<String>
)

@ -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<GenreDTO>?,
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<ProductionCountry>,
@Json(name = "release_date")
val releaseDate: String,
val revenue: Int,
val runtime: Int?,
//var spokenLanguages : Array<SpokenLanguage>,
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?
){
}

@ -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<Int>?,
@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?
) {
}

@ -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<MovieResultDTO>,
@Json(name = "total_results")
val totalResults : Int,
@Json(name = "total_pages")
val totalPages : Int
) {}

@ -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<List<Movie>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(movie : Movie)
@Query("DELETE FROM movies_table")
suspend fun deleteAll()
}

@ -0,0 +1,9 @@
package fr.iut.pm.movieapplication.data.dao
import androidx.room.Entity
@Entity("movies_table")
class MovieEntity {
}

@ -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<Genre>,
val genres: Array<Genre>?,
@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<ProductionCompany>,
@Relation(
parentColumn = "movieId",
entityColumn = ""
)
val posterPath: String?,
val productionCompanies: Array<ProductionCompany>?,
@ColumnInfo(name = "production_countries")
val productionCountries: Array<ProductionCountry>,
val productionCountries: Array<ProductionCountry>?,
@ColumnInfo(name = "release_date")
val releaseDate: Date,
val revenue: Int,
val releaseDate: String?,
val revenue: Int?,
val runtime: Int?,
//var spokenLanguages : Array<SpokenLanguage>,
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 {

@ -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<Movie>,
val totalResults : Int,
val totalPages : Int
){
}

@ -0,0 +1,7 @@
package fr.iut.pm.movieapplication.network.dtos
data class GenreDTO(
private val id : Int,
private val name : String
) {
}

@ -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<Movie>) -> Unit ) {
val listMovie : MutableList<Movie> = mutableListOf()
RetrofitInstance.api.getPopularMovies().enqueue(object :
Callback<PopularDTO> {
override fun onResponse(call: Call<PopularDTO>, response: Response<PopularDTO>) {
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<PopularDTO>, t: Throwable) {
Log.d("Error failure", t.message.toString())
}
})
}
fun getTrends(callback: (List<Movie>) -> Unit) {
val listMovie : MutableList<Movie> = mutableListOf()
RetrofitInstance.api.getTrending().enqueue(object : Callback<PopularDTO> {
override fun onResponse(call: Call<PopularDTO>, response: Response<PopularDTO>) {
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<PopularDTO>, t: Throwable) {
Log.d("Error failure", t.message.toString())
}
})
}
}

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

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

@ -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<Movie>
) : RecyclerView.Adapter<HomeItemAdapter.ViewHolder>() {
class ViewHolder(view : View) : RecyclerView.ViewHolder(view) {
val itemImage: ImageView = view.findViewById<ImageView>(R.id.item_image)
val itemName: TextView = view.findViewById<TextView>(R.id.item_name)
val itemDate: TextView = view.findViewById<TextView>(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
}

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

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

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

@ -0,0 +1,4 @@
package fr.iut.pm.movieapplication.ui.viewmodel
class HomeSectionsVM {
}

@ -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<List<Movie>>()
val popularMovies : LiveData<List<Movie>> = _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 <T : ViewModel> create(modelClass: Class<T>): T {
return MoviesVM(repository) as T
}
}

@ -0,0 +1,9 @@
package fr.iut.pm.movieapplication.ui.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
inline fun <VM : ViewModel> viewModelFactory(crossinline f: () -> VM) =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T = f() as T
}

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

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

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/light_green"/>
<item android:state_checked="false" android:color="@color/light_grey"/>
</selector>

@ -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 @@
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_height="wrap_content"
android:background="@color/dark_blue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:itemTextColor="@drawable/item_selector"
app:itemIconTint="@drawable/item_selector"
app:labelVisibilityMode="labeled"
app:menu="@menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -12,48 +12,58 @@
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/home_page_trends_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_trends_section_title"
android:textSize="20sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_trends_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<TextView
android:id="@+id/home_page_popularity_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_popularity_section_title"
android:textSize="20sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_popularity_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<TextView
android:id="@+id/home_page_free_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_free_section_title"
android:textSize="20sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_free_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
/>
<TextView
android:id="@+id/home_page_trends_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_trends_section_title"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginTop="@dimen/default_margin"
style="@style/SectionTitleStyle"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_trends_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<TextView
android:id="@+id/home_page_popularity_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_popularity_section_title"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginTop="@dimen/default_margin"
style="@style/SectionTitleStyle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_popularity_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<TextView
android:id="@+id/home_page_free_section_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/home_page_free_section_title"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginTop="@dimen/default_margin"
style="@style/SectionTitleStyle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_free_recycler_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

@ -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"
/>
</LinearLayout>

@ -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">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="200dp"
app:cardCornerRadius="15dp"
app:cardCornerRadius="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/home_section_item_image"
android:id="@+id/item_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
@ -26,21 +27,19 @@
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/home_section_item_name"
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nom du film"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardView" />
<TextView
android:id="@+id/home_section_item_date"
android:id="@+id/item_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="23 nov 2012"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/home_section_item_name" />
app:layout_constraintTop_toBottomOf="@+id/item_name" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -2,7 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="175dp"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
@ -10,6 +10,7 @@
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="@dimen/default_margin"
app:layout_constraintTop_toTopOf="parent"
app:cardCornerRadius="10dp">
@ -19,22 +20,24 @@
android:orientation="vertical">
<ImageView
android:id="@+id/item_image"
android:layout_width="match_parent"
android:layout_height="210dp"
android:scaleType="centerCrop"
android:background="@color/black" />
<TextView
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nom du film"
android:layout_height="20dp"
android:layout_gravity="center"
android:textAlignment="center"
/>
<TextView
android:id="@+id/item_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="23 nov 2015"
android:layout_height="20dp"
android:layout_gravity="center"
android:textAlignment="center"
/>

@ -3,21 +3,18 @@
<item
android:id="@+id/home_page"
android:title="@string/bottom_home_item"
android:icon="@drawable/ic_home"
/>
android:title="@string/bottom_home_item" />
<item
android:id="@+id/movies_page"
android:title="@string/bottom_movies_item"
android:icon="@drawable/ic_movie"
/>
android:title="@string/bottom_movies_item" />
<item
android:id="@+id/series_page"
android:title="@string/bottom_series_item"
android:icon="@drawable/ic_tv_shows"
/>
android:title="@string/bottom_series_item" />
<item
android:id="@+id/artist_page"
android:title="@string/bottom_artist_item"
android:icon="@drawable/ic_baseline_star_border_24"/>
android:icon="@drawable/ic_baseline_star_border_24"
android:title="@string/bottom_artist_item" />
</menu>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/search_bar"
android:title="Search"
app:showAsAction="collapseActionView|ifRoom"
app:actionViewClass="androidx.appcompat.widget.SearchView" />
</menu>

@ -3,21 +3,18 @@
<item
android:id="@+id/home_page"
android:title="@string/bottom_home_item"
android:icon="@drawable/ic_home"
/>
android:title="@string/bottom_home_item" />
<item
android:id="@+id/movies_page"
android:title="@string/bottom_movies_item"
android:icon="@drawable/ic_movie"
/>
android:title="@string/bottom_movies_item" />
<item
android:id="@+id/series_page"
android:title="@string/bottom_series_item"
android:icon="@drawable/ic_tv_shows"
/>
android:title="@string/bottom_series_item" />
<item
android:id="@+id/artist_page"
android:title="@string/bottom_artist_item"
android:icon="@drawable/ic_baseline_star_border_24"/>
android:icon="@drawable/ic_baseline_star_border_24"
android:title="@string/bottom_artist_item" />
</menu>

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MovieApplication" parent="Theme.Material3.Dark.NoActionBar">
<style name="Theme.MovieApplication" parent="Theme.Material3.Dark">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/dark_blue</item>
<item name="colorPrimaryVariant">@color/black</item>

@ -8,7 +8,9 @@
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="light_grey">#e3e3e3</color>
<color name="dark_blue">#032541</color>
<color name="light_blue">#01B4E4</color>
<color name="lighter_green">#c0fecf</color>
<color name="light_green">#1ed5a9 </color>
</resources>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="default_margin">20dp</dimen>
</resources>

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MovieApplication" parent="@style/Theme.Material3.Light">
<style name="Theme.MovieApplication" parent="Theme.Material3.Light">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/light_blue</item>
<item name="colorPrimaryVariant">@color/dark_blue</item>
@ -13,4 +13,30 @@
<item name="android:statusBarColor" tools:targetApi="21">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<!-- Create the component for the default title -->
<style name="DefaultTextStyle">
<item name="android:textColor">@color/black</item>
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">@font/source_sans_pro</item>
</style>
<style name="SubtitleTextStyle" parent="DefaultTextStyle">
<item name="android:textColor">@color/black</item>
<item name="android:textSize">20sp</item>
</style>
<style name="SectionTitleStyle" parent="DefaultTextStyle">
<item name="android:textSize">24sp</item>
</style>
<style name="TitleTextStyle" parent="SubtitleTextStyle">
<item name="android:textColor">@color/black</item>
<item name="android:textSize">24sp</item>
</style>
<style name="BottomMenuStyle" parent="Widget.Material3.BottomNavigationView">
<item name="android:textSize">16sp</item>
</style>
</resources>

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

Loading…
Cancel
Save