Merge pull request #104 from SELab1/tasksoverview

Tasksoverview
This commit is contained in:
brreynie 2023-05-09 22:29:26 +02:00 committed by GitHub Enterprise
commit d22d40439d
24 changed files with 380 additions and 205 deletions

View file

@ -2,14 +2,16 @@ package be.ugent.sel.studeez.common.composable.feed
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import be.ugent.sel.studeez.data.SelectedTask import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.domain.FeedDAO import be.ugent.sel.studeez.domain.FeedDAO
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TaskDAO import be.ugent.sel.studeez.domain.TaskDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject

View file

@ -1,13 +1,7 @@
package be.ugent.sel.studeez.common.composable.tasks package be.ugent.sel.studeez.common.composable.tasks
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.Icon import androidx.compose.material.Icon
@ -15,6 +9,8 @@ import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.List
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -24,16 +20,20 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.R.string as AppText
import be.ugent.sel.studeez.common.composable.StealthButton import be.ugent.sel.studeez.common.composable.StealthButton
import be.ugent.sel.studeez.data.local.models.task.Subject import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import be.ugent.sel.studeez.R.string as AppText
@Composable @Composable
fun SubjectEntry( fun SubjectEntry(
subject: Subject, subject: Subject,
onViewSubject: () -> Unit, onViewSubject: () -> Unit,
getStudyTime: () -> Flow<Int>,
) { ) {
val studytime by getStudyTime().collectAsState(initial = 0)
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -70,7 +70,7 @@ fun SubjectEntry(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
text = HoursMinutesSeconds(subject.time).toString(), text = HoursMinutesSeconds(studytime).toString(),
) )
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@ -80,7 +80,7 @@ fun SubjectEntry(
imageVector = Icons.Default.List, imageVector = Icons.Default.List,
contentDescription = stringResource(id = AppText.tasks) contentDescription = stringResource(id = AppText.tasks)
) )
Text(text = "0/0") // TODO Text(text = "${subject.taskCompletedCount}/${subject.taskCount}")
} }
} }
} }
@ -104,9 +104,12 @@ fun SubjectEntryPreview() {
subject = Subject( subject = Subject(
name = "Test Subject", name = "Test Subject",
argb_color = 0xFFFFD200, argb_color = 0xFFFFD200,
time = 60 taskCount = 5,
taskCompletedCount = 2,
), ),
) {} onViewSubject = {},
getStudyTime = { flowOf() }
)
} }
@Preview @Preview
@ -116,7 +119,8 @@ fun OverflowSubjectEntryPreview() {
subject = Subject( subject = Subject(
name = "Testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt", name = "Testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
argb_color = 0xFFFFD200, argb_color = 0xFFFFD200,
time = 60
), ),
) {} onViewSubject = {},
getStudyTime = { flowOf() }
)
} }

View file

@ -1,17 +1,7 @@
package be.ugent.sel.studeez.common.composable.tasks package be.ugent.sel.studeez.common.composable.tasks
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box import androidx.compose.material.*
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Card
import androidx.compose.material.Checkbox
import androidx.compose.material.CheckboxDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -31,7 +21,7 @@ import be.ugent.sel.studeez.resources
fun TaskEntry( fun TaskEntry(
task: Task, task: Task,
onCheckTask: (Boolean) -> Unit, onCheckTask: (Boolean) -> Unit,
onDeleteTask: () -> Unit, onArchiveTask: () -> Unit,
onStartTask: () -> Unit onStartTask: () -> Unit
) { ) {
Card( Card(
@ -81,7 +71,7 @@ fun TaskEntry(
Box(modifier = Modifier.weight(7f)) { Box(modifier = Modifier.weight(7f)) {
if (task.completed) { if (task.completed) {
IconButton( IconButton(
onClick = onDeleteTask, onClick = onArchiveTask,
modifier = Modifier modifier = Modifier
.padding(start = 20.dp) .padding(start = 20.dp)
) { ) {

View file

@ -1,10 +1,22 @@
package be.ugent.sel.studeez.data.local.models.task package be.ugent.sel.studeez.data.local.models.task
import com.google.firebase.firestore.DocumentId import com.google.firebase.firestore.DocumentId
import com.google.firebase.firestore.Exclude
data class Subject( data class Subject(
@DocumentId val id: String = "", @DocumentId val id: String = "",
val name: String = "", val name: String = "",
val time: Int = 0,
val argb_color: Long = 0, val argb_color: Long = 0,
var archived: Boolean = false,
@get:Exclude @set:Exclude
var taskCount: Int = 0,
@get:Exclude @set:Exclude
var taskCompletedCount: Int = 0,
) )
object SubjectDocument {
const val id = "id"
const val name = "name"
const val archived = "archived"
const val argb_color = "argb_color"
}

View file

@ -5,10 +5,15 @@ import com.google.firebase.firestore.DocumentId
data class Task( data class Task(
@DocumentId val id: String = "", @DocumentId val id: String = "",
val name: String = "", val name: String = "",
val completed: Boolean = false, var completed: Boolean = false,
val time: Int = 0, val time: Int = 0,
val subjectId: String = "", val subjectId: String = "",
) var archived: Boolean = false,
) {
fun archive() {
this.archived = true
}
}
object TaskDocument { object TaskDocument {
const val id = "id" const val id = "id"
@ -16,4 +21,5 @@ object TaskDocument {
const val completed = "completed" const val completed = "completed"
const val time = "time" const val time = "time"
const val subjectId = "subjectId" const val subjectId = "subjectId"
const val archived = "archived"
} }

View file

@ -12,5 +12,10 @@ interface SubjectDAO {
fun deleteSubject(oldSubject: Subject) fun deleteSubject(oldSubject: Subject)
fun updateSubject(newSubject: Subject) fun updateSubject(newSubject: Subject)
suspend fun getTaskCount(subject: Subject): Int
suspend fun getCompletedTaskCount(subject: Subject): Int
fun getStudyTime(subject: Subject): Flow<Int>
suspend fun getSubject(subjectId: String): Subject? suspend fun getSubject(subjectId: String): Subject?
} }

View file

@ -14,7 +14,5 @@ interface TaskDAO {
fun deleteTask(oldTask: Task) fun deleteTask(oldTask: Task)
fun toggleTaskCompleted(task: Task, completed: Boolean)
suspend fun getTask(subjectId: String, taskId: String): Task suspend fun getTask(subjectId: String, taskId: String): Task
} }

View file

@ -1,11 +1,14 @@
package be.ugent.sel.studeez.domain.implementation package be.ugent.sel.studeez.domain.implementation
import be.ugent.sel.studeez.data.local.models.task.Subject import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task import be.ugent.sel.studeez.data.local.models.task.SubjectDocument
import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.SubjectDAO import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.domain.TaskDAO
import com.google.firebase.firestore.AggregateSource
import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.snapshots import com.google.firebase.firestore.ktx.snapshots
import com.google.firebase.firestore.ktx.toObject import com.google.firebase.firestore.ktx.toObject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -16,11 +19,20 @@ import javax.inject.Inject
class FireBaseSubjectDAO @Inject constructor( class FireBaseSubjectDAO @Inject constructor(
private val firestore: FirebaseFirestore, private val firestore: FirebaseFirestore,
private val auth: AccountDAO, private val auth: AccountDAO,
private val taskDAO: TaskDAO,
) : SubjectDAO { ) : SubjectDAO {
override fun getSubjects(): Flow<List<Subject>> { override fun getSubjects(): Flow<List<Subject>> {
return currentUserSubjectsCollection() return currentUserSubjectsCollection()
.subjectNotArchived()
.snapshots() .snapshots()
.map { it.toObjects(Subject::class.java) } .map { it.toObjects(Subject::class.java) }
.map { subjects ->
subjects.map { subject ->
subject.taskCount = getTaskCount(subject)
subject.taskCompletedCount = getCompletedTaskCount(subject)
subject
}
}
} }
override suspend fun getSubject(subjectId: String): Subject? { override suspend fun getSubject(subjectId: String): Subject? {
@ -39,8 +51,45 @@ class FireBaseSubjectDAO @Inject constructor(
currentUserSubjectsCollection().document(newSubject.id).set(newSubject) currentUserSubjectsCollection().document(newSubject.id).set(newSubject)
} }
override suspend fun getTaskCount(subject: Subject): Int {
return subjectTasksCollection(subject)
.taskNotArchived()
.count()
.get(AggregateSource.SERVER)
.await()
.count.toInt()
}
override suspend fun getCompletedTaskCount(subject: Subject): Int {
return subjectTasksCollection(subject)
.taskNotArchived()
.taskNotCompleted()
.count()
.get(AggregateSource.SERVER)
.await()
.count.toInt()
}
override fun getStudyTime(subject: Subject): Flow<Int> {
return taskDAO.getTasks(subject)
.map { tasks -> tasks.sumOf { it.time } }
}
private fun currentUserSubjectsCollection(): CollectionReference = private fun currentUserSubjectsCollection(): CollectionReference =
firestore.collection(FireBaseCollections.USER_COLLECTION) firestore.collection(FireBaseCollections.USER_COLLECTION)
.document(auth.currentUserId) .document(auth.currentUserId)
.collection(FireBaseCollections.SUBJECT_COLLECTION) .collection(FireBaseCollections.SUBJECT_COLLECTION)
private fun subjectTasksCollection(subject: Subject): CollectionReference =
firestore.collection(FireBaseCollections.USER_COLLECTION)
.document(auth.currentUserId)
.collection(FireBaseCollections.SUBJECT_COLLECTION)
.document(subject.id)
.collection(FireBaseCollections.TASK_COLLECTION)
fun CollectionReference.subjectNotArchived(): Query =
this.whereEqualTo(SubjectDocument.archived, false)
fun Query.subjectNotArchived(): Query =
this.whereEqualTo(SubjectDocument.archived, false)
} }

View file

@ -7,10 +7,10 @@ import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.TaskDAO import be.ugent.sel.studeez.domain.TaskDAO
import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.Query
import com.google.firebase.firestore.ktx.snapshots import com.google.firebase.firestore.ktx.snapshots
import com.google.firebase.firestore.ktx.toObject import com.google.firebase.firestore.ktx.toObject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.tasks.await import kotlinx.coroutines.tasks.await
import javax.inject.Inject import javax.inject.Inject
@ -21,6 +21,7 @@ class FireBaseTaskDAO @Inject constructor(
) : TaskDAO { ) : TaskDAO {
override fun getTasks(subject: Subject): Flow<List<Task>> { override fun getTasks(subject: Subject): Flow<List<Task>> {
return selectedSubjectTasksCollection(subject.id) return selectedSubjectTasksCollection(subject.id)
.taskNotArchived()
.snapshots() .snapshots()
.map { it.toObjects(Task::class.java) } .map { it.toObjects(Task::class.java) }
} }
@ -34,23 +35,34 @@ class FireBaseTaskDAO @Inject constructor(
} }
override fun updateTask(newTask: Task) { override fun updateTask(newTask: Task) {
selectedSubjectTasksCollection(newTask.id).document(newTask.id).set(newTask) selectedSubjectTasksCollection(newTask.subjectId)
.document(newTask.id)
.set(newTask)
} }
override fun deleteTask(oldTask: Task) { override fun deleteTask(oldTask: Task) {
selectedSubjectTasksCollection(oldTask.subjectId).document(oldTask.id).delete() selectedSubjectTasksCollection(oldTask.subjectId).document(oldTask.id).delete()
} }
override fun toggleTaskCompleted(task: Task, completed: Boolean) {
selectedSubjectTasksCollection(task.subjectId)
.document(task.id)
.update(TaskDocument.completed, completed)
}
private fun selectedSubjectTasksCollection(subjectId: String): CollectionReference = private fun selectedSubjectTasksCollection(subjectId: String): CollectionReference =
firestore.collection(FireBaseCollections.USER_COLLECTION) firestore.collection(FireBaseCollections.USER_COLLECTION)
.document(auth.currentUserId) .document(auth.currentUserId)
.collection(FireBaseCollections.SUBJECT_COLLECTION) .collection(FireBaseCollections.SUBJECT_COLLECTION)
.document(subjectId) .document(subjectId)
.collection(FireBaseCollections.TASK_COLLECTION) .collection(FireBaseCollections.TASK_COLLECTION)
} }
// Extend CollectionReference and Query with some filters
fun CollectionReference.taskNotArchived(): Query =
this.whereEqualTo(TaskDocument.archived, false)
fun Query.taskNotArchived(): Query =
this.whereEqualTo(TaskDocument.archived, false)
fun CollectionReference.taskNotCompleted(): Query =
this.whereEqualTo(TaskDocument.completed, true)
fun Query.taskNotCompleted(): Query =
this.whereEqualTo(TaskDocument.completed, true)

View file

@ -7,15 +7,17 @@ import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.FeedDAO import be.ugent.sel.studeez.domain.FeedDAO
import be.ugent.sel.studeez.domain.SessionDAO import be.ugent.sel.studeez.domain.SessionDAO
import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.domain.TaskDAO import be.ugent.sel.studeez.domain.TaskDAO
import com.google.firebase.Timestamp import com.google.firebase.Timestamp
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject import javax.inject.Inject
class FirebaseFeedDAO @Inject constructor( class FirebaseFeedDAO @Inject constructor(
private val sessionDAO: SessionDAO, private val sessionDAO: SessionDAO,
private val taskDAO: TaskDAO, private val taskDAO: TaskDAO,
private val subjectDAO: FireBaseSubjectDAO private val subjectDAO: SubjectDAO
) : FeedDAO { ) : FeedDAO {
/** /**

View file

@ -24,12 +24,12 @@ import be.ugent.sel.studeez.screens.sessions.SessionsRoute
import be.ugent.sel.studeez.screens.settings.SettingsRoute import be.ugent.sel.studeez.screens.settings.SettingsRoute
import be.ugent.sel.studeez.screens.sign_up.SignUpRoute import be.ugent.sel.studeez.screens.sign_up.SignUpRoute
import be.ugent.sel.studeez.screens.splash.SplashRoute import be.ugent.sel.studeez.screens.splash.SplashRoute
import be.ugent.sel.studeez.screens.tasks.SubjectRoute import be.ugent.sel.studeez.screens.subjects.SubjectRoute
import be.ugent.sel.studeez.screens.tasks.TaskRoute import be.ugent.sel.studeez.screens.tasks.TaskRoute
import be.ugent.sel.studeez.screens.tasks.forms.SubjectAddRoute import be.ugent.sel.studeez.screens.subjects.form.SubjectCreateRoute
import be.ugent.sel.studeez.screens.tasks.forms.SubjectEditRoute import be.ugent.sel.studeez.screens.subjects.form.SubjectEditRoute
import be.ugent.sel.studeez.screens.tasks.forms.TaskAddRoute import be.ugent.sel.studeez.screens.tasks.form.TaskCreateRoute
import be.ugent.sel.studeez.screens.tasks.forms.TaskEditRoute import be.ugent.sel.studeez.screens.tasks.form.TaskEditRoute
import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute
import be.ugent.sel.studeez.screens.timer_form.TimerEditRoute import be.ugent.sel.studeez.screens.timer_form.TimerEditRoute
import be.ugent.sel.studeez.screens.timer_form.timer_type_select.TimerTypeSelectScreen import be.ugent.sel.studeez.screens.timer_form.timer_type_select.TimerTypeSelectScreen
@ -81,7 +81,7 @@ fun StudeezNavGraph(
} }
composable(StudeezDestinations.ADD_SUBJECT_FORM) { composable(StudeezDestinations.ADD_SUBJECT_FORM) {
SubjectAddRoute( SubjectCreateRoute(
goBack = goBack, goBack = goBack,
openAndPopUp = openAndPopUp, openAndPopUp = openAndPopUp,
viewModel = hiltViewModel(), viewModel = hiltViewModel(),
@ -105,7 +105,7 @@ fun StudeezNavGraph(
} }
composable(StudeezDestinations.ADD_TASK_FORM) { composable(StudeezDestinations.ADD_TASK_FORM) {
TaskAddRoute( TaskCreateRoute(
goBack = goBack, goBack = goBack,
openAndPopUp = openAndPopUp, openAndPopUp = openAndPopUp,
viewModel = hiltViewModel(), viewModel = hiltViewModel(),

View file

@ -1,9 +1,11 @@
package be.ugent.sel.studeez.screens.session_recap package be.ugent.sel.studeez.screens.session_recap
import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.SessionReportState import be.ugent.sel.studeez.data.SessionReportState
import be.ugent.sel.studeez.data.local.models.SessionReport import be.ugent.sel.studeez.data.local.models.SessionReport
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.SessionDAO import be.ugent.sel.studeez.domain.SessionDAO
import be.ugent.sel.studeez.domain.TaskDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -13,6 +15,8 @@ import javax.inject.Inject
class SessionRecapViewModel @Inject constructor( class SessionRecapViewModel @Inject constructor(
sessionReportState: SessionReportState, sessionReportState: SessionReportState,
private val sessionDAO: SessionDAO, private val sessionDAO: SessionDAO,
private val taskDAO: TaskDAO,
private val selectedTask: SelectedTask,
logService: LogService logService: LogService
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
@ -24,6 +28,8 @@ class SessionRecapViewModel @Inject constructor(
fun saveSession(open: (String, String) -> Unit) { fun saveSession(open: (String, String) -> Unit) {
sessionDAO.saveSession(getSessionReport()) sessionDAO.saveSession(getSessionReport())
val newTask = selectedTask().copy(time = selectedTask().time + report.studyTime)
taskDAO.updateTask(newTask)
open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP) open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP)
} }

View file

@ -0,0 +1,121 @@
package be.ugent.sel.studeez.screens.subjects
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.common.composable.NewTaskSubjectButton
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
import be.ugent.sel.studeez.common.composable.tasks.SubjectEntry
import be.ugent.sel.studeez.data.local.models.task.Subject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun SubjectRoute(
open: (String) -> Unit,
viewModel: SubjectViewModel,
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
) {
val uiState by viewModel.uiState.collectAsState()
SubjectScreen(
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
onAddSubject = { viewModel.onAddSubject(open) },
onViewSubject = { viewModel.onViewSubject(it, open) },
getStudyTime = viewModel::getStudyTime,
uiState,
)
}
@Composable
fun SubjectScreen(
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
onAddSubject: () -> Unit,
onViewSubject: (Subject) -> Unit,
getStudyTime: (Subject) -> Flow<Int>,
uiState: SubjectUiState,
) {
PrimaryScreenTemplate(
title = stringResource(AppText.my_subjects),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
barAction = {},
) {
when (uiState) {
SubjectUiState.Loading -> Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
}
is SubjectUiState.Succes -> {
Column(
modifier = Modifier.padding(top = 5.dp)
) {
NewTaskSubjectButton(onClick = onAddSubject, AppText.new_subject)
LazyColumn {
items(uiState.subjects) {
SubjectEntry(
subject = it,
onViewSubject = { onViewSubject(it) },
getStudyTime = { getStudyTime(it) },
)
}
}
}
}
}
}
}
@Preview
@Composable
fun SubjectScreenPreview() {
SubjectScreen(
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
onAddSubject = {},
onViewSubject = {},
getStudyTime = { flowOf() },
uiState = SubjectUiState.Succes(
listOf(
Subject(
name = "Test Subject",
argb_color = 0xFFFFD200,
taskCount = 5, taskCompletedCount = 2,
)
)
)
)
}
@Preview
@Composable
fun SubjectScreenLoadingPreview() {
SubjectScreen(
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
onAddSubject = {},
onViewSubject = {},
getStudyTime = { flowOf() },
uiState = SubjectUiState.Loading
)
}

View file

@ -0,0 +1,8 @@
package be.ugent.sel.studeez.screens.subjects
import be.ugent.sel.studeez.data.local.models.task.Subject
sealed interface SubjectUiState {
object Loading : SubjectUiState
data class Succes(val subjects: List<Subject>) : SubjectUiState
}

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.screens.tasks package be.ugent.sel.studeez.screens.subjects
import androidx.lifecycle.viewModelScope
import be.ugent.sel.studeez.data.SelectedSubject import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.local.models.task.Subject import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
@ -7,7 +8,7 @@ import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.*
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -16,12 +17,21 @@ class SubjectViewModel @Inject constructor(
private val selectedSubject: SelectedSubject, private val selectedSubject: SelectedSubject,
logService: LogService, logService: LogService,
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
fun addSubject(open: (String) -> Unit) {
val uiState: StateFlow<SubjectUiState> = subjectDAO.getSubjects()
.map { SubjectUiState.Succes(it) }
.stateIn(
scope = viewModelScope,
initialValue = SubjectUiState.Loading,
started = SharingStarted.Eagerly,
)
fun onAddSubject(open: (String) -> Unit) {
open(StudeezDestinations.ADD_SUBJECT_FORM) open(StudeezDestinations.ADD_SUBJECT_FORM)
} }
fun getSubjects(): Flow<List<Subject>> { fun getStudyTime(subject: Subject): Flow<Int> {
return subjectDAO.getSubjects() return subjectDAO.getStudyTime(subject)
} }
fun onViewSubject(subject: Subject, open: (String) -> Unit) { fun onViewSubject(subject: Subject, open: (String) -> Unit) {

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.subjects.form
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -19,10 +19,10 @@ import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.R.string as AppText
@Composable @Composable
fun SubjectAddRoute( fun SubjectCreateRoute(
goBack: () -> Unit, goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit, openAndPopUp: (String, String) -> Unit,
viewModel: SubjectFormViewModel, viewModel: SubjectCreateFormViewModel,
) { ) {
val uiState by viewModel.uiState val uiState by viewModel.uiState
SubjectForm( SubjectForm(
@ -39,7 +39,7 @@ fun SubjectAddRoute(
fun SubjectEditRoute( fun SubjectEditRoute(
goBack: () -> Unit, goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit, openAndPopUp: (String, String) -> Unit,
viewModel: SubjectFormViewModel, viewModel: SubjectEditFormViewModel,
) { ) {
val uiState by viewModel.uiState val uiState by viewModel.uiState
SubjectForm( SubjectForm(

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.subjects.form
data class SubjectFormUiState( data class SubjectFormUiState(
val name: String = "", val name: String = "",

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.subjects.form
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.data.SelectedSubject import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.local.models.task.Subject import be.ugent.sel.studeez.data.local.models.task.Subject
@ -10,25 +11,17 @@ import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel abstract class SubjectFormViewModel(
class SubjectFormViewModel @Inject constructor( protected val subjectDAO: SubjectDAO,
private val subjectDAO: SubjectDAO, protected val selectedSubject: SelectedSubject,
private val selectedSubject: SelectedSubject,
logService: LogService, logService: LogService,
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
var uiState = mutableStateOf( abstract val uiState: MutableState<SubjectFormUiState>
if (selectedSubject.isSet()) SubjectFormUiState(
name = selectedSubject().name,
color = selectedSubject().argb_color
)
else SubjectFormUiState()
)
private set
private val name: String protected val name: String
get() = uiState.value.name get() = uiState.value.name
private val color: Long protected val color: Long
get() = uiState.value.color get() = uiState.value.color
fun onNameChange(newValue: String) { fun onNameChange(newValue: String) {
@ -38,12 +31,16 @@ class SubjectFormViewModel @Inject constructor(
fun onColorChange(newValue: Long) { fun onColorChange(newValue: Long) {
uiState.value = uiState.value.copy(color = newValue) uiState.value = uiState.value.copy(color = newValue)
} }
fun onDelete(openAndPopUp: (String, String) -> Unit) {
subjectDAO.deleteSubject(selectedSubject())
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
} }
@HiltViewModel
class SubjectCreateFormViewModel @Inject constructor(
subjectDAO: SubjectDAO,
selectedSubject: SelectedSubject,
logService: LogService,
) : SubjectFormViewModel(subjectDAO, selectedSubject, logService) {
override val uiState = mutableStateOf(SubjectFormUiState())
fun onCreate(openAndPopUp: (String, String) -> Unit) { fun onCreate(openAndPopUp: (String, String) -> Unit) {
val newSubject = Subject( val newSubject = Subject(
name = name, name = name,
@ -57,6 +54,25 @@ class SubjectFormViewModel @Inject constructor(
// open(StudeezDestinations.TASKS_SCREEN) // open(StudeezDestinations.TASKS_SCREEN)
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.ADD_SUBJECT_FORM) openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.ADD_SUBJECT_FORM)
} }
}
@HiltViewModel
class SubjectEditFormViewModel @Inject constructor(
subjectDAO: SubjectDAO,
selectedSubject: SelectedSubject,
logService: LogService,
) : SubjectFormViewModel(subjectDAO, selectedSubject, logService) {
override val uiState = mutableStateOf(
SubjectFormUiState(
name = selectedSubject().name,
color = selectedSubject().argb_color
)
)
fun onDelete(openAndPopUp: (String, String) -> Unit) {
subjectDAO.updateSubject(selectedSubject().copy(archived = true))
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
}
fun onEdit(openAndPopUp: (String, String) -> Unit) { fun onEdit(openAndPopUp: (String, String) -> Unit) {
val newSubject = selectedSubject().copy( val newSubject = selectedSubject().copy(

View file

@ -1,80 +0,0 @@
package be.ugent.sel.studeez.screens.tasks
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.common.composable.NewTaskSubjectButton
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
import be.ugent.sel.studeez.common.composable.tasks.SubjectEntry
import be.ugent.sel.studeez.data.local.models.task.Subject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun SubjectRoute(
open: (String) -> Unit,
viewModel: SubjectViewModel,
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
) {
SubjectScreen(
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
addSubject = { viewModel.addSubject(open) },
getSubjects = viewModel::getSubjects,
onViewSubject = { viewModel.onViewSubject(it, open) },
)
}
@Composable
fun SubjectScreen(
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
addSubject: () -> Unit,
getSubjects: () -> Flow<List<Subject>>,
onViewSubject: (Subject) -> Unit,
) {
PrimaryScreenTemplate(
title = stringResource(AppText.my_subjects),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
barAction = {},
) {
val subjects = getSubjects().collectAsState(initial = emptyList())
Column(
modifier = Modifier.padding(top = 5.dp)
) {
LazyColumn {
items(subjects.value) {
SubjectEntry(
subject = it,
onViewSubject = { onViewSubject(it) },
)
}
}
NewTaskSubjectButton(onClick = addSubject, AppText.new_subject)
}
}
}
@Preview
@Composable
fun SubjectScreenPreview() {
SubjectScreen(
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
addSubject = {},
getSubjects = { flowOf() },
onViewSubject = {},
)
}

View file

@ -27,10 +27,10 @@ data class TaskActions(
val addTask: () -> Unit, val addTask: () -> Unit,
val getSubject: () -> Subject, val getSubject: () -> Subject,
val getTasks: () -> Flow<List<Task>>, val getTasks: () -> Flow<List<Task>>,
val deleteTask: (Task) -> Unit,
val onCheckTask: (Task, Boolean) -> Unit, val onCheckTask: (Task, Boolean) -> Unit,
val editSubject: () -> Unit, val editSubject: () -> Unit,
val startTask: (Task) -> Unit val startTask: (Task) -> Unit,
val archiveTask: (Task) -> Unit,
) )
fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskActions { fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskActions {
@ -38,10 +38,10 @@ fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskAction
addTask = { viewModel.addTask(open) }, addTask = { viewModel.addTask(open) },
getTasks = viewModel::getTasks, getTasks = viewModel::getTasks,
getSubject = viewModel::getSelectedSubject, getSubject = viewModel::getSelectedSubject,
deleteTask = viewModel::deleteTask,
onCheckTask = { task, isChecked -> viewModel.toggleTaskCompleted(task, isChecked) }, onCheckTask = { task, isChecked -> viewModel.toggleTaskCompleted(task, isChecked) },
editSubject = { viewModel.editSubject(open) }, editSubject = { viewModel.editSubject(open) },
startTask = { task -> viewModel.startTask(task, open) } startTask = { task -> viewModel.startTask(task, open) },
archiveTask = viewModel::archiveTask
) )
} }
@ -76,7 +76,7 @@ fun TaskScreen(
TaskEntry( TaskEntry(
task = it, task = it,
onCheckTask = { isChecked -> taskActions.onCheckTask(it, isChecked) }, onCheckTask = { isChecked -> taskActions.onCheckTask(it, isChecked) },
onDeleteTask = { taskActions.deleteTask(it) }, onArchiveTask = { taskActions.archiveTask(it) },
onStartTask = { taskActions.startTask(it) } onStartTask = { taskActions.startTask(it) }
) )
} }
@ -108,10 +108,10 @@ fun TaskScreenPreview() {
{}, {},
{ Subject(name = "Test Subject") }, { Subject(name = "Test Subject") },
{ flowOf() }, { flowOf() },
{},
{ _, _ -> run {} }, { _, _ -> run {} },
{}, {},
{} {},
{},
) )
) )
} }

View file

@ -5,7 +5,6 @@ import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.local.models.task.Subject import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.domain.TaskDAO import be.ugent.sel.studeez.domain.TaskDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
@ -16,7 +15,6 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class TaskViewModel @Inject constructor( class TaskViewModel @Inject constructor(
private val taskDAO: TaskDAO, private val taskDAO: TaskDAO,
private val subjectDAO: SubjectDAO,
private val selectedSubject: SelectedSubject, private val selectedSubject: SelectedSubject,
private val selectedTask: SelectedTask, private val selectedTask: SelectedTask,
logService: LogService, logService: LogService,
@ -29,11 +27,6 @@ class TaskViewModel @Inject constructor(
return taskDAO.getTasks(selectedSubject()) return taskDAO.getTasks(selectedSubject())
} }
fun deleteSubject(open: (String) -> Unit) {
subjectDAO.deleteSubject(selectedSubject())
open(StudeezDestinations.SUBJECT_SCREEN)
}
fun getSelectedSubject(): Subject { fun getSelectedSubject(): Subject {
return selectedSubject() return selectedSubject()
} }
@ -42,8 +35,12 @@ class TaskViewModel @Inject constructor(
taskDAO.deleteTask(task) taskDAO.deleteTask(task)
} }
fun archiveTask(task: Task) {
taskDAO.updateTask(task.copy(archived = true))
}
fun toggleTaskCompleted(task: Task, completed: Boolean) { fun toggleTaskCompleted(task: Task, completed: Boolean) {
taskDAO.toggleTaskCompleted(task, completed) taskDAO.updateTask(task.copy(completed = completed))
} }
fun editSubject(open: (String) -> Unit) { fun editSubject(open: (String) -> Unit) {

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.tasks.form
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -18,10 +18,10 @@ import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.R.string as AppText
@Composable @Composable
fun TaskAddRoute( fun TaskCreateRoute(
goBack: () -> Unit, goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit, openAndPopUp: (String, String) -> Unit,
viewModel: TaskFormViewModel, viewModel: TaskCreateFormViewModel,
) { ) {
val uiState by viewModel.uiState val uiState by viewModel.uiState
TaskForm( TaskForm(
@ -37,7 +37,7 @@ fun TaskAddRoute(
fun TaskEditRoute( fun TaskEditRoute(
goBack: () -> Unit, goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit, openAndPopUp: (String, String) -> Unit,
viewModel: TaskFormViewModel, viewModel: TaskEditFormViewModel,
) { ) {
val uiState by viewModel.uiState val uiState by viewModel.uiState
TaskForm( TaskForm(

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.tasks.form
data class TaskFormUiState( data class TaskFormUiState(
val name: String = "", val name: String = "",

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.screens.tasks.forms package be.ugent.sel.studeez.screens.tasks.form
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.data.SelectedSubject import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.SelectedTask import be.ugent.sel.studeez.data.SelectedTask
@ -11,38 +12,54 @@ import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel abstract class TaskFormViewModel(
class TaskFormViewModel @Inject constructor( protected val taskDAO: TaskDAO,
private val taskDAO: TaskDAO, protected val selectedSubject: SelectedSubject,
private val selectedSubject: SelectedSubject, protected val selectedTask: SelectedTask,
private val selectedTask: SelectedTask,
logService: LogService, logService: LogService,
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
var uiState = mutableStateOf( abstract val uiState: MutableState<TaskFormUiState>
if (selectedTask.isSet()) TaskFormUiState(selectedTask().name) else TaskFormUiState()
)
private set
private val name: String protected val name: String
get() = uiState.value.name get() = uiState.value.name
fun onNameChange(newValue: String) { fun onNameChange(newValue: String) {
uiState.value = uiState.value.copy(name = newValue) uiState.value = uiState.value.copy(name = newValue)
} }
fun onDelete(openAndPopUp: (String, String) -> Unit) {
taskDAO.deleteTask(selectedTask())
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM)
} }
@HiltViewModel
class TaskCreateFormViewModel @Inject constructor(
taskDAO: TaskDAO,
selectedSubject: SelectedSubject,
selectedTask: SelectedTask,
logService: LogService,
) : TaskFormViewModel(taskDAO, selectedSubject, selectedTask, logService) {
override val uiState = mutableStateOf(TaskFormUiState())
fun onCreate(openAndPopUp: (String, String) -> Unit) { fun onCreate(openAndPopUp: (String, String) -> Unit) {
val newTask = Task(name = name, subjectId = selectedSubject().id) val newTask = Task(name = name, subjectId = selectedSubject().id)
taskDAO.saveTask(newTask) taskDAO.saveTask(newTask)
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.ADD_TASK_FORM) openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.ADD_TASK_FORM)
} }
}
@HiltViewModel
class TaskEditFormViewModel @Inject constructor(
taskDAO: TaskDAO,
selectedSubject: SelectedSubject,
selectedTask: SelectedTask,
logService: LogService,
) : TaskFormViewModel(taskDAO, selectedSubject, selectedTask, logService) {
override val uiState = mutableStateOf(TaskFormUiState())
fun onDelete(openAndPopUp: (String, String) -> Unit) {
taskDAO.deleteTask(selectedTask())
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM)
}
fun onEdit(openAndPopUp: (String, String) -> Unit) { fun onEdit(openAndPopUp: (String, String) -> Unit) {
val newTask = Task(name = name) val newTask = selectedTask().copy(name = name)
taskDAO.updateTask(newTask) taskDAO.updateTask(newTask)
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM) openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM)
} }