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 e378200..9773a27 100644
Binary files a/app/release/baselineProfiles/0/app-release.dm and b/app/release/baselineProfiles/0/app-release.dm differ
diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm
index 5882dbe..4b8215a 100644
Binary files a/app/release/baselineProfiles/1/app-release.dm and b/app/release/baselineProfiles/1/app-release.dm differ
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