mirror of
https://github.com/wismna/DoNext.git
synced 2025-12-06 00:02:40 -05:00
Compare commits
3 Commits
7dddc62377
...
e07f389fac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e07f389fac | ||
|
|
313e514624 | ||
|
|
8e78f9b464 |
48
.idea/caches/deviceStreaming.xml
generated
48
.idea/caches/deviceStreaming.xml
generated
@@ -232,6 +232,18 @@
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2640" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="blazer" />
|
||||
<option name="id" value="blazer" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Pixel 10 Pro" />
|
||||
<option name="screenDensity" value="420" />
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2410" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="32" />
|
||||
<option name="brand" value="google" />
|
||||
@@ -439,6 +451,18 @@
|
||||
<option name="screenX" value="720" />
|
||||
<option name="screenY" value="1600" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="frankel" />
|
||||
<option name="id" value="frankel" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Pixel 10" />
|
||||
<option name="screenDensity" value="420" />
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2424" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
@@ -657,6 +681,18 @@
|
||||
<option name="screenX" value="720" />
|
||||
<option name="screenY" value="1600" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="mustang" />
|
||||
<option name="id" value="mustang" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Pixel 10 Pro XL" />
|
||||
<option name="screenDensity" value="390" />
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2404" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="34" />
|
||||
<option name="brand" value="samsung" />
|
||||
@@ -755,6 +791,18 @@
|
||||
<option name="screenX" value="1080" />
|
||||
<option name="screenY" value="2340" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="36" />
|
||||
<option name="brand" value="google" />
|
||||
<option name="codename" value="rango" />
|
||||
<option name="id" value="rango" />
|
||||
<option name="labId" value="google" />
|
||||
<option name="manufacturer" value="Google" />
|
||||
<option name="name" value="Pixel 10 Pro Fold" />
|
||||
<option name="screenDensity" value="390" />
|
||||
<option name="screenX" value="2076" />
|
||||
<option name="screenY" value="2152" />
|
||||
</PersistentDeviceSelectionData>
|
||||
<PersistentDeviceSelectionData>
|
||||
<option name="api" value="30" />
|
||||
<option name="brand" value="google" />
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.ui.unit.dp
|
||||
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.TaskItemViewModel
|
||||
|
||||
@Composable
|
||||
fun DueTodayTasksScreen(
|
||||
@@ -41,7 +40,7 @@ fun DueTodayTasksScreen(
|
||||
items(tasks, key = { it.id!! }) { task ->
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
viewModel = TaskItemViewModel(task),
|
||||
task = task,
|
||||
onTaskClick = { onTaskClick(task) },
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!)
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DrawerState
|
||||
import androidx.compose.material3.DrawerValue
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
@@ -31,7 +32,10 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -46,22 +50,20 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
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 com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: MainViewModel = hiltViewModel()
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||
val scope = rememberCoroutineScope()
|
||||
// TODO: find a way to get rid of this
|
||||
val taskViewModel: TaskViewModel = hiltViewModel()
|
||||
|
||||
if (viewModel.isLoading) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
@@ -71,7 +73,7 @@ fun MainScreen(
|
||||
}
|
||||
|
||||
if (viewModel.showTaskSheet) {
|
||||
TaskBottomSheet(taskViewModel) { viewModel.showTaskSheet = false }
|
||||
TaskBottomSheet { viewModel.onDismissTaskSheet() }
|
||||
}
|
||||
if (viewModel.showAddListSheet) {
|
||||
AddListBottomSheet { viewModel.showAddListSheet = false }
|
||||
@@ -82,21 +84,11 @@ fun MainScreen(
|
||||
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
MenuScreen (
|
||||
currentDestination = viewModel.currentDestination,
|
||||
onNavigate = { route ->
|
||||
scope.launch {
|
||||
drawerState.close()
|
||||
navController.navigate(route) {
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
MenuScreen (currentDestination = viewModel.currentDestination)
|
||||
},
|
||||
drawerState = drawerState
|
||||
) {
|
||||
AppContent(viewModel = viewModel, taskViewModel = taskViewModel, navController = navController, scope = scope, drawerState = drawerState)
|
||||
AppContent(viewModel = viewModel, navController = navController, scope = scope, drawerState = drawerState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,11 +96,22 @@ fun MainScreen(
|
||||
fun AppContent(
|
||||
modifier : Modifier = Modifier,
|
||||
viewModel: MainViewModel,
|
||||
taskViewModel: TaskViewModel,
|
||||
navController: NavHostController,
|
||||
scope: CoroutineScope,
|
||||
drawerState: DrawerState
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.uiEventBus.events.collectLatest { event ->
|
||||
when (event) {
|
||||
is UiEvent.Navigate -> {
|
||||
drawerState.close()
|
||||
navController.navigate(event.route)
|
||||
}
|
||||
is UiEvent.NavigateBack -> navController.popBackStack()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
modifier = modifier.background(MaterialTheme.colorScheme.primaryContainer),
|
||||
containerColor = Color.Transparent,
|
||||
@@ -123,7 +126,7 @@ fun AppContent(
|
||||
navigationIcon = {
|
||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
||||
if (viewModel.currentDestination.showBackButton) {
|
||||
IconButton(onClick = { navController.popBackStack() }) {
|
||||
IconButton(onClick = { viewModel.navigateBack() }) {
|
||||
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "Back")
|
||||
}
|
||||
} else {
|
||||
@@ -154,9 +157,10 @@ fun AppContent(
|
||||
floatingActionButton = {
|
||||
when (val dest = viewModel.currentDestination) {
|
||||
is AppDestination.TaskList -> {
|
||||
TaskListFab(
|
||||
taskListId = dest.taskListId,
|
||||
showBottomSheet = { viewModel.showTaskSheet = it }
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = { viewModel.onNewTaskButtonClicked(dest.taskListId) },
|
||||
icon = { Icon(Icons.Filled.Add, "Create a task.") },
|
||||
text = { Text("Create a task") },
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
@@ -192,14 +196,20 @@ fun AppContent(
|
||||
type = NavType.LongType
|
||||
})
|
||||
) { navBackStackEntry ->
|
||||
// TODO: when task list has been deleted, we should not navigate to it event if in the stack
|
||||
val taskListId = navBackStackEntry.arguments?.getLong("taskListId") ?: return@composable
|
||||
val listExists by remember(taskListId, viewModel.destinations) {
|
||||
derivedStateOf { viewModel.doesListExist(taskListId) }
|
||||
}
|
||||
LaunchedEffect(listExists) {
|
||||
if (!viewModel.doesListExist(taskListId)) {
|
||||
viewModel.navigateBack()
|
||||
}
|
||||
}
|
||||
|
||||
val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
|
||||
TaskListScreen(
|
||||
viewModel = taskListViewModel,
|
||||
onTaskClick = { task ->
|
||||
taskViewModel.startEditTask(task)
|
||||
viewModel.showTaskSheet = true
|
||||
}
|
||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -212,19 +222,13 @@ fun AppContent(
|
||||
composable(AppDestination.DueTodayList.route) {
|
||||
DueTodayTasksScreen (
|
||||
modifier = Modifier,
|
||||
onTaskClick = { task ->
|
||||
taskViewModel.startEditTask(task)
|
||||
viewModel.showTaskSheet = true
|
||||
}
|
||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
||||
)
|
||||
}
|
||||
composable(AppDestination.RecycleBin.route) {
|
||||
RecycleBinScreen(
|
||||
modifier = Modifier,
|
||||
onTaskClick = { task ->
|
||||
taskViewModel.startEditTask(task)
|
||||
viewModel.showTaskSheet = true
|
||||
}
|
||||
onTaskClick = { task -> viewModel.onTaskClicked(task) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.wismna.geoffroy.donext.presentation.viewmodel.MenuViewModel
|
||||
fun MenuScreen(
|
||||
viewModel: MenuViewModel = hiltViewModel(),
|
||||
currentDestination: AppDestination,
|
||||
onNavigate: (String) -> Unit
|
||||
) {
|
||||
ModalDrawerSheet(
|
||||
drawerContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
@@ -58,7 +57,7 @@ fun MenuScreen(
|
||||
},
|
||||
icon = { Icon(Icons.Default.Today, contentDescription = "Due Today") },
|
||||
selected = currentDestination is AppDestination.DueTodayList,
|
||||
onClick = { onNavigate(AppDestination.DueTodayList.route) },
|
||||
onClick = { viewModel.navigateTo(AppDestination.DueTodayList.route) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
HorizontalDivider()
|
||||
@@ -74,7 +73,7 @@ fun MenuScreen(
|
||||
icon = { Icon(Icons.Default.LineWeight, contentDescription = list.name) },
|
||||
selected = currentDestination is AppDestination.TaskList &&
|
||||
currentDestination.taskListId == list.id,
|
||||
onClick = { onNavigate("taskList/${list.id}") },
|
||||
onClick = { viewModel.navigateTo("taskList/${list.id}") },
|
||||
badge = {
|
||||
if (list.overdueCount > 0) {
|
||||
Badge { Text(list.overdueCount.toString()) }
|
||||
@@ -91,14 +90,14 @@ fun MenuScreen(
|
||||
label = { Text("Recycle Bin") },
|
||||
icon = { Icon(Icons.Default.Delete, contentDescription = "Recycle Bin") },
|
||||
selected = currentDestination is AppDestination.RecycleBin,
|
||||
onClick = { onNavigate(AppDestination.RecycleBin.route) },
|
||||
onClick = { viewModel.navigateTo(AppDestination.RecycleBin.route) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
NavigationDrawerItem(
|
||||
label = { Text("Edit Lists") },
|
||||
icon = { Icon(Icons.Default.EditNote, contentDescription = "Edit Lists") },
|
||||
selected = currentDestination is AppDestination.ManageLists,
|
||||
onClick = { onNavigate(AppDestination.ManageLists.route) },
|
||||
onClick = { viewModel.navigateTo(AppDestination.ManageLists.route) },
|
||||
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import androidx.compose.ui.unit.dp
|
||||
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.TaskItemViewModel
|
||||
|
||||
@Composable
|
||||
fun RecycleBinScreen(
|
||||
@@ -77,7 +76,7 @@ fun RecycleBinScreen(
|
||||
items(items, key = { it.task.id!! }) { item ->
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
viewModel = TaskItemViewModel(item.task),
|
||||
task = item.task,
|
||||
onTaskClick = { onTaskClick(item.task) },
|
||||
onSwipeLeft = {
|
||||
viewModel.restore(item.task.id!!)
|
||||
|
||||
@@ -38,16 +38,18 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.wismna.geoffroy.donext.domain.model.Priority
|
||||
import com.wismna.geoffroy.donext.domain.model.Task
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
|
||||
|
||||
@Composable
|
||||
fun TaskItemScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: TaskItemViewModel,
|
||||
task: Task,
|
||||
onTaskClick: (taskId: Long) -> Unit,
|
||||
onSwipeLeft: () -> Unit,
|
||||
onSwipeRight: () -> Unit
|
||||
) {
|
||||
val viewModel = TaskItemViewModel(task)
|
||||
// TODO: change this
|
||||
val dismissState = rememberSwipeToDismissBoxState(
|
||||
confirmValueChange = {
|
||||
|
||||
@@ -8,12 +8,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.filled.Add
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -21,13 +16,10 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import com.wismna.geoffroy.donext.domain.model.Task
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskItemViewModel
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
|
||||
|
||||
@Composable
|
||||
fun TaskListScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: TaskListViewModel = hiltViewModel<TaskListViewModel>(),
|
||||
onTaskClick: (Task) -> Unit) {
|
||||
val tasks = viewModel.tasks
|
||||
@@ -50,7 +42,7 @@ fun TaskListScreen(
|
||||
) { task ->
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
viewModel = TaskItemViewModel(task),
|
||||
task = task,
|
||||
onTaskClick = { onTaskClick(task) },
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!, true)
|
||||
@@ -81,7 +73,7 @@ fun TaskListScreen(
|
||||
) { task ->
|
||||
TaskItemScreen(
|
||||
modifier = Modifier.animateItem(),
|
||||
viewModel = TaskItemViewModel(task),
|
||||
task = task,
|
||||
onTaskClick = { onTaskClick(task) },
|
||||
onSwipeLeft = {
|
||||
viewModel.updateTaskDone(task.id!!, false)
|
||||
@@ -95,20 +87,4 @@ fun TaskListScreen(
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TaskListFab(
|
||||
taskListId: Long,
|
||||
viewModel: TaskViewModel = hiltViewModel(),
|
||||
showBottomSheet: (Boolean) -> Unit = {}
|
||||
) {
|
||||
ExtendedFloatingActionButton(
|
||||
onClick = {
|
||||
viewModel.startNewTask(taskListId)
|
||||
showBottomSheet(true)
|
||||
},
|
||||
icon = { Icon(Icons.Filled.Add, "Create a task.") },
|
||||
text = { Text("Create a task") },
|
||||
)
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import com.wismna.geoffroy.donext.domain.extension.toLocalDate
|
||||
import com.wismna.geoffroy.donext.domain.model.Priority
|
||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
|
||||
@@ -53,7 +54,7 @@ import java.time.format.FormatStyle
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TaskBottomSheet(
|
||||
viewModel: TaskViewModel,
|
||||
viewModel: TaskViewModel = hiltViewModel(),
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
val titleFocusRequester = remember { FocusRequester() }
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.wismna.geoffroy.donext.presentation.ui.events
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -7,15 +7,20 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
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.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
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
getTaskListsUseCase: GetTaskListsUseCase
|
||||
getTaskListsUseCase: GetTaskListsUseCase,
|
||||
val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var isLoading by mutableStateOf(true)
|
||||
@@ -50,6 +55,33 @@ class MainViewModel @Inject constructor(
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun navigateBack() {
|
||||
viewModelScope.launch {
|
||||
uiEventBus.send(UiEvent.NavigateBack)
|
||||
}
|
||||
}
|
||||
|
||||
fun onNewTaskButtonClicked(taskLisId: Long) {
|
||||
showTaskSheet = true
|
||||
viewModelScope.launch {
|
||||
uiEventBus.send(UiEvent.CreateNewTask(taskLisId))
|
||||
}
|
||||
}
|
||||
|
||||
fun onTaskClicked(task: Task) {
|
||||
showTaskSheet = true
|
||||
viewModelScope.launch {
|
||||
uiEventBus.send(UiEvent.EditTask(task))
|
||||
}
|
||||
}
|
||||
|
||||
fun onDismissTaskSheet() {
|
||||
showTaskSheet = false
|
||||
viewModelScope.launch {
|
||||
uiEventBus.send(UiEvent.CloseTask)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentDestination(navBackStackEntry: NavBackStackEntry?) {
|
||||
val route = navBackStackEntry?.destination?.route
|
||||
val taskListId = navBackStackEntry?.arguments?.getLong("taskListId")
|
||||
@@ -61,4 +93,10 @@ class MainViewModel @Inject constructor(
|
||||
}
|
||||
} ?: startDestination
|
||||
}
|
||||
|
||||
fun doesListExist(taskListId: Long): Boolean {
|
||||
return destinations.any { dest ->
|
||||
dest is AppDestination.TaskList && dest.taskListId == taskListId
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,20 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.wismna.geoffroy.donext.domain.model.TaskListWithOverdue
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetDueTodayTasksUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsWithOverdueUseCase
|
||||
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
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MenuViewModel @Inject constructor(
|
||||
getTaskListsWithOverdue: GetTaskListsWithOverdueUseCase,
|
||||
getDueTodayTasks: GetDueTodayTasksUseCase
|
||||
getDueTodayTasks: GetDueTodayTasksUseCase,
|
||||
private val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var taskLists by mutableStateOf<List<TaskListWithOverdue>>(emptyList())
|
||||
private set
|
||||
|
||||
@@ -38,4 +41,10 @@ class MenuViewModel @Inject constructor(
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun navigateTo(route: String) {
|
||||
viewModelScope.launch {
|
||||
uiEventBus.send(UiEvent.Navigate(route))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class TaskListViewModel @Inject constructor(
|
||||
getTasks: GetTasksForListUseCase,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val toggleTaskDone: ToggleTaskDoneUseCase,
|
||||
private val toggleTaskDeleted: ToggleTaskDeletedUseCase,
|
||||
savedStateHandle: SavedStateHandle
|
||||
) : ViewModel() {
|
||||
|
||||
var tasks by mutableStateOf<List<Task>>(emptyList())
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.wismna.geoffroy.donext.domain.model.Priority
|
||||
import com.wismna.geoffroy.donext.domain.model.Task
|
||||
import com.wismna.geoffroy.donext.domain.usecase.AddTaskUseCase
|
||||
import com.wismna.geoffroy.donext.domain.usecase.UpdateTaskUseCase
|
||||
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.Instant
|
||||
@@ -19,7 +21,8 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class TaskViewModel @Inject constructor(
|
||||
private val createTaskUseCase: AddTaskUseCase,
|
||||
private val updateTaskUseCase: UpdateTaskUseCase
|
||||
private val updateTaskUseCase: UpdateTaskUseCase,
|
||||
private val uiEventBus: UiEventBus
|
||||
) : ViewModel() {
|
||||
|
||||
var title by mutableStateOf("")
|
||||
@@ -38,10 +41,23 @@ class TaskViewModel @Inject constructor(
|
||||
private var editingTaskId: Long? = null
|
||||
private var taskListId: Long? = null
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
uiEventBus.events.collect { event ->
|
||||
when (event) {
|
||||
is UiEvent.EditTask -> startEditTask(event.task)
|
||||
is UiEvent.CreateNewTask -> startNewTask(event.taskListId)
|
||||
is UiEvent.CloseTask -> reset()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun screenTitle(): String = if (isDeleted) "Task details" else if (isEditing()) "Edit Task" else "New Task"
|
||||
fun isEditing(): Boolean = editingTaskId != null
|
||||
|
||||
fun startNewTask(selectedListId: Long) {
|
||||
private fun startNewTask(selectedListId: Long) {
|
||||
editingTaskId = null
|
||||
taskListId = selectedListId
|
||||
title = ""
|
||||
@@ -51,7 +67,7 @@ class TaskViewModel @Inject constructor(
|
||||
isDeleted = false
|
||||
}
|
||||
|
||||
fun startEditTask(task: Task) {
|
||||
private fun startEditTask(task: Task) {
|
||||
editingTaskId = task.id
|
||||
taskListId = task.taskListId
|
||||
title = task.name
|
||||
@@ -84,8 +100,6 @@ class TaskViewModel @Inject constructor(
|
||||
} else {
|
||||
createTaskUseCase(taskListId!!, title, description, priority, dueDate)
|
||||
}
|
||||
// reset state after save
|
||||
reset()
|
||||
onDone?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user