Prettify a bit the report UI.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-09-24 11:02:10 +02:00
parent 3645b92a82
commit 1bbd523e88
4 changed files with 217 additions and 60 deletions

View file

@ -1,12 +1,18 @@
package com.pixelized.headache.ui.page.summary.monthly
import android.icu.util.Calendar
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.snapping.SnapPosition
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.NavigationBarDefaults
import androidx.compose.material3.Scaffold
@ -22,6 +28,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.keepScreenOn
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
@ -36,7 +44,6 @@ import com.pixelized.headache.ui.page.summary.monthly.item.MonthSummaryTitle
import com.pixelized.headache.ui.page.summary.monthly.item.MonthSummaryTitleUio
import com.pixelized.headache.ui.theme.HeadacheTheme
import com.pixelized.headache.ui.theme.color.HeadacheColorPalette
import java.util.Date
@Stable
data object MonthSummaryPageDefault {
@ -72,6 +79,11 @@ fun MonthSummaryPage(
@OptIn(ExperimentalMaterial3Api::class)
private fun MonthSummaryContent(
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
flingBehavior: FlingBehavior = rememberSnapFlingBehavior(
lazyListState = state,
snapPosition = SnapPosition.Start,
),
spacing: Dp = MonthSummaryPageDefault.spacing,
listPadding: PaddingValues = MonthSummaryPageDefault.listPadding,
events: State<Map<MonthSummaryTitleUio, List<MonthSummaryItemUio>>>,
@ -95,6 +107,8 @@ private fun MonthSummaryContent(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues = paddingValues),
state = state,
flingBehavior = flingBehavior,
contentPadding = listPadding,
verticalArrangement = Arrangement.spacedBy(space = spacing),
reverseLayout = false,
@ -123,37 +137,109 @@ private fun MonthSummaryContent(
@Composable
@Preview
private fun MonthSummaryPreview() {
private fun MonthSummaryPreview(
@PreviewParameter(MonthSummaryPreviewProvider::class) preview: Map<MonthSummaryTitleUio, List<MonthSummaryItemUio>>,
) {
HeadacheTheme {
val events = remember {
mutableStateOf(
mapOf(
MonthSummaryTitleUio(
date = Date(),
) to listOf(
MonthSummaryItemUio(
date = Date(),
days = 8,
pills = listOf(
MonthSummaryPillItemUio(
label = "Spifen 400",
amount = 4,
color = HeadacheColorPalette.Pill.Spifen400,
),
MonthSummaryPillItemUio(
label = "Élétriptan 40",
amount = 2,
color = HeadacheColorPalette.Pill.Eletriptan40,
),
),
),
),
)
)
}
val events = remember { mutableStateOf(preview) }
MonthSummaryContent(
events = events,
onItem = { },
)
}
}
private class MonthSummaryPreviewProvider :
PreviewParameterProvider<Map<MonthSummaryTitleUio, List<MonthSummaryItemUio>>> {
private fun date(
year: Int,
) = Calendar.getInstance().also {
it.set(Calendar.YEAR, year)
it.set(Calendar.MONTH, Calendar.JANUARY)
it.set(Calendar.DAY_OF_MONTH, 1)
it.set(Calendar.MILLISECONDS_IN_DAY, 1)
}
private fun Calendar.year(
vararg month: MonthSummaryItemUio,
): Pair<MonthSummaryTitleUio, List<MonthSummaryItemUio>> {
this.add(Calendar.YEAR, -1)
return MonthSummaryTitleUio(
date = this.time
) to month.toList()
}
private fun Calendar.month(
headache: Int = 0,
eletriptan: Int = 0,
ibuprofen: Int = 0,
paracetamol: Int = 0,
spifen: Int = 0,
): MonthSummaryItemUio {
val date = this.time
this.add(Calendar.MONTH, 1)
return MonthSummaryItemUio(
date = date,
days = headache,
pills = listOfNotNull(
eletriptan.takeIf { it > 0 }?.let {
MonthSummaryPillItemUio(
label = "Élétriptan 40",
amount = it,
color = HeadacheColorPalette.Pill.Eletriptan40,
)
},
ibuprofen.takeIf { it > 0 }?.let {
MonthSummaryPillItemUio(
label = "Ibuprofène 400",
amount = it,
color = HeadacheColorPalette.Pill.Ibuprofene400,
)
},
paracetamol.takeIf { it > 0 }?.let {
MonthSummaryPillItemUio(
label = "Paracetamol 1000",
amount = it,
color = HeadacheColorPalette.Pill.Paracetamol1000,
)
},
spifen.takeIf { it > 0 }?.let {
MonthSummaryPillItemUio(
label = "Spifen 400",
amount = it,
color = HeadacheColorPalette.Pill.Spifen400,
)
},
),
)
}
override val values: Sequence<Map<MonthSummaryTitleUio, List<MonthSummaryItemUio>>>
get() = sequenceOf(
mapOf(
with(date(year = 2025)) {
year(
month(headache = 6, eletriptan = 4, spifen = 6),
month(headache = 15, eletriptan = 9, paracetamol = 2, spifen = 14),
month(headache = 14, eletriptan = 6, spifen = 10),
month(headache = 16, eletriptan = 7, spifen = 11),
month(headache = 14, eletriptan = 7, ibuprofen = 1, spifen = 12),
month(headache = 12, eletriptan = 3, spifen = 10),
month(headache = 7, spifen = 3),
month(headache = 8, eletriptan = 1, spifen = 4),
month(headache = 8, eletriptan = 1, spifen = 4),
month(),
month(),
month(),
)
},
with(date(year = 2024)) {
year(
month(),
month(),
)
}
)
)
}

View file

@ -5,6 +5,7 @@ import android.icu.text.DateFormat
import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -67,7 +68,7 @@ object ReportBoxDefault {
@Stable
val barSize: DpSize = DpSize(
width = 28.dp,
height = 320.dp,
height = 240.dp,
)
@Stable
@ -90,6 +91,7 @@ fun ReportBox(
barSpace: Dp = ReportBoxDefault.barSpace,
titleSpace: Dp = ReportBoxDefault.titleSpace,
item: ReportBoxUio,
onMonth: (ReportBoxUio.Month) -> Unit,
) {
Column(
modifier = modifier,
@ -109,6 +111,7 @@ fun ReportBox(
barSize = barSize,
barShape = barShape,
item = it,
onItem = onMonth,
)
}
}
@ -122,10 +125,12 @@ private fun Month(
barSize: DpSize = ReportBoxDefault.barSize,
barShape: Shape = ReportBoxDefault.barShape,
item: ReportBoxUio.Month,
onItem: (ReportBoxUio.Month) -> Unit,
) {
Column(
modifier = Modifier
.width(width = barSize.width)
.clickable { onItem(item) }
.then(other = modifier),
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -174,6 +179,7 @@ private fun ReportBoxPreview(
Surface {
ReportBox(
item = preview,
onMonth = { },
)
}
}

View file

@ -3,6 +3,9 @@ package com.pixelized.headache.ui.page.summary.report
import android.icu.util.Calendar
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.snapping.SnapPosition
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -13,8 +16,15 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults
import androidx.compose.material3.Scaffold
@ -42,6 +52,8 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.pixelized.headache.R
import com.pixelized.headache.ui.navigation.destination.navigateToEventPage
import com.pixelized.headache.ui.navigation.main.LocalMainNavigator
import com.pixelized.headache.ui.theme.HeadacheTheme
import com.pixelized.headache.ui.theme.color.HeadacheColorPalette
import com.pixelized.headache.utils.extention.calculate
@ -66,6 +78,7 @@ data object ReportPageDefault {
fun ReportPage(
viewModel: ReportViewModel = hiltViewModel(),
) {
val navigator = LocalMainNavigator.current
val events = viewModel.events.collectAsStateWithLifecycle()
ReportContent(
@ -73,6 +86,9 @@ fun ReportPage(
.keepScreenOn()
.fillMaxSize(),
events = events,
onMonth = {
navigator.navigateToEventPage(date = it.date)
},
)
}
@ -80,11 +96,17 @@ fun ReportPage(
@Composable
private fun ReportContent(
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
flingBehavior: FlingBehavior = rememberSnapFlingBehavior(
lazyListState = state,
snapPosition = SnapPosition.Start,
),
paddingValues: PaddingValues = ReportPageDefault.paddingValues,
contentSpace: Dp = ReportPageDefault.contentSpace,
barSpace: Dp = ReportPageDefault.barSpace,
barSize: DpSize = rememberBarSize(column = 12, paddingValues = paddingValues, space = barSpace),
events: State<List<ReportBoxUio>>,
onMonth: (ReportBoxUio.Month) -> Unit,
) {
Scaffold(
modifier = modifier,
@ -95,42 +117,27 @@ private fun ReportContent(
containerColor = NavigationBarDefaults.containerColor,
),
title = {
Text(text = stringResource(R.string.year_summary_title))
Text(
text = stringResource(R.string.year_summary_title),
)
},
actions = {
Column(
modifier = Modifier.padding(end = 16.dp)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
verticalAlignment = Alignment.CenterVertically,
Box {
val expanded = remember { mutableStateOf(false) }
IconButton(
onClick = { expanded.value = true },
) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = HeadacheColorPalette.Calendar.Headache,
)
)
Text(
style = MaterialTheme.typography.labelSmall,
text = "Jours de migraine",
Icon(
imageVector = Icons.Default.Info,
contentDescription = null,
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
verticalAlignment = Alignment.CenterVertically,
DropdownMenu(
expanded = expanded.value,
onDismissRequest = { expanded.value = false }
) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = HeadacheColorPalette.Calendar.Pill,
)
)
Text(
style = MaterialTheme.typography.labelSmall,
text = "Prise de cachet",
Legend(
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp)
)
}
}
@ -140,6 +147,8 @@ private fun ReportContent(
content = { it ->
LazyColumn(
modifier = Modifier.padding(paddingValues = it),
state = state,
flingBehavior = flingBehavior,
contentPadding = paddingValues,
verticalArrangement = Arrangement.spacedBy(space = contentSpace),
) {
@ -150,6 +159,7 @@ private fun ReportContent(
barSize = barSize,
barSpace = barSpace,
item = item,
onMonth = onMonth,
)
}
}
@ -157,6 +167,48 @@ private fun ReportContent(
)
}
@Composable
private fun Legend(
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = HeadacheColorPalette.Calendar.Headache,
)
)
Text(
style = MaterialTheme.typography.labelSmall,
text = "Jours de migraine",
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = HeadacheColorPalette.Calendar.Pill,
)
)
Text(
style = MaterialTheme.typography.labelSmall,
text = "Prise de cachet",
)
}
}
}
@Composable
private fun rememberBarSize(
column: Int,
@ -186,6 +238,7 @@ private fun ReportPreview(
Surface {
ReportContent(
events = remember { mutableStateOf(preview) },
onMonth = { },
)
}
}

View file

@ -1,5 +1,8 @@
package com.pixelized.headache.ui.page.summary.yearly
import androidx.compose.foundation.gestures.FlingBehavior
import androidx.compose.foundation.gestures.snapping.SnapPosition
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.WindowInsets
@ -7,8 +10,10 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults
@ -87,6 +92,11 @@ fun YearSummaryPage(
@Composable
fun YearSummaryContent(
modifier: Modifier = Modifier,
state: LazyGridState = rememberLazyGridState(),
flingBehavior: FlingBehavior = rememberSnapFlingBehavior(
lazyGridState = state,
snapPosition = SnapPosition.Start,
),
paddingValues: PaddingValues = YearSummaryPageDefault.paddingValues,
space: Dp = YearSummaryPageDefault.space,
daySize: Dp = rememberDaySize(column = YearSummaryPageDefault.column),
@ -117,6 +127,8 @@ fun YearSummaryContent(
}
LazyVerticalGrid(
modifier = Modifier.padding(paddingValues = it),
state = state,
flingBehavior = flingBehavior,
columns = GridCells.Adaptive(minSize = daySize * 7),
horizontalArrangement = Arrangement.spacedBy(space = space),
verticalArrangement = Arrangement.spacedBy(space = space),
@ -128,7 +140,7 @@ fun YearSummaryContent(
contentType = { "Title" },
) {
Text(
modifier = Modifier.padding(top = 16.dp),
modifier = Modifier.padding(top = 16.dp),
style = MaterialTheme.typography.displaySmall,
text = "$year",
)