mirror of
https://github.com/wismna/DoNext.git
synced 2025-12-06 08:12:37 -05:00
Restore due date on task list items
Replace toast with snackbar with an undo action
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.wismna.geoffroy.donext.presentation.screen
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -10,7 +9,6 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.DueTodayViewModel
|
||||
@@ -31,7 +29,6 @@ fun DueTodayTasksScreen(
|
||||
Text("Nothing due today !")
|
||||
}
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
LazyColumn(
|
||||
modifier = modifier.padding(8.dp)
|
||||
) {
|
||||
@@ -39,15 +36,8 @@ fun DueTodayTasksScreen(
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
task = task,
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!)
|
||||
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onSwipeRight = {
|
||||
viewModel.deleteTask(task.id!!)
|
||||
Toast.makeText(context, "Task moved to recycle bin", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
onSwipeLeft = { viewModel.updateTaskDone(task.id!!) },
|
||||
onSwipeRight = { viewModel.deleteTask(task.id!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalNavigationDrawer
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
@@ -53,7 +57,6 @@ import com.wismna.geoffroy.donext.domain.model.AppDestination
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.MainViewModel
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -63,7 +66,6 @@ fun MainScreen(
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
if (viewModel.isLoading) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
@@ -88,7 +90,7 @@ fun MainScreen(
|
||||
},
|
||||
drawerState = drawerState
|
||||
) {
|
||||
AppContent(viewModel = viewModel, navController = navController, scope = scope, drawerState = drawerState)
|
||||
AppContent(viewModel = viewModel, navController = navController, drawerState = drawerState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +99,11 @@ fun AppContent(
|
||||
modifier : Modifier = Modifier,
|
||||
viewModel: MainViewModel,
|
||||
navController: NavHostController,
|
||||
scope: CoroutineScope,
|
||||
drawerState: DrawerState
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.uiEventBus.events.collectLatest { event ->
|
||||
when (event) {
|
||||
@@ -109,13 +113,24 @@ fun AppContent(
|
||||
}
|
||||
is UiEvent.NavigateBack -> navController.popBackStack()
|
||||
is UiEvent.EditTask -> { viewModel.showTaskSheet = true }
|
||||
else -> {}
|
||||
is UiEvent.ShowUndoSnackbar -> {
|
||||
val result = snackbarHostState.showSnackbar(
|
||||
message = event.message,
|
||||
actionLabel = "Undo",
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
event.undoAction()
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
modifier = modifier.background(MaterialTheme.colorScheme.primaryContainer),
|
||||
containerColor = Color.Transparent,
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(viewModel.currentDestination.title) },
|
||||
|
||||
@@ -75,11 +75,9 @@ fun RecycleBinScreen(
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
task = item.task,
|
||||
onSwipeLeft = {
|
||||
viewModel.restore(item.task.id!!)
|
||||
Toast.makeText(context, "Task restored", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onSwipeLeft = { viewModel.restore(item.task.id!!) },
|
||||
onSwipeRight = {
|
||||
// TODO: add confirmation dialog
|
||||
viewModel.deleteForever(item.task.id!!)
|
||||
Toast.makeText(context, "Task deleted", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ fun TaskItemScreen(
|
||||
)
|
||||
|
||||
// Due date badge
|
||||
viewModel.dueDateText?.let { dueMillis ->
|
||||
viewModel.dueDate?.let { dueMillis ->
|
||||
Badge(
|
||||
modifier = Modifier
|
||||
.align(
|
||||
@@ -134,7 +134,7 @@ fun TaskItemScreen(
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 1.dp, end = 1.dp),
|
||||
text = viewModel.dueDateText,
|
||||
text = viewModel.dueDate!!,
|
||||
color = if (viewModel.isOverdue) Color.White else MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.wismna.geoffroy.donext.presentation.screen
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -9,26 +9,39 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
||||
|
||||
@Composable
|
||||
fun TaskListScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: TaskListViewModel = hiltViewModel<TaskListViewModel>(),
|
||||
) {
|
||||
val tasks = viewModel.tasks
|
||||
|
||||
if (tasks.isEmpty()) {
|
||||
// Placeholder when recycle bin is empty
|
||||
Column (
|
||||
modifier = modifier.fillMaxSize().padding(10.dp),
|
||||
Arrangement.Center
|
||||
) {
|
||||
Text("Nothing here!", modifier.fillMaxWidth(), textAlign = TextAlign.Center)
|
||||
Text("Add tasks with the Create Task button", modifier.fillMaxWidth(), textAlign = TextAlign.Center)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Split tasks into active and done
|
||||
val (active, done) = remember(tasks) {
|
||||
tasks.partition { !it.isDone }
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(8.dp),
|
||||
@@ -42,14 +55,8 @@ fun TaskListScreen(
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
task = task,
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!, true)
|
||||
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onSwipeRight = {
|
||||
viewModel.deleteTask(task.id!!)
|
||||
Toast.makeText(context, "Task moved to recycle bin", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
onSwipeLeft = { viewModel.updateTaskDone(task.id!!, true) },
|
||||
onSwipeRight = { viewModel.deleteTask(task.id!!) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -72,14 +79,8 @@ fun TaskListScreen(
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
task = task,
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!, false)
|
||||
Toast.makeText(context, "Task in progress", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onSwipeRight = {
|
||||
viewModel.deleteTask(task.id!!)
|
||||
Toast.makeText(context, "Task moved to recycle bin", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onSwipeLeft = { viewModel.updateTaskDone(task.id!!, false) },
|
||||
onSwipeRight = { viewModel.deleteTask(task.id!!) },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ import com.wismna.geoffroy.donext.domain.model.Task
|
||||
sealed class UiEvent {
|
||||
data class Navigate(val route: String) : UiEvent()
|
||||
data object NavigateBack : UiEvent()
|
||||
data class ShowSnackbar(val message: String) : UiEvent()
|
||||
|
||||
data class EditTask(val task: Task) : UiEvent()
|
||||
data class CreateNewTask(val taskListId: Long) : UiEvent()
|
||||
data object CloseTask : UiEvent()
|
||||
data class ShowUndoSnackbar(
|
||||
val message: String,
|
||||
val undoAction: () -> Unit
|
||||
) : UiEvent()
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import com.wismna.geoffroy.donext.domain.model.Task
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetDueTodayTasksUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDeletedUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDoneUseCase
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -17,16 +19,17 @@ import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class DueTodayViewModel @Inject constructor(
|
||||
getDueTodayTasks: GetDueTodayTasksUseCase,
|
||||
private val toggleTaskDeleted: ToggleTaskDeletedUseCase,
|
||||
private val toggleTaskDone: ToggleTaskDoneUseCase
|
||||
getDueTodayTasksUseCase: GetDueTodayTasksUseCase,
|
||||
private val toggleTaskDeletedUseCase: ToggleTaskDeletedUseCase,
|
||||
private val toggleTaskDoneUseCase: ToggleTaskDoneUseCase,
|
||||
private val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var dueTodayTasks by mutableStateOf<List<Task>>(emptyList())
|
||||
private set
|
||||
|
||||
init {
|
||||
getDueTodayTasks()
|
||||
getDueTodayTasksUseCase()
|
||||
.onEach { tasks ->
|
||||
dueTodayTasks = tasks
|
||||
}
|
||||
@@ -35,12 +38,35 @@ class DueTodayViewModel @Inject constructor(
|
||||
|
||||
fun updateTaskDone(taskId: Long) {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDone(taskId, true)
|
||||
toggleTaskDoneUseCase(taskId, true)
|
||||
|
||||
uiEventBus.send(
|
||||
UiEvent.ShowUndoSnackbar(
|
||||
message = "Task done",
|
||||
undoAction = {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDoneUseCase(taskId, false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteTask(taskId: Long) {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDeleted(taskId, true)
|
||||
toggleTaskDeletedUseCase(taskId, true)
|
||||
|
||||
uiEventBus.send(
|
||||
UiEvent.ShowUndoSnackbar(
|
||||
message = "Task moved to trash",
|
||||
undoAction = {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDeletedUseCase(taskId, false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,10 @@ class MainViewModel @Inject constructor(
|
||||
AppDestination.ManageLists +
|
||||
AppDestination.RecycleBin +
|
||||
AppDestination.DueTodayList
|
||||
isLoading = false
|
||||
if (startDestination == AppDestination.ManageLists && destinations.isNotEmpty()) {
|
||||
startDestination = destinations.first()
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.wismna.geoffroy.donext.domain.model.AppDestination
|
||||
import com.wismna.geoffroy.donext.domain.model.TaskListWithOverdue
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetDueTodayTasksUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsWithOverdueUseCase
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.wismna.geoffroy.donext.domain.usecase.EmptyRecycleBinUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetDeletedTasksUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.PermanentlyDeleteTaskUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDeletedUseCase
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -18,10 +20,11 @@ import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RecycleBinViewModel @Inject constructor(
|
||||
private val getDeletedTasks: GetDeletedTasksUseCase,
|
||||
private val restoreTask: ToggleTaskDeletedUseCase,
|
||||
private val permanentlyDeleteTask: PermanentlyDeleteTaskUseCase,
|
||||
private val emptyRecycleBinUseCase: EmptyRecycleBinUseCase
|
||||
private val getDeletedTasksUseCase: GetDeletedTasksUseCase,
|
||||
private val toggleTaskDeletedUseCase: ToggleTaskDeletedUseCase,
|
||||
private val permanentlyDeleteTaskUseCase: PermanentlyDeleteTaskUseCase,
|
||||
private val emptyRecycleBinUseCase: EmptyRecycleBinUseCase,
|
||||
private val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var deletedTasks by mutableStateOf<List<TaskWithListName>>(emptyList())
|
||||
@@ -32,7 +35,7 @@ class RecycleBinViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun loadDeletedTasks() {
|
||||
getDeletedTasks()
|
||||
getDeletedTasksUseCase()
|
||||
.onEach { tasks ->
|
||||
deletedTasks = tasks
|
||||
}
|
||||
@@ -41,14 +44,25 @@ class RecycleBinViewModel @Inject constructor(
|
||||
|
||||
fun restore(taskId: Long) {
|
||||
viewModelScope.launch {
|
||||
restoreTask(taskId, false)
|
||||
toggleTaskDeletedUseCase(taskId, false)
|
||||
loadDeletedTasks()
|
||||
|
||||
uiEventBus.send(
|
||||
UiEvent.ShowUndoSnackbar(
|
||||
message = "Task restored",
|
||||
undoAction = {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDeletedUseCase(taskId, true)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteForever(taskId: Long) {
|
||||
viewModelScope.launch {
|
||||
permanentlyDeleteTask(taskId)
|
||||
permanentlyDeleteTaskUseCase(taskId)
|
||||
loadDeletedTasks()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,41 +24,25 @@ class TaskItemViewModel @Inject constructor(
|
||||
var id: Long? = null
|
||||
var name: String? = null
|
||||
var description: String? = null
|
||||
var dueDate: Long? = null
|
||||
var dueDate: String? = null
|
||||
var isDone: Boolean = false
|
||||
var isDeleted: Boolean = false
|
||||
var priority: Priority = Priority.NORMAL
|
||||
|
||||
var isOverdue: Boolean = false
|
||||
val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
|
||||
|
||||
val isOverdue: Boolean = dueDate?.let { millis ->
|
||||
val dueDate = millis.toLocalDate()
|
||||
dueDate.isBefore(today)
|
||||
} ?: false
|
||||
|
||||
val dueDateText: String? = dueDate?.let { formatDueDate(it) }
|
||||
|
||||
private fun formatDueDate(dueMillis: Long): String {
|
||||
val dueDate = dueMillis.toLocalDate()
|
||||
|
||||
return when {
|
||||
dueDate.isEqual(today) -> "Today"
|
||||
dueDate.isEqual(today.plusDays(1)) -> "Tomorrow"
|
||||
dueDate.isEqual(today.minusDays(1)) -> "Yesterday"
|
||||
dueDate.isAfter(today) && dueDate.isBefore(today.plusDays(7)) ->
|
||||
dueDate.dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault())
|
||||
else ->
|
||||
dueDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.getDefault()))
|
||||
}
|
||||
}
|
||||
|
||||
fun populateTask(task: Task) {
|
||||
id = task.id!!
|
||||
name = task.name
|
||||
description = task.description
|
||||
dueDate = task.dueDate?.let { formatDueDate(it) }
|
||||
isDone = task.isDone
|
||||
isDeleted = task.isDeleted
|
||||
priority = task.priority
|
||||
isOverdue = task.dueDate?.let { millis ->
|
||||
val dueDate = millis.toLocalDate()
|
||||
dueDate.isBefore(today)
|
||||
} ?: false
|
||||
}
|
||||
|
||||
fun onTaskClicked(task: Task) {
|
||||
@@ -66,4 +50,19 @@ class TaskItemViewModel @Inject constructor(
|
||||
uiEventBus.send(UiEvent.EditTask(task))
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatDueDate(dueMillis: Long): String {
|
||||
val dueDateLocal = dueMillis.toLocalDate()
|
||||
|
||||
return when {
|
||||
dueDateLocal.isEqual(today) -> "Today"
|
||||
dueDateLocal.isEqual(today.plusDays(1)) -> "Tomorrow"
|
||||
dueDateLocal.isEqual(today.minusDays(1)) -> "Yesterday"
|
||||
dueDateLocal.isAfter(today) && dueDateLocal.isBefore(today.plusDays(7)) ->
|
||||
dueDateLocal.dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault())
|
||||
else ->
|
||||
dueDateLocal.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.getDefault()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import com.wismna.geoffroy.donext.domain.model.Task
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetTasksForListUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDeletedUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.ToggleTaskDoneUseCase
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -18,10 +20,11 @@ import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TaskListViewModel @Inject constructor(
|
||||
getTasks: GetTasksForListUseCase,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val toggleTaskDone: ToggleTaskDoneUseCase,
|
||||
private val toggleTaskDeleted: ToggleTaskDeletedUseCase,
|
||||
getTasksUseCase: GetTasksForListUseCase,
|
||||
private val toggleTaskDoneUseCase: ToggleTaskDoneUseCase,
|
||||
private val toggleTaskDeletedUseCase: ToggleTaskDeletedUseCase,
|
||||
private val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var tasks by mutableStateOf<List<Task>>(emptyList())
|
||||
@@ -32,7 +35,7 @@ class TaskListViewModel @Inject constructor(
|
||||
private val taskListId: Long = checkNotNull(savedStateHandle["taskListId"])
|
||||
|
||||
init {
|
||||
getTasks(taskListId)
|
||||
getTasksUseCase(taskListId)
|
||||
.onEach { list ->
|
||||
tasks = list
|
||||
isLoading = false
|
||||
@@ -42,12 +45,34 @@ class TaskListViewModel @Inject constructor(
|
||||
|
||||
fun updateTaskDone(taskId: Long, isDone: Boolean) {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDone(taskId, isDone)
|
||||
toggleTaskDoneUseCase(taskId, isDone)
|
||||
|
||||
uiEventBus.send(
|
||||
UiEvent.ShowUndoSnackbar(
|
||||
message = "Task done",
|
||||
undoAction = {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDoneUseCase(taskId, !isDone)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
fun deleteTask(taskId: Long) {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDeleted(taskId, true)
|
||||
toggleTaskDeletedUseCase(taskId, true)
|
||||
|
||||
uiEventBus.send(
|
||||
UiEvent.ShowUndoSnackbar(
|
||||
message = "Task moved to trash",
|
||||
undoAction = {
|
||||
viewModelScope.launch {
|
||||
toggleTaskDeletedUseCase(taskId, false)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user