From 51bf0c7496e7ec6e755d58c02520bf6a8e6e9eca Mon Sep 17 00:00:00 2001 From: "Andres Gomez, Thomas (ITDV RL)" Date: Fri, 19 Sep 2025 14:25:32 +0200 Subject: [PATCH] Add year summary feature --- .idea/deploymentTargetSelector.xml | 6 +- app/release/baselineProfiles/0/app-release.dm | Bin 4559 -> 4568 bytes app/release/baselineProfiles/1/app-release.dm | Bin 4525 -> 4520 bytes .../headache/ui/navigation/MainNavDisplay.kt | 2 + .../destination/MonthSummaryDestination.kt | 2 +- .../destination/YearSummaryDestination.kt | 19 ++ .../page/event/edit/EventEditBottomSheet.kt | 57 +++- .../ui/page/event/edit/EventEditFactory.kt | 9 + .../ui/page/event/edit/EventPillEdit.kt | 19 ++ .../headache/ui/page/home/HomePage.kt | 11 + .../{item => month}/MonthSummaryFactory.kt | 13 +- .../summary/{ => month}/MonthSummaryPage.kt | 17 +- .../{ => month}/MonthSummaryViewModel.kt | 6 +- .../{ => month}/item/MonthSummaryBox.kt | 2 +- .../{ => month}/item/MonthSummaryCell.kt | 2 +- .../{ => month}/item/MonthSummaryItem.kt | 8 +- .../{ => month/item}/MonthSummaryPillItem.kt | 2 +- .../{ => month}/item/MonthSummaryTitle.kt | 2 +- .../page/summary/year/YearSummaryFactory.kt | 91 ++++++ .../ui/page/summary/year/YearSummaryPage.kt | 277 ++++++++++++++++++ .../page/summary/year/YearSummaryViewModel.kt | 28 ++ .../page/summary/year/item/YearSummaryDay.kt | 127 ++++++++ .../summary/year/item/YearSummaryMonth.kt | 185 ++++++++++++ .../ui/theme/color/HeadacheColorPalette.kt | 2 +- app/src/main/res/values-fr/strings.xml | 3 +- app/src/main/res/values/strings.xml | 3 +- 26 files changed, 852 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/com/pixelized/headache/ui/navigation/destination/YearSummaryDestination.kt rename app/src/main/java/com/pixelized/headache/ui/page/summary/{item => month}/MonthSummaryFactory.kt (88%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/MonthSummaryPage.kt (93%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/MonthSummaryViewModel.kt (85%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/item/MonthSummaryBox.kt (99%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/item/MonthSummaryCell.kt (68%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/item/MonthSummaryItem.kt (94%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month/item}/MonthSummaryPillItem.kt (97%) rename app/src/main/java/com/pixelized/headache/ui/page/summary/{ => month}/item/MonthSummaryTitle.kt (97%) create mode 100644 app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryFactory.kt create mode 100644 app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryPage.kt create mode 100644 app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryViewModel.kt create mode 100644 app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryDay.kt create mode 100644 app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryMonth.kt diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index ee099a0..c925b19 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -5,9 +5,6 @@ - - @@ -17,6 +14,9 @@ + + \ No newline at end of file diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm index e37820002f5a00ca5684535cf82bd811a059759d..9773a27447879a819c976987c4cbc5d1380cbc1d 100644 GIT binary patch delta 4441 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 KJe#i|NDu%g_QMVU delta 4458 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 bf};Gi+yHM@Hjn})1}2751_lNfK@blBHAc0j diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm index 5882dbe50ade67915720340d0cefc56b4c172629..4b8215a676b675860eab6879f7fdd8b3c273e21c 100644 GIT binary patch delta 4408 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 ZtR*+Vo0SbD&BVaOP|Co-pd<+50RXD}?fU=# diff --git a/app/src/main/java/com/pixelized/headache/ui/navigation/MainNavDisplay.kt b/app/src/main/java/com/pixelized/headache/ui/navigation/MainNavDisplay.kt index 425665e..0b88856 100644 --- a/app/src/main/java/com/pixelized/headache/ui/navigation/MainNavDisplay.kt +++ b/app/src/main/java/com/pixelized/headache/ui/navigation/MainNavDisplay.kt @@ -13,6 +13,7 @@ import com.pixelized.headache.ui.navigation.destination.calendarChooserDestinati import com.pixelized.headache.ui.navigation.destination.eventDestinationEntry import com.pixelized.headache.ui.navigation.destination.homeDestinationEntry import com.pixelized.headache.ui.navigation.destination.monthSummaryDestinationEntry +import com.pixelized.headache.ui.navigation.destination.yearSummaryDestinationEntry val LocalNavigator = staticCompositionLocalOf { error("Local Navigation no yet ready") @@ -42,6 +43,7 @@ fun MainNavDisplay( calendarChooserDestinationEntry() eventDestinationEntry() monthSummaryDestinationEntry() + yearSummaryDestinationEntry() } ) } diff --git a/app/src/main/java/com/pixelized/headache/ui/navigation/destination/MonthSummaryDestination.kt b/app/src/main/java/com/pixelized/headache/ui/navigation/destination/MonthSummaryDestination.kt index 88eeac3..2f4541a 100644 --- a/app/src/main/java/com/pixelized/headache/ui/navigation/destination/MonthSummaryDestination.kt +++ b/app/src/main/java/com/pixelized/headache/ui/navigation/destination/MonthSummaryDestination.kt @@ -3,7 +3,7 @@ package com.pixelized.headache.ui.navigation.destination import androidx.navigation3.runtime.EntryProviderBuilder import androidx.navigation3.runtime.entry import com.pixelized.headache.ui.navigation.Navigator -import com.pixelized.headache.ui.page.summary.MonthSummaryPage +import com.pixelized.headache.ui.page.summary.month.MonthSummaryPage data object MonthSummaryDestination diff --git a/app/src/main/java/com/pixelized/headache/ui/navigation/destination/YearSummaryDestination.kt b/app/src/main/java/com/pixelized/headache/ui/navigation/destination/YearSummaryDestination.kt new file mode 100644 index 0000000..6fd30fb --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/navigation/destination/YearSummaryDestination.kt @@ -0,0 +1,19 @@ +package com.pixelized.headache.ui.navigation.destination + +import androidx.navigation3.runtime.EntryProviderBuilder +import androidx.navigation3.runtime.entry +import com.pixelized.headache.ui.navigation.Navigator +import com.pixelized.headache.ui.page.summary.year.YearSummaryPage + + +data object YearSummaryDestination + +fun EntryProviderBuilder<*>.yearSummaryDestinationEntry() { + entry { + YearSummaryPage() + } +} + +fun Navigator.navigateToYearSummary() { + goTo(YearSummaryDestination) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/page/event/edit/EventEditBottomSheet.kt b/app/src/main/java/com/pixelized/headache/ui/page/event/edit/EventEditBottomSheet.kt index 71f4053..e0915d6 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/event/edit/EventEditBottomSheet.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/event/edit/EventEditBottomSheet.kt @@ -41,6 +41,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.pixelized.headache.R import com.pixelized.headache.ui.common.error.HandleErrorMessage import com.pixelized.headache.ui.theme.HeadacheTheme +import com.pixelized.headache.ui.theme.color.HeadacheColorPalette import com.pixelized.headache.utils.extention.capitalize import kotlinx.coroutines.launch import java.util.Date @@ -223,20 +224,60 @@ private class EventEditPreviewPreviewProvider : PreviewParameterProvider Unit, onEvent: () -> Unit, onMonthSummary: () -> Unit, + onYearSummary: () -> Unit, ) { Scaffold( modifier = modifier, @@ -87,6 +92,12 @@ private fun HomePageContent( onClick = onMonthSummary, ) } + item { + NavigationItem( + label = stringResource(R.string.year_summary_title), + onClick = onYearSummary, + ) + } } } ) diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryFactory.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryFactory.kt similarity index 88% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryFactory.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryFactory.kt index 82a0b40..eb624aa 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryFactory.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryFactory.kt @@ -1,13 +1,16 @@ -package com.pixelized.headache.ui.page.summary.item +package com.pixelized.headache.ui.page.summary.month import android.icu.util.Calendar import androidx.compose.ui.graphics.Color import com.pixelized.headache.repository.event.Event -import com.pixelized.headache.ui.page.summary.MonthSummaryPillItemUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryBoxUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryCell +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryItemUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryPillItemUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryTitleUio import com.pixelized.headache.utils.extention.event import javax.inject.Inject import kotlin.math.max -import kotlin.reflect.KClass class MonthSummaryFactory @Inject constructor() { private val calendar = Calendar.getInstance() @@ -86,11 +89,11 @@ class MonthSummaryFactory @Inject constructor() { date = calendar.apply { event = entry.key }.time, headacheRatio = entry.value.size.toFloat() / monthMaxDay, headacheAmount = entry.value.size, - headacheColor = Color.Red, + headacheColor = Color.Companion.Red, pillRatio = pillAmount.takeIf { it > 0 } ?.let { it.toFloat() / maxPillAmount.toFloat() }, pillAmount = pillAmount, - pillColor = Color.Blue, + pillColor = Color.Companion.Blue, ) } .sortedByDescending { it.date } diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPage.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryPage.kt similarity index 93% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPage.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryPage.kt index 3fa67d4..97fd466 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPage.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryPage.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary +package com.pixelized.headache.ui.page.summary.month import androidx.compose.animation.AnimatedContent import androidx.compose.animation.fadeIn @@ -44,13 +44,14 @@ import com.pixelized.headache.ui.navigation.LocalNavigator import com.pixelized.headache.ui.navigation.destination.navigateToEventPage import com.pixelized.headache.ui.page.event.edit.EventEditBottomSheet import com.pixelized.headache.ui.page.event.edit.EventEditBottomSheetViewModel -import com.pixelized.headache.ui.page.summary.item.MonthSummaryBox -import com.pixelized.headache.ui.page.summary.item.MonthSummaryBoxUio -import com.pixelized.headache.ui.page.summary.item.MonthSummaryCell -import com.pixelized.headache.ui.page.summary.item.MonthSummaryItem -import com.pixelized.headache.ui.page.summary.item.MonthSummaryItemUio -import com.pixelized.headache.ui.page.summary.item.MonthSummaryTitle -import com.pixelized.headache.ui.page.summary.item.MonthSummaryTitleUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryBox +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryBoxUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryCell +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryItem +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryItemUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryPillItemUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryTitle +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryTitleUio import com.pixelized.headache.ui.theme.HeadacheTheme import com.pixelized.headache.ui.theme.color.HeadacheColorPalette import java.util.Date diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryViewModel.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryViewModel.kt similarity index 85% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryViewModel.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryViewModel.kt index 611f980..86f038a 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryViewModel.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/MonthSummaryViewModel.kt @@ -1,12 +1,10 @@ -package com.pixelized.headache.ui.page.summary +package com.pixelized.headache.ui.page.summary.month import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.pixelized.headache.repository.event.Event import com.pixelized.headache.repository.event.EventRepository -import com.pixelized.headache.ui.page.summary.item.MonthSummaryCell -import com.pixelized.headache.ui.page.summary.item.MonthSummaryFactory -import com.pixelized.headache.ui.page.summary.item.MonthSummaryTitleUio +import com.pixelized.headache.ui.page.summary.month.item.MonthSummaryCell import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryBox.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryBox.kt similarity index 99% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryBox.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryBox.kt index c3ba0ba..dc4d060 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryBox.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryBox.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary.item +package com.pixelized.headache.ui.page.summary.month.item import android.annotation.SuppressLint import android.icu.text.SimpleDateFormat diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryCell.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryCell.kt similarity index 68% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryCell.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryCell.kt index be6308a..863d793 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryCell.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryCell.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary.item +package com.pixelized.headache.ui.page.summary.month.item import androidx.compose.runtime.Stable import java.util.Date diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryItem.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryItem.kt similarity index 94% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryItem.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryItem.kt index c228ad8..9adf1f0 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryItem.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryItem.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary.item +package com.pixelized.headache.ui.page.summary.month.item import android.annotation.SuppressLint import android.icu.text.SimpleDateFormat @@ -14,14 +14,13 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier 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.DpSize import androidx.compose.ui.unit.dp -import com.pixelized.headache.ui.page.summary.MonthSummaryPillItem -import com.pixelized.headache.ui.page.summary.MonthSummaryPillItemUio import com.pixelized.headache.ui.theme.HeadacheTheme import com.pixelized.headache.ui.theme.color.HeadacheColorPalette import com.pixelized.headache.utils.extention.capitalize @@ -68,11 +67,10 @@ fun MonthSummaryItem( Row( horizontalArrangement = Arrangement.spacedBy(space = spacing.width) ) { - formatter.format(item.date) Text( modifier = Modifier.alignByBaseline(), style = MaterialTheme.typography.titleLarge, - text = formatter.format(item.date).capitalize(), + text = remember(formatter, item.date) { formatter.format(item.date) }.capitalize(), ) Text( modifier = Modifier.alignByBaseline(), diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPillItem.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryPillItem.kt similarity index 97% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPillItem.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryPillItem.kt index f879986..f0c799e 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/MonthSummaryPillItem.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryPillItem.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary +package com.pixelized.headache.ui.page.summary.month.item import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryTitle.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryTitle.kt similarity index 97% rename from app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryTitle.kt rename to app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryTitle.kt index 6bf9ea4..65cc3ec 100644 --- a/app/src/main/java/com/pixelized/headache/ui/page/summary/item/MonthSummaryTitle.kt +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/month/item/MonthSummaryTitle.kt @@ -1,4 +1,4 @@ -package com.pixelized.headache.ui.page.summary.item +package com.pixelized.headache.ui.page.summary.month.item import android.annotation.SuppressLint import android.icu.text.SimpleDateFormat diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryFactory.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryFactory.kt new file mode 100644 index 0000000..088574f --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryFactory.kt @@ -0,0 +1,91 @@ +package com.pixelized.headache.ui.page.summary.year + +import android.icu.util.Calendar +import com.pixelized.headache.repository.event.Event +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryDayUio +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryMonthUio +import javax.inject.Inject + + +class YearSummaryFactory @Inject constructor() { + + fun convertToUio( + events: Collection, + ): List { + + val monthFirstDayCalendar = Calendar.getInstance().apply { + firstDayOfWeek = Calendar.MONDAY + setMinimalDaysInFirstWeek(1) + } + val monthLastDayCalendar = Calendar.getInstance().apply { + firstDayOfWeek = Calendar.MONDAY + setMinimalDaysInFirstWeek(1) + } + val currentDayCalendar = Calendar.getInstance().apply { + firstDayOfWeek = Calendar.MONDAY + setMinimalDaysInFirstWeek(1) + } + + return events + .fold(initial = hashMapOf>>()) { acc, event -> + acc.also { + val years = it.getOrPut(key = event.date.year) { hashMapOf() } + val months = years.getOrPut(key = event.date.month) { hashMapOf() } + months[event.date.day] = event + } + } + .map { yearEntry -> + YearUio( + year = yearEntry.key, + months = yearEntry.value.map { monthEntry -> + monthFirstDayCalendar.apply { + set(Calendar.YEAR, yearEntry.key) + set(Calendar.MONTH, monthEntry.key) + set(Calendar.DAY_OF_MONTH, 1) + set(Calendar.MILLISECONDS_IN_DAY, 1) + } + monthLastDayCalendar.apply { + time = monthFirstDayCalendar.time + add(Calendar.MONTH, 1) + add(Calendar.DAY_OF_MONTH, -1) + } + currentDayCalendar.apply { + time = monthFirstDayCalendar.time + } + val initial = MutableList( + size = monthLastDayCalendar.get(Calendar.WEEK_OF_MONTH), + ) { + mutableListOf() + } + val weeks = (1..monthLastDayCalendar.get(Calendar.DAY_OF_MONTH)) + .fold(initial = initial) { accumulator, dayNumber -> + val event: Event? = monthEntry.value.get(dayNumber) + val weekIndex = currentDayCalendar + .apply { + set(Calendar.YEAR, yearEntry.key) + set(Calendar.MONTH, monthEntry.key) + set(Calendar.DAY_OF_MONTH, dayNumber) + set(Calendar.MILLISECONDS_IN_DAY, 1) + } + .get(Calendar.WEEK_OF_MONTH) - 1 + val day = YearSummaryDayUio( + number = dayNumber, + headache = event != null, + pills = event?.pills?.map { it.color } ?: emptyList(), + ) + accumulator.also { acc -> + acc[weekIndex] = acc.get(index = weekIndex).also { week -> + week.add(day) + } + } + } + YearSummaryMonthUio( + date = monthFirstDayCalendar.time, + weeks = weeks, + ) + }, + ) + } + .sortedByDescending { it.year } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryPage.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryPage.kt new file mode 100644 index 0000000..5b48ec6 --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryPage.kt @@ -0,0 +1,277 @@ +package com.pixelized.headache.ui.page.summary.year + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Add +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.pixelized.headache.R +import com.pixelized.headache.ui.navigation.LocalNavigator +import com.pixelized.headache.ui.navigation.destination.navigateToEventPage +import com.pixelized.headache.ui.page.event.edit.EventEditBottomSheet +import com.pixelized.headache.ui.page.event.edit.EventEditBottomSheetViewModel +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryDayDefault +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryDayUio +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryMonth +import com.pixelized.headache.ui.page.summary.year.item.YearSummaryMonthUio +import com.pixelized.headache.ui.theme.HeadacheTheme +import java.util.Calendar +import java.util.Date + +@Stable +data class YearUio( + val year: Int, + val months: List, +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun YearSummaryPage( + viewModel: YearSummaryViewModel = hiltViewModel(), + editViewModel: EventEditBottomSheetViewModel = hiltViewModel(), +) { + val navigation = LocalNavigator.current + val uio = viewModel.events.collectAsStateWithLifecycle() + + YearSummaryContent( + modifier = Modifier + .systemBarsPadding() + .fillMaxSize(), + uio = uio, + onBack = { + navigation.popBackstack() + }, + onMonth = { + navigation.navigateToEventPage(date = it.date) + }, + onAddEvent = { + editViewModel.show() + }, + ) + + EventEditBottomSheet( + viewModel = editViewModel, + onDismissRequest = { editViewModel.dismiss() }, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun YearSummaryContent( + modifier: Modifier = Modifier, + uio: State>, + onBack: () -> Unit, + onMonth: (YearSummaryMonthUio) -> Unit, + onAddEvent: () -> Unit, +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + navigationIcon = { + IconButton( + onClick = onBack, + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = null, + ) + } + }, + title = { + Text(text = stringResource(R.string.year_summary_title)) + }, + ) + }, + floatingActionButton = { + FloatingActionButton( + containerColor = MaterialTheme.colorScheme.primary, + shape = CircleShape, + onClick = onAddEvent, + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null, + ) + } + }, + content = { paddingValues -> + LazyVerticalGrid( + modifier = Modifier.padding(paddingValues = paddingValues), + columns = GridCells.Adaptive( + minSize = YearSummaryDayDefault.size * 7, + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalArrangement = Arrangement.spacedBy(space = 4.dp), + contentPadding = PaddingValues( + start = 16.dp, + top = 16.dp, + end = 16.dp, + bottom = 16.dp + 16.dp + 56.dp, + ), + ) { + uio.value.forEachIndexed { index, (year, months) -> + item( + span = { GridItemSpan(maxCurrentLineSpan) }, + contentType = { "Title" }, + ) { + Text( + modifier = Modifier.padding( + top = when (index) { + 0 -> 0.dp + else -> 16.dp + } + ), + style = MaterialTheme.typography.displaySmall, + text = "$year", + ) + } + items( + items = months, + key = { it.date.time }, + contentType = { "Month" }, + ) { + YearSummaryMonth( + uio = it, + onMonth = onMonth, + ) + } + } + } + } + ) +} + +@Composable +@Preview +private fun YearSummaryPreview( + @PreviewParameter(YearPreviewProvider::class) preview: List, +) { + HeadacheTheme { + Surface { + YearSummaryContent( + uio = remember { mutableStateOf(preview) }, + onBack = { }, + onMonth = { }, + onAddEvent = { }, + ) + } + } +} + +private class YearPreviewProvider() : PreviewParameterProvider> { + + private fun year( + year: Int, + vararg months: YearSummaryMonthUio, + ) = YearUio( + year = year, + months = months.toList(), + ) + + private fun month( + month: Date, + vararg weeks: List, + ) = YearSummaryMonthUio( + date = month, + weeks = weeks.toList(), + ) + + private fun week( + vararg days: YearSummaryDayUio, + ) = days.toList() + + private fun day( + number: Int, + headache: Boolean = false, + pills: List = emptyList(), + ) = YearSummaryDayUio( + number = number, + headache = headache, + pills = pills, + ) + + override val values: Sequence> = sequenceOf( + listOf( + year( + year = 2025, + month( + month = Calendar.getInstance().apply { + set(Calendar.YEAR, 2025) + set(Calendar.MONTH, Calendar.JANUARY) + }.time, + week(day(1), day(2), day(3), day(4), day(5)), + week(day(6), day(7), day(8), day(9), day(10), day(11), day(12)), + week(day(13), day(14), day(15), day(16), day(17), day(18), day(19)), + week(day(20), day(21), day(22), day(23), day(24), day(25), day(26)), + week(day(27), day(28), day(29), day(30), day(31)), + ), + month( + month = Calendar.getInstance().apply { + set(Calendar.YEAR, 2025) + set(Calendar.MONTH, Calendar.FEBRUARY) + }.time, + week(day(1), day(2)), + week(day(3), day(4), day(5), day(6), day(7), day(8), day(9)), + week(day(10), day(11), day(12), day(13), day(14), day(15), day(16)), + week(day(17), day(18), day(19), day(20), day(21), day(22), day(23)), + week(day(24), day(25), day(26), day(27), day(28)), + ), + month( + month = Calendar.getInstance().apply { + set(Calendar.YEAR, 2025) + set(Calendar.MONTH, Calendar.MARCH) + }.time, + week(day(1), day(2)), + week(day(3), day(4), day(5), day(6), day(7), day(8), day(9)), + week(day(10), day(11), day(12), day(13), day(14), day(15), day(16)), + week(day(17), day(18), day(19), day(20), day(21), day(22), day(23)), + week(day(24), day(25), day(26), day(27), day(28), day(29), day(30)), + week(day(31)), + ), + month( + month = Calendar.getInstance().apply { + set(Calendar.YEAR, 2025) + set(Calendar.MONTH, Calendar.APRIL) + }.time, + week(day(1), day(2), day(3), day(4), day(5), day(6)), + week(day(7), day(8), day(9), day(10), day(11), day(12), day(13)), + week(day(14), day(15), day(16), day(17), day(18), day(19), day(20)), + week(day(21), day(22), day(23), day(24), day(25), day(26), day(27)), + week(day(28), day(29), day(30), day(31)), + ), + ) + ), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryViewModel.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryViewModel.kt new file mode 100644 index 0000000..56ab4a5 --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/YearSummaryViewModel.kt @@ -0,0 +1,28 @@ +package com.pixelized.headache.ui.page.summary.year + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.pixelized.headache.repository.event.EventRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import javax.inject.Inject + + +@HiltViewModel +class YearSummaryViewModel @Inject constructor( + eventRepository: EventRepository, + summaryFactory: YearSummaryFactory, +) : ViewModel() { + + val events: StateFlow> = eventRepository + .eventsListFlow() + .map(summaryFactory::convertToUio) + .stateIn( + scope = viewModelScope, + started = SharingStarted.Lazily, + initialValue = emptyList(), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryDay.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryDay.kt new file mode 100644 index 0000000..7785374 --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryDay.kt @@ -0,0 +1,127 @@ +package com.pixelized.headache.ui.page.summary.year.item + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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 com.pixelized.headache.ui.theme.HeadacheTheme +import com.pixelized.headache.ui.theme.color.HeadacheColorPalette + +@Stable +object YearSummaryDayDefault { + @Stable + val size: Dp = 16.dp + + @Stable + val pill: Dp = 2.dp +} + +@Stable +data class YearSummaryDayUio( + val number: Int, + val headache: Boolean, + val pills: List, +) + +@Composable +fun YearSummaryDay( + modifier: Modifier = Modifier, + size: Dp = YearSummaryDayDefault.size, + pill: Dp = YearSummaryDayDefault.pill, + day: YearSummaryDayUio, +) { + Box( + modifier = Modifier + .size(size = size) + .then(other = modifier), + ) { + if (day.headache) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(vertical = pill + 1.dp) + .background(color = HeadacheColorPalette.Pill.Unknown) + + ) + } + Text( + modifier = Modifier.align(alignment = Alignment.Center), + style = MaterialTheme.typography.labelSmall, + text = "${day.number}", + ) + if (day.headache) { + Row( + modifier = Modifier.align(alignment = Alignment.BottomCenter), + horizontalArrangement = Arrangement.spacedBy(space = 1.dp), + ) { + day.pills.forEach { + Box( + modifier = Modifier + .background(color = it) + .size(size = pill) + ) + } + } + } + } +} + +@Composable +@Preview +private fun YearSummaryDayPreview( + @PreviewParameter(DayPreviewProvider::class) preview: YearSummaryDayUio, +) { + HeadacheTheme { + YearSummaryDay( + day = preview, + ) + } +} + +private class DayPreviewProvider() : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + YearSummaryDayUio( + number = 1, + headache = false, + pills = emptyList(), + ), + YearSummaryDayUio( + number = 2, + headache = true, + pills = emptyList(), + ), + YearSummaryDayUio( + number = 3, + headache = true, + pills = listOf( + HeadacheColorPalette.Pill.Eletriptan40, + ), + ), + YearSummaryDayUio( + number = 3, + headache = true, + pills = listOf( + HeadacheColorPalette.Pill.Eletriptan40, + HeadacheColorPalette.Pill.Ibuprofene400, + HeadacheColorPalette.Pill.Spifen400, + HeadacheColorPalette.Pill.Paracetamol1000, + ), + ), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryMonth.kt b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryMonth.kt new file mode 100644 index 0000000..eefd335 --- /dev/null +++ b/app/src/main/java/com/pixelized/headache/ui/page/summary/year/item/YearSummaryMonth.kt @@ -0,0 +1,185 @@ +package com.pixelized.headache.ui.page.summary.year.item + +import android.annotation.SuppressLint +import android.icu.text.DateFormat +import android.icu.text.SimpleDateFormat +import android.icu.util.Calendar +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.ripple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import com.pixelized.headache.ui.theme.HeadacheTheme +import com.pixelized.headache.ui.theme.color.HeadacheColorPalette +import com.pixelized.headache.utils.extention.capitalize +import java.util.Date +import java.util.Locale + +@Stable +data object YearSummaryMonthDefault { + @SuppressLint("ConstantLocale") + @Stable + val formatter = SimpleDateFormat("MMMM", Locale.getDefault()) +} + +@Stable +data class YearSummaryMonthUio( + val date: Date, + val weeks: List>, +) + +@Composable +fun YearSummaryMonth( + modifier: Modifier = Modifier, + formatter: DateFormat = YearSummaryMonthDefault.formatter, + uio: YearSummaryMonthUio, + onMonth: (YearSummaryMonthUio) -> Unit, +) { + Column( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = ripple(bounded = false), + onClick = { onMonth(uio) } + ) + .then(other = modifier), + ) { + Text( + modifier = Modifier.align(alignment = Alignment.Start), + style = MaterialTheme.typography.titleMedium, + text = remember(uio.date) { formatter.format(uio.date) }.capitalize(), + ) + Column( + modifier = Modifier.height(height = remember { YearSummaryDayDefault.size * 6 }), + ) { + uio.weeks.forEachIndexed { index, week -> + Row( + modifier = Modifier.width(width = remember { YearSummaryDayDefault.size * 7 }), + horizontalArrangement = when (index) { + 0 -> Arrangement.End + else -> Arrangement.Start + }, + ) { + week.forEach { day -> + YearSummaryDay(day = day) + } + } + } + } + } +} + +@Composable +@Preview +private fun YearSummaryMonthPreview( + @PreviewParameter(MonthPreviewProvider::class) preview: YearSummaryMonthUio, +) { + HeadacheTheme { + Surface { + YearSummaryMonth( + uio = preview, + onMonth = { }, + ) + } + } +} + +private class MonthPreviewProvider() : PreviewParameterProvider { + + fun day( + number: Int, + headache: Boolean = false, + pills: List = emptyList(), + ): YearSummaryDayUio = YearSummaryDayUio( + number = number, + headache = headache, + pills = pills, + ) + + override val values: Sequence + get() = sequenceOf( + YearSummaryMonthUio( + date = Calendar.getInstance().apply { + set(Calendar.YEAR, 2025) + set(Calendar.MONTH, Calendar.JULY) + }.time, + weeks = listOf( + listOf( + day(number = 1), + day(number = 2), + day(number = 3), + day(number = 4), + ), + listOf( + day(number = 5), + day(number = 6, headache = true), + day(number = 7), + day(number = 8, headache = true), + day(number = 9), + day(number = 10), + day(number = 11), + ), + listOf( + day(number = 12), + day(number = 13), + day(number = 14), + day( + number = 15, + headache = true, + pills = listOf(HeadacheColorPalette.Pill.Spifen400), + ), + day(number = 16), + day(number = 17), + day(number = 18), + ), + listOf( + day( + number = 19, + headache = true, + pills = listOf(HeadacheColorPalette.Pill.Spifen400), + ), + day(number = 20), + day(number = 21), + day(number = 22, headache = true), + day(number = 23), + day(number = 24), + day(number = 25), + ), + listOf( + day( + number = 26, + headache = true, + pills = listOf( + HeadacheColorPalette.Pill.Spifen400, + HeadacheColorPalette.Pill.Eletriptan40, + ), + ), + day(number = 27, headache = true), + day(number = 28), + day(number = 29), + day( + number = 30, + headache = true, + pills = listOf(HeadacheColorPalette.Pill.Spifen400), + ), + day(number = 31), + ), + ), + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/headache/ui/theme/color/HeadacheColorPalette.kt b/app/src/main/java/com/pixelized/headache/ui/theme/color/HeadacheColorPalette.kt index 8332525..1dbb3b9 100644 --- a/app/src/main/java/com/pixelized/headache/ui/theme/color/HeadacheColorPalette.kt +++ b/app/src/main/java/com/pixelized/headache/ui/theme/color/HeadacheColorPalette.kt @@ -20,7 +20,7 @@ object HeadacheColorPalette { val Ibuprofene400 = Additional.Blue val Paracetamol1000 = Additional.Green val Spifen400 = Additional.Yellow - val Eletriptan40 = Additional.Pink + val Eletriptan40 = Additional.VeryLightPink } @Immutable diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 26f2570..e659fe7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -8,5 +8,6 @@ Choix du calendrier Évennement migraineux - Suivi des migraines + Suivi mensuel + Suivi annuel \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9e124a5..6a220e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,5 +8,6 @@ Choose your calendar Headache event - Headache summary + Monthly follow-up + Annual follow-up \ No newline at end of file