Merge branch 'development' into better_screens
This commit is contained in:
commit
654abb7690
21 changed files with 198 additions and 122 deletions
|
@ -123,9 +123,6 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-firestore-ktx'
|
||||
implementation 'com.google.firebase:firebase-perf-ktx'
|
||||
implementation 'com.google.firebase:firebase-config-ktx'
|
||||
|
||||
// Colorpicker
|
||||
implementation 'com.github.skydoves:colorpicker-compose:1.0.2'
|
||||
}
|
||||
|
||||
// Allow references to generate code
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package be.ugent.sel.studeez.common.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun FormComposable(
|
||||
title: String,
|
||||
popUp: () -> Unit,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
SecondaryScreenTemplate(title = title, popUp = popUp) {
|
||||
Box(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,9 +31,13 @@ import be.ugent.sel.studeez.R.string as AppText
|
|||
fun SubjectEntry(
|
||||
subject: Subject,
|
||||
onViewSubject: () -> Unit,
|
||||
getTaskCount: () -> Flow<Int>,
|
||||
getCompletedTaskCount: () -> Flow<Int>,
|
||||
getStudyTime: () -> Flow<Int>,
|
||||
) {
|
||||
val studytime by getStudyTime().collectAsState(initial = 0)
|
||||
val taskCount by getTaskCount().collectAsState(initial = 0)
|
||||
val completedTaskCount by getCompletedTaskCount().collectAsState(initial = 0)
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -80,7 +84,7 @@ fun SubjectEntry(
|
|||
imageVector = Icons.Default.List,
|
||||
contentDescription = stringResource(id = AppText.tasks)
|
||||
)
|
||||
Text(text = "${subject.taskCompletedCount}/${subject.taskCount}")
|
||||
Text(text = "${completedTaskCount}/${taskCount}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,11 +108,11 @@ fun SubjectEntryPreview() {
|
|||
subject = Subject(
|
||||
name = "Test Subject",
|
||||
argb_color = 0xFFFFD200,
|
||||
taskCount = 5,
|
||||
taskCompletedCount = 2,
|
||||
),
|
||||
onViewSubject = {},
|
||||
getStudyTime = { flowOf() }
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -121,6 +125,8 @@ fun OverflowSubjectEntryPreview() {
|
|||
argb_color = 0xFFFFD200,
|
||||
),
|
||||
onViewSubject = {},
|
||||
getStudyTime = { flowOf() }
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package be.ugent.sel.studeez.common.ext
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import kotlin.random.Random
|
||||
|
||||
fun Color.Companion.generateRandomArgb(): Long {
|
||||
val random = Random
|
||||
val mask: Long = (0x000000FFL shl random.nextInt(0, 3)).inv()
|
||||
return random.nextLong(0xFF000000L, 0xFFFFFFFFL) and mask
|
||||
}
|
|
@ -8,10 +8,6 @@ data class Subject(
|
|||
val name: String = "",
|
||||
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 {
|
||||
|
|
|
@ -6,14 +6,13 @@ class FunctionalPomodoroTimer(
|
|||
val repeats: Int
|
||||
) : FunctionalTimer(studyTime) {
|
||||
|
||||
var breaksRemaining = repeats
|
||||
var breaksRemaining = repeats - 1
|
||||
var isInBreak = false
|
||||
|
||||
override fun tick() {
|
||||
if (hasEnded()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (hasCurrentCountdownEnded()) {
|
||||
if (isInBreak) {
|
||||
breaksRemaining--
|
||||
|
|
|
@ -13,8 +13,10 @@ interface SubjectDAO {
|
|||
|
||||
fun updateSubject(newSubject: Subject)
|
||||
|
||||
suspend fun getTaskCount(subject: Subject): Int
|
||||
suspend fun getCompletedTaskCount(subject: Subject): Int
|
||||
suspend fun archiveSubject(subject: Subject)
|
||||
|
||||
fun getTaskCount(subject: Subject): Flow<Int>
|
||||
fun getCompletedTaskCount(subject: Subject): Flow<Int>
|
||||
fun getStudyTime(subject: Subject): Flow<Int>
|
||||
|
||||
suspend fun getSubject(subjectId: String): Subject?
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package be.ugent.sel.studeez.domain.implementation
|
||||
|
||||
import android.util.Log
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.data.local.models.task.SubjectDocument
|
||||
import be.ugent.sel.studeez.data.local.models.task.Task
|
||||
import be.ugent.sel.studeez.data.local.models.task.TaskDocument
|
||||
import be.ugent.sel.studeez.domain.AccountDAO
|
||||
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.FirebaseFirestore
|
||||
import com.google.firebase.firestore.Query
|
||||
|
@ -15,6 +17,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.count
|
||||
|
||||
class FireBaseSubjectDAO @Inject constructor(
|
||||
private val firestore: FirebaseFirestore,
|
||||
|
@ -26,13 +29,6 @@ class FireBaseSubjectDAO @Inject constructor(
|
|||
.subjectNotArchived()
|
||||
.snapshots()
|
||||
.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? {
|
||||
|
@ -51,23 +47,26 @@ class FireBaseSubjectDAO @Inject constructor(
|
|||
currentUserSubjectsCollection().document(newSubject.id).set(newSubject)
|
||||
}
|
||||
|
||||
override suspend fun getTaskCount(subject: Subject): Int {
|
||||
return subjectTasksCollection(subject)
|
||||
override suspend fun archiveSubject(subject: Subject) {
|
||||
currentUserSubjectsCollection().document(subject.id).update(SubjectDocument.archived, true)
|
||||
currentUserSubjectsCollection().document(subject.id)
|
||||
.collection(FireBaseCollections.TASK_COLLECTION)
|
||||
.taskNotArchived()
|
||||
.count()
|
||||
.get(AggregateSource.SERVER)
|
||||
.await()
|
||||
.count.toInt()
|
||||
.get().await()
|
||||
.documents
|
||||
.forEach {
|
||||
it.reference.update(TaskDocument.archived, true)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getCompletedTaskCount(subject: Subject): Int {
|
||||
return subjectTasksCollection(subject)
|
||||
.taskNotArchived()
|
||||
.taskNotCompleted()
|
||||
.count()
|
||||
.get(AggregateSource.SERVER)
|
||||
.await()
|
||||
.count.toInt()
|
||||
override fun getTaskCount(subject: Subject): Flow<Int> {
|
||||
return taskDAO.getTasks(subject)
|
||||
.map(List<Task>::count)
|
||||
}
|
||||
|
||||
override fun getCompletedTaskCount(subject: Subject): Flow<Int> {
|
||||
return taskDAO.getTasks(subject)
|
||||
.map { tasks -> tasks.count { it.completed && !it.archived } }
|
||||
}
|
||||
|
||||
override fun getStudyTime(subject: Subject): Flow<Int> {
|
||||
|
|
|
@ -25,9 +25,9 @@ import be.ugent.sel.studeez.screens.settings.SettingsRoute
|
|||
import be.ugent.sel.studeez.screens.sign_up.SignUpRoute
|
||||
import be.ugent.sel.studeez.screens.splash.SplashRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.SubjectRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.TaskRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectCreateRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectEditRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.TaskRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskCreateRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskEditRoute
|
||||
import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute
|
||||
|
@ -51,6 +51,7 @@ fun StudeezNavGraph(
|
|||
val open: (String) -> Unit = { appState.navigate(it) }
|
||||
val openAndPopUp: (String, String) -> Unit =
|
||||
{ route, popUp -> appState.navigateAndPopUp(route, popUp) }
|
||||
val clearAndNavigate: (route: String) -> Unit = { route -> appState.clearAndNavigate(route) }
|
||||
|
||||
val drawerActions: DrawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp)
|
||||
val navigationBarActions: NavigationBarActions =
|
||||
|
@ -200,7 +201,7 @@ fun StudeezNavGraph(
|
|||
|
||||
composable(StudeezDestinations.SESSION_RECAP) {
|
||||
SessionRecapRoute(
|
||||
openAndPopUp = openAndPopUp,
|
||||
clearAndNavigate = clearAndNavigate,
|
||||
viewModel = hiltViewModel()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,18 +4,13 @@ import android.media.MediaPlayer
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
@ -23,7 +18,7 @@ import be.ugent.sel.studeez.R.string as AppText
|
|||
class BreakSessionScreen(
|
||||
private val funPomoDoroTimer: FunctionalPomodoroTimer,
|
||||
private var mediaplayer: MediaPlayer?
|
||||
): AbstractSessionScreen() {
|
||||
) : AbstractSessionScreen() {
|
||||
|
||||
@Composable
|
||||
override fun MidSection() {
|
||||
|
@ -37,23 +32,31 @@ class BreakSessionScreen(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
repeat(funPomoDoroTimer.repeats - funPomoDoroTimer.breaksRemaining) {
|
||||
Dot(color = Color.DarkGray)
|
||||
}
|
||||
if (!funPomoDoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray)
|
||||
repeat(funPomoDoroTimer.breaksRemaining - 1) {
|
||||
Dot(color = Color.Gray)
|
||||
if (funPomoDoroTimer.hasEnded()) {
|
||||
repeat(funPomoDoroTimer.repeats) {
|
||||
Dot(Color.Green)
|
||||
}
|
||||
} else {
|
||||
repeat(funPomoDoroTimer.repeats - funPomoDoroTimer.breaksRemaining - 1) {
|
||||
Dot(color = Color.DarkGray)
|
||||
}
|
||||
if (!funPomoDoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray)
|
||||
repeat(funPomoDoroTimer.breaksRemaining) {
|
||||
Dot(color = Color.Gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Dot(color: Color) {
|
||||
Box(modifier = Modifier
|
||||
.padding(5.dp)
|
||||
.size(10.dp)
|
||||
.clip(CircleShape)
|
||||
.background(color))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(5.dp)
|
||||
.size(10.dp)
|
||||
.clip(CircleShape)
|
||||
.background(color)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -32,24 +32,24 @@ data class SessionRecapActions(
|
|||
|
||||
fun getSessionRecapActions(
|
||||
viewModel: SessionRecapViewModel,
|
||||
openAndPopUp: (String, String) -> Unit,
|
||||
clearAndNavigate: (String) -> Unit,
|
||||
): SessionRecapActions {
|
||||
return SessionRecapActions(
|
||||
viewModel::getSessionReport,
|
||||
{ viewModel.saveSession(openAndPopUp) },
|
||||
{ viewModel.discardSession(openAndPopUp) }
|
||||
{ viewModel.saveSession(clearAndNavigate) },
|
||||
{ viewModel.discardSession(clearAndNavigate) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SessionRecapRoute(
|
||||
openAndPopUp: (String, String) -> Unit,
|
||||
clearAndNavigate: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: SessionRecapViewModel,
|
||||
) {
|
||||
SessionRecapScreen(
|
||||
modifier = modifier,
|
||||
getSessionRecapActions(viewModel, openAndPopUp)
|
||||
getSessionRecapActions(viewModel, clearAndNavigate)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,15 +24,15 @@ class SessionRecapViewModel @Inject constructor(
|
|||
return selectedSessionReport()
|
||||
}
|
||||
|
||||
fun saveSession(open: (String, String) -> Unit) {
|
||||
fun saveSession(open: (String) -> Unit) {
|
||||
sessionDAO.saveSession(getSessionReport())
|
||||
val newTask =
|
||||
selectedTask().copy(time = selectedTask().time + selectedSessionReport().studyTime)
|
||||
taskDAO.updateTask(newTask)
|
||||
open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP)
|
||||
open(StudeezDestinations.HOME_SCREEN)
|
||||
}
|
||||
|
||||
fun discardSession(open: (String, String) -> Unit) {
|
||||
open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP)
|
||||
fun discardSession(open: (String) -> Unit) {
|
||||
open(StudeezDestinations.HOME_SCREEN)
|
||||
}
|
||||
}
|
|
@ -36,6 +36,8 @@ fun SubjectRoute(
|
|||
navigationBarActions = navigationBarActions,
|
||||
onAddSubject = { viewModel.onAddSubject(open) },
|
||||
onViewSubject = { viewModel.onViewSubject(it, open) },
|
||||
getTaskCount = viewModel::getTaskCount,
|
||||
getCompletedTaskCount = viewModel::getCompletedTaskCount,
|
||||
getStudyTime = viewModel::getStudyTime,
|
||||
uiState,
|
||||
)
|
||||
|
@ -47,6 +49,8 @@ fun SubjectScreen(
|
|||
navigationBarActions: NavigationBarActions,
|
||||
onAddSubject: () -> Unit,
|
||||
onViewSubject: (Subject) -> Unit,
|
||||
getTaskCount: (Subject) -> Flow<Int>,
|
||||
getCompletedTaskCount: (Subject) -> Flow<Int>,
|
||||
getStudyTime: (Subject) -> Flow<Int>,
|
||||
uiState: SubjectUiState,
|
||||
) {
|
||||
|
@ -76,6 +80,8 @@ fun SubjectScreen(
|
|||
SubjectEntry(
|
||||
subject = it,
|
||||
onViewSubject = { onViewSubject(it) },
|
||||
getTaskCount = { getTaskCount(it) },
|
||||
getCompletedTaskCount = { getCompletedTaskCount(it) },
|
||||
getStudyTime = { getStudyTime(it) },
|
||||
)
|
||||
}
|
||||
|
@ -94,13 +100,14 @@ fun SubjectScreenPreview() {
|
|||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
|
||||
onAddSubject = {},
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
uiState = SubjectUiState.Succes(
|
||||
listOf(
|
||||
Subject(
|
||||
name = "Test Subject",
|
||||
argb_color = 0xFFFFD200,
|
||||
taskCount = 5, taskCompletedCount = 2,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -115,7 +122,9 @@ fun SubjectScreenLoadingPreview() {
|
|||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
|
||||
onAddSubject = {},
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
uiState = SubjectUiState.Loading
|
||||
uiState = SubjectUiState.Loading,
|
||||
)
|
||||
}
|
|
@ -30,6 +30,14 @@ class SubjectViewModel @Inject constructor(
|
|||
open(StudeezDestinations.ADD_SUBJECT_FORM)
|
||||
}
|
||||
|
||||
fun getTaskCount(subject: Subject): Flow<Int> {
|
||||
return subjectDAO.getTaskCount(subject)
|
||||
}
|
||||
|
||||
fun getCompletedTaskCount(subject: Subject): Flow<Int> {
|
||||
return subjectDAO.getCompletedTaskCount(subject)
|
||||
}
|
||||
|
||||
fun getStudyTime(subject: Subject): Flow<Int> {
|
||||
return subjectDAO.getStudyTime(subject)
|
||||
}
|
||||
|
|
|
@ -2,20 +2,28 @@ package be.ugent.sel.studeez.screens.subjects.form
|
|||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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 androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||
import be.ugent.sel.studeez.common.composable.DeleteButton
|
||||
import be.ugent.sel.studeez.common.composable.FormComposable
|
||||
import be.ugent.sel.studeez.common.composable.LabelledInputField
|
||||
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.common.ext.generateRandomArgb
|
||||
import be.ugent.sel.studeez.resources
|
||||
import kotlinx.coroutines.launch
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
|
@ -31,7 +39,7 @@ fun SubjectCreateRoute(
|
|||
uiState = uiState,
|
||||
onConfirm = { viewModel.onCreate(openAndPopUp) },
|
||||
onNameChange = viewModel::onNameChange,
|
||||
onColorChange = {},
|
||||
onColorChange = viewModel::onColorChange,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -42,16 +50,19 @@ fun SubjectEditRoute(
|
|||
viewModel: SubjectEditFormViewModel,
|
||||
) {
|
||||
val uiState by viewModel.uiState
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
SubjectForm(
|
||||
title = AppText.edit_subject,
|
||||
goBack = goBack,
|
||||
uiState = uiState,
|
||||
onConfirm = { viewModel.onEdit(openAndPopUp) },
|
||||
onNameChange = viewModel::onNameChange,
|
||||
onColorChange = {},
|
||||
onColorChange = viewModel::onColorChange,
|
||||
) {
|
||||
DeleteButton(text = AppText.delete_subject) {
|
||||
viewModel.onDelete(openAndPopUp)
|
||||
coroutineScope.launch {
|
||||
viewModel.onDelete(openAndPopUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,21 +74,21 @@ fun SubjectForm(
|
|||
uiState: SubjectFormUiState,
|
||||
onConfirm: () -> Unit,
|
||||
onNameChange: (String) -> Unit,
|
||||
onColorChange: (Color) -> Unit,
|
||||
onColorChange: (Long) -> Unit,
|
||||
extraButton: @Composable () -> Unit = {},
|
||||
) {
|
||||
SecondaryScreenTemplate(
|
||||
FormComposable(
|
||||
title = resources().getString(title),
|
||||
popUp = goBack,
|
||||
) {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
LabelledInputField(
|
||||
singleLine = true,
|
||||
value = uiState.name,
|
||||
onValueChange = onNameChange,
|
||||
placeholder = { Text(stringResource(id = AppText.name)) },
|
||||
modifier = Modifier.fieldModifier(),
|
||||
onNewValue = onNameChange,
|
||||
label = AppText.name,
|
||||
)
|
||||
ColorPicker(onColorChange, uiState)
|
||||
BasicButton(
|
||||
text = AppText.confirm,
|
||||
modifier = Modifier.basicButton(),
|
||||
|
@ -88,6 +99,24 @@ fun SubjectForm(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ColorPicker(
|
||||
onColorChange: (Long) -> Unit,
|
||||
uiState: SubjectFormUiState,
|
||||
) {
|
||||
Button(
|
||||
onClick = { onColorChange(Color.generateRandomArgb()) },
|
||||
modifier = Modifier.fieldModifier(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = Color(uiState.color),
|
||||
contentColor = Color.White,
|
||||
),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
) {
|
||||
Text(text = stringResource(id = AppText.regenerate_color))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddSubjectFormPreview() {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package be.ugent.sel.studeez.screens.subjects.form
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import be.ugent.sel.studeez.common.ext.generateRandomArgb
|
||||
|
||||
data class SubjectFormUiState(
|
||||
val name: String = "",
|
||||
val color: Long = 0xFFFFD200,
|
||||
val color: Long = Color.generateRandomArgb(),
|
||||
)
|
|
@ -2,10 +2,13 @@ package be.ugent.sel.studeez.screens.subjects.form
|
|||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import be.ugent.sel.studeez.common.ext.generateRandomArgb
|
||||
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.domain.TaskDAO
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
@ -59,6 +62,7 @@ class SubjectCreateFormViewModel @Inject constructor(
|
|||
@HiltViewModel
|
||||
class SubjectEditFormViewModel @Inject constructor(
|
||||
subjectDAO: SubjectDAO,
|
||||
private val taskDAO: TaskDAO,
|
||||
selectedSubject: SelectedSubject,
|
||||
logService: LogService,
|
||||
) : SubjectFormViewModel(subjectDAO, selectedSubject, logService) {
|
||||
|
@ -69,17 +73,19 @@ class SubjectEditFormViewModel @Inject constructor(
|
|||
)
|
||||
)
|
||||
|
||||
fun onDelete(openAndPopUp: (String, String) -> Unit) {
|
||||
subjectDAO.updateSubject(selectedSubject().copy(archived = true))
|
||||
suspend fun onDelete(openAndPopUp: (String, String) -> Unit) {
|
||||
subjectDAO.archiveSubject(selectedSubject())
|
||||
openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
|
||||
}
|
||||
|
||||
fun onEdit(openAndPopUp: (String, String) -> Unit) {
|
||||
val newSubject = selectedSubject().copy(
|
||||
name = name,
|
||||
argb_color = color,
|
||||
selectedSubject.set(
|
||||
selectedSubject().copy(
|
||||
name = name,
|
||||
argb_color = color,
|
||||
)
|
||||
)
|
||||
subjectDAO.updateSubject(newSubject)
|
||||
subjectDAO.updateSubject(selectedSubject())
|
||||
openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM)
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ 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.composable.FormComposable
|
||||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.common.ext.fieldModifier
|
||||
import be.ugent.sel.studeez.resources
|
||||
|
@ -62,7 +62,7 @@ fun TaskForm(
|
|||
onNameChange: (String) -> Unit,
|
||||
extraButton: @Composable () -> Unit = {}
|
||||
) {
|
||||
SecondaryScreenTemplate(
|
||||
FormComposable(
|
||||
title = resources().getString(title),
|
||||
popUp = goBack,
|
||||
) {
|
||||
|
|
|
@ -3,7 +3,7 @@ package be.ugent.sel.studeez.screens.timer_form
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.FormComposable
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
|
@ -36,7 +36,10 @@ fun TimerFormScreen(
|
|||
) {
|
||||
val timerFormScreen = getTimerInfo().accept(GetTimerFormScreen())
|
||||
|
||||
SecondaryScreenTemplate(title = stringResource(id = label), popUp = popUp) {
|
||||
FormComposable(
|
||||
title = stringResource(id = label),
|
||||
popUp = popUp
|
||||
) {
|
||||
timerFormScreen(onConfirmClick)
|
||||
}
|
||||
}
|
|
@ -1,17 +1,7 @@
|
|||
package be.ugent.sel.studeez.screens.timer_form.form_screens
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.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.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||
|
@ -32,32 +22,24 @@ abstract class AbstractTimerFormScreen(private val timerInfo: TimerInfo) {
|
|||
timerInfo.name = name
|
||||
timerInfo.description = description
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxHeight().verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Column {
|
||||
|
||||
// Fields that every timer shares (ommited id)
|
||||
LabelledInputField(
|
||||
value = name,
|
||||
onNewValue = { name = it },
|
||||
label = R.string.name
|
||||
)
|
||||
// Fields that every timer shares (ommited id)
|
||||
LabelledInputField(
|
||||
value = name,
|
||||
onNewValue = { name = it },
|
||||
label = R.string.name
|
||||
)
|
||||
|
||||
LabelledInputField(
|
||||
value = description,
|
||||
onNewValue = { description = it },
|
||||
label = AppText.description,
|
||||
singleLine = false
|
||||
)
|
||||
LabelledInputField(
|
||||
value = description,
|
||||
onNewValue = { description = it },
|
||||
label = AppText.description,
|
||||
singleLine = false
|
||||
)
|
||||
|
||||
ExtraFields()
|
||||
ExtraFields()
|
||||
|
||||
}
|
||||
BasicButton(R.string.save, Modifier.basicButton()) {
|
||||
onSaveClick(timerInfo)
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<string name="delete_subject">Delete Subject</string>
|
||||
<string name="delete_task">Delete Task</string>
|
||||
<string name="view_tasks">View</string>
|
||||
<string name="regenerate_color">Regenerate Color</string>
|
||||
|
||||
<!-- Sessions -->
|
||||
<string name="sessions_temp_description">Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own.</string> <!-- TODO Remove this description line once implemented. -->
|
||||
|
|
Reference in a new issue