From 70b7ea7ff8faf0960377a49c235b6edfcb2a8a9b Mon Sep 17 00:00:00 2001 From: Chocolaterie <110991127+Chocolaterie@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:21:04 +0100 Subject: [PATCH] Correction finale --- .../tpfilrouge/article/ArticleActivity.kt | 4 +- .../article/ArticleDetailFragment.kt | 72 ++++++++++++++ .../article/DetailArticleViewModel.kt | 9 ++ .../tpfilrouge/article/ListArticleFragment.kt | 94 +++++++++++------- app/src/main/res/drawable/card_bg.png | Bin 0 -> 2107 bytes 5 files changed, 142 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/com/example/tpfilrouge/article/ArticleDetailFragment.kt create mode 100644 app/src/main/java/com/example/tpfilrouge/article/DetailArticleViewModel.kt create mode 100644 app/src/main/res/drawable/card_bg.png diff --git a/app/src/main/java/com/example/tpfilrouge/article/ArticleActivity.kt b/app/src/main/java/com/example/tpfilrouge/article/ArticleActivity.kt index 0b16ce1..a72ee59 100644 --- a/app/src/main/java/com/example/tpfilrouge/article/ArticleActivity.kt +++ b/app/src/main/java/com/example/tpfilrouge/article/ArticleActivity.kt @@ -26,13 +26,15 @@ fun ArticleActivityPage() { val navController = rememberNavController(); var viewModel = ListArticleViewModel(); + var detailViewModel = DetailArticleViewModel(); NavHost( navController = navController, startDestination = "list_article" ) { - composable("list_article") { ListArticleFragmentPage(viewModel, navController) } + composable("list_article") { ListArticleFragmentPage(viewModel, detailViewModel, navController) } composable("article_form") { ArticleFormFragmentPage(viewModel, navController) } + composable("article_detail") { DetailArticleFragmentPage(detailViewModel) } } } diff --git a/app/src/main/java/com/example/tpfilrouge/article/ArticleDetailFragment.kt b/app/src/main/java/com/example/tpfilrouge/article/ArticleDetailFragment.kt new file mode 100644 index 0000000..9bdb7bc --- /dev/null +++ b/app/src/main/java/com/example/tpfilrouge/article/ArticleDetailFragment.kt @@ -0,0 +1,72 @@ +package com.example.tpfilrouge.article + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import coil.compose.AsyncImage +import com.example.tpfilrouge.R +import com.example.tpfilrouge.ui.theme.EniPage + + +@Composable +fun DetailArticleFragmentPage( + viewModel: DetailArticleViewModel +) { + // Ecouter les changements de la liste d'article dans le ViewModel + val articleState by viewModel.article.collectAsState(); + + EniPage { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(40.dp) + ) { + Text( + text = articleState.title, + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + style = TextStyle(color = Color.White, fontSize = 28.sp) + ) + Row(modifier = Modifier + .padding(10.dp) + .fillMaxWidth() + .padding(vertical = 14.dp)) { + AsyncImage( + model = articleState.imgPath, + contentDescription = "", + modifier = Modifier + .width(82.dp) + .padding(horizontal = 5.dp), + placeholder = painterResource(R.drawable.reset_password_ic), + ) + Column(modifier = Modifier.padding(start = 5.dp)) { + Text(articleState.desc, style = TextStyle(color = Color.White, fontSize = 20.sp)) + } + } + } + } +} + +@Preview( + showBackground = true, +) +@Composable +fun DetailArticleFragmentPreview() { + var viewModel = DetailArticleViewModel(); + DetailArticleFragmentPage(viewModel) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tpfilrouge/article/DetailArticleViewModel.kt b/app/src/main/java/com/example/tpfilrouge/article/DetailArticleViewModel.kt new file mode 100644 index 0000000..b8cb91e --- /dev/null +++ b/app/src/main/java/com/example/tpfilrouge/article/DetailArticleViewModel.kt @@ -0,0 +1,9 @@ +package com.example.tpfilrouge.article + +import kotlinx.coroutines.flow.MutableStateFlow + +class DetailArticleViewModel { + + var article = MutableStateFlow
(Article("", "", "")); + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tpfilrouge/article/ListArticleFragment.kt b/app/src/main/java/com/example/tpfilrouge/article/ListArticleFragment.kt index 2cd0774..6b2df8f 100644 --- a/app/src/main/java/com/example/tpfilrouge/article/ListArticleFragment.kt +++ b/app/src/main/java/com/example/tpfilrouge/article/ListArticleFragment.kt @@ -1,13 +1,18 @@ package com.example.tpfilrouge.article +import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box 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.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit @@ -22,7 +27,9 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle @@ -39,52 +46,63 @@ import com.example.tpfilrouge.ui.theme.EniPage import kotlinx.coroutines.flow.MutableStateFlow @Composable -fun ArticleCard(article: Article, viewModel: ListArticleViewModel, navController: NavController?=null){ +fun ArticleCard(article: Article, viewModel: ListArticleViewModel, detailViewModel: DetailArticleViewModel, navController: NavController?=null){ ElevatedCard( elevation = CardDefaults.cardElevation(defaultElevation = 6.dp), + shape = RoundedCornerShape(0.dp), modifier = Modifier.fillMaxWidth().padding(vertical = 14.dp) ) { - Row(modifier = Modifier.padding(10.dp)) { - AsyncImage( - model = article.imgPath, - contentDescription = "", - modifier = Modifier.width(82.dp).padding(horizontal = 5.dp), - placeholder = painterResource(R.drawable.reset_password_ic), - ) - Column(modifier = Modifier.padding(start = 5.dp)) { - Text(article.title, - style = TextStyle(fontWeight = FontWeight.Bold, fontSize = 15.sp)) - Text(article.desc) - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { - IconButton(onClick = { - }) { - Icon(imageVector = Icons.Filled.Info, contentDescription = "Voir") - } - IconButton(onClick = { - // Dire au viewmodel qu'on va être en mode édition - viewModel.isEdit.value = true; - // Dire au viewmodel quel article on va modifier - viewModel.editedArticle = article; - // Dire au viewmodel quel Id d'article en cours de proccessus - viewModel.editedArticleId = article.id; - // naviguer dans le formulaire - navController!!.navigate("article_form") - }) { - Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") - } - IconButton(onClick = { - viewModel.callDeleteArticleApi(article.id); - }) { - Icon(imageVector = Icons.Filled.Delete, contentDescription = "Delete") + Box(Modifier.background(brush = Brush.linearGradient(listOf( + Color(0xFF3a3b5d), + Color(0xFF535479), + ))).fillMaxSize()) { + Row(modifier = Modifier.padding(10.dp)) { + AsyncImage( + model = article.imgPath, + contentDescription = "", + modifier = Modifier.width(82.dp).padding(horizontal = 5.dp), + placeholder = painterResource(R.drawable.reset_password_ic), + ) + Column(modifier = Modifier.padding(start = 5.dp)) { + Text(article.title, + style = TextStyle(fontWeight = FontWeight.Bold, fontSize = 15.sp, color = Color.White)) + Text(article.desc, style = TextStyle(color = Color.White)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + IconButton(onClick = { + + detailViewModel.article.value = article; + navController!!.navigate("article_detail"); + + }) { + Icon(imageVector = Icons.Filled.Info, tint = Color.White, contentDescription = "Voir") + } + IconButton(onClick = { + // Dire au viewmodel qu'on va être en mode édition + viewModel.isEdit.value = true; + // Dire au viewmodel quel article on va modifier + viewModel.editedArticle = article; + // Dire au viewmodel quel Id d'article en cours de proccessus + viewModel.editedArticleId = article.id; + // naviguer dans le formulaire + navController!!.navigate("article_form") + }) { + Icon(imageVector = Icons.Filled.Edit, tint = Color.White, contentDescription = "Edit") + } + IconButton(onClick = { + viewModel.callDeleteArticleApi(article.id); + }) { + Icon(imageVector = Icons.Filled.Delete, tint = Color.White, contentDescription = "Delete") + } } } } } + } } @Composable -fun ListArticleFragmentPage(viewModel: ListArticleViewModel, navController: NavController? = null) { +fun ListArticleFragmentPage(viewModel: ListArticleViewModel, detailViewModel: DetailArticleViewModel, navController: NavController? = null) { // Ecouter les changements de la liste d'article dans le ViewModel val articlesState by viewModel.articles.collectAsState(); @@ -98,6 +116,9 @@ fun ListArticleFragmentPage(viewModel: ListArticleViewModel, navController: NavC textAlign = TextAlign.Center, style = TextStyle(color = Color.White, fontSize = 28.sp)) EniButton("Ajouter un Article") { + // Passer le edit à false pour revenir en mode ajout dans le form + viewModel.isEdit.value = false; + navController!!.navigate("article_form") } EniButton("Rafraichir") { @@ -106,7 +127,7 @@ fun ListArticleFragmentPage(viewModel: ListArticleViewModel, navController: NavC } LazyColumn { items(articlesState) { article -> - ArticleCard(article, viewModel, navController) + ArticleCard(article, viewModel, detailViewModel, navController) } } } @@ -119,10 +140,11 @@ fun ListArticleFragmentPage(viewModel: ListArticleViewModel, navController: NavC @Composable fun ListArticleActivityPreview() { var viewModel = ListArticleViewModel(); + var detailViewModel = DetailArticleViewModel(); viewModel.articles = MutableStateFlow(listOf( Article("Teletubies", "Meilleur série du monde", "https://avatar.iran.liara.run/public"), Article("Velocipastor", "Meilleur film du monde, gros budget", "https://avatar.iran.liara.run/public"), Article("Photo mouton béret paille ?", "Pourquoi", "https://avatar.iran.liara.run/public") )); - ListArticleFragmentPage(viewModel) + ListArticleFragmentPage(viewModel, detailViewModel) } \ No newline at end of file diff --git a/app/src/main/res/drawable/card_bg.png b/app/src/main/res/drawable/card_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..5150f603d63970a59630d6c835ae2c2e1f5fa447 GIT binary patch literal 2107 zcmV-B2*me^P)EX>4Tx04R}tkv&MmP!xqvQ>7x64t5X`$xxl_qD34_6^me@v=v%)FnQ@8G-*gu zTpR`0f`dPcRRUL0ade% zOfn(n3#($_6+Vn31V3UDGxbzNu&AwMxlU^gNh~3SG(^Z~po$tSL}}MZF_EG3gol6B@u$fpldB3w zjs?`ALUR1zfAD*@W@%>HO$sJ}{ukT+m;eI1K)Y$%-^aGyJ^}pCz?IhZ*IU5cC+W?u z7C8b!+rY(jSCjXE%N=0kNtX=Ck^HoTQVDoJqi-qz!?(cTnmf17IZhvd9L;L^1~@nb zCd-t)?(yz{-nsqT)0y87ypnRn<}Z>+00006VoOIv0F(g30La^uSTq0t010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=>Z-O2`dI0?7{#502y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00t9DL_t(|+U;G@jw2}yq&mrDl8kh(_ptx}RVUpq+#l3E zY?A9?fOJE-+ZP#Ww7atk0b`fT#sL2Q>mR0(hLjTTe~z|CA7o0HcgWcnt?euOw`z>a z*4^h_F1X7qrQdQZ%5UenZqU~Rq+fsjktSFy(tEZ^vIr`9v(@1P1oAINy)TvV!@%&N z7#n7yK}7)UpD%^;q)>L1zAm31Vf>o`01X!Q8=I(oK~6Vl?|CR>IkjnwF2KCMQ6o^! zm*Yfa>6+dyr?BYF0ARC*%#Ey!IgFKV80=&NV!?VlXa+V|Mgul60qJrM0N5S?loW67 z{fQS8*1|1s03rp43 zlz0Q-2Z6>qSOnpFg+29k__}_CHE+%U=1h}9CHbbf$T%dIY10CHaKQi+6oNSrAQQlw z7=MHQe|{Xpn%^P^fEGt)1_&GSRrFGJ>o|L6=uCI!R0E)#p#Hm!SXqgaA1U zkb1}a{`QXqU|JUAQcT?`RA$Kzz-(d=S~68*+#*!`-ENnl|NAijCH;SB9!g9A>ktQG zMYixT932cYR>A^RVSo2Zwxe_s4Epbn0Z5IameoeXop76&9eW%9lBCCA;*SRNG^zx= zUC%-PcVhrhTUbtMS)jaWotN{d97u!7)2s*xX|`)pbKTf?zDAXRx6j!7-wyz2U=?`O z02HWh(XC(^l@)s)3D!w?^(<#H-w~+FY{eWs?x4(;{4gP%gZ?|n0Z55Ji2)S6o-9b+ z(r}gXE6HP?IHfP6HE7pM(0?BxfXu_TXe;{1=1obUuu4?o|G@>J!P=^G3Jm)1hXF{b zF)E737a>7Ar68Rn#0J4pLBn_bz7eB1OjFQ*7XTp7wzI$nI?MXh6^iQJ4k~4aS?**I zsjSZK3)kWn#XpW1fHKKey~qOV7{R;%$XhZC*^dG_o>hRIrvOV>OR>yUrvZ`DHIDu| z005J{@fvq$!D<>YuT@3c?%p3i!4OF0BA|{zQ#@aT(CIKColimk{V)J&2v9oo!@}~^WvB8x9;T@Mcf|lqN<3SYek&-h zdThJ0fCX}((BnG|ovxp8^3N9ln0UroO?&MmAnbvlJ8N%28!|aOw*Sx?Xh$+oSp+0n zgInDE;{*WmOJ|bM$f}B4(1`55rIh-80iJIIyxKZl0qCl2JJA{(rzxFJhp<`~ z0HC~g|Jf%Oej%5QPZPUEXA!YL8 z+BEnX@*ogg2L`8?=J_Srp7FN zNvQ}3>%l;!z%D|HnP-2LPk(dvgEasa?samwYp;f<_~4QqO&jDyhW)poPo&` z7i(qGJ2%lh2i0K7#%` z0{|;U;Sw!cxWA;{qEvxO_x5Q6agiS}q~Stst0%Xh|7PuIW2_^LqI3Z$Z8dCb#?#eL z?L)0fn@-mYBe`|fyLjsV98Yx2s|2>p+}fBy_X7HiiiYw41Zg$IGu zuL8L#2%5bISR5qA4A#jeLOlERe_;TUxA$^|E}d;>LDA8)5qFKf0