From 86aab6c3da904323c5ca362c13d6263155207e4c Mon Sep 17 00:00:00 2001 From: Gato Date: Sat, 6 Jun 2026 06:39:00 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20[#22]=20vue=20Scheduled=20(t=C3=A2ches?= =?UTF-8?q?=20planifi=C3=A9es=20group=C3=A9es=20par=20date=20:=20aujourd'h?= =?UTF-8?q?ui,=20demain,=20cette=20semaine,=20plus=20tard)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mobile/ui/scheduled/ScheduledScreen.kt | 56 +++++++++++++++++ .../mobile/ui/scheduled/ScheduledViewModel.kt | 60 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledScreen.kt create mode 100644 app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledViewModel.kt diff --git a/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledScreen.kt b/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledScreen.kt new file mode 100644 index 0000000..a6a083c --- /dev/null +++ b/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledScreen.kt @@ -0,0 +1,56 @@ +package com.planify.mobile.ui.scheduled + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.CalendarMonth +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.planify.mobile.domain.model.Task +import com.planify.mobile.ui.components.EmptyState +import com.planify.mobile.ui.components.TaskRow + +@Composable +fun ScheduledScreen( + onTaskClick: (Task) -> Unit, + viewModel: ScheduledViewModel = hiltViewModel(), +) { + val groups by viewModel.groups.collectAsState() + + if (groups.isEmpty()) { + EmptyState( + icon = Icons.Outlined.CalendarMonth, + title = "Aucune tâche planifiée", + subtitle = "Les tâches avec une date d'échéance apparaîtront ici", + ) + return + } + + LazyColumn(modifier = Modifier.fillMaxSize()) { + groups.forEach { group -> + item(key = group.label) { + Text( + text = group.label, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + ) + } + items(group.tasks, key = { it.id }) { task -> + TaskRow( + task = task, + onClick = { onTaskClick(task) }, + onCheckedChange = { viewModel.toggleTask(task) }, + ) + } + } + } +} diff --git a/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledViewModel.kt b/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledViewModel.kt new file mode 100644 index 0000000..09b9d34 --- /dev/null +++ b/app/src/main/java/com/planify/mobile/ui/scheduled/ScheduledViewModel.kt @@ -0,0 +1,60 @@ +package com.planify.mobile.ui.scheduled + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.planify.mobile.domain.model.Task +import com.planify.mobile.domain.repository.TaskRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import java.time.LocalDate +import javax.inject.Inject + +data class ScheduledGroup(val label: String, val tasks: List) + +@HiltViewModel +class ScheduledViewModel @Inject constructor( + private val taskRepository: TaskRepository, +) : ViewModel() { + + val groups = taskRepository.getScheduledTasks() + .map { tasks -> groupByDate(tasks) } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList()) + + private fun groupByDate(tasks: List): List { + val today = LocalDate.now() + val tomorrow = today.plusDays(1) + val endOfWeek = today.plusDays(7) + + val buckets = linkedMapOf( + "Aujourd'hui" to mutableListOf(), + "Demain" to mutableListOf(), + "Cette semaine" to mutableListOf(), + "Plus tard" to mutableListOf(), + ) + + for (task in tasks) { + val date = runCatching { LocalDate.parse(task.dueDate?.date ?: "") }.getOrNull() ?: continue + when { + date == today -> buckets["Aujourd'hui"]!!.add(task) + date == tomorrow -> buckets["Demain"]!!.add(task) + date <= endOfWeek -> buckets["Cette semaine"]!!.add(task) + else -> buckets["Plus tard"]!!.add(task) + } + } + + return buckets.entries + .filter { it.value.isNotEmpty() } + .map { ScheduledGroup(it.key, it.value) } + } + + fun toggleTask(task: Task) { + viewModelScope.launch { taskRepository.checkTask(task.id, !task.checked) } + } + + fun deleteTask(task: Task) { + viewModelScope.launch { taskRepository.deleteTask(task.id) } + } +}