diff --git a/Android/VeraxApplication/app/build.gradle.kts b/Android/VeraxApplication/app/build.gradle.kts index f7d95bb..cd4f400 100644 --- a/Android/VeraxApplication/app/build.gradle.kts +++ b/Android/VeraxApplication/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + kotlin("plugin.serialization") version "1.5.10" } android { @@ -55,12 +56,19 @@ dependencies { implementation ("com.squareup.retrofit2:retrofit:2.9.0") implementation ("com.squareup.retrofit2:converter-gson:2.9.0") + implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0") + implementation ("androidx.compose.runtime:runtime-livedata:1.0.0-alpha07") + implementation("androidx.core:core-ktx:1.10.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.activity:activity-compose:1.7.0") implementation("androidx.navigation:navigation-compose:2.4.0-alpha08") + implementation ("com.squareup.okhttp3:logging-interceptor:4.9.1") + + implementation ("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") + implementation ("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0") implementation(platform("androidx.compose:compose-bom:2023.08.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") diff --git a/Android/VeraxApplication/app/src/main/AndroidManifest.xml b/Android/VeraxApplication/app/src/main/AndroidManifest.xml index 9088017..b21fe6d 100644 --- a/Android/VeraxApplication/app/src/main/AndroidManifest.xml +++ b/Android/VeraxApplication/app/src/main/AndroidManifest.xml @@ -12,7 +12,10 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.VeraxApplication" - tools:targetApi="31"> + tools:targetApi="31" + android:networkSecurityConfig="@xml/network_security_config" + > + () + + // Observer les données du ViewModel + val articlesViewModel: ArticlesViewModel = viewModel() + + // Observez les articles du ViewModel + val articlesApi by articlesViewModel.articles.observeAsState(initial = articles) var theme = listOf("Economique", "Culture", "Politique", "Faits divers") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - //TopBarVerax(theme = theme, articles = articlesApi) - TopBarVerax(theme = theme, articles = articles) - VeraxNavHost() + TopBarVerax(articles = articlesApi, theme = theme) - } - } -} \ No newline at end of file + + VeraxNavHost() + +} diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleDTO.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleDTO.kt index dc32e47..e0ba6bb 100644 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleDTO.kt +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleDTO.kt @@ -11,33 +11,37 @@ data class ArticleDTO ( val titre: String, @SerializedName("description") val description: String, - @SerializedName("imagePrincipale") - val imagePrincipale: String, + @SerializedName("temps") + val temps: String, @SerializedName("date") val date: String, @SerializedName("auteur") val auteur: String, - @SerializedName("contenu") - val contenu: List, - @SerializedName("temps") - val temps: String, + @SerializedName("categorie") + val categorie: String, + @SerializedName("imagePrincipale") + val imagePrincipale: String, @SerializedName("note") val note: String, + ) { fun toModel(): Article { return Article( id, titre, description, - auteur, + temps, date, + auteur, + categorie, imagePrincipale, - temps, note, - ) + ) } } + + data class ContenuDTO ( @SerializedName("id") val id: Int, diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleRepository.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleRepository.kt deleted file mode 100644 index d635093..0000000 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticleRepository.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.veraxapplication.modele.api - -class ArticleRepository { - -} \ No newline at end of file diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticlesViewModel.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticlesViewModel.kt new file mode 100644 index 0000000..a0a14da --- /dev/null +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/ArticlesViewModel.kt @@ -0,0 +1,54 @@ + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.veraxapplication.modele.api.IArticleService +import com.example.veraxapplication.modele.articles.Article +import kotlinx.coroutines.launch +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +object ArticleApiClient { + private const val BASE_URL = "http://181.214.189.133:9092/" + + private val logging = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + + private val httpClient = OkHttpClient.Builder().apply { + addInterceptor(logging) + }.build() + + val retrofit: Retrofit = Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .client(httpClient) + .build() +} + +class ArticlesViewModel : ViewModel() { + private val _articles = MutableLiveData>() + val articles: LiveData> = _articles + + private val service = ArticleApiClient.retrofit.create(IArticleService::class.java) + + init { + loadArticles() + } + + fun loadArticles() { + viewModelScope.launch { + try { + val articlesDto = service.getArticles() // Pas besoin d'appeler .execute() + // Convertissez les DTO en modèles de données si nécessaire + _articles.value = articlesDto.map { it.toModel() } + } catch (e: Exception) { + Log.e("ArticlesViewModel", "Erreur lors du chargement des articles", e) + } + } + } +} \ No newline at end of file diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleAPI.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleAPI.kt deleted file mode 100644 index 33f0822..0000000 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleAPI.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.veraxapplication.modele.api - -import com.example.veraxapplication.modele.articles.Article -import retrofit2.Call -import retrofit2.http.GET - -interface IArticleAPI { - @GET("articles/") - fun getArticles(): Call> -} \ No newline at end of file diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleService.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleService.kt new file mode 100644 index 0000000..dbe6d71 --- /dev/null +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/api/IArticleService.kt @@ -0,0 +1,8 @@ +package com.example.veraxapplication.modele.api + +import retrofit2.http.GET + +interface IArticleService { + @GET("articles") + suspend fun getArticles(): List +} \ No newline at end of file diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/Article.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/Article.kt index 34ff9f0..cb978c8 100644 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/Article.kt +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/Article.kt @@ -1,6 +1,5 @@ package com.example.veraxapplication.modele.articles -import com.example.veraxapplication.modele.api.ArticleDTO import com.example.veraxapplication.modele.articles.contenus.Contenu class Article( @@ -10,10 +9,11 @@ class Article( val temps: String, val date: String, val auteur: String, + val categorie: String, val note: String, val imagePrincipale: String ) { - private val lContenus: MutableList = java.util.ArrayList() + public val lContenus: MutableList = java.util.ArrayList() init { // Initialisation des contenus si nécessaire diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/StubArticles.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/StubArticles.kt index 1c604ac..d1a1124 100644 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/StubArticles.kt +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/modele/articles/StubArticles.kt @@ -24,8 +24,9 @@ class StubArticles() : IArticlesDataManager { "Thinkerview", "Thinkerview est une chaîne passionnante chaîne youtube d'interview-débat.", "3", - "date a revoir", - "Siwa", + "02/09/2024", + "Tony", + "Politique", "12", "https://cdn.discordapp.com/attachments/1150826798549049554/1219554341388816437/stub1.webp?ex=660bb97d&is=65f9447d&hm=3e1e8d3372ae897fa4e2aa1ec730d976d74b35fce96cb8d78d6f9239e2836564&" ) @@ -38,8 +39,9 @@ class StubArticles() : IArticlesDataManager { "Le réchauffement climatique : un mythe ?", "Revenons sur les différentes controverses à ce sujet.", "7", - "date a revoir", - "Siwa", + "02/09/2024", + "Tony", + "Politique", "12", "https://cdn.discordapp.com/attachments/1150826798549049554/1219555874339815454/stub2.webp?ex=660bbaea&is=65f945ea&hm=80aef945e8410b18395c716fdd19265608f7b1263731192d5c69f807fce9e944&" ) @@ -52,8 +54,9 @@ class StubArticles() : IArticlesDataManager { "La terre plate : vraiment ?", "Pour réfuter la fausse croyance que la Terre est plate, il est essentiel de s'appuyer sur des preuves scientifiques et des observations historiques. ", "5", - "date a revoir", - "Siwa", + "02/09/2024", + "Tony", + "Politique", "12", "https://cdn.discordapp.com/attachments/1150826798549049554/1219547864196317225/stub1.webp?ex=660bb374&is=65f93e74&hm=a9e5dd48faa3ae68c358309af8949c46dfd4dea9c4d6e3d845d707784e5341cf&" @@ -67,8 +70,9 @@ class StubArticles() : IArticlesDataManager { "L'ia & humanité : quel avenir ? ", "Explorons les progrès remarquables dans le domaine de l'IA, les secteurs qu'elle révolutionne, et les implications éthiques majeures qu'elle soulève.", "9", - "date a revoir", - "Luthen", + "02/09/2024", + "Tony", + "Politique", "12", "https://cdn.discordapp.com/attachments/1150826798549049554/1219560686254817290/stub1.webp?ex=660bbf65&is=65f94a65&hm=021bd8c90c89347f31373468cc7a03ae15f1d3f9988a5b4325149c6df938d7bb&" ) diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/article/Article.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/article/Article.kt index 899ae40..96e2c39 100644 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/article/Article.kt +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/article/Article.kt @@ -1,5 +1,6 @@ package com.example.veraxapplication.ui.article +import android.util.Log import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -7,8 +8,10 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -28,6 +31,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.rememberImagePainter import com.example.veraxapplication.modele.articles.Article +import com.example.veraxapplication.modele.articles.contenus.Contenu import com.example.veraxapplication.modele.articles.contenus.ContenuMedia import com.example.veraxapplication.modele.articles.contenus.ContenuParagraphe import com.example.veraxapplication.ui.theme.Salmon @@ -59,21 +63,14 @@ fun AffichageUnArticleInfo(e : Article){ Text(text = e.titre, fontFamily = FontFamily.Serif, fontSize = 30.sp) - Box(modifier = Modifier - .padding(15.dp) - .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp)) - .clip(RoundedCornerShape(10.dp)) - .background(Salmon) - ) { - Column (modifier = Modifier.padding(15.dp)) { - Text(text = "Auteur : "+e.auteur, fontSize = 17.sp) - Text(text = "Description : "+e.description, fontSize = 17.sp) - Text(text = "Temps de lecture : "+e.temps+" minutes", fontSize = 17.sp) - } - } + DisplayHeader(author = e.auteur, description = e.description , lectureTime = e.temps) + + var imageURl = e.note + Log.d("ImageLoad", "URL de l'image reçue de l'API : $imageURl") + Image( painter = rememberImagePainter( - data = e.imagePrincipale + data = imageURl ), contentScale = ContentScale.Crop, contentDescription = null, @@ -107,91 +104,115 @@ fun AfficherArticle(e : Article){ Text(text = e.titre, fontFamily = FontFamily.Serif, fontSize = 30.sp) - Box( - modifier = Modifier - .padding(15.dp) - .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp)) - .clip(RoundedCornerShape(10.dp)) - .background(Salmon) - ) { - Column(modifier = Modifier.padding(15.dp)) { - Text(text = "Auteur : "+e.auteur, fontSize = 17.sp) - Text(text = "Description : "+e.description, fontSize = 17.sp) - Text(text = "Temps de lecture : " + e.temps + " minutes", fontSize = 17.sp) - } - } + // Affichage des informations de l'article + DisplayHeader(author = e.auteur, description = e.description, lectureTime = e.temps) + + Text(text = "coucou") + +/* Image( - painter = rememberImagePainter( - data = e.imagePrincipale - ), - contentScale = ContentScale.Crop, + painter = rememberImagePainter(data = e.imagePrincipale), + contentScale = ContentScale.FillHeight, contentDescription = null, modifier = Modifier .size(350.dp) - .align(Alignment.CenterHorizontally) .padding(5.dp, 35.dp) - ) - + .fillMaxWidth() + .wrapContentWidth(Alignment.CenterHorizontally) + )*/ + - Column (modifier = Modifier.align(Alignment.Start)){ - for (text in e.contenus){ - when(text){ - is ContenuMedia -> { - Text(text = text.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold) - when(text.typeContenu){ - "image" -> { - Image( - painter = rememberImagePainter( - data = text.lien - ), - contentScale = ContentScale.FillHeight , - contentDescription = null, - modifier = Modifier - .size(350.dp) - .align(Alignment.CenterHorizontally) - .padding(5.dp, 35.dp) - ) - } - "video" -> { - Text(text = "Ici une video ..."+ text.toString(), fontSize = 15.sp, textAlign = TextAlign.Start) - //faut je vois comment on fait pour inclure une video ... - } - } + // Affichage contenus + //DisplayContenu(e.lContenus) + + + } +} +@Composable +fun DisplayHeader(author: String, description: String, lectureTime: String) { + Box( + modifier = Modifier + .padding(15.dp) + .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp)) + .clip(RoundedCornerShape(10.dp)) + .background(Salmon) + ) { + Column(modifier = Modifier.padding(15.dp)) { + Text(text = "Auteur : "+ author, fontSize = 17.sp) + Text(text = "Description : "+ description, fontSize = 17.sp) + Text(text = "Temps de lecture : " + lectureTime + " minutes", fontSize = 17.sp) + } + } +} +@Composable +fun DisplayContenu(contenus: List) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + for (contenu in contenus) { + when (contenu) { + is ContenuMedia -> { + Text(text = contenu.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold) + when (contenu.typeContenu) { + "image" -> { + Image( + painter = rememberImagePainter(data = contenu.lien), + contentScale = ContentScale.FillHeight, + contentDescription = null, + modifier = Modifier + .size(350.dp) + .padding(5.dp, 35.dp) + .fillMaxWidth() + .wrapContentWidth(Alignment.CenterHorizontally) // Centrer l'image + ) + } + "video" -> { + // Pour l'instant, un simple texte pour les vidéos + Text(text = "Ici une vidéo ... ${contenu.lien}", fontSize = 15.sp, textAlign = TextAlign.Start) + // Implémentation pour vidéo à venir... + } } - is ContenuParagraphe ->{ - Text(text = text.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold) - Text(text = text.toString(), fontSize = 16.sp, textAlign = TextAlign.Start) - } + } + is ContenuParagraphe -> { + Text(text = contenu.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold) + Text(text = contenu.texte, fontSize = 16.sp, textAlign = TextAlign.Start) } } } } } + /* @Composable fun DisplayImage(image: String) { - Log.d("DisplayImage", "Chargement de l'image à partir de l'URL : $image") + Image( + painter = rememberImagePainter( + data = image + ), + contentScale = ContentScale.Crop, + contentDescription = null, + modifier = Modifier + .size(350.dp) + .align(Alignment.CenterHorizontally) + .padding(5.dp, 35.dp) + ) +} - Log.d("DisplayImage", "Painter créé avec succès") - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Image( +@Composable +fun DisplayImage(image: String) { + Image( painter = rememberImagePainter( - data = image, - builder = { - scale(Scale.FILL) - } + data = e.imagePrincipale ), + contentScale = ContentScale.Crop, contentDescription = null, - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .size(350.dp) + .align(Alignment.CenterHorizontally) + .padding(5.dp, 35.dp) ) - } } diff --git a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/topBar/TopBarVerax.kt b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/topBar/TopBarVerax.kt index 5a48c80..f91a239 100644 --- a/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/topBar/TopBarVerax.kt +++ b/Android/VeraxApplication/app/src/main/java/com/example/veraxapplication/ui/topBar/TopBarVerax.kt @@ -35,7 +35,6 @@ import androidx.compose.ui.unit.sp import com.example.veraxapplication.R import com.example.veraxapplication.modele.articles.Article import com.example.veraxapplication.ui.article.AffichageLesArticles -import com.example.veraxapplication.ui.article.AfficherArticle import com.example.veraxapplication.ui.theme.Orange @OptIn(ExperimentalMaterial3Api::class) diff --git a/Android/VeraxApplication/app/src/main/res/xml/network_security_config.xml b/Android/VeraxApplication/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..1208de3 --- /dev/null +++ b/Android/VeraxApplication/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + 181.214.189.133 + + \ No newline at end of file