Compare commits

...

13 Commits

@ -64,6 +64,19 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.0") implementation("androidx.activity:activity-compose:1.7.0")
implementation("androidx.navigation:navigation-compose:2.4.0-alpha08") implementation("androidx.navigation:navigation-compose:2.4.0-alpha08")
implementation ("com.squareup.okhttp3:logging-interceptor:4.9.1")
// Jetpack Compose
implementation("androidx.compose.ui:ui:1.6.4")
implementation ("androidx.compose.material:material:1.6.4")
implementation ("androidx.compose.ui:ui-tooling:1.6.4")
// ExoPlayer
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 ("com.squareup.okhttp3:logging-interceptor:4.9.1")

@ -4,21 +4,20 @@ import ArticlesViewModel
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.veraxapplication.articles.IArticlesDataManager import com.example.veraxapplication.articles.IArticlesDataManager
import com.example.veraxapplication.articles.StubArticles import com.example.veraxapplication.articles.StubArticles
import com.example.veraxapplication.navigation.VeraxNavHost
import com.example.veraxapplication.ui.topBar.TopBarVerax 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 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 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 //doc couleur background pas finie: https://developer.android.com/jetpack/compose/components/scaffold
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -46,12 +45,8 @@ fun VeraxContent() {
var theme = listOf("Economique", "Culture", "Politique", "Faits divers") var theme = listOf("Economique", "Culture", "Politique", "Faits divers")
TopBarVerax(articles = articlesApi, theme = theme) TopBarVerax(articles = articlesApi, theme = theme)
// VeraxNavHost()
}
VeraxNavHost()
}

@ -1,11 +0,0 @@
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
)
*/

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

@ -1,9 +1,7 @@
package com.example.veraxapplication.modele package com.example.veraxapplication.modele
import com.example.veraxapplication.modele.user.User
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
object RetrofitClientUser { object RetrofitClientUser {

@ -1,22 +1,46 @@
package com.example.veraxapplication.navigation package com.example.veraxapplication.navigation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.example.veraxapplication.MainActivity import com.example.veraxapplication.MainActivity
import com.example.veraxapplication.modele.articles.Article
import com.example.veraxapplication.ui.article.AffichageLesArticles
import com.example.veraxapplication.ui.article.AfficherArticle
@Composable @Composable
fun VeraxNavHost() { fun VeraxNavHost(articles : List<Article>, navController: NavHostController) {
val navController = rememberNavController()
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = "accueil" startDestination = "accueil"
){ ){
composable(route="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 ->
articles.find { it.id == articleid }?.let {
AfficherArticle(
e = it
)
}
}
} }
} }

@ -1,17 +1,15 @@
package com.example.veraxapplication.ui.article package com.example.veraxapplication.ui.article
import VideoPlayer
import android.util.Log import android.util.Log
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@ -31,46 +29,46 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.rememberImagePainter import coil.compose.rememberImagePainter
import com.example.veraxapplication.modele.articles.Article 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.ContenuMedia
import com.example.veraxapplication.modele.articles.contenus.ContenuParagraphe import com.example.veraxapplication.modele.articles.contenus.ContenuParagraphe
import com.example.veraxapplication.ui.theme.Salmon import com.example.veraxapplication.ui.theme.Salmon
@Composable @Composable
fun AffichageLesArticles(articles : List<Article>){ fun AffichageLesArticles(articles : List<Article>, goToArticle: (Article) -> Unit){
Column(modifier = Modifier.verticalScroll(rememberScrollState())){ Column(modifier = Modifier.verticalScroll(rememberScrollState())){
for(article in articles){ for(article in articles){
Box (Modifier.clickable { /*faut je regarde la doc*/ }){ Box {
AffichageUnArticleInfo(e = article) AffichageUnArticleInfo(e = article, goToArticle)
} }
} }
} }
} }
@Composable @Composable
fun AffichageUnArticleInfo(e : Article){ fun AffichageUnArticleInfo(e : Article, goToArticle: (Article) -> Unit){
Column(modifier = Modifier Column(modifier = Modifier
.padding(7.dp) .padding(7.dp)
.border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp)) .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp))
.padding(5.dp)) { .padding(5.dp)) {
/*DisplayTitle(title = e.Title)
DisplayHeader(author = e.Author, description = e.Description, lectureTime = e.LectureTime)
DisplayImage(image = e.Image)
DisplayContentArticle(content = e.Content)*/
Text(text = e.titre, fontFamily = FontFamily.Serif, fontSize = 30.sp) Text(text = e.titre, fontFamily = FontFamily.Serif, fontSize = 30.sp)
DisplayHeader(author = e.auteur, description = e.description , lectureTime = e.temps) Box(modifier = Modifier
.padding(15.dp)
var imageURl = e.note .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp))
Log.d("ImageLoad", "URL de l'image reçue de l'API : $imageURl") .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)
}
}
Log.d("ImageLoad", e.toString())
Image( Image(
painter = rememberImagePainter( painter = rememberImagePainter(
data = imageURl data = e.imagePrincipale
), ),
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
contentDescription = null, contentDescription = null,
@ -79,15 +77,16 @@ fun AffichageUnArticleInfo(e : Article){
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp) .padding(5.dp, 35.dp)
) )
Button(onClick = { /*TODO*/ },
Button(onClick = { goToArticle(e)},
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = Salmon, containerColor = Salmon,
contentColor = Color.Black contentColor = Color.Black
), ),
border = BorderStroke(1.dp, Color.Black), border = BorderStroke(1.dp, Color.Black),
modifier = Modifier modifier = Modifier
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)
) { ) {
Text(text = "Voir plus") Text(text = "Voir plus")
} }
@ -95,41 +94,91 @@ fun AffichageUnArticleInfo(e : Article){
} }
} }
@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 @Composable
DisplayHeader(author = e.auteur, description = e.description, lectureTime = e.temps) fun AfficherArticle(e : Article) {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(7.dp)
.padding(5.dp)
) {
Text(text = "coucou") 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( Image(
painter = rememberImagePainter(data = e.imagePrincipale), painter = rememberImagePainter(
contentScale = ContentScale.FillHeight, data = e.imagePrincipale
),
contentScale = ContentScale.Crop,
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.size(350.dp) .size(350.dp)
.align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp) .padding(5.dp, 35.dp)
.fillMaxWidth() )
.wrapContentWidth(Alignment.CenterHorizontally)
)*/
Column(modifier = Modifier) {
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
)
// le player video marche a moitié mais honnetenement je comprends pas le soucis
VideoPlayer(videoUrl = text.lien)
}
}
// Affichage contenus
//DisplayContenu(e.lContenus)
}
is ContenuParagraphe -> {
Text(text = text.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold)
Text(text = text.toString(), fontSize = 16.sp, textAlign = TextAlign.Start)
}
}
}
}
} }
} }
@Composable @Composable
fun DisplayHeader(author: String, description: String, lectureTime: String) { fun DisplayHeader(author: String, description: String, lectureTime: String) {
Box( Box(
@ -147,104 +196,17 @@ fun DisplayHeader(author: String, description: String, lectureTime: String) {
} }
} }
@Composable @Composable
fun DisplayContenu(contenus: List<Contenu>) { fun DisplayImage(imageURl : String){
Column(horizontalAlignment = Alignment.CenterHorizontally) { Log.d("ImageLoad", "URL de l'image reçue de l'API : $imageURl")
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 = contenu.titre, fontSize = 20.sp, fontWeight = FontWeight.Bold)
Text(text = contenu.texte, fontSize = 16.sp, textAlign = TextAlign.Start)
}
}
}
}
}
/*
@Composable
fun DisplayImage(image: String) {
Image( Image(
painter = rememberImagePainter( painter = rememberImagePainter(
data = image data = imageURl
), ),
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.size(350.dp) .size(350.dp)
.align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp) .padding(5.dp, 35.dp)
) )
} }
@Composable
fun DisplayImage(image: String) {
Image(
painter = rememberImagePainter(
data = e.imagePrincipale
),
contentScale = ContentScale.Crop,
contentDescription = null,
modifier = Modifier
.size(350.dp)
.align(Alignment.CenterHorizontally)
.padding(5.dp, 35.dp)
)
}
@Composable
fun DisplayHeader(author: String, description: String, lectureTime: String) {
Box(modifier = Modifier
.fillMaxWidth()
.border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp))
.clip(RoundedCornerShape(10.dp))
.background(Salmon)
.padding(10.dp)) {
Column () {
Text(text = author)
Text(text = description)
Text(text = "Lecture Time: " + lectureTime + " minutes")
}
}
}
@Composable
fun DisplayTitle(title: String) {
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally){
Text(text = title, fontFamily = FontFamily.Serif, fontSize = 30.sp)
}
}
@Composable
fun DisplayContentArticle(content: List<Contenu>) {
Column {
for(e in content){
Text(text = e.Content, fontSize = 15.sp, fontFamily = FontFamily.Serif, textAlign = TextAlign.Justify, modifier = Modifier.padding(10.dp))
}
}
}*/

@ -0,0 +1,42 @@
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
}
)
}

@ -5,12 +5,13 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
@ -32,9 +33,11 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp 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.R
import com.example.veraxapplication.modele.articles.Article import com.example.veraxapplication.modele.articles.Article
import com.example.veraxapplication.ui.article.AffichageLesArticles import com.example.veraxapplication.navigation.VeraxNavHost
import com.example.veraxapplication.ui.theme.Orange import com.example.veraxapplication.ui.theme.Orange
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -43,7 +46,12 @@ fun TopBarVerax(theme: List<String>, articles: List<Article>) {
var leMenu by remember { var leMenu by remember {
mutableStateOf(false) mutableStateOf(false)
} }
Row() {
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
Row( modifier = Modifier.background(Color.Blue).fillMaxSize()) {
Scaffold( Scaffold(
topBar = { topBar = {
CenterAlignedTopAppBar( CenterAlignedTopAppBar(
@ -58,14 +66,16 @@ fun TopBarVerax(theme: List<String>, articles: List<Article>) {
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
}, },
navigationIcon = { navigationIcon = { if (navBackStackEntry?.destination?.route != "accueil"){
IconButton(onClick = { /* action() */ }) { IconButton(onClick = { navController.popBackStack() }) {
Icon( Icon(
imageVector = Icons.Filled.ArrowBack, imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Retour", contentDescription = "Retour",
Modifier.size(30.dp) Modifier.size(30.dp)
) )
} }
}
}, },
actions = { actions = {
IconButton(onClick = { leMenu = !leMenu }) { IconButton(onClick = { leMenu = !leMenu }) {
@ -78,7 +88,11 @@ fun TopBarVerax(theme: List<String>, articles: List<Article>) {
DropdownMenu( DropdownMenu(
expanded = leMenu, onDismissRequest = { leMenu = false }, expanded = leMenu, onDismissRequest = { leMenu = false },
modifier = Modifier modifier = Modifier
.border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(10.dp)) .border(
width = 1.dp,
color = Color.Black,
shape = RoundedCornerShape(10.dp)
)
.background(Orange) .background(Orange)
) { ) {
theme.sorted().forEach { theme.sorted().forEach {
@ -125,8 +139,10 @@ fun TopBarVerax(theme: List<String>, articles: List<Article>) {
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
) { ) {
AffichageLesArticles(articles = articles) // AffichageLesArticles(articles = articles)
// AfficherArticle(articles.get(0)); // AfficherArticle(articles.get(0))
VeraxNavHost(articles = articles, navController)
} }

Loading…
Cancel
Save