Skip to content

Commit 728f5de

Browse files
committed
Add dedicated task list screen — view and manage all tasks
1 parent 47bf3f1 commit 728f5de

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package com.opentasker.ui.screens
2+
3+
import androidx.compose.foundation.layout.*
4+
import androidx.compose.foundation.lazy.LazyColumn
5+
import androidx.compose.foundation.lazy.items
6+
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.filled.Add
8+
import androidx.compose.material.icons.filled.Delete
9+
import androidx.compose.material3.*
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.collectAsState
12+
import androidx.compose.runtime.getValue
13+
import androidx.compose.ui.Alignment
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.unit.dp
16+
import androidx.lifecycle.ViewModel
17+
import androidx.lifecycle.ViewModelProvider
18+
import androidx.lifecycle.viewmodel.compose.viewModel
19+
import androidx.lifecycle.viewModelScope
20+
import com.opentasker.core.model.Task
21+
import com.opentasker.core.storage.AppDatabase
22+
import kotlinx.coroutines.flow.StateFlow
23+
import kotlinx.coroutines.flow.map
24+
import kotlinx.coroutines.flow.stateIn
25+
import kotlinx.coroutines.flow.SharingStarted
26+
27+
/**
28+
* ViewModel for task list screen — loads and manages task list from database.
29+
*/
30+
class TaskListScreenViewModel(private val db: AppDatabase) : ViewModel() {
31+
val tasks: StateFlow<List<Task>> = db.taskDao()
32+
.getAllAsFlow()
33+
.map { entities -> entities.map { it.toDomain() } }
34+
.stateIn(
35+
scope = viewModelScope,
36+
started = SharingStarted.Lazily,
37+
initialValue = emptyList()
38+
)
39+
}
40+
41+
class TaskListScreenViewModelFactory(private val db: AppDatabase) : ViewModelProvider.Factory {
42+
@Suppress("UNCHECKED_CAST")
43+
override fun <T : ViewModel> create(modelClass: Class<T>): T {
44+
return TaskListScreenViewModel(db) as T
45+
}
46+
}
47+
48+
/**
49+
* Screen to display all tasks in a list with add/edit/delete options.
50+
*/
51+
@OptIn(androidx.compose.material3.ExperimentalMaterial3Api::class)
52+
@Composable
53+
fun TaskListScreen(
54+
db: AppDatabase,
55+
onCreateTask: () -> Unit,
56+
onEditTask: (Task) -> Unit,
57+
onDeleteTask: (Task) -> Unit,
58+
onBack: () -> Unit,
59+
) {
60+
val viewModel: TaskListScreenViewModel = viewModel(
61+
factory = TaskListScreenViewModelFactory(db)
62+
)
63+
val tasks by viewModel.tasks.collectAsState()
64+
65+
Scaffold(
66+
topBar = {
67+
TopAppBar(
68+
title = { Text("Tasks") },
69+
)
70+
},
71+
floatingActionButton = {
72+
Button(onClick = onCreateTask) {
73+
Icon(Icons.Filled.Add, contentDescription = "Add")
74+
Text("New Task")
75+
}
76+
}
77+
) { inner ->
78+
Column(modifier = Modifier
79+
.fillMaxSize()
80+
.padding(inner)
81+
.padding(16.dp)
82+
) {
83+
if (tasks.isEmpty()) {
84+
Text(
85+
"No tasks yet. Create one to get started!",
86+
style = MaterialTheme.typography.bodyLarge,
87+
modifier = Modifier.padding(bottom = 16.dp)
88+
)
89+
} else {
90+
LazyColumn {
91+
items(tasks, key = { it.id }) { task ->
92+
TaskCardItem(
93+
task = task,
94+
onEdit = { onEditTask(task) },
95+
onDelete = { onDeleteTask(task) }
96+
)
97+
}
98+
}
99+
}
100+
101+
Spacer(modifier = Modifier.weight(1f))
102+
103+
Button(
104+
onClick = onBack,
105+
modifier = Modifier
106+
.fillMaxWidth()
107+
.padding(top = 16.dp)
108+
) {
109+
Text("Back to Profiles")
110+
}
111+
}
112+
}
113+
}
114+
115+
@Composable
116+
fun TaskCardItem(
117+
task: Task,
118+
onEdit: () -> Unit,
119+
onDelete: () -> Unit,
120+
) {
121+
Card(
122+
modifier = Modifier
123+
.fillMaxWidth()
124+
.padding(vertical = 8.dp),
125+
shape = MaterialTheme.shapes.medium,
126+
) {
127+
Column(modifier = Modifier
128+
.fillMaxWidth()
129+
.padding(12.dp)
130+
) {
131+
Row(
132+
modifier = Modifier
133+
.fillMaxWidth(),
134+
horizontalArrangement = Arrangement.SpaceBetween,
135+
verticalAlignment = Alignment.CenterVertically
136+
) {
137+
Column(modifier = Modifier.weight(1f)) {
138+
Text(task.name, style = MaterialTheme.typography.titleSmall)
139+
Text(
140+
"Actions: ${task.actions.size} | Priority: ${task.priority}",
141+
style = MaterialTheme.typography.bodySmall
142+
)
143+
}
144+
IconButton(onClick = onDelete) {
145+
Icon(Icons.Filled.Delete, contentDescription = "Delete")
146+
}
147+
}
148+
Row(
149+
modifier = Modifier
150+
.fillMaxWidth()
151+
.padding(top = 8.dp),
152+
horizontalArrangement = Arrangement.End
153+
) {
154+
Button(onClick = onEdit) {
155+
Text("Edit")
156+
}
157+
}
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)