resolve conflicts and merge

This commit is contained in:
Lukas Barragan Torres 2023-05-05 11:02:18 +02:00
commit 13b9c0591f
38 changed files with 1291 additions and 64 deletions

View file

@ -9,7 +9,12 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color

View file

@ -0,0 +1,80 @@
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

@ -0,0 +1,31 @@
package be.ugent.sel.studeez.screens.tasks
import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
@HiltViewModel
class SubjectViewModel @Inject constructor(
private val subjectDAO: SubjectDAO,
private val selectedSubject: SelectedSubject,
logService: LogService,
) : StudeezViewModel(logService) {
fun addSubject(open: (String) -> Unit) {
open(StudeezDestinations.ADD_SUBJECT_FORM)
}
fun getSubjects(): Flow<List<Subject>> {
return subjectDAO.getSubjects()
}
fun onViewSubject(subject: Subject, open: (String) -> Unit) {
selectedSubject.set(subject)
open(StudeezDestinations.TASKS_SCREEN)
}
}

View file

@ -0,0 +1,113 @@
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.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
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.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.composable.tasks.TaskEntry
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import be.ugent.sel.studeez.R.string as AppText
data class TaskActions(
val addTask: () -> Unit,
val getSubject: () -> Subject,
val getTasks: () -> Flow<List<Task>>,
val deleteTask: (Task) -> Unit,
val onCheckTask: (Task, Boolean) -> Unit,
val editSubject: () -> Unit,
)
fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskActions {
return TaskActions(
addTask = { viewModel.addTask(open) },
getTasks = viewModel::getTasks,
getSubject = viewModel::getSelectedSubject,
deleteTask = viewModel::deleteTask,
onCheckTask = { task, isChecked -> viewModel.toggleTaskCompleted(task, isChecked) },
editSubject = { viewModel.editSubject(open) }
)
}
@Composable
fun TaskRoute(
goBack: () -> Unit,
open: (String) -> Unit,
viewModel: TaskViewModel,
) {
TaskScreen(
goBack = goBack,
taskActions = getTaskActions(viewModel = viewModel, open = open),
)
}
@Composable
fun TaskScreen(
goBack: () -> Unit,
taskActions: TaskActions,
) {
SecondaryScreenTemplate(
title = taskActions.getSubject().name,
popUp = goBack,
barAction = { EditAction(onClick = taskActions.editSubject) }
) {
val tasks = taskActions.getTasks().collectAsState(initial = emptyList())
Column(
modifier = Modifier.padding(top = 5.dp)
) {
LazyColumn {
items(tasks.value) {
TaskEntry(
task = it,
onCheckTask = { isChecked -> taskActions.onCheckTask(it, isChecked) },
onDeleteTask = { taskActions.deleteTask(it) },
)
}
}
NewTaskSubjectButton(onClick = taskActions.addTask, AppText.new_task)
}
}
}
@Composable
fun EditAction(
onClick: () -> Unit
) {
IconButton(onClick = onClick) {
Icon(
imageVector = Icons.Default.Edit,
contentDescription = stringResource(AppText.edit_task)
)
}
}
@Preview
@Composable
fun TaskScreenPreview() {
TaskScreen(
goBack = {},
taskActions = TaskActions(
{},
{ Subject(name = "Test Subject") },
{ flowOf() },
{},
{ _, _ -> run {} },
{},
)
)
}

View file

@ -0,0 +1,50 @@
package be.ugent.sel.studeez.screens.tasks
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.Task
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.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
@HiltViewModel
class TaskViewModel @Inject constructor(
private val taskDAO: TaskDAO,
private val subjectDAO: SubjectDAO,
private val selectedSubject: SelectedSubject,
logService: LogService,
) : StudeezViewModel(logService) {
fun addTask(open: (String) -> Unit) {
open(StudeezDestinations.ADD_TASK_FORM)
}
fun getTasks(): Flow<List<Task>> {
return taskDAO.getTasks(selectedSubject())
}
fun deleteSubject(open: (String) -> Unit) {
subjectDAO.deleteSubject(selectedSubject())
open(StudeezDestinations.SUBJECT_SCREEN)
}
fun getSelectedSubject(): Subject {
return selectedSubject()
}
fun deleteTask(task: Task) {
taskDAO.deleteTask(task)
}
fun toggleTaskCompleted(task: Task, completed: Boolean) {
taskDAO.toggleTaskCompleted(task, completed)
}
fun editSubject(open: (String) -> Unit) {
open(StudeezDestinations.EDIT_SUBJECT_FORM)
}
}

View file

@ -0,0 +1,119 @@
package be.ugent.sel.studeez.screens.tasks.forms
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.composable.DeleteButton
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.common.ext.fieldModifier
import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun SubjectAddRoute(
goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit,
viewModel: SubjectFormViewModel,
) {
val uiState by viewModel.uiState
SubjectForm(
title = AppText.new_subject,
goBack = goBack,
uiState = uiState,
onConfirm = { viewModel.onCreate(openAndPopUp) },
onNameChange = viewModel::onNameChange,
onColorChange = {},
)
}
@Composable
fun SubjectEditRoute(
goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit,
viewModel: SubjectFormViewModel,
) {
val uiState by viewModel.uiState
SubjectForm(
title = AppText.edit_subject,
goBack = goBack,
uiState = uiState,
onConfirm = { viewModel.onEdit(openAndPopUp) },
onNameChange = viewModel::onNameChange,
onColorChange = {},
) {
DeleteButton(text = AppText.delete_subject) {
viewModel.onDelete(openAndPopUp)
}
}
}
@Composable
fun SubjectForm(
@StringRes title: Int,
goBack: () -> Unit,
uiState: SubjectFormUiState,
onConfirm: () -> Unit,
onNameChange: (String) -> Unit,
onColorChange: (Color) -> Unit,
extraButton: @Composable () -> Unit = {},
) {
SecondaryScreenTemplate(
title = resources().getString(title),
popUp = goBack,
) {
Column {
OutlinedTextField(
singleLine = true,
value = uiState.name,
onValueChange = onNameChange,
placeholder = { Text(stringResource(id = AppText.name)) },
modifier = Modifier.fieldModifier(),
)
BasicButton(
text = AppText.confirm,
modifier = Modifier.basicButton(),
onClick = onConfirm,
)
extraButton()
}
}
}
@Preview
@Composable
fun AddSubjectFormPreview() {
SubjectForm(
title = AppText.new_subject,
goBack = {},
uiState = SubjectFormUiState(),
onConfirm = {},
onNameChange = {},
onColorChange = {},
)
}
@Preview
@Composable
fun EditSubjectFormPreview() {
SubjectForm(
title = AppText.edit_subject,
goBack = {},
uiState = SubjectFormUiState(
name = "Test Subject",
),
onConfirm = {},
onNameChange = {},
onColorChange = {},
) {
DeleteButton(text = AppText.delete_subject) {}
}
}

View file

@ -0,0 +1,6 @@
package be.ugent.sel.studeez.screens.tasks.forms
data class SubjectFormUiState(
val name: String = "",
val color: Long = 0xFFFFD200,
)

View file

@ -0,0 +1,69 @@
package be.ugent.sel.studeez.screens.tasks.forms
import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.SubjectDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class SubjectFormViewModel @Inject constructor(
private val subjectDAO: SubjectDAO,
private val selectedSubject: SelectedSubject,
logService: LogService,
) : StudeezViewModel(logService) {
var uiState = mutableStateOf(
if (selectedSubject.isSet()) SubjectFormUiState(
name = selectedSubject().name,
color = selectedSubject().argb_color
)
else SubjectFormUiState()
)
private set
private val name: String
get() = uiState.value.name
private val color: Long
get() = uiState.value.color
fun onNameChange(newValue: String) {
uiState.value = uiState.value.copy(name = newValue)
}
fun onColorChange(newValue: Long) {
uiState.value = uiState.value.copy(color = newValue)
}
fun onDelete(openAndPopUp: (String, String) -> Unit) {
subjectDAO.deleteSubject(selectedSubject())
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
}
fun onCreate(openAndPopUp: (String, String) -> Unit) {
val newSubject = Subject(
name = name,
argb_color = color,
)
subjectDAO.saveSubject(
newSubject
)
// TODO open newly created subject
// selectedSubject.set(newSubject)
// open(StudeezDestinations.TASKS_SCREEN)
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.ADD_SUBJECT_FORM)
}
fun onEdit(openAndPopUp: (String, String) -> Unit) {
val newSubject = selectedSubject().copy(
name = name,
argb_color = color,
)
subjectDAO.updateSubject(newSubject)
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
}
}

View file

@ -0,0 +1,113 @@
package be.ugent.sel.studeez.screens.tasks.forms
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.composable.DeleteButton
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.common.ext.fieldModifier
import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun TaskAddRoute(
goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit,
viewModel: TaskFormViewModel,
) {
val uiState by viewModel.uiState
TaskForm(
title = AppText.new_task,
goBack = goBack,
uiState = uiState,
onConfirm = { viewModel.onCreate(openAndPopUp) },
onNameChange = viewModel::onNameChange
)
}
@Composable
fun TaskEditRoute(
goBack: () -> Unit,
openAndPopUp: (String, String) -> Unit,
viewModel: TaskFormViewModel,
) {
val uiState by viewModel.uiState
TaskForm(
title = AppText.edit_task,
goBack = goBack,
uiState = uiState,
onConfirm = { viewModel.onEdit(openAndPopUp) },
onNameChange = viewModel::onNameChange
) {
DeleteButton(text = AppText.delete_task) {
viewModel.onDelete(openAndPopUp)
}
}
}
@Composable
fun TaskForm(
@StringRes title: Int,
goBack: () -> Unit,
uiState: TaskFormUiState,
onConfirm: () -> Unit,
onNameChange: (String) -> Unit,
extraButton: @Composable () -> Unit = {}
) {
SecondaryScreenTemplate(
title = resources().getString(title),
popUp = goBack,
) {
Column {
OutlinedTextField(
singleLine = true,
value = uiState.name,
onValueChange = onNameChange,
placeholder = { Text(stringResource(id = AppText.name)) },
modifier = Modifier.fieldModifier(),
)
BasicButton(
text = AppText.confirm,
modifier = Modifier.basicButton(),
onClick = onConfirm,
)
extraButton()
}
}
}
@Preview
@Composable
fun AddTaskFormPreview() {
TaskForm(
title = AppText.new_task,
goBack = {},
uiState = TaskFormUiState(),
onConfirm = {},
onNameChange = {},
)
}
@Preview
@Composable
fun EditTaskFormPreview() {
TaskForm(
title = AppText.edit_task,
goBack = {},
uiState = TaskFormUiState(
name = "Test Task",
),
onConfirm = {},
onNameChange = {},
) {
DeleteButton(text = AppText.delete_task) {}
}
}

View file

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

View file

@ -0,0 +1,49 @@
package be.ugent.sel.studeez.screens.tasks.forms
import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TaskDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class TaskFormViewModel @Inject constructor(
private val taskDAO: TaskDAO,
private val selectedSubject: SelectedSubject,
private val selectedTask: SelectedTask,
logService: LogService,
) : StudeezViewModel(logService) {
var uiState = mutableStateOf(
if (selectedTask.isSet()) TaskFormUiState(selectedTask().name) else TaskFormUiState()
)
private set
private val name: String
get() = uiState.value.name
fun onNameChange(newValue: String) {
uiState.value = uiState.value.copy(name = newValue)
}
fun onDelete(openAndPopUp: (String, String) -> Unit) {
taskDAO.deleteTask(selectedTask())
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM)
}
fun onCreate(openAndPopUp: (String, String) -> Unit) {
val newTask = Task(name = name, subjectId = selectedSubject().id)
taskDAO.saveTask(newTask)
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.ADD_TASK_FORM)
}
fun onEdit(openAndPopUp: (String, String) -> Unit) {
val newTask = Task(name = name)
taskDAO.updateTask(newTask)
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_TASK_FORM)
}
}

View file

@ -6,7 +6,11 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import be.ugent.sel.studeez.R