Skip to content

Commit

Permalink
Add "Add task list…" button at top of the tasks list
Browse files Browse the repository at this point in the history
  • Loading branch information
opatry committed Sep 30, 2024
1 parent fbf0e95 commit 00b75de
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ import org.jetbrains.compose.resources.stringResource

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
actual fun TaskListsMasterDetail(viewModel: TaskListsViewModel) {
actual fun TaskListsMasterDetail(
viewModel: TaskListsViewModel,
onNewTaskList: (String) -> Unit
) {
val taskLists by viewModel.taskLists.collectAsState(emptyList())

// need to store a saveable (Serializable/Parcelable) object
Expand All @@ -63,16 +66,16 @@ actual fun TaskListsMasterDetail(viewModel: TaskListsViewModel) {
listPane = {
AnimatedPane {
if (taskLists.isEmpty()) {
// TODO dialog to ask for the new task list name
val newTaskListName = stringResource(Res.string.default_task_list_title)
NoTaskListEmptyState {
viewModel.createTaskList(newTaskListName)
onNewTaskList(newTaskListName)
}
} else {
Row {
TaskListsColumn(
taskLists,
selectedItem = taskLists.find { it.id == navigator.currentDestination?.content },
onNewTaskList = { onNewTaskList("") },
onItemClick = { taskList ->
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, taskList.id)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.unit.dp
import net.opatry.tasks.app.ui.component.EditTextDialog
import net.opatry.tasks.app.ui.component.MissingScreen
import net.opatry.tasks.app.ui.component.ProfileIcon
import net.opatry.tasks.app.ui.screen.TaskListsMasterDetail
Expand Down Expand Up @@ -88,6 +89,9 @@ fun TasksApp(userViewModel: UserViewModel, tasksViewModel: TaskListsViewModel) {
tasksViewModel.enableAutoRefresh(isFocused && isSigned)
}

var newTaskListDefaultTitle by remember { mutableStateOf("") }
var showNewTaskListDialog by remember { mutableStateOf(false) }

NavigationSuiteScaffold(navigationSuiteItems = {
// Only if expanded state
if (false) {
Expand Down Expand Up @@ -134,7 +138,24 @@ fun TasksApp(userViewModel: UserViewModel, tasksViewModel: TaskListsViewModel) {
}
}

TaskListsMasterDetail(tasksViewModel)
TaskListsMasterDetail(tasksViewModel) { title ->
newTaskListDefaultTitle = title
showNewTaskListDialog = true
}

if (showNewTaskListDialog) {
EditTextDialog(
onDismissRequest = { showNewTaskListDialog = false },
validateLabel = "Create",
onValidate = { title ->
showNewTaskListDialog = false
tasksViewModel.createTaskList(title)
},
dialogTitle = "New task list",
initialText = newTaskListDefaultTitle,
allowBlank = false
)
}
}

AppTasksScreen.Calendar -> MissingScreen(stringResource(AppTasksScreen.Calendar.labelRes), LucideIcons.Calendar)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,28 @@

package net.opatry.tasks.app.ui.component

import CircleFadingPlus
import LucideIcons
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand All @@ -44,16 +54,39 @@ import net.opatry.tasks.app.ui.tooling.TaskfolioPreview
import net.opatry.tasks.app.ui.tooling.TaskfolioThemedPreview


@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TaskListsColumn(
taskLists: List<TaskListUIModel>,
selectedItem: TaskListUIModel? = null,
onNewTaskList: () -> Unit,
onItemClick: (TaskListUIModel) -> Unit
) {
LazyColumn(contentPadding = PaddingValues(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
val listState = rememberLazyListState()
LazyColumn(state = listState, verticalArrangement = Arrangement.spacedBy(8.dp)) {
stickyHeader {
Box(
Modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.padding(horizontal = 8.dp)
) {
// TODO could be a "in-place" replace with a text field (no border)
TextButton(
onClick = onNewTaskList,
) {
RowWithIcon("Add task list…", LucideIcons.CircleFadingPlus)
}
}

AnimatedVisibility(listState.firstVisibleItemScrollOffset > 0) {
HorizontalDivider()
}
}
items(taskLists) { taskList ->
TaskListRow(
taskList,
Modifier.padding(horizontal = 8.dp),
isSelected = taskList.id == selectedItem?.id,
onClick = { onItemClick(taskList) }
)
Expand All @@ -64,6 +97,7 @@ fun TaskListsColumn(
@Composable
fun TaskListRow(
taskList: TaskListUIModel,
modifier: Modifier = Modifier,
isSelected: Boolean = false,
onClick: () -> Unit
) {
Expand All @@ -72,7 +106,7 @@ fun TaskListRow(
else -> Color.Transparent
}

Card(colors = CardDefaults.outlinedCardColors(), onClick = onClick) {
Card(onClick = onClick, modifier = modifier, colors = CardDefaults.outlinedCardColors()) {
ListItem(
headlineContent = {
Text(taskList.title, overflow = TextOverflow.Ellipsis, maxLines = 1)
Expand All @@ -96,8 +130,8 @@ private fun TaskListRowScaffold(
"TODO DATE",
tasks = emptyList(),
),
isSelected,
{}
isSelected = isSelected,
onClick = {}
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ import androidx.compose.runtime.Composable
import net.opatry.tasks.app.ui.TaskListsViewModel

@Composable
expect fun TaskListsMasterDetail(viewModel: TaskListsViewModel)
expect fun TaskListsMasterDetail(
viewModel: TaskListsViewModel,
onNewTaskList: (String) -> Unit
)
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ import net.opatry.tasks.resources.default_task_list_title
import org.jetbrains.compose.resources.stringResource

@Composable
actual fun TaskListsMasterDetail(viewModel: TaskListsViewModel) {
actual fun TaskListsMasterDetail(
viewModel: TaskListsViewModel,
onNewTaskList: (String) -> Unit
) {
val taskLists by viewModel.taskLists.collectAsState(emptyList())

// Store the list id, and not the list object to prevent keeping
Expand All @@ -52,16 +55,16 @@ actual fun TaskListsMasterDetail(viewModel: TaskListsViewModel) {

Row(Modifier.fillMaxWidth()) {
if (taskLists.isEmpty()) {
// TODO dialog to ask for the new task list name
val newTaskListName = stringResource(Res.string.default_task_list_title)
NoTaskListEmptyState {
viewModel.createTaskList(newTaskListName)
onNewTaskList(newTaskListName)
}
} else {
Box(Modifier.weight(.3f)) {
TaskListsColumn(
taskLists,
selectedItem = taskLists.find { it.id == currentTaskListId },
onNewTaskList = { onNewTaskList("") },
onItemClick = { taskList ->
currentTaskListId = taskList.id
}
Expand Down

0 comments on commit 00b75de

Please sign in to comment.