Compare commits

...

22 Commits

@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
kotlin("plugin.serialization") version "1.5.10"
}
android {
@ -51,14 +52,35 @@ android {
dependencies {
// Retrofit
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 ("androidx.media3:media3-session:1.3.0")
implementation("com.google.android.exoplayer:exoplayer-core:2.19.1")
implementation ("com.google.android.exoplayer:exoplayer-ui:2.19.1")
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")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("com.google.firebase:firebase-crashlytics-buildtools:2.9.9")
implementation("androidx.navigation:navigation-compose:2.8.0-alpha05")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
@ -66,6 +88,8 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation("io.coil-kt:coil-compose:1.4.0")
}

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools"
>
<application
android:allowBackup="true"
@ -11,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"
>
<activity
android:name=".MainActivity"
android:exported="true"
@ -24,5 +28,6 @@
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

@ -1,181 +1,63 @@
package com.example.veraxapplication
import android.graphics.Paint.Align
import ArticlesViewModel
import IUsersDataManager
import StubUsers
import android.os.Bundle
import android.text.Layout
import android.view.Menu
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.ui.graphics.Color
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults.containerColor
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.runtime.livedata.observeAsState
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.veraxapplication.modele.IArticlesDataManager
import com.example.veraxapplication.articles.StubArticles
import com.example.veraxapplication.modele.api.UsersViewModel
import com.example.veraxapplication.navigation.VeraxNavHost
import com.example.veraxapplication.ui.connexion.AfficherForm
import com.example.veraxapplication.ui.topBar.TopBarVerax
// doc navBar: https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#TopAppBar(kotlin.Function0,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,androidx.compose.foundation.layout.WindowInsets,androidx.compose.material3.TopAppBarColors,androidx.compose.material3.TopAppBarScrollBehavior)
// doc compose, pleins de trucs: https://developer.android.com/jetpack/compose/text?hl=fr
//doc couleur background pas finie: https://developer.android.com/jetpack/compose/components/scaffold
class MainActivity : ComponentActivity() {
// un truc vite fait pour avoir un visi
var article = listOf("Thinkerview", "thinkerview.jgp", "Thinkerview est une chaîne youtube d'interview-débat")
var theme = listOf("Economique","Culture","Politique","Faits divers")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TopBarVerax(theme = theme, article = article)
// allez sur la doc de Scaffold sur Android Dev et si vous comprenez comment on doit faire bien ouej
VeraxContent()
}
}
}
// Il faudrait mettre ca dans un fichier appart mais je connais plus les conventions ...
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBarVerax(theme : List<String>, article : List<String>) {
var leMenu by remember {
mutableStateOf(false)
}
Row(
Modifier.background(Color.Cyan)
) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
text = "Verax",
style = TextStyle(fontSize = 35.sp),
color = colorResource(R.color.red),
textAlign = TextAlign.Center,
/*backcolor = topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer),*/ //version recommandée par le prof
modifier = Modifier.fillMaxWidth()
)
},
navigationIcon = {
IconButton(onClick = { /* action() */ }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Retour",
Modifier.size(30.dp)
)
}
},
actions = {
IconButton(onClick = { leMenu = !leMenu }) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "Menu",
Modifier.size(35.dp)
)
}
DropdownMenu(
expanded = leMenu, onDismissRequest = { leMenu = false },
modifier = Modifier
.background(Color.hsl(0.08F, 1F, 0.96F))
) {
theme.sorted().forEach {
DropdownMenuItem(
text = {
Text(
it,
style = TextStyle(fontSize = 25.sp),
modifier = Modifier
.padding(10.dp)
)
},
onClick = { /* faut un moyen d'appeler une methode diff pour chaque, ca doit etre faisable facilement */ }
)
}
}
}
)
},
bottomBar = {
// Faudrait pouvoir faire un flex sur les boutons parce que là ils sont juste côte à côte
BottomAppBar(containerColor = Color.Black, contentColor = Color.White) {
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Filled.Home,
contentDescription = "Home",
Modifier.size(35.dp)
)
}
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Filled.Person,
contentDescription = "Account",
Modifier.size(35.dp)
)
}
}
}
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
AffichageUnArticle(article = article)
}
}
}
}
fun VeraxContent() {
@Composable
fun AffichageUnArticle(article : List<String>){
Column {
for(e in article){
Text(text = e)
}
}
// Initialiser les données ou observer les données du ViewModel
var dataManager: IArticlesDataManager = StubArticles()
var articles = dataManager.getDerniersArticles(4)
var usersManager: IUsersDataManager = StubUsers()
var users = usersManager.getUsers();
// Observer les données du ViewModel
val articlesViewModel: ArticlesViewModel = viewModel()
// Observez les articles du ViewModel
val articlesApi by articlesViewModel.articles.observeAsState(initial = articles)
val usersViewModel: UsersViewModel = viewModel()
val usersApi by usersViewModel.users.observeAsState(initial = users)
var theme = listOf("Economique", "Culture", "Politique", "Faits divers")
TopBarVerax(articles = articlesApi, theme = theme, articlesStub= articles)
}

@ -0,0 +1,11 @@
package com.example.veraxapplication.data
/*
data class Article(
var Title : String,
var Description : String,
var Image : String,
var Author : String,
var Content : List<Paragraph>,
var LectureTime : String
)
*/

@ -0,0 +1,6 @@
package com.example.veraxapplication.data
/*
data class Paragraph(
var Content : String,
)
*/

@ -0,0 +1,11 @@
package com.example.veraxapplication.modele
import com.example.veraxapplication.modele.articles.Article
interface IArticlesDataManager {
val allArticles: List<Any?>?
fun getArticle(id: Int): Article?
fun getDerniersArticles(nbArticles: Int): List<Article>
}

@ -0,0 +1,9 @@
import com.example.veraxapplication.modele.user.User
interface IUsersDataManager {
val allUsers: List<Any?>?
fun getUser(pseudo : String): User?
fun getUsers(): List<User>
}

@ -0,0 +1,53 @@
package com.example.veraxapplication.modele.api
import com.example.veraxapplication.modele.articles.Article
import com.google.gson.annotations.SerializedName
data class ArticleDTO (
@SerializedName("id")
val id: Int,
@SerializedName("titre")
val titre: String,
@SerializedName("description")
val description: String,
@SerializedName("temps")
val temps: String,
@SerializedName("date")
val date: String,
@SerializedName("auteur")
val auteur: String,
@SerializedName("categorie")
val categorie: String,
@SerializedName("imagePrincipale")
val imagePrincipale: String,
@SerializedName("note")
val note: String,
) {
fun toModel(): Article {
return Article(
id,
titre,
description,
temps,
date,
auteur,
categorie,
imagePrincipale,
note,
)
}
}
data class ContenuDTO (
@SerializedName("id")
val id: Int,
@SerializedName("typeContenu")
val typeContenu: String,
@SerializedName("titre")
val titre: String,
@SerializedName("texte")
val texte: String,
)

@ -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<List<Article>>()
val articles: LiveData<List<Article>> = _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)
}
}
}
}

@ -0,0 +1,8 @@
package com.example.veraxapplication.modele.api
import retrofit2.http.GET
interface IArticleService {
@GET("articles")
suspend fun getArticles(): List<ArticleDTO>
}

@ -0,0 +1,11 @@
package com.example.veraxapplication.modele.api
import com.example.veraxapplication.modele.user.User
import retrofit2.Call
import retrofit2.http.GET
interface IUserService {
@GET("users")
suspend fun getUsers(): List<UserDTO>
}

@ -0,0 +1,32 @@
package com.example.veraxapplication.modele.api
import com.example.veraxapplication.modele.user.User
import com.google.gson.annotations.SerializedName
data class UserDTO (
@SerializedName("pseudo")
val pseudo: String,
@SerializedName("mdp")
val mdp: String,
@SerializedName("mail")
val mail: String,
@SerializedName("nom")
val nom: String,
@SerializedName("prenom")
val prenom: String,
@SerializedName("role")
val role: String,
) {
fun toModel(): User {
return User(
pseudo,
mdp,
mail,
nom,
prenom,
role,
)
}
}

@ -0,0 +1,63 @@
package com.example.veraxapplication.modele.api
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.articles.Article
import com.example.veraxapplication.modele.user.User
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClientUser {
private const val BASE_URL = "https://codefirst.iut.uca.fr/containers/Verax-verax-api"
private val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
private val httpClient = OkHttpClient.Builder().apply {
addInterceptor(logging)
}.build()
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
// interface UserApiService {
// @GET("users")
// suspend fun getUsers() : List<User>
// }
}
class UsersViewModel : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
private val service = ArticleApiClient.retrofit.create(IUserService::class.java)
init {
loadUsers()
}
fun loadUsers() {
viewModelScope.launch {
try {
val usersDto = service.getUsers() // Pas besoin d'appeler .execute()
// Convertissez les DTO en modèles de données si nécessaire
_users.value = usersDto.map { it.toModel() }
} catch (e: Exception) {
Log.e("UsersViewModel", "Erreur lors du chargement des users", e)
}
}
}
}

@ -0,0 +1,36 @@
package com.example.veraxapplication.modele.articles
import com.example.veraxapplication.modele.articles.contenus.Contenu
class Article(
val id: Int,
val titre: String,
val description: String,
val temps: String,
val date: String,
val auteur: String,
val categorie: String,
val imagePrincipale: String,
val note: String
) {
public val lContenus: MutableList<Contenu> = java.util.ArrayList()
init {
// Initialisation des contenus si nécessaire
}
fun remplirArticle(lContenus: List<Contenu>?) {
if (lContenus != null) {
this.lContenus.addAll(lContenus)
}
}
val contenus: List<Any>
get() = lContenus
override fun toString(): String {
return "Article(id=$id, titre='$titre', description='$description', temps='$temps', date='$date', auteur='$auteur', imagePrincipale='$imagePrincipale', note=$note, contenus=${lContenus.size} contenus)"
}
}

@ -0,0 +1,442 @@
package com.example.veraxapplication.articles
import com.example.veraxapplication.modele.IArticlesDataManager
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
class StubArticles() : IArticlesDataManager {
private var lArticles: MutableList<Article>? = null
init {
chargerArticles()
}
private fun chargerArticles() {
lArticles = java.util.ArrayList<Article>()
val contenuMap: Map<String, List<Contenu>> = chargerContenuParagraphe()
// Article 1
val article1 = Article(
1,
"Thinkerview",
"Thinkerview est une chaîne passionnante chaîne youtube d'interview-débat.",
"3",
"02/09/2024",
"Siwa",
"Politique",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219554341388816437/stub1.webp?ex=660bb97d&is=65f9447d&hm=3e1e8d3372ae897fa4e2aa1ec730d976d74b35fce96cb8d78d6f9239e2836564&",
"12"
)
article1.remplirArticle(contenuMap["article1"])
lArticles!!.add(article1)
// Article 2
val article2 = Article(
2,
"Le réchauffement climatique : un mythe ?",
"Revenons sur les différentes controverses à ce sujet.",
"7",
"02/09/2024",
"Siwa",
"Politique",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219555874339815454/stub2.webp?ex=660bbaea&is=65f945ea&hm=80aef945e8410b18395c716fdd19265608f7b1263731192d5c69f807fce9e944&",
"12"
)
article2.remplirArticle(contenuMap["article5"])
lArticles!!.add(article2)
// Article 4
val article3 = Article(
3,
"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",
"02/09/2024",
"Siwa",
"Politique",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219547864196317225/stub1.webp?ex=660bb374&is=65f93e74&hm=a9e5dd48faa3ae68c358309af8949c46dfd4dea9c4d6e3d845d707784e5341cf&",
"12"
)
article3.remplirArticle(contenuMap["article4"])
lArticles!!.add(article3)
// Article 4
val article4 = Article(
4,
"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",
"02/09/2024",
"Luthen",
"Politique",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219560686254817290/stub1.webp?ex=660bbf65&is=65f94a65&hm=021bd8c90c89347f31373468cc7a03ae15f1d3f9988a5b4325149c6df938d7bb&",
"12"
)
article4.remplirArticle(contenuMap["article6"])
lArticles!!.add(article4)
}
private fun chargerContenuParagraphe(): Map<String, List<Contenu>> {
val contenuMap: MutableMap<String, List<Contenu>> = HashMap<String, List<Contenu>>()
val article1Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
val article2Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
val article3Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
val article4Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
val article5Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
val article6Contenus: MutableList<Contenu> = java.util.ArrayList<Contenu>()
// Contenu de l'article 1
article1Contenus.add(
ContenuParagraphe(
1, "Le mystérieux cygne noir.",
"Sous les traits dun mystérieux cygne noir, un objet vidéo non identifié plane dans la galaxie " +
" médiatique. Ambiance Star Wars. Après une musique lancinante, sur fond noir et fumée grisâtre," +
" un invité apparaît, et la voix dun intervieweur-mystère situé hors champ linvite à se" +
" présenter « succinctement ». Cest ainsi quon entre dans le monde de ThinkerView," +
" chaîne qui a commencé à diffuser en janvier 2013 sur YouTube. Ici, pas de publicité," +
" pas de montage, pas deffets de lumière. Le calme, peut-être pour annoncer la tempête."
)
)
article1Contenus.add(
ContenuMedia(
0,
"Des sujets majeurs abordés",
"https://www.systext.org/sites/default/files/styles/large/public/Ill_Thinkerview_Janv2022.png?itok=JvlFQmCH"
)
)
article1Contenus.add(
ContenuParagraphe(
2, "Penser, réfléchir et s'exprimer librement.",
("Dernier carton en date : un entretien de deux heures avec Juan Branco, lavocat du gilet" +
" jaune Maxime Nicolle et « conseiller juridique » de Wikileaks. Quelques jours avant lui," +
" cétait au tour de François Boulo, autre avocat inscrit au barreau de Rouen et lun des" +
" porte-parole des « gilets jaunes ». « Ici, les gens ont vraiment le temps de développer" +
" leurs idées, confie Boulo. Il faut pouvoir écouter une pensée complète, sans être interrompu." +
" » Aux yeux de ce fils dune famille de droite populaire (paysans et commerçants), ThinkerView" +
" a réalisé ce dont Pierre Bourdieu avait rêvé. Sil sabreuve à cette source depuis « un an ou" +
" deux », en réalité, ce nest pas lui qui la trouvée, mais linverse. Magie des algorithmes.")
)
)
article1Contenus.add(
ContenuMedia(
1,
"De prestigieux et fascinants invités",
"https://i.ytimg.com/vi/_D-AnsdbnRI/maxresdefault.jpg"
)
)
article1Contenus.add(
ContenuParagraphe(
3, "Une alternative dans un monde aux informations formatées",
("\\\"Nous faisons des interviews aux perspectives alternatives dans un monde aux informations formatées\\\"," +
" explique le site Thinkerview. La marque a adopté un cygne noir comme logo, un clin d'œil à la théorie" +
" du cygne noir (expliquée dans cet article de Challenges), soit un événement qui a peu de" +
" chances de se produire mais qui, s'il se produit, a des conséquences considérables." +
"\n" +
" Les invités viennent d'horizons divers avec une petite préférence pour les" +
" intellectuels iconoclastes et les contestataires de tous bords, de l'ancien" +
" ministre grec Yanis Varoufakis à l'historien et essayiste Emmanuel Todd, en" +
" passant par les journalistes Natacha Polony et Laurent Obertone ou encore" +
" la coqueluche des \\\"gilets jaunes\\\" Etienne Chouard. \\\"On est au milieu de" +
" toutes les communautés qui s'écharpent sur internet, de l'extrême droite à" +
" l'extrême gauche, explique Sky. On cherche à créer un terrain neutre pour" +
" que tout le monde puisse échanger.")
)
)
article1Contenus.add(
ContenuMedia.newVideo(
2,
"Prendre le temps d'écouter les experts dans leurs domaines.",
"https://www.youtube.com/embed/1tTksQL2kqs"
)
)
// Contenu de l'article 2
article2Contenus.add(
ContenuParagraphe(
1, "Oui les Ukrainiens reprennent du terrain",
"Timéo demande à Eric Biegala, grand reporter à la rédaction internationale de Radio France..."
)
)
article2Contenus.add(
ContenuMedia(
1,
"Des violents affrontements",
"https://images.ladepeche.fr/api/v1/images/view/655a496a7097bc144658af8c/large/image.jpg?v=1"
)
)
article2Contenus.add(
ContenuParagraphe(
2, "Non les rayons ne seront pas vides cet hiver",
"Lorenzo se demande s'il est vrai \"qu'il y aura une pénurie de produits étrangers cet hiver\"..."
)
)
article2Contenus.add(
ContenuMedia(
2, "Une carte en perpétuelle évolution",
"https://ds1.static.rtbf.be/image/media/object/default/16x9/1920x1080/4/e/6/4e67668ff30a378cbf0a9172f92712a7.jpg"
)
)
article2Contenus.add(
ContenuParagraphe(
3, "Le gaz va augmenter en 2023, mais l'Etat va continuer à aider",
"Isra se demande s'il est vrai \"que le gaz va être plus cher cet hiver\"..."
)
)
// Contenu de l'article 3
article3Contenus.add(
ContenuParagraphe(
1, "Une certaine \"tempête Jinette\" en Guyane",
"Ne vous laissez pas convaincre par les nuages et les pluies au-dessus de l'île de Cayenne ce matin..."
)
)
article3Contenus.add(
ContenuMedia(
1, "Pour aujourd'hui, la vigilance est au vert en Guyane.",
"https://medias.franceantilles.fr/api/v1/images/view/6560a041c9b8a232734f9fda/width_1000/image.jpg"
)
)
article3Contenus.add(
ContenuParagraphe(
2, "De simples petites averses en prévision !",
"Les quelques averses qui passent actuellement au-dessus de l'île de Cayenne et des savanes ne sont que passagères..."
)
)
article3Contenus.add(
ContenuMedia(
2, "Le faux document en question. Diffusé depuis hier soir.",
"https://medias.franceantilles.fr/api/v1/images/view/6560b08a04eeb6664b7f5488/width_1000/image.jpg"
)
)
// contenu article 4
article4Contenus.add(
ContenuParagraphe(
1,
"Introduction",
"Depuis l'antiquité, l'humanité s'est questionnée sur la forme de la Terre. Malgré la croyance populaire que les anciens pensaient la Terre plate, de nombreux philosophes, mathématiciens et astronomes de différentes cultures avaient déjà conclu que la Terre était sphérique. La théorie de la Terre plate, cependant, persiste dans certains cercles aujourd'hui, malgré une abondance de preuves contraires."
)
)
article4Contenus.add(
ContenuMedia(
1,
"la terre plate : un vieux mythe",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219547863709913128/stub2.webp?ex=660bb374&is=65f93e74&hm=bd349fe6896af98f169987089ff1527a515129d9582c1cf8399e3d4ee35d0e31&"
)
)
article4Contenus.add(
(ContenuParagraphe(
2,
"Preuves historiques de la sphéricité de la Terre",
("Observations des éclipses lunaires : Les éclipses lunaires se produisent lorsque la Terre se trouve entre le Soleil et la Lune, projetant son ombre sur la Lune. Cette ombre est toujours ronde, ce qui suggère fortement que la Terre est sphérique.\n" +
"\n" +
"Expérience de l'horizon : Lorsqu'on observe un navire s'éloigner en mer, il semble disparaître progressivement, avec la coque qui disparaît en premier et les voiles en dernier. Cela ne pourrait se produire si la Terre était plate.\n" +
"\n" +
"Variation de la gravité : La gravité agit de manière uniforme autour d'une sphère, attirant tout vers le centre. Si la Terre était plate, la gravité agirait différemment et nous le remarquerions dans nos déplacements et nos observations.\n" +
"\n" +
"Photographies de l'espace : Depuis le XXe siècle, l'humanité a pu observer la Terre depuis l'espace, confirmant sans ambiguïté sa forme sphérique grâce à des milliers de photographies.")
))
)
article4Contenus.add(
ContenuParagraphe(
3, "Preuves scientifiques contemporaines",
("Satellites et GPS : Le fonctionnement du système de positionnement global (GPS) repose sur l'existence de satellites orbitant autour d'une Terre sphérique. La précision de ce système serait impossible sur une Terre plate.\n" +
"\n" +
"Vols aériens : Les trajets des avions et leur temps de vol s'expliquent par la courbure de la Terre. Les routes aériennes utilisent souvent ce qu'on appelle des \"routes orthodromiques\", qui sont les chemins les plus courts entre deux points sur une sphère, indiquant encore la forme sphérique de la Terre.\n" +
"\n" +
"La physique de Newton et la gravitation universelle : Les lois du mouvement de Newton et sa théorie de la gravitation universelle ne peuvent s'expliquer que si la Terre est une sphère. Ces théories ont été vérifiées à de multiples reprises par des expériences et des observations.")
)
)
article4Contenus.add(
ContenuParagraphe(
4, "Explications et réfutations des arguments des platistes",
("La question de l'horizon toujours à niveau : Les platistes argumentent souvent que si la Terre était ronde, l'horizon ne semblerait pas toujours plat. Cependant, cela s'explique par la taille massive de la Terre par rapport à notre champ de vision. La courbure est trop légère pour être perçue à l'œil nu sur de courtes distances.\n" +
"\n" +
"La théorie de la conspiration de la NASA : Un argument fréquent est que les images de la Terre depuis l'espace sont des faux. Cependant, des agences spatiales du monde entier, y compris celles de pays en conflit ou en compétition, ont fourni des images cohérentes de la Terre.\n" +
"\n" +
"Les expériences de niveau d'eau et de laser : Certains platistes utilisent des expériences de niveau d'eau ou de laser sur de longues distances pour prouver que la Terre est plate. Ces expériences ne tiennent cependant pas compte de la réfraction atmosphérique ou de la précision des instruments utilisés.")
)
)
article4Contenus.add(
ContenuMedia(
1,
"Une planete observée",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219547863139483698/stub3.webp?ex=660bb374&is=65f93e74&hm=26eac72039dc1d65bebfaa5e90972c0c0177c9d281121f58d33757419586bb62&"
)
)
article4Contenus.add(
ContenuParagraphe(
5,
"Conclusion",
"La croyance que la Terre est plate est contredite par une multitude de preuves et d'observations faites au fil des millénaires. De la science ancienne aux technologies modernes, chaque preuve renforce la conclusion que la Terre est une sphère. La science et l'observation directe nous fournissent une compréhension claire de notre monde, nous permettant de rejeter les mythes et les désinformations tels que la théorie de la Terre plate."
)
)
// article 5
article5Contenus.add(
ContenuParagraphe(
1,
"Introduction",
"Le réchauffement climatique fait référence à l'augmentation à long terme de la température moyenne de l'atmosphère terrestre et des océans. Cette tendance, principalement attribuée aux activités humaines depuis la révolution industrielle, entraîne des changements climatiques significatifs et potentiellement irréversibles. Les preuves de ce phénomène sont multiples et incluent des données atmosphériques, océaniques et terrestres."
)
)
article5Contenus.add(
ContenuParagraphe(
2, "Causes du réchauffement climatique",
("Émissions de gaz à effet de serre (GES) : La principale cause du réchauffement climatique est l'augmentation des émissions de GES, notamment le dioxyde de carbone (CO2), le méthane (CH4) et le protoxyde d'azote (N2O), résultant de la combustion des combustibles fossiles, de la déforestation, de l'agriculture intensive et de l'industrie.\n" +
"\n" +
"Déforestation : La réduction des forêts mondiales diminue la capacité de la Terre à absorber le CO2 de l'atmosphère, exacerbant ainsi l'effet de serre.\n" +
"\n" +
"Agriculture et élevage : Ces activités contribuent significativement aux émissions de CH4 et de N2O, à travers la fermentation entérique des ruminants et l'utilisation d'engrais chimiques.")
)
)
article5Contenus.add(
ContenuMedia(
1,
"Un chaos annoncé.",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219555873253490698/stub4.webp?ex=660bbaea&is=65f945ea&hm=d19e48c6ada7d824a9d7f859f657d5a81135dc2817f5791ac7e4f308369e1dc2&"
)
)
article5Contenus.add(
ContenuParagraphe(
3, "Conséquences du réchauffement climatique",
("Changements météorologiques extrêmes : L'augmentation de la température entraîne des vagues de chaleur plus fréquentes et plus intenses, des tempêtes plus violentes, des sécheresses et des inondations.\n" +
"\n" +
"Montée des eaux : La fonte des glaciers et des calottes glaciaires, ainsi que l'expansion thermique des océans, entraînent une élévation du niveau de la mer, menaçant les zones côtières et les îles basses.\n" +
"\n" +
"Perturbation des écosystèmes : Le réchauffement climatique affecte la biodiversité, avec des espèces contraintes de migrer, de s'adapter ou risquant l'extinction.\n" +
"\n" +
"Impacts sur la santé humaine : Les vagues de chaleur, la pollution atmosphérique et la propagation de maladies vectorielles sont exacerbées par le changement climatique, posant des risques accrus pour la santé humaine.")
)
)
article5Contenus.add(
ContenuParagraphe(
4, "Solutions au réchauffement climatique",
("Réduction des émissions de GES : Limiter les émissions à travers l'adoption de technologies propres, l'amélioration de l'efficacité énergétique et le développement des énergies renouvelables.\n" +
"\n" +
"Séquestration du carbone : Reboiser et restaurer les écosystèmes naturels pour augmenter l'absorption de CO2 de l'atmosphère.\n" +
"\n" +
"Innovation technologique : Développer et déployer des technologies de capture et de stockage du carbone, ainsi que des solutions d'énergie renouvelable avancées.\n" +
"\n" +
"Action politique globale : Mettre en œuvre des accords internationaux, comme l'Accord de Paris, pour coordonner les efforts mondiaux de lutte contre le changement climatique.\n" +
"\n" +
"Sensibilisation et éducation : Informer le public sur les causes et les conséquences du réchauffement climatique et sur les moyens d'agir à titre individuel et collectif.")
)
)
article5Contenus.add(
ContenuMedia(
1,
"Un avenir à écrire",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219555873710542909/stub3.webp?ex=660bbaea&is=65f945ea&hm=8e702e51a2e4defba269341894a2d70dfc9d52de453ded2b0ad131d8e367aa41&"
)
)
article5Contenus.add(
ContenuParagraphe(
5,
"Conclusion",
"Le réchauffement climatique est une urgence planétaire qui exige une action immédiate et concertée. Les preuves scientifiques sont indéniables et montrent que les activités humaines sont la principale cause de ce phénomène. En adoptant des mesures de mitigation et d'adaptation, en innovant dans les technologies propres et en travaillant ensemble à tous les niveaux de la société, nous pouvons faire face à ce défi et assurer un avenir durable pour les générations futures. Il est impératif d'agir maintenant pour prévenir les pires conséquences du changement climatique."
)
)
// Article 6
article6Contenus.add(
ContenuParagraphe(
1,
"Introduction",
"L'IA désigne les systèmes ou machines capables de réaliser des tâches nécessitant une intelligence humaine. Ces dernières années, des progrès substantiels ont été réalisés, notamment grâce à des techniques comme l'apprentissage profond (deep learning), permettant aux machines de traiter et d'analyser de grandes quantités de données de manière plus efficace que jamais."
)
)
article6Contenus.add(
ContenuParagraphe(
2, "Secteurs Transformés par l'IA",
("Santé : L'IA est utilisée pour diagnostiquer des maladies plus rapidement et avec plus de précision, personnaliser les traitements et même prédire les risques de maladies avant qu'elles ne surviennent.\n" +
"Automobile : Les technologies d'IA sont au cœur du développement des véhicules autonomes, promettant de réduire les accidents de la route causés par l'erreur humaine.\n" +
"Finance : L'IA transforme le secteur financier en optimisant les opérations, en détectant les fraudes et en personnalisant les services pour les clients.\n" +
"Environnement : Grâce à l'IA, nous pouvons mieux comprendre les changements climatiques, optimiser la consommation d'énergie et développer des solutions plus durables.")
)
)
article6Contenus.add(
ContenuMedia(
1,
"Quel avenir ?",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219560685592248320/stub2.webp?ex=660bbf65&is=65f94a65&hm=5c6ccd06b39526391826a74ad178f1b56711d6eadcc3625a380d4f6f37e34b2a&"
)
)
article6Contenus.add(
ContenuParagraphe(
3,
"Implications Éthiques de l'IA",
("Les avancées de l'IA ne sont pas sans soulever d'importantes questions éthiques :\n" +
"\n" +
"Vie privée et surveillance : L'utilisation accrue de l'IA dans la surveillance pose des questions sur le droit à la vie privée et la possibilité d'une surveillance de masse.\n" +
"Sécurité : Les technologies d'IA, en particulier les armes autonomes, soulèvent des préoccupations en matière de sécurité mondiale et de contrôle humain sur les machines.\n" +
"Biais et discrimination : Les systèmes d'IA peuvent perpétuer ou même exacerber les biais sociaux et raciaux s'ils ne sont pas correctement conçus et surveillés.\n" +
"Emploi et économie : L'automatisation poussée par l'IA menace de perturber le marché du travail, posant des questions sur le futur de l'emploi et l'équité économique.")
)
)
article6Contenus.add(
ContenuMedia(
1,
"IA et humains égaux ?",
"https://cdn.discordapp.com/attachments/1150826798549049554/1219560881621569606/stub3.webp?ex=660bbf94&is=65f94a94&hm=5242c98d2c475bf05990e1b921ea5cc112cb6dded11ae28001fd777d8cb3b7ec&"
)
)
article6Contenus.add(
ContenuParagraphe(
4,
"Naviguer dans l'Avenir de l'IA",
("Pour maximiser les bénéfices de l'IA tout en minimisant ses risques, une approche multidisciplinaire est nécessaire, impliquant des experts en technologie, en éthique, en droit et dans d'autres domaines clés. Les principes suivants pourraient guider le développement responsable de l'IA :\n" +
"\n" +
"Transparence : Les processus de prise de décision de l'IA devraient être transparents, permettant une compréhension et une confiance accrues.\n" +
"Équité : Des mesures doivent être prises pour s'assurer que les systèmes d'IA traitent tous les individus équitablement et sans discrimination.\n" +
"Sécurité : La sécurité doit être une priorité à toutes les étapes du développement et de l'implémentation de l'IA.\n" +
"Responsabilité : Les développeurs et les utilisateurs d'IA doivent être tenus responsables des impacts de leurs systèmes.")
)
)
article6Contenus.add(
ContenuParagraphe(
5,
"Conclusion",
"Les avancées de l'IA offrent des possibilités extraordinaires pour le progrès humain, mais elles exigent aussi une réflexion profonde sur les valeurs que nous souhaitons préserver dans une ère de plus en plus automatisée. En abordant les défis éthiques avec sérieux et en collaborant à l'échelle mondiale, nous pouvons orienter le développement de l'IA vers un avenir qui reflète le meilleur de l'humanité."
)
)
// -=-=-=-=
contenuMap.put("article1", article1Contenus)
contenuMap.put("article2", article2Contenus)
contenuMap.put("article3", article3Contenus)
contenuMap.put("article4", article4Contenus)
contenuMap.put("article5", article5Contenus)
contenuMap.put("article6", article6Contenus)
return contenuMap
}
override val allArticles: List<Article>? // Assurez-vous que lArticles est bien une liste d'Article et non pas une liste de Any?
get() = lArticles
override fun getArticle(id: Int): Article? {
println("Passage dans getArticle avec comme id : $id")
lArticles?.let {
println("Nombre d'articles disponibles : ${it.size}")
val articleARenvoyer: Article? = it.find { article -> article.id == id }
println(articleARenvoyer)
return articleARenvoyer
}
return null // Retourne null si lArticles est null
}
override fun getDerniersArticles(nbArticles: Int): List<Article> {
return lArticles?.takeIf { it.isNotEmpty() }?.take(nbArticles) ?: emptyList()
}
}

@ -0,0 +1,8 @@
package com.example.veraxapplication.modele.articles.contenus
abstract class Contenu(var id: Int) {
var typeContenu: String? = null
protected set
}

@ -0,0 +1,30 @@
package com.example.veraxapplication.modele.articles.contenus
class ContenuMedia(id: Int, var titre: String, var lien: String) : Contenu(id) {
init {
this.typeContenu = "image"
}
val contenu: Map<String, String>
get() {
val contenu: MutableMap<String, String> = HashMap()
contenu["titre"] = titre
contenu["contenu"] = lien
return contenu
}
companion object {
fun newVideo(id: Int, titre: String, lien: String): ContenuMedia {
val temp = ContenuMedia(id, titre, lien)
temp.typeContenu = "video"
return temp
}
}
override fun toString(): String {
return "$lien\n\n"
}
}

@ -0,0 +1,20 @@
package com.example.veraxapplication.modele.articles.contenus
class ContenuParagraphe(id: Int, var titre: String, var texte: String) : Contenu(id) {
init {
this.typeContenu = "paragraphe"
}
val contenu: Map<String, String>
get() {
val contenu: MutableMap<String, String> = HashMap()
contenu["titre"] = titre
contenu["contenu"] = texte
return contenu
}
override fun toString(): String {
return "$texte \n\n"
}
}

@ -0,0 +1,78 @@
import com.example.veraxapplication.modele.IArticlesDataManager
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.modele.user.User
class StubUsers() : IUsersDataManager {
private var lUsers: MutableList<User>? = null
init {
chargerUsers()
}
private fun chargerUsers() {
lUsers = java.util.ArrayList<User>()
val user1 = User (
"NoaSil",
"1234",
"",
"Sillard",
"Noa",
"Admin"
)
lUsers!!.add(user1)
val user2 = User (
"Sha",
"1234",
"",
"Cascarra",
"Shana",
"Admin"
)
lUsers!!.add(user2)
val user3 = User (
"TonyF",
"1234",
"tony@gmail.com",
"Fages",
"Tony",
"Admin"
)
lUsers!!.add(user3)
val user4 = User (
"JeanSwaggLaPuissance63",
"1234",
"jean.lapuissance@gmail.com",
"Marcillac",
"Jean",
"Admin"
)
lUsers!!.add(user4)
}
override val allUsers: List<User>?
get() = lUsers
override fun getUser(pseudo : String): User? {
println("Passage dans getUser avec comme pseudo : $pseudo")
lUsers?.let {
println("Nombre d'utilisateurs disponibles : ${it.size}")
val userARenvoyer: User? = it.find { user -> user.pseudo == pseudo }
return userARenvoyer
}
return null
}
override fun getUsers(): List<User>
{
return lUsers?.takeIf { it.isNotEmpty() }?.take(lUsers!!.size) ?: emptyList()
}
}

@ -0,0 +1,3 @@
package com.example.veraxapplication.modele.user
data class User(val pseudo : String, val mdp : String, val mail : String, val nom : String, val prenom : String, val role : String)

@ -0,0 +1,46 @@
package com.example.veraxapplication.navigation
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.example.veraxapplication.modele.articles.Article
import com.example.veraxapplication.ui.article.AffichageLesArticles
import com.example.veraxapplication.ui.article.AfficherArticle
@Composable
fun VeraxNavHost(articles : List<Article>, navController: NavHostController, articlesStub: List<Article>) {
NavHost(
navController = navController,
startDestination = "accueil"
){
composable(route="accueil"){
AffichageLesArticles(
articles = articles,
goToArticle = {
navController.navigate("article/${it.id}")
}
)
}
composable(
route="article/{articleid}",
arguments= listOf(navArgument("articleid"){ type= NavType.IntType})
){
it.arguments?.getInt("articleid")?.let { articleid ->
articlesStub.find { it.id == articleid }?.let {
AfficherArticle(
e = it
)
}
}
}
}
}

@ -0,0 +1,189 @@
package com.example.veraxapplication.ui.article
import VideoPlayer
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
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
@Composable
fun AffichageLesArticles(articles : List<Article>, goToArticle: (Article) -> Unit){
Column(modifier = Modifier.verticalScroll(rememberScrollState())){
for(article in articles){
Box {
AffichageUnArticleInfo(e = article, goToArticle)
}
}
}
}
@Composable
fun AffichageUnArticleInfo(e : Article, goToArticle: (Article) -> Unit){
Column(modifier = Modifier
.padding(7.dp)
.border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp))
.padding(5.dp)) {
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)
}
}
Image(
painter = rememberImagePainter(
data = e.imagePrincipale
),
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = Modifier
.size(350.dp)
.align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp)
)
Button(onClick = { goToArticle(e)},
colors = ButtonDefaults.buttonColors(
containerColor = Salmon,
contentColor = Color.Black
),
border = BorderStroke(1.dp, Color.Black),
modifier = Modifier
.align(Alignment.CenterHorizontally)
) {
Text(text = "Voir plus")
}
}
}
@Composable
fun AfficherArticle(e : Article){
Column(modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(7.dp)
.padding(5.dp)) {
Text(text = e.titre, fontFamily = FontFamily.Serif, fontSize = 30.sp)
// Affichage des informations de l'article
DisplayHeader(author = e.auteur, description = e.description, lectureTime = e.temps)
Image(
painter = rememberImagePainter(
data = e.imagePrincipale
),
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = Modifier
.size(350.dp)
.align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp)
)
// 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<Contenu>) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
for (contenu in contenus) {
when (contenu) {
is ContenuMedia -> {
Log.d("Img", contenu.titre + " " + contenu.lien)
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" -> {
Text(
text = "Ici une video ..." + contenu.toString(),
fontSize = 15.sp,
textAlign = TextAlign.Start
)
VideoPlayer(videoUrl = contenu.lien)
}
}
}
is ContenuParagraphe -> {
Text(text = contenu.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold)
Text(text = contenu.texte, fontSize = 16.sp, textAlign = TextAlign.Start)
}
}
}
}
}

@ -0,0 +1,41 @@
import android.view.ViewGroup
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.ui.PlayerView
@Composable
fun VideoPlayer(videoUrl : String){
val context = LocalContext.current
val player = ExoPlayer.Builder(context).build()
val playerView = PlayerView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
val mediaItem = MediaItem.Builder()
.setUri(videoUrl)
.build()
player.setMediaItem(mediaItem)
player.prepare()
player.play()
AndroidView(
factory = { context -> playerView },
modifier = Modifier.fillMaxSize(),
update = { view ->
view.player = player
}
)
}

@ -0,0 +1,23 @@
package com.example.veraxapplication.ui.connexion
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.veraxapplication.modele.user.User
@Composable
fun AfficherForm(users : List<User>) {
var pseudo = "DEFAULT"
var mdp = "DEFAULT"
Column {
TextField(value = "Pseudo", onValueChange = { value -> pseudo = value }, modifier = Modifier.padding(5.dp))
TextField(value = "Mot de passe", onValueChange = { value -> mdp = value }, modifier = Modifier.padding(5.dp))
for (u in users) {
Text(text = u.pseudo)
}
}
}

@ -8,4 +8,5 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
val Orange = Color(0xFFFADCD1)
val Salmon = Color(0xFFE9967A)

@ -22,9 +22,9 @@ private val DarkColorScheme = darkColorScheme(
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
primary = Salmon,
secondary = PurpleGrey40,
tertiary = Pink40
tertiary = Salmon
/* Other default colors to override
background = Color(0xFFFFFBFE),

@ -0,0 +1,125 @@
package com.example.veraxapplication.ui.topBar
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.example.veraxapplication.R
import com.example.veraxapplication.modele.articles.Article
import com.example.veraxapplication.navigation.VeraxNavHost
import com.example.veraxapplication.ui.theme.Orange
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TopBarVerax(theme: List<String>, articles: List<Article>, articlesStub : List<Article>) {
/*var leMenu by remember { mutableStateOf(false) }*/
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
Row( modifier = Modifier.background(Color.Blue).fillMaxSize()) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
//text = R.string.app_name,
text= "Verax",
style = TextStyle(fontSize = 35.sp),
color = colorResource(R.color.red),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
},
navigationIcon = { if (navBackStackEntry?.destination?.route != "accueil"){
IconButton(onClick = { navController.popBackStack() }) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Retour",
Modifier.size(30.dp)
)
}
}
}/*,
actions = {
IconButton(onClick = { leMenu = !leMenu }) {
Icon(
imageVector = Icons.Filled.Menu,
contentDescription = "Menu",
Modifier.size(35.dp)
)
}
DropdownMenu(
expanded = leMenu, onDismissRequest = { leMenu = false },
modifier = Modifier
.border(
width = 1.dp,
color = Color.Black,
shape = RoundedCornerShape(10.dp)
)
.background(Orange)
) {
theme.sorted().forEach {
DropdownMenuItem(
text = {
Text(
it,
style = TextStyle(fontSize = 25.sp),
modifier = Modifier
.padding(10.dp)
)
},
onClick = { }
)
}
}
}*/
)
}
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
VeraxNavHost(articles = articles, navController, articlesStub= articlesStub)
}
}
}
}

@ -1,3 +1,3 @@
<resources>
<string name="app_name">VeraxApplication</string>
<string name="app_name">Verax</string>
</resources>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">181.214.189.133</domain>
<domain includeSubdomains="true">codefirst.iut.uca.fr/containers/Verax-verax-api</domain>
</domain-config>
</network-security-config>
Loading…
Cancel
Save