Merge branch 'development' into better_screens

This commit is contained in:
brreynie 2023-05-15 20:55:20 +02:00 committed by GitHub Enterprise
commit 654abb7690
21 changed files with 198 additions and 122 deletions

View file

@ -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

View file

@ -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()
}
}
}

View file

@ -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() },
)
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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--

View file

@ -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?

View file

@ -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> {

View file

@ -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()
)
}

View file

@ -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

View file

@ -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)
)
}

View file

@ -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)
}
}

View file

@ -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,
)
}

View file

@ -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)
}

View file

@ -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() {

View file

@ -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(),
)

View file

@ -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)
}
}

View file

@ -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,
) {

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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. -->