mirror of
https://github.com/wismna/DoNext.git
synced 2025-12-06 00:02:40 -05:00
Use events for task clicks
This commit is contained in:
@@ -13,14 +13,12 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.DueTodayViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.DueTodayViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DueTodayTasksScreen(
|
fun DueTodayTasksScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: DueTodayViewModel = hiltViewModel(),
|
viewModel: DueTodayViewModel = hiltViewModel(),
|
||||||
onTaskClick: (task: Task) -> Unit
|
|
||||||
) {
|
) {
|
||||||
val tasks = viewModel.dueTodayTasks
|
val tasks = viewModel.dueTodayTasks
|
||||||
|
|
||||||
@@ -41,7 +39,6 @@ fun DueTodayTasksScreen(
|
|||||||
TaskItemScreen(
|
TaskItemScreen(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItem(),
|
||||||
task = task,
|
task = task,
|
||||||
onTaskClick = { onTaskClick(task) },
|
|
||||||
onSwipeLeft = {
|
onSwipeLeft = {
|
||||||
viewModel.updateTaskDone(task.id!!)
|
viewModel.updateTaskDone(task.id!!)
|
||||||
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ fun AppContent(
|
|||||||
navController.navigate(event.route)
|
navController.navigate(event.route)
|
||||||
}
|
}
|
||||||
is UiEvent.NavigateBack -> navController.popBackStack()
|
is UiEvent.NavigateBack -> navController.popBackStack()
|
||||||
|
is UiEvent.EditTask -> { viewModel.showTaskSheet = true }
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,10 +208,7 @@ fun AppContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
|
val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
|
||||||
TaskListScreen(
|
TaskListScreen(viewModel = taskListViewModel)
|
||||||
viewModel = taskListViewModel,
|
|
||||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
composable(AppDestination.ManageLists.route) {
|
composable(AppDestination.ManageLists.route) {
|
||||||
@@ -220,16 +218,10 @@ fun AppContent(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(AppDestination.DueTodayList.route) {
|
composable(AppDestination.DueTodayList.route) {
|
||||||
DueTodayTasksScreen (
|
DueTodayTasksScreen (modifier = Modifier)
|
||||||
modifier = Modifier,
|
|
||||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
composable(AppDestination.RecycleBin.route) {
|
composable(AppDestination.RecycleBin.route) {
|
||||||
RecycleBinScreen(
|
RecycleBinScreen(modifier = Modifier)
|
||||||
modifier = Modifier,
|
|
||||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,12 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.RecycleBinViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.RecycleBinViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RecycleBinScreen(
|
fun RecycleBinScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: RecycleBinViewModel = hiltViewModel(),
|
viewModel: RecycleBinViewModel = hiltViewModel(),
|
||||||
onTaskClick: (task: Task) -> Unit
|
|
||||||
) {
|
) {
|
||||||
val tasks = viewModel.deletedTasks
|
val tasks = viewModel.deletedTasks
|
||||||
|
|
||||||
@@ -77,7 +75,6 @@ fun RecycleBinScreen(
|
|||||||
TaskItemScreen(
|
TaskItemScreen(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItem(),
|
||||||
task = item.task,
|
task = item.task,
|
||||||
onTaskClick = { onTaskClick(item.task) },
|
|
||||||
onSwipeLeft = {
|
onSwipeLeft = {
|
||||||
viewModel.restore(item.task.id!!)
|
viewModel.restore(item.task.id!!)
|
||||||
Toast.makeText(context, "Task restored", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Task restored", Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import androidx.compose.ui.text.style.TextDecoration
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import com.wismna.geoffroy.donext.domain.model.Priority
|
import com.wismna.geoffroy.donext.domain.model.Priority
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
import com.wismna.geoffroy.donext.domain.model.Task
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
|
||||||
@@ -45,11 +46,11 @@ import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
|
|||||||
fun TaskItemScreen(
|
fun TaskItemScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
task: Task,
|
task: Task,
|
||||||
onTaskClick: (taskId: Long) -> Unit,
|
viewModel: TaskItemViewModel = hiltViewModel<TaskItemViewModel>(),
|
||||||
onSwipeLeft: () -> Unit,
|
onSwipeLeft: () -> Unit,
|
||||||
onSwipeRight: () -> Unit
|
onSwipeRight: () -> Unit
|
||||||
) {
|
) {
|
||||||
val viewModel = TaskItemViewModel(task)
|
viewModel.populateTask(task)
|
||||||
// TODO: change this
|
// TODO: change this
|
||||||
val dismissState = rememberSwipeToDismissBoxState(
|
val dismissState = rememberSwipeToDismissBoxState(
|
||||||
confirmValueChange = {
|
confirmValueChange = {
|
||||||
@@ -78,7 +79,7 @@ fun TaskItemScreen(
|
|||||||
)
|
)
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onClick = { onTaskClick(viewModel.id) },
|
onClick = { viewModel.onTaskClicked(task) },
|
||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
containerColor = MaterialTheme.colorScheme.surfaceContainer,
|
||||||
),
|
),
|
||||||
@@ -109,7 +110,7 @@ fun TaskItemScreen(
|
|||||||
) {
|
) {
|
||||||
// Title
|
// Title
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.name,
|
text = viewModel.name!!,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
style = baseStyle,
|
style = baseStyle,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -150,7 +151,7 @@ fun TaskItemScreen(
|
|||||||
) {
|
) {
|
||||||
if (!viewModel.description.isNullOrBlank()) {
|
if (!viewModel.description.isNullOrBlank()) {
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.description,
|
text = viewModel.description!!,
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
style = baseStyle.copy(
|
style = baseStyle.copy(
|
||||||
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
|
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
|
||||||
|
|||||||
@@ -15,13 +15,12 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TaskListScreen(
|
fun TaskListScreen(
|
||||||
viewModel: TaskListViewModel = hiltViewModel<TaskListViewModel>(),
|
viewModel: TaskListViewModel = hiltViewModel<TaskListViewModel>(),
|
||||||
onTaskClick: (Task) -> Unit) {
|
) {
|
||||||
val tasks = viewModel.tasks
|
val tasks = viewModel.tasks
|
||||||
|
|
||||||
// Split tasks into active and done
|
// Split tasks into active and done
|
||||||
@@ -43,7 +42,6 @@ fun TaskListScreen(
|
|||||||
TaskItemScreen(
|
TaskItemScreen(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItem(),
|
||||||
task = task,
|
task = task,
|
||||||
onTaskClick = { onTaskClick(task) },
|
|
||||||
onSwipeLeft = {
|
onSwipeLeft = {
|
||||||
viewModel.updateTaskDone(task.id!!, true)
|
viewModel.updateTaskDone(task.id!!, true)
|
||||||
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Task done", Toast.LENGTH_SHORT).show()
|
||||||
@@ -74,7 +72,6 @@ fun TaskListScreen(
|
|||||||
TaskItemScreen(
|
TaskItemScreen(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItem(),
|
||||||
task = task,
|
task = task,
|
||||||
onTaskClick = { onTaskClick(task) },
|
|
||||||
onSwipeLeft = {
|
onSwipeLeft = {
|
||||||
viewModel.updateTaskDone(task.id!!, false)
|
viewModel.updateTaskDone(task.id!!, false)
|
||||||
Toast.makeText(context, "Task in progress", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Task in progress", Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.wismna.geoffroy.donext.presentation.ui.events
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class UiEventBus @Inject constructor() {
|
||||||
|
private val _events = MutableSharedFlow<UiEvent>(replay = 1)
|
||||||
|
val events = _events.asSharedFlow()
|
||||||
|
|
||||||
|
suspend fun send(event: UiEvent) {
|
||||||
|
_events.emit(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.NavBackStackEntry
|
import androidx.navigation.NavBackStackEntry
|
||||||
import com.wismna.geoffroy.donext.domain.model.AppDestination
|
import com.wismna.geoffroy.donext.domain.model.AppDestination
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
|
||||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
||||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
import com.wismna.geoffroy.donext.presentation.ui.events.UiEvent
|
||||||
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
import com.wismna.geoffroy.donext.presentation.ui.events.UiEventBus
|
||||||
@@ -68,13 +67,6 @@ class MainViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onTaskClicked(task: Task) {
|
|
||||||
showTaskSheet = true
|
|
||||||
viewModelScope.launch {
|
|
||||||
uiEventBus.send(UiEvent.EditTask(task))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDismissTaskSheet() {
|
fun onDismissTaskSheet() {
|
||||||
showTaskSheet = false
|
showTaskSheet = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
@@ -1,31 +1,42 @@
|
|||||||
package com.wismna.geoffroy.donext.presentation.viewmodel
|
package com.wismna.geoffroy.donext.presentation.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.wismna.geoffroy.donext.domain.extension.toLocalDate
|
import com.wismna.geoffroy.donext.domain.extension.toLocalDate
|
||||||
import com.wismna.geoffroy.donext.domain.model.Priority
|
import com.wismna.geoffroy.donext.domain.model.Priority
|
||||||
import com.wismna.geoffroy.donext.domain.model.Task
|
import com.wismna.geoffroy.donext.domain.model.Task
|
||||||
|
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.launch
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.FormatStyle
|
import java.time.format.FormatStyle
|
||||||
import java.time.format.TextStyle
|
import java.time.format.TextStyle
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TaskItemViewModel(task: Task) {
|
@HiltViewModel
|
||||||
val id: Long = task.id!!
|
class TaskItemViewModel @Inject constructor(
|
||||||
val name: String = task.name
|
private val uiEventBus: UiEventBus
|
||||||
val description: String? = task.description
|
): ViewModel() {
|
||||||
val isDone: Boolean = task.isDone
|
var id: Long? = null
|
||||||
val isDeleted: Boolean = task.isDeleted
|
var name: String? = null
|
||||||
val priority: Priority = task.priority
|
var description: String? = null
|
||||||
|
var dueDate: Long? = null
|
||||||
|
var isDone: Boolean = false
|
||||||
|
var isDeleted: Boolean = false
|
||||||
|
var priority: Priority = Priority.NORMAL
|
||||||
|
|
||||||
val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
|
val today: LocalDate = LocalDate.now(ZoneId.systemDefault())
|
||||||
|
|
||||||
val isOverdue: Boolean = task.dueDate?.let { millis ->
|
val isOverdue: Boolean = dueDate?.let { millis ->
|
||||||
val dueDate = millis.toLocalDate()
|
val dueDate = millis.toLocalDate()
|
||||||
dueDate.isBefore(today)
|
dueDate.isBefore(today)
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
val dueDateText: String? = task.dueDate?.let { formatDueDate(it) }
|
val dueDateText: String? = dueDate?.let { formatDueDate(it) }
|
||||||
|
|
||||||
private fun formatDueDate(dueMillis: Long): String {
|
private fun formatDueDate(dueMillis: Long): String {
|
||||||
val dueDate = dueMillis.toLocalDate()
|
val dueDate = dueMillis.toLocalDate()
|
||||||
@@ -40,4 +51,19 @@ class TaskItemViewModel(task: Task) {
|
|||||||
dueDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.getDefault()))
|
dueDate.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.getDefault()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun populateTask(task: Task) {
|
||||||
|
id = task.id!!
|
||||||
|
name = task.name
|
||||||
|
description = task.description
|
||||||
|
isDone = task.isDone
|
||||||
|
isDeleted = task.isDeleted
|
||||||
|
priority = task.priority
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onTaskClicked(task: Task) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
uiEventBus.send(UiEvent.EditTask(task))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,8 +45,8 @@ class TaskViewModel @Inject constructor(
|
|||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
uiEventBus.events.collect { event ->
|
uiEventBus.events.collect { event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
is UiEvent.EditTask -> startEditTask(event.task)
|
|
||||||
is UiEvent.CreateNewTask -> startNewTask(event.taskListId)
|
is UiEvent.CreateNewTask -> startNewTask(event.taskListId)
|
||||||
|
is UiEvent.EditTask -> startEditTask(event.task)
|
||||||
is UiEvent.CloseTask -> reset()
|
is UiEvent.CloseTask -> reset()
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user