mirror of
https://github.com/wismna/DoNext.git
synced 2025-10-03 07:30:13 -04:00
Fix navigation (once and for all ?)
Implement inline edit lists feature Improve task list bottom sheet design
This commit is contained in:
@@ -46,7 +46,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.9.3")
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.9.4")
|
||||||
implementation("androidx.activity:activity-compose:1.11.0")
|
implementation("androidx.activity:activity-compose:1.11.0")
|
||||||
implementation(platform("androidx.compose:compose-bom:2025.09.00"))
|
implementation(platform("androidx.compose:compose-bom:2025.09.00"))
|
||||||
implementation("androidx.compose.ui:ui")
|
implementation("androidx.compose.ui:ui")
|
||||||
|
@@ -44,6 +44,10 @@ class TaskRepositoryImpl @Inject constructor(
|
|||||||
taskListDao.insertTaskList(taskList.toEntity())
|
taskListDao.insertTaskList(taskList.toEntity())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun updateTaskList(taskList: TaskList) {
|
||||||
|
taskListDao.updateTaskList(taskList.toEntity())
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun deleteTaskList(taskListId: Long, isDeleted: Boolean) {
|
override suspend fun deleteTaskList(taskListId: Long, isDeleted: Boolean) {
|
||||||
taskDao.deleteAllTasksFromList(taskListId, isDeleted)
|
taskDao.deleteAllTasksFromList(taskListId, isDeleted)
|
||||||
taskListDao.deleteTaskList(taskListId, isDeleted)
|
taskListDao.deleteTaskList(taskListId, isDeleted)
|
||||||
|
@@ -14,6 +14,7 @@ interface TaskRepository {
|
|||||||
|
|
||||||
fun getTaskLists(): Flow<List<TaskList>>
|
fun getTaskLists(): Flow<List<TaskList>>
|
||||||
suspend fun insertTaskList(taskList: TaskList)
|
suspend fun insertTaskList(taskList: TaskList)
|
||||||
|
suspend fun updateTaskList(taskList: TaskList)
|
||||||
suspend fun deleteTaskList(taskListId: Long, isDeleted: Boolean)
|
suspend fun deleteTaskList(taskListId: Long, isDeleted: Boolean)
|
||||||
fun getTaskListsWithOverdue(nowMillis: Long): Flow<List<TaskListWithOverdue>>
|
fun getTaskListsWithOverdue(nowMillis: Long): Flow<List<TaskListWithOverdue>>
|
||||||
}
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
package com.wismna.geoffroy.donext.domain.usecase
|
||||||
|
|
||||||
|
import com.wismna.geoffroy.donext.domain.model.TaskList
|
||||||
|
import com.wismna.geoffroy.donext.domain.repository.TaskRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class UpdateTaskListUseCase @Inject constructor(
|
||||||
|
private val repository: TaskRepository
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(taskListId: Long, title: String, order: Int) {
|
||||||
|
repository.updateTaskList(
|
||||||
|
TaskList(
|
||||||
|
id = taskListId,
|
||||||
|
name = title,
|
||||||
|
order = order,
|
||||||
|
isDeleted = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.filled.Add
|
|||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -31,15 +32,13 @@ import androidx.compose.material3.rememberDrawerState
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
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 androidx.navigation.NavHostController
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
@@ -50,6 +49,7 @@ import com.wismna.geoffroy.donext.domain.model.AppDestination
|
|||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.MainViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.MainViewModel
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskListViewModel
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.TaskViewModel
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -58,8 +58,6 @@ fun MainScreen(
|
|||||||
viewModel: MainViewModel = hiltViewModel()
|
viewModel: MainViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
var showTaskSheet by remember { mutableStateOf(false) }
|
|
||||||
var showAddListSheet by remember { mutableStateOf(false) }
|
|
||||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val taskViewModel: TaskViewModel = hiltViewModel()
|
val taskViewModel: TaskViewModel = hiltViewModel()
|
||||||
@@ -71,23 +69,20 @@ fun MainScreen(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val startDestination = viewModel.destinations.firstOrNull() ?: AppDestination.ManageLists
|
if (viewModel.showTaskSheet) {
|
||||||
if (showTaskSheet) {
|
TaskBottomSheet(taskViewModel) { viewModel.showTaskSheet = false }
|
||||||
TaskBottomSheet(taskViewModel) { showTaskSheet = false }
|
|
||||||
}
|
}
|
||||||
if (showAddListSheet) {
|
if (viewModel.showAddListSheet) {
|
||||||
AddListBottomSheet { showAddListSheet = false }
|
AddListBottomSheet { viewModel.showAddListSheet = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||||
val currentDestination =
|
viewModel.setCurrentDestination(navBackStackEntry)
|
||||||
viewModel.deriveDestination(navBackStackEntry?.destination?.route)
|
|
||||||
?: startDestination
|
|
||||||
|
|
||||||
ModalNavigationDrawer(
|
ModalNavigationDrawer(
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
MenuScreen (
|
MenuScreen (
|
||||||
currentDestination = currentDestination,
|
currentDestination = viewModel.currentDestination,
|
||||||
onNavigate = { route ->
|
onNavigate = { route ->
|
||||||
scope.launch { drawerState.close() }
|
scope.launch { drawerState.close() }
|
||||||
navController.navigate(route) {
|
navController.navigate(route) {
|
||||||
@@ -98,12 +93,25 @@ fun MainScreen(
|
|||||||
},
|
},
|
||||||
drawerState = drawerState
|
drawerState = drawerState
|
||||||
) {
|
) {
|
||||||
|
AppContent(viewModel = viewModel, taskViewModel = taskViewModel, navController = navController, scope = scope, drawerState = drawerState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AppContent(
|
||||||
|
modifier : Modifier = Modifier,
|
||||||
|
viewModel: MainViewModel,
|
||||||
|
taskViewModel: TaskViewModel,
|
||||||
|
navController: NavHostController,
|
||||||
|
scope: CoroutineScope,
|
||||||
|
drawerState: DrawerState
|
||||||
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier.background(MaterialTheme.colorScheme.primaryContainer),
|
modifier = modifier.background(MaterialTheme.colorScheme.primaryContainer),
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(currentDestination!!.title) },
|
title = { Text(viewModel.currentDestination.title) },
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||||
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
@@ -111,7 +119,7 @@ fun MainScreen(
|
|||||||
),
|
),
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
||||||
if (currentDestination!!.showBackButton) {
|
if (viewModel.currentDestination.showBackButton) {
|
||||||
IconButton(onClick = { navController.popBackStack() }) {
|
IconButton(onClick = { navController.popBackStack() }) {
|
||||||
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
|
Icon(Icons.Default.ArrowBack, contentDescription = "Back")
|
||||||
}
|
}
|
||||||
@@ -126,8 +134,8 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if (currentDestination is AppDestination.ManageLists) {
|
if (viewModel.currentDestination is AppDestination.ManageLists) {
|
||||||
IconButton(onClick = { showAddListSheet = true }) {
|
IconButton(onClick = { viewModel.showAddListSheet = true }) {
|
||||||
Icon(Icons.Default.Add, contentDescription = "Add List")
|
Icon(Icons.Default.Add, contentDescription = "Add List")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,11 +143,11 @@ fun MainScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
when (val dest = currentDestination) {
|
when (val dest = viewModel.currentDestination) {
|
||||||
is AppDestination.TaskList -> {
|
is AppDestination.TaskList -> {
|
||||||
TaskListFab(
|
TaskListFab(
|
||||||
taskListId = dest.taskListId,
|
taskListId = dest.taskListId,
|
||||||
showBottomSheet = { showTaskSheet = it }
|
showBottomSheet = { viewModel.showTaskSheet = it }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
@@ -155,7 +163,7 @@ fun MainScreen(
|
|||||||
) {
|
) {
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = startDestination.route,
|
startDestination = viewModel.startDestination.route,
|
||||||
enterTransition = {
|
enterTransition = {
|
||||||
slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }, animationSpec = tween(300))
|
slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }, animationSpec = tween(300))
|
||||||
},
|
},
|
||||||
@@ -169,32 +177,31 @@ fun MainScreen(
|
|||||||
slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth }, animationSpec = tween(300))
|
slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth }, animationSpec = tween(300))
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
viewModel.destinations.forEach { destination ->
|
//viewModel.destinations.forEach { destination ->
|
||||||
composable(
|
composable(
|
||||||
route = "taskList/{taskListId}",
|
route = "taskList/{taskListId}",
|
||||||
arguments = listOf(navArgument("taskListId") {
|
arguments = listOf(navArgument("taskListId") {
|
||||||
type = NavType.LongType
|
type = NavType.LongType
|
||||||
})
|
})
|
||||||
) { navBackStackEntry ->
|
) { navBackStackEntry ->
|
||||||
val viewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
|
val taskListViewModel: TaskListViewModel = hiltViewModel(navBackStackEntry)
|
||||||
TaskListScreen(
|
TaskListScreen(
|
||||||
viewModel = viewModel,
|
viewModel = taskListViewModel,
|
||||||
onTaskClick = { task ->
|
onTaskClick = { task ->
|
||||||
taskViewModel.startEditTask(task)
|
taskViewModel.startEditTask(task)
|
||||||
showTaskSheet = true
|
viewModel.showTaskSheet = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
|
|
||||||
composable(AppDestination.ManageLists.route) {
|
composable(AppDestination.ManageLists.route) {
|
||||||
ManageListsScreen(
|
ManageListsScreen(
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
showAddListSheet = {showAddListSheet = true}
|
showAddListSheet = {viewModel.showAddListSheet = true}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@@ -7,11 +7,11 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Edit
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@@ -23,9 +23,8 @@ import androidx.compose.material3.ListItem
|
|||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -33,12 +32,11 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
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.TaskList
|
|
||||||
import com.wismna.geoffroy.donext.presentation.viewmodel.ManageListsViewModel
|
import com.wismna.geoffroy.donext.presentation.viewmodel.ManageListsViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -52,13 +50,41 @@ fun ManageListsScreen(
|
|||||||
|
|
||||||
LazyColumn(modifier = modifier.fillMaxWidth().padding()) {
|
LazyColumn(modifier = modifier.fillMaxWidth().padding()) {
|
||||||
itemsIndexed(lists, key = { _, list -> list.id!! }) { index, list ->
|
itemsIndexed(lists, key = { _, list -> list.id!! }) { index, list ->
|
||||||
|
|
||||||
|
var isInEditMode by remember { mutableStateOf(false) }
|
||||||
|
var editedName by remember { mutableStateOf(list.name) }
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier.animateItem(),
|
modifier = Modifier.animateItem(),
|
||||||
headlineContent = { Text(list.name) },
|
headlineContent = {
|
||||||
|
if (isInEditMode) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = editedName,
|
||||||
|
onValueChange = { editedName = it },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Text(list.name)
|
||||||
|
}
|
||||||
|
},
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
|
if (isInEditMode) {
|
||||||
Row {
|
Row {
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
||||||
IconButton(onClick = { /* TODO: edit list */ }) {
|
IconButton(onClick = { isInEditMode = false }) {
|
||||||
|
Icon(Icons.Default.Close, contentDescription = "Cancel")
|
||||||
|
}
|
||||||
|
IconButton(onClick = {
|
||||||
|
viewModel.updateTaskListName(list.copy(name = editedName))
|
||||||
|
isInEditMode = false
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Check, contentDescription = "Save")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Row {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
|
||||||
|
IconButton(onClick = { isInEditMode = true }) {
|
||||||
Icon(Icons.Default.Edit, contentDescription = "Edit")
|
Icon(Icons.Default.Edit, contentDescription = "Edit")
|
||||||
}
|
}
|
||||||
IconButton(onClick = { viewModel.deleteTaskList(list.id!!) }) {
|
IconButton(onClick = { viewModel.deleteTaskList(list.id!!) }) {
|
||||||
@@ -67,40 +93,13 @@ fun ManageListsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun EditableListRow(
|
|
||||||
list: TaskList,
|
|
||||||
onNameChange: (String) -> Unit,
|
|
||||||
//onTypeChange: (ListType) -> Unit,
|
|
||||||
onDone: () -> Unit
|
|
||||||
) {
|
|
||||||
var name by remember { mutableStateOf(list.name) }
|
|
||||||
//var type by remember { mutableStateOf(list.type) }
|
|
||||||
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(8.dp)
|
|
||||||
) {
|
|
||||||
TextField(
|
|
||||||
value = name,
|
|
||||||
onValueChange = { name = it },
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
singleLine = true
|
|
||||||
)
|
|
||||||
// TODO: implement type
|
|
||||||
//DropdownSelector(selected = type, onSelect = { type = it; onTypeChange(it) })
|
|
||||||
IconButton(onClick = onDone) {
|
|
||||||
Icon(Icons.Default.Check, contentDescription = "Save")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AddListBottomSheet(
|
fun AddListBottomSheet(
|
||||||
@@ -122,11 +121,21 @@ fun AddListBottomSheet(
|
|||||||
Text("Create New List", style = MaterialTheme.typography.titleMedium)
|
Text("Create New List", style = MaterialTheme.typography.titleMedium)
|
||||||
|
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
TextField(
|
/*TextField(
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { name = it },
|
||||||
label = { Text("List Name") },
|
label = { Text("List Name") },
|
||||||
singleLine = true
|
singleLine = true
|
||||||
|
)*/
|
||||||
|
OutlinedTextField(
|
||||||
|
value = name,
|
||||||
|
singleLine = true,
|
||||||
|
onValueChange = { name = it },
|
||||||
|
label = { Text("Title") },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.focusRequester(titleFocusRequester),
|
||||||
|
isError = name.isEmpty(),
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
@@ -142,8 +151,8 @@ fun AddListBottomSheet(
|
|||||||
|
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
|
Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
|
||||||
TextButton(onClick = onDismiss) { Text("Cancel") }
|
//TextButton(onClick = onDismiss) { Text("Cancel") }
|
||||||
Spacer(Modifier.width(8.dp))
|
//Spacer(Modifier.width(8.dp))
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
viewModel.createTaskList(name/*, type, description*/, 1)
|
viewModel.createTaskList(name/*, type, description*/, 1)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
|
@@ -5,6 +5,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
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.usecase.GetTaskListsUseCase
|
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
@@ -23,6 +24,15 @@ class MainViewModel @Inject constructor(
|
|||||||
var destinations by mutableStateOf<List<AppDestination>>(emptyList())
|
var destinations by mutableStateOf<List<AppDestination>>(emptyList())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var startDestination by mutableStateOf<AppDestination>(AppDestination.ManageLists)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var currentDestination by mutableStateOf(startDestination)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var showTaskSheet by mutableStateOf(false)
|
||||||
|
var showAddListSheet by mutableStateOf(false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
getTaskLists()
|
getTaskLists()
|
||||||
.onEach { lists ->
|
.onEach { lists ->
|
||||||
@@ -30,17 +40,20 @@ class MainViewModel @Inject constructor(
|
|||||||
AppDestination.TaskList(taskList.id!!, taskList.name)
|
AppDestination.TaskList(taskList.id!!, taskList.name)
|
||||||
} + AppDestination.ManageLists
|
} + AppDestination.ManageLists
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
if (!destinations.isEmpty()) startDestination = destinations.first()
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deriveDestination(route: String?): AppDestination? {
|
fun setCurrentDestination(navBackStackEntry: NavBackStackEntry?) {
|
||||||
if (route == null) return null
|
val route = navBackStackEntry?.destination?.route
|
||||||
return destinations.firstOrNull { dest ->
|
val taskListId = navBackStackEntry?.arguments?.getLong("taskListId")
|
||||||
|
|
||||||
|
currentDestination = destinations.firstOrNull { dest ->
|
||||||
when (dest) {
|
when (dest) {
|
||||||
is AppDestination.TaskList -> route.startsWith("tasklist/")
|
is AppDestination.TaskList -> taskListId != null && dest.taskListId == taskListId
|
||||||
else -> dest.route == route
|
else -> dest.route == route
|
||||||
}
|
}
|
||||||
}
|
} ?: startDestination
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,6 +9,7 @@ import com.wismna.geoffroy.donext.domain.model.TaskList
|
|||||||
import com.wismna.geoffroy.donext.domain.usecase.AddTaskListUseCase
|
import com.wismna.geoffroy.donext.domain.usecase.AddTaskListUseCase
|
||||||
import com.wismna.geoffroy.donext.domain.usecase.DeleteTaskListUseCase
|
import com.wismna.geoffroy.donext.domain.usecase.DeleteTaskListUseCase
|
||||||
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
import com.wismna.geoffroy.donext.domain.usecase.GetTaskListsUseCase
|
||||||
|
import com.wismna.geoffroy.donext.domain.usecase.UpdateTaskListUseCase
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -19,6 +20,7 @@ import javax.inject.Inject
|
|||||||
class ManageListsViewModel @Inject constructor(
|
class ManageListsViewModel @Inject constructor(
|
||||||
getTaskListsUseCase: GetTaskListsUseCase,
|
getTaskListsUseCase: GetTaskListsUseCase,
|
||||||
private val addTaskListUseCase: AddTaskListUseCase,
|
private val addTaskListUseCase: AddTaskListUseCase,
|
||||||
|
private val updateTaskListUseCase: UpdateTaskListUseCase,
|
||||||
private val deleteTaskListUseCase: DeleteTaskListUseCase
|
private val deleteTaskListUseCase: DeleteTaskListUseCase
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
@@ -38,6 +40,11 @@ class ManageListsViewModel @Inject constructor(
|
|||||||
addTaskListUseCase(title, order)
|
addTaskListUseCase(title, order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun updateTaskListName(taskList: TaskList) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
updateTaskListUseCase(taskList.id!!, taskList.name, taskList.order)
|
||||||
|
}
|
||||||
|
}
|
||||||
fun deleteTaskList(taskId: Long) {
|
fun deleteTaskList(taskId: Long) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
deleteTaskListUseCase(taskId)
|
deleteTaskListUseCase(taskId)
|
||||||
|
Reference in New Issue
Block a user