11package fr.utbm.sy43.pilulito.ui.screens
22
3+ import androidx.compose.animation.core.Animatable
4+ import androidx.compose.animation.core.FastOutSlowInEasing
5+ import androidx.compose.animation.core.tween
36import androidx.compose.foundation.background
47import androidx.compose.foundation.layout.*
58import androidx.compose.foundation.lazy.LazyColumn
@@ -22,6 +25,7 @@ import fr.utbm.sy43.pilulito.ui.components.TopBarComponent
2225import fr.utbm.sy43.pilulito.viewmodels.DayStats
2326import fr.utbm.sy43.pilulito.viewmodels.DrugStat
2427import fr.utbm.sy43.pilulito.viewmodels.HistoryViewModel
28+ import kotlinx.coroutines.launch
2529
2630private val Orange = Color (0xFFFF6C00 )
2731private val OrangeLight = Color (0xFFFFF3EC )
@@ -138,16 +142,25 @@ private fun GlobalScoreCard(taken: Int, total: Int) {
138142 color = Color (0xFF888888 )
139143 )
140144 }
145+ val animatedProgress = remember { Animatable (0f ) }
146+
147+ LaunchedEffect (ratio) {
148+ animatedProgress.animateTo(
149+ targetValue = ratio,
150+ animationSpec = tween(durationMillis = 1000 , easing = FastOutSlowInEasing )
151+ )
152+ }
153+
141154 Box (contentAlignment = Alignment .Center ) {
142155 CircularProgressIndicator (
143- progress = { ratio },
144- modifier = Modifier .size(72 .dp),
145- strokeWidth = 7 .dp,
146- color = Green ,
147- trackColor = Red .copy(alpha = 0.25f )
156+ progress = { animatedProgress.value },
157+ modifier = Modifier .size(72 .dp),
158+ strokeWidth = 7 .dp,
159+ color = Green ,
160+ trackColor = Red .copy(alpha = 0.25f )
148161 )
149162 Text (
150- text = " ${(ratio * 100 ).toInt()} %" ,
163+ text = " ${(animatedProgress.value * 100 ).toInt()} %" ,
151164 fontSize = 15 .sp,
152165 fontWeight = FontWeight .Bold ,
153166 color = Color (0xFF333333 )
@@ -237,9 +250,19 @@ private fun DayBar(day: DayStats, maxBarHeight: Float) {
237250 .clip(RoundedCornerShape (topStart = 8 .dp, topEnd = 8 .dp)),
238251 contentAlignment = Alignment .BottomCenter
239252 ) {
253+ val animatedPendingH = remember { Animatable (0f ) }
254+ val animatedMissedH = remember { Animatable (0f ) }
255+ val animatedTakenH = remember { Animatable (0f ) }
256+
257+ LaunchedEffect (day) {
258+ launch { animatedPendingH.animateTo(pendingH.value, tween(800 , easing = FastOutSlowInEasing )) }
259+ launch { animatedMissedH.animateTo(missedH.value, tween(800 , easing = FastOutSlowInEasing )) }
260+ launch { animatedTakenH.animateTo(takenH.value, tween(800 , easing = FastOutSlowInEasing )) }
261+ }
262+
240263 Column (
241- modifier = Modifier .fillMaxSize() ,
242- verticalArrangement = Arrangement . Bottom
264+ verticalArrangement = Arrangement . Bottom ,
265+ modifier = Modifier .fillMaxHeight()
243266 ) {
244267 if (day.total == 0 ) {
245268 Box (
@@ -253,24 +276,24 @@ private fun DayBar(day: DayStats, maxBarHeight: Float) {
253276 Box (
254277 modifier = Modifier
255278 .fillMaxWidth()
256- .height(pendingH )
279+ .height(animatedPendingH.value.dp )
257280 .background(Grey )
258281 )
259282 }
260283 if (day.missed > 0 ) {
261284 Box (
262285 modifier = Modifier
263286 .fillMaxWidth()
264- .height(missedH )
287+ .height(animatedMissedH.value.dp )
265288 .background(Red )
266289 )
267290 }
268291 if (day.taken > 0 ) {
269292 Box (
270293 modifier = Modifier
271294 .fillMaxWidth()
272- .height(takenH )
273- .clip(RoundedCornerShape (topStart = 8 .dp, topEnd = 8 .dp))
295+ .height(animatedTakenH.value.dp )
296+ // .clip(RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp))
274297 .background(Green )
275298 )
276299 }
@@ -327,22 +350,39 @@ private fun DrugStatRow(stat: DrugStat) {
327350 )
328351 }
329352
353+ val total = stat.total.coerceAtLeast(1 )
354+ val takenTarget = stat.taken.toFloat() / total
355+ val missedTarget = stat.missed.toFloat() / total
356+ val pendingTarget = stat.pending.toFloat() / total
357+
358+ val animatedTaken = remember { Animatable (0f ) }
359+ val animatedMissed = remember { Animatable (0f ) }
360+ val animatedPending = remember { Animatable (0f ) }
361+
362+ LaunchedEffect (stat) {
363+ launch { animatedTaken.animateTo(takenTarget, tween(800 , easing = FastOutSlowInEasing )) }
364+ launch { animatedMissed.animateTo(missedTarget, tween(800 , easing = FastOutSlowInEasing )) }
365+ launch { animatedPending.animateTo(pendingTarget, tween(800 , easing = FastOutSlowInEasing )) }
366+ }
367+
330368 Row (
331369 modifier = Modifier
332370 .fillMaxWidth()
333371 .height(10 .dp)
334372 .clip(RoundedCornerShape (50 ))
335373 ) {
336- val total = stat.total.coerceAtLeast(1 )
337- val takenW = stat.taken.toFloat() / total
338- val missedW = stat.missed.toFloat() / total
339- val pendingW = stat.pending.toFloat() / total
374+ if (stat.taken > 0 )
375+ Box (Modifier .weight(animatedTaken.value.coerceAtLeast(0.0001f )).fillMaxHeight().background(Green ))
376+ if (stat.missed > 0 )
377+ Box (Modifier .weight(animatedMissed.value.coerceAtLeast(0.0001f )).fillMaxHeight().background(Red ))
378+ if (stat.pending > 0 )
379+ Box (Modifier .weight(animatedPending.value.coerceAtLeast(0.0001f )).fillMaxHeight().background(Grey ))
340380
341- if (stat.taken > 0 ) Box (Modifier .weight(takenW).fillMaxHeight().background(Green ))
342- if (stat.missed > 0 ) Box (Modifier .weight(missedW).fillMaxHeight().background(Red ))
343- if (stat.pending > 0 ) Box (Modifier .weight(pendingW).fillMaxHeight().background(Grey ))
381+ val remainingWeight = (1f - animatedTaken.value - animatedMissed.value - animatedPending.value).coerceAtLeast(0.0001f )
382+ Box (Modifier .weight(remainingWeight).fillMaxHeight().background(Color (0xFFEEEEEE )))
344383
345- if (stat.total == 0 ) Box (Modifier .weight(1f ).fillMaxHeight().background(Color (0xFFEEEEEE )))
384+ if (stat.total == 0 )
385+ Box (Modifier .weight(1f ).fillMaxHeight().background(Color (0xFFEEEEEE )))
346386 }
347387
348388 Row (horizontalArrangement = Arrangement .spacedBy(12 .dp)) {
0 commit comments