début implémentation api themoviedb, mais foireux de fou

pull/17/head
louwar 2 years ago
parent 745ecb427c
commit 07bdd4bac2

@ -15,6 +15,8 @@ android {
versionName "1.0" versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
} }
buildTypes { buildTypes {
@ -31,28 +33,34 @@ android {
jvmTarget = '1.8' jvmTarget = '1.8'
} }
buildFeatures { buildFeatures {
dataBinding true
viewBinding true viewBinding true
} }
} }
dependencies { dependencies {
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.5.0' implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'androidx.core:core-ktx:1.9.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "com.squareup.okhttp3:okhttp:4.9.3" implementation "com.squareup.okhttp3:okhttp:4.9.3"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.3" implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
implementation "com.google.code.gson:gson:2.8.9" implementation "com.google.code.gson:gson:2.8.9"
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'androidx.fragment:fragment-ktx:1.5.6'
implementation 'androidx.multidex:multidex:2.0.1'
} }

@ -1,21 +1,10 @@
package fr.iut.cinecool package fr.iut.cinecool
import retrofit2.Call
import com.google.android.gms.common.api.Response
import com.google.gson.GsonBuilder
import fr.iut.cinecool.interfaces.ApiService
import fr.iut.cinecool.model.MovieResponse
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.security.auth.callback.Callback
class ApiClient { class ApiClient {
companion object { companion object {
private const val BASE_URL = "https://api.themoviedb.org/3/" /*private const val BASE_URL = "https://api.themoviedb.org/3/"
fun create(): ApiService { fun create(): ApiService {
@ -49,8 +38,8 @@ class ApiClient {
val apiKey = "a97243d7813d31446f6c43284e6854d5" val apiKey = "a97243d7813d31446f6c43284e6854d5"
val call = movieApiService.getPopularMovies(apiKey) val call = movieApiService.getPopularMovies(apiKey)
// TO DO
/*call.enqueue(object : Callback<MovieResponse> { call.enqueue(object : Callback<MovieResponse> {
override fun onResponse(call: Call<MovieResponse>, response: Response<MovieResponse>) { override fun onResponse(call: Call<MovieResponse>, response: Response<MovieResponse>) {
// Code à exécuter lorsque la réponse est reçue // Code à exécuter lorsque la réponse est reçue
val movies = response.body()?.results val movies = response.body()?.results
@ -60,7 +49,7 @@ class ApiClient {
override fun onFailure(call: Call<MovieResponse>, t: Throwable) { override fun onFailure(call: Call<MovieResponse>, t: Throwable) {
// Code à exécuter en cas d'échec de la requête // Code à exécuter en cas d'échec de la requête
} }
})*/ })
*/
} }
} }

@ -5,49 +5,41 @@ import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import fr.iut.cinecool.interfaces.ITheMovieDbApiCallback
import fr.iut.cinecool.model.Movie
import fr.iut.cinecool.model.MovieAPI
import fr.iut.cinecool.services.TheMovieDbApiClient
import retrofit2.Call
import retrofit2.Response
import javax.security.auth.callback.Callback
class DetailActivity : AppCompatActivity() { class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?){ override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.vu_detail) setContentView(R.layout.vu_detail)
// Récupération de la référence de l'ImageButton // Récupérer l'identifiant du film depuis les extras de l'intent
val backButton: ImageButton =findViewById(R.id.backButton) val movieId = intent.getIntExtra("movieId", -1)
// Ajout d'un listener pour gérer le clic sur le bouton // Appeler la méthode pour charger les détails du film
backButton.setOnClickListener{ // loadMovieDetails(movieId)
// Code à exécuter lorsque l'utilisateur clique sur le bouton de retour
// Par exemple, pour fermer l'activité en cours et revenir à l'activité précédente :
finish()
}
// Récupération de la référence du TextView
val textView: TextView =findViewById(R.id.titreFilm)
// Modification du texte affiché dans le TextView
textView.text="Titre de la page"
// Récupération des références des ImageView
val imageView2: ImageView =findViewById(R.id.logo)
val imageView3:ImageView=findViewById(R.id.afficheFilm)
// Chargement des images à partir de fichiers ou d'Internet, par exemple :
/*Glide.with(this)
.load(R.drawable.cinema)
.into(imageView2)
Glide.with(this)
.load(R.drawable.imitation_game)
.into(imageView3)*/
// Récupération de la référence du TextView 2
val textView2:TextView=findViewById(R.id.description)
// Modification du texte affiché dans le TextView 2
textView2.text="Contenu de la page"
} }
/*private fun loadMovieDetails(movieId: Int) {
val apiClient = TheMovieDbApiClient(getString(R.string.tmdb_api_key))
apiClient.getMovieDetails(movieId, object : ITheMovieDbApiCallback<MovieAPI> {
override fun onSuccess(result: MovieAPI) {
// Afficher les détails du film dans la vue
titreFilm.text = result.title
description.text = result.overview
Picasso.get().load("https://image.tmdb.org/t/p/w500/${result.posterPath}").into(afficheFilm)
}
override fun onError(error: Throwable) {
// Gérer l'erreur de récupération des détails du film
}
})
}*/
} }

@ -0,0 +1,75 @@
package fr.iut.cinecool
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MovieDetailFragment : Fragment() {
/*
private lateinit var binding: FragmentMovieDetailBinding
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?, savedInstanceState: Bundle?): View
{
binding = FragmentMovieDetailBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
val movieId = arguments?.getInt(ARG_MOVIE_ID)
// Appel de l'API pour récupérer les détails du film
CoroutineScope(Dispatchers.IO).launch {
val response = movieId?.let { MovieApiService().getMovieDetails(it) }
withContext(Dispatchers.Main)
{
if (response != null) {
if (response.isSuccessful)
{
val movie = response.body()
if (movie != null)
{
// Affichage des détails du film dans l'interface utilisateur
binding.titreFilm.text = movie.title
binding.description.text = movie.overview
binding.afficheFilm.load("https://image.tmdb.org/t/p/w500${movie.posterPath}") // Utilisation de la librairie Coil pour charger l'image
}
} else
{
Toast.makeText(
requireContext(),
getString(R.string.error_loading_movie),
Toast.LENGTH_SHORT
).show()
}
}
}
}
// Ajout d'un écouteur de clic pour le bouton de retour
binding.backButton.setOnClickListener {
requireActivity().onBackPressed()
}
}
companion object {
private const val ARG_MOVIE_ID = "movie_id"
fun newInstance(movieId: Int): MovieDetailFragment {
val args = Bundle().apply {
putInt(ARG_MOVIE_ID, movieId)
}
return MovieDetailFragment().apply {
arguments = args
}
}
}*/
}

@ -0,0 +1,25 @@
package fr.iut.cinecool
import fr.iut.cinecool.services.TheMovieDbApiClient
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
object RetrofitClient {
private const val BASE_URL = "https://api.themoviedb.org/3/"
private val okHttpClient = OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
val api: TheMovieDbApiClient = retrofit.create(TheMovieDbApiClient::class.java)
}

@ -1,15 +0,0 @@
package fr.iut.cinecool.interfaces
import fr.iut.cinecool.model.Movie
import fr.iut.cinecool.model.MovieResponse
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface ApiService {
@GET("movie/popular")
fun getPopularMovies(@Query("api_key") apiKey: String): Call<MovieResponse>
}

@ -0,0 +1,6 @@
package fr.iut.cinecool.interfaces
interface ITheMovieDbApiCallback<T> {
fun onSuccess(result: T)
fun onError(error: Throwable)
}

@ -0,0 +1,12 @@
package fr.iut.cinecool.interfaces
import fr.iut.cinecool.model.Movie
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface ITheMovieDbService {
@GET("movie/{movieId}")
fun getMovieDetails(@Path("movieId") movieId: Int, @Query("api_key") apiKey: String): Call<Movie>
}

@ -1,7 +0,0 @@
package fr.iut.cinecool.model
import com.google.gson.annotations.SerializedName
// MovieResponse pour stocker la réponse JSON de l'API :
data class MovieResponse(
@SerializedName("results") val movies: List<Movie>
)

@ -0,0 +1,57 @@
package fr.iut.cinecool.services
import fr.iut.cinecool.interfaces.ITheMovieDbApiCallback
import fr.iut.cinecool.interfaces.ITheMovieDbService
import fr.iut.cinecool.model.MovieAPI
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class TheMovieDbApiClient(apiKey: String) {
private val service: ITheMovieDbService = Retrofit.Builder()
.baseUrl("https://api.themoviedb.org/3/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ITheMovieDbService::class.java)
private val apiKeyInterceptor = Interceptor { chain ->
val url = chain.request().url.newBuilder()
.addQueryParameter("tmdb_api_key", apiKey)
.build()
val request = chain.request().newBuilder()
.url(url)
.build()
chain.proceed(request)
}
private val client: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(apiKeyInterceptor)
.build()
/*fun getMovieDetails(movieId: Int, callback: ITheMovieDbApiCallback<MovieAPI>) {
service.getMovieDetails(movieId).enqueue(object : Callback<MovieAPI> {
override fun onResponse(call: Call<MovieAPI>, response: Response<MovieAPI>) {
if (response.isSuccessful) {
val result = response.body()
if (result != null) {
callback.onSuccess(result)
} else {
callback.onError(Throwable("Empty response body"))
}
} else {
callback.onError(Throwable("Error ${response.code()}: ${response.message()}"))
}
}
override fun onFailure(call: Call<MovieAPI>, t: Throwable) {
callback.onError(t)
}
})
}*/
}

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

@ -14,7 +14,7 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/Back_arrow" /> app:srcCompat="@drawable/back_arrow" />
<TextView <TextView
android:id="@+id/titreFilm" android:id="@+id/titreFilm"

@ -41,7 +41,7 @@
android:scaleType="fitCenter" android:scaleType="fitCenter"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/Filtrage" app:srcCompat="@drawable/filtrage"
tools:layout_editor_absoluteY="16dp" tools:layout_editor_absoluteY="16dp"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"

@ -9,4 +9,6 @@
<string name="hello_first_fragment">Hello first fragment</string> <string name="hello_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string> <string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="error_loading_movie">erreur de chargement des films</string>
<string name="tmdb_api_key">a97243d7813d31446f6c43284e6854d5</string>
</resources> </resources>

@ -2,5 +2,5 @@
plugins { plugins {
id 'com.android.application' version '7.4.2' apply false id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '7.4.2' apply false id 'com.android.library' version '7.4.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false id 'org.jetbrains.kotlin.android' version '1.8.20-RC2' apply false
} }
Loading…
Cancel
Save