addTimer finished

This commit is contained in:
Rune Dyselinck 2023-05-02 13:57:03 +02:00
parent 535ef85c6d
commit 4b4c9539f8
7 changed files with 193 additions and 99 deletions

View file

@ -172,7 +172,6 @@ fun StudeezNavGraph(
composable(StudeezDestinations.ADD_TIMER_SCREEN) {
AddTimerRoute(
open = open,
openAndPopUp = openAndPopUp,
goBack = goBack,
viewModel = hiltViewModel()
)

View file

@ -0,0 +1,24 @@
package be.ugent.sel.studeez.common.composable.navbar
import android.app.TimePickerDialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
@Composable
fun BasicTimePicker(
onHoursChange: (Int) -> Unit,
onMinutesChange: (Int) -> Unit,
Hours: Int,
Minutes: Int,
): TimePickerDialog {
return TimePickerDialog(
LocalContext.current,
{ _, mHour: Int, mMinute: Int ->
onHoursChange(mHour)
onMinutesChange(mMinute)
},
Hours,
Minutes,
true
)
}

View file

@ -1,11 +1,12 @@
package be.ugent.sel.studeez.screens.timer_overview.add_timer
data class AddTimerUiState(
val studyTimeHours: Float = 1f,
val studyTimeMinutes: Float = 0f,
val studyTimeHours: Int = 1,
val studyTimeMinutes: Int = 0,
val withBreaks: Boolean = false,
val breakTime: Float = 5f,
val repeats: Float = 1f,
val name: String = "",
val description: String = "",
val breakTimeMinutes: Int = 5,
val breakTimeHours: Int = 0,
val repeats: Int = 1,
val name: String = "Timer",
val description: String = "Long study session",
)

View file

@ -3,7 +3,6 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer
import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TimerDAO
import be.ugent.sel.studeez.screens.StudeezViewModel
@ -24,8 +23,11 @@ class AddTimerViewModel @Inject constructor(
private val studyTimeMinutes
get() = uiState.value.studyTimeMinutes
private val breakTime
get() = uiState.value.breakTime
private val breakTimeHours
get() = uiState.value.breakTimeHours
private val breakTimeMinutes
get() = uiState.value.breakTimeMinutes
private val repeats
get() = uiState.value.repeats
@ -36,24 +38,28 @@ class AddTimerViewModel @Inject constructor(
private val description
get() = uiState.value.description
fun onStudyTimeHoursChange(newValue: Float) {
fun onStudyTimeHoursChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeHours = newValue)
}
fun onStudyTimeMinutesChange(newValue: Float) {
fun onStudyTimeMinutesChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeMinutes = newValue)
}
fun onWithBreaksChange(newValue: Boolean) {
uiState.value = uiState.value.copy(withBreaks = newValue)
fun onWithBreaksChange() {
uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks)
}
fun onBreakTimeChange(newValue: Float) {
uiState.value = uiState.value.copy(breakTime = newValue)
fun onBreakTimeHourChange(newValue: Int) {
uiState.value = uiState.value.copy(breakTimeHours = newValue)
}
fun onRepeatsChange(newValue: Float) {
fun onBreakTimeMinutesChange(newValue: Int) {
uiState.value = uiState.value.copy(breakTimeMinutes = newValue)
}
fun onRepeatsChange(newValue: Int) {
uiState.value = uiState.value.copy(repeats = newValue)
}
@ -62,15 +68,15 @@ class AddTimerViewModel @Inject constructor(
timerDAO.saveTimer(PomodoroTimerInfo(
name = uiState.value.name,
description = uiState.value.description,
studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60,
breakTime = breakTime.toInt() * 60,
repeats = repeats.toInt()
studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60,
breakTime = breakTimeHours * 60 * 60 + breakTimeMinutes * 60,
repeats = repeats
))
} else {
timerDAO.saveTimer(CustomTimerInfo(
name = uiState.value.name,
description = uiState.value.description,
studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60
studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60
))
}
}

View file

@ -6,45 +6,54 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Checkbox
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.composable.navbar.BasicTimePicker
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme
data class AddTimerActions(
val open: (String) -> Unit,
val goBack: () -> Unit,
val onStudyTimeHoursChange: (Float) -> Unit,
val onStudyTimeMinutesChange: (Float) -> Unit,
val onBreakTimeChange: (Float) -> Unit,
val onRepeatsChange: (Float) -> Unit,
val onWithBreaksChange: (Boolean) -> Unit,
val onStudyTimeHoursChange: (Int) -> Unit,
val onStudyTimeMinutesChange: (Int) -> Unit,
val onBreakTimeHourChange: (Int) -> Unit,
val onBreakTimeMinutesChange: (Int) -> Unit,
val onRepeatsChange: (Int) -> Unit,
val onWithBreaksChange: () -> Unit,
val addTimer: () -> Unit,
val onNameChange: (String) -> Unit,
val onDescriptionChange: (String) -> Unit,
)
fun getAddTimerActions(
open: (String) -> Unit,
goBack: () -> Unit,
viewModel: AddTimerViewModel,
): AddTimerActions {
return AddTimerActions(
open = open,
goBack = goBack,
onWithBreaksChange = viewModel::onWithBreaksChange,
onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange,
onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange,
onBreakTimeChange = viewModel::onBreakTimeChange,
onBreakTimeHourChange = viewModel::onBreakTimeHourChange,
onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange,
onRepeatsChange = viewModel::onRepeatsChange,
addTimer = viewModel::addTimer,
onNameChange = viewModel::onNameChange,
@ -55,7 +64,6 @@ fun getAddTimerActions(
@Composable
fun AddTimerRoute(
open: (String) -> Unit,
openAndPopUp: (String, String) -> Unit,
goBack: () -> Unit,
viewModel: AddTimerViewModel,
) {
@ -63,6 +71,7 @@ fun AddTimerRoute(
AddTimerScreen(
addTimerActions = getAddTimerActions(
open = open,
goBack = goBack,
viewModel = viewModel,
),
@ -75,6 +84,20 @@ fun AddTimerScreen(
addTimerActions: AddTimerActions,
uiState: AddTimerUiState,
) {
val mStudyTimePicker = BasicTimePicker(
onHoursChange = addTimerActions.onStudyTimeHoursChange,
onMinutesChange = addTimerActions.onStudyTimeMinutesChange,
Hours = uiState.studyTimeHours,
Minutes = uiState.studyTimeMinutes
)
val mBreakTimePicker = BasicTimePicker(
onHoursChange = addTimerActions.onBreakTimeHourChange,
onMinutesChange = addTimerActions.onBreakTimeMinutesChange,
Hours = uiState.breakTimeHours,
Minutes = uiState.breakTimeMinutes
)
SecondaryScreenTemplate(
title = resources().getString(R.string.add_timer),
popUp = addTimerActions.goBack
@ -82,52 +105,40 @@ fun AddTimerScreen(
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
item {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
modifier = Modifier
.padding(16.dp)
) {
Text(
text = "How long do you want to study?",
text = stringResource(R.string.addTimer_question),
textAlign = TextAlign.Center
)
}
}
item {
Text(
text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}"
text = uiState.studyTimeHours.toString() + stringResource(R.string.addTimer_studytime_1) + uiState.studyTimeMinutes + stringResource(
R.string.addTimer_studytime_2)
)
}
item {
Slider(
value = uiState.studyTimeHours,
onValueChange = {
addTimerActions.onStudyTimeHoursChange(it)
Button(
onClick = {
mStudyTimePicker.show()
},
steps = 8,
valueRange = 1f..10f,
enabled = true
)
}
item {
Text(
text = "${uiState.studyTimeMinutes.toInt()} minutes"
)
}
item {
Slider(
value = uiState.studyTimeMinutes,
onValueChange = {
addTimerActions.onStudyTimeMinutesChange(it)
},
steps = 11,
valueRange = 0f..60f,
enabled = true
)
) {
Text(
text = stringResource(R.string.addTimer_timepicker),
)
}
}
item {
Row(
modifier = Modifier.fillMaxWidth(),
@ -135,68 +146,99 @@ fun AddTimerScreen(
horizontalArrangement = Arrangement.Center
) {
Text(
text = "With breaks?",
text = stringResource(R.string.addTimer_break_question),
)
Checkbox(
checked = uiState.withBreaks,
onCheckedChange = { addTimerActions.onWithBreaksChange(it) }
onCheckedChange = { addTimerActions.onWithBreaksChange() }
)
}
}
if (uiState.withBreaks) {
item {
Text(
text = if (uiState.repeats == 1) uiState.repeats.toString() + stringResource(
R.string.addTimer_break_1)
else uiState.repeats.toString() + stringResource(
R.string.addTimer_break_s)
)
TextField(
value = uiState.repeats.toString(),
onValueChange = { it: String ->
it.toIntOrNull()?.let { it1 ->
addTimerActions.onRepeatsChange(
kotlin.math.abs(it1)
)
}
}
)
}
item {
Text(
text = uiState.breakTimeHours.toString() + stringResource(R.string.breakTime_1) + uiState.breakTimeMinutes + stringResource(
R.string.breakTime_2)
)
}
item {
Button(
onClick = {
mBreakTimePicker.show()
},
) {
Text(
text = stringResource(R.string.addTimer_timepicker),
)
}
}
}
item {
Text(
text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "",
)
}
item {
Slider(
value = uiState.breakTime,
onValueChange = {
addTimerActions.onBreakTimeChange(it)
},
steps = 11,
valueRange = 0f..60f,
enabled = uiState.withBreaks
)
}
item {
Text(
text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else ""
)
}
item {
Slider(
value = uiState.repeats,
onValueChange = {
addTimerActions.onRepeatsChange(it)
},
steps = 8,
valueRange = 1f..10f,
enabled = uiState.withBreaks
)
}
item {
Text(
text = "Timer name"
text = stringResource(R.string.addTimer_name)
)
}
item {
TextField(
value = uiState.name,
onValueChange = { addTimerActions.onNameChange(it) }
)
}
item {
if (uiState.name == "") {
Text(
text = stringResource(R.string.addTimer_name_error),
color = Color.Red
)
}
}
item {
Text(
text = "Timer description"
text = stringResource(R.string.addTimer_description)
)
}
item {
TextField(
value = uiState.description,
onValueChange = { addTimerActions.onDescriptionChange(it) }
)
}
item {
if (uiState.description == "") {
Text(
text = stringResource(R.string.addTimer_description_error),
color = Color.Red
)
}
}
item {
Row(
modifier = Modifier
@ -208,7 +250,12 @@ fun AddTimerScreen(
BasicButton(
text = R.string.add_timer,
modifier = Modifier,
onClick = addTimerActions.addTimer
onClick = {
if (uiState.description != "" && uiState.name != "") {
addTimerActions.addTimer()
addTimerActions.open(StudeezDestinations.TIMER_OVERVIEW_SCREEN)
}
}
)
}
}
@ -220,8 +267,8 @@ fun AddTimerScreen(
@Composable
fun AddTimerScreenPreview() { StudeezTheme {
AddTimerScreen(
addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}),
addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}),
uiState = AddTimerUiState()
)
}
}
}

View file

@ -64,7 +64,9 @@ fun TimerSelectionScreen(
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
) {
LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(7.dp),
) {
// All timers
items(timers.value) { timerInfo ->
TimerEntry(

View file

@ -79,4 +79,19 @@
<!-- About -->
<string name="about">About Studeez</string>
<!-- Add Timer -->
<string name="addTimer_description_error">Timer description cannot be empty!</string>
<string name="addTimer_description">Timer description</string>
<string name="addTimer_name_error">Timer name cannot be empty!</string>
<string name="addTimer_name">Timer name</string>
<string name="addTimer_timepicker">Open Time Picker</string>
<string name="breakTime_1">" hours and "</string>
<string name="breakTime_2">" minutes of breaktime"</string>
<string name="addTimer_break_1">" break"</string>
<string name="addTimer_break_s">" breaks"</string>
<string name="addTimer_break_question">With breaks?</string>
<string name="addTimer_studytime_1">" hours and "</string>
<string name="addTimer_studytime_2">" minutes of studytime"</string>
<string name="addTimer_question">How long do you want to study?</string>
</resources>