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) { composable(StudeezDestinations.ADD_TIMER_SCREEN) {
AddTimerRoute( AddTimerRoute(
open = open, open = open,
openAndPopUp = openAndPopUp,
goBack = goBack, goBack = goBack,
viewModel = hiltViewModel() 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 package be.ugent.sel.studeez.screens.timer_overview.add_timer
data class AddTimerUiState( data class AddTimerUiState(
val studyTimeHours: Float = 1f, val studyTimeHours: Int = 1,
val studyTimeMinutes: Float = 0f, val studyTimeMinutes: Int = 0,
val withBreaks: Boolean = false, val withBreaks: Boolean = false,
val breakTime: Float = 5f, val breakTimeMinutes: Int = 5,
val repeats: Float = 1f, val breakTimeHours: Int = 0,
val name: String = "", val repeats: Int = 1,
val description: String = "", 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 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.CustomTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo 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.LogService
import be.ugent.sel.studeez.domain.TimerDAO import be.ugent.sel.studeez.domain.TimerDAO
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
@ -24,8 +23,11 @@ class AddTimerViewModel @Inject constructor(
private val studyTimeMinutes private val studyTimeMinutes
get() = uiState.value.studyTimeMinutes get() = uiState.value.studyTimeMinutes
private val breakTime private val breakTimeHours
get() = uiState.value.breakTime get() = uiState.value.breakTimeHours
private val breakTimeMinutes
get() = uiState.value.breakTimeMinutes
private val repeats private val repeats
get() = uiState.value.repeats get() = uiState.value.repeats
@ -36,24 +38,28 @@ class AddTimerViewModel @Inject constructor(
private val description private val description
get() = uiState.value.description get() = uiState.value.description
fun onStudyTimeHoursChange(newValue: Float) { fun onStudyTimeHoursChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeHours = newValue) uiState.value = uiState.value.copy(studyTimeHours = newValue)
} }
fun onStudyTimeMinutesChange(newValue: Float) { fun onStudyTimeMinutesChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeMinutes = newValue) uiState.value = uiState.value.copy(studyTimeMinutes = newValue)
} }
fun onWithBreaksChange(newValue: Boolean) { fun onWithBreaksChange() {
uiState.value = uiState.value.copy(withBreaks = newValue) uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks)
} }
fun onBreakTimeChange(newValue: Float) { fun onBreakTimeHourChange(newValue: Int) {
uiState.value = uiState.value.copy(breakTime = newValue) 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) uiState.value = uiState.value.copy(repeats = newValue)
} }
@ -62,15 +68,15 @@ class AddTimerViewModel @Inject constructor(
timerDAO.saveTimer(PomodoroTimerInfo( timerDAO.saveTimer(PomodoroTimerInfo(
name = uiState.value.name, name = uiState.value.name,
description = uiState.value.description, description = uiState.value.description,
studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60, studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60,
breakTime = breakTime.toInt() * 60, breakTime = breakTimeHours * 60 * 60 + breakTimeMinutes * 60,
repeats = repeats.toInt() repeats = repeats
)) ))
} else { } else {
timerDAO.saveTimer(CustomTimerInfo( timerDAO.saveTimer(CustomTimerInfo(
name = uiState.value.name, name = uiState.value.name,
description = uiState.value.description, 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.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Checkbox import androidx.compose.material.Checkbox
import androidx.compose.material.Slider
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.TextField import androidx.compose.material.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue 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.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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 import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate 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.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme import be.ugent.sel.studeez.ui.theme.StudeezTheme
data class AddTimerActions( data class AddTimerActions(
val open: (String) -> Unit,
val goBack: () -> Unit, val goBack: () -> Unit,
val onStudyTimeHoursChange: (Float) -> Unit, val onStudyTimeHoursChange: (Int) -> Unit,
val onStudyTimeMinutesChange: (Float) -> Unit, val onStudyTimeMinutesChange: (Int) -> Unit,
val onBreakTimeChange: (Float) -> Unit, val onBreakTimeHourChange: (Int) -> Unit,
val onRepeatsChange: (Float) -> Unit, val onBreakTimeMinutesChange: (Int) -> Unit,
val onWithBreaksChange: (Boolean) -> Unit, val onRepeatsChange: (Int) -> Unit,
val onWithBreaksChange: () -> Unit,
val addTimer: () -> Unit, val addTimer: () -> Unit,
val onNameChange: (String) -> Unit, val onNameChange: (String) -> Unit,
val onDescriptionChange: (String) -> Unit, val onDescriptionChange: (String) -> Unit,
) )
fun getAddTimerActions( fun getAddTimerActions(
open: (String) -> Unit,
goBack: () -> Unit, goBack: () -> Unit,
viewModel: AddTimerViewModel, viewModel: AddTimerViewModel,
): AddTimerActions { ): AddTimerActions {
return AddTimerActions( return AddTimerActions(
open = open,
goBack = goBack, goBack = goBack,
onWithBreaksChange = viewModel::onWithBreaksChange, onWithBreaksChange = viewModel::onWithBreaksChange,
onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange, onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange,
onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange, onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange,
onBreakTimeChange = viewModel::onBreakTimeChange, onBreakTimeHourChange = viewModel::onBreakTimeHourChange,
onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange,
onRepeatsChange = viewModel::onRepeatsChange, onRepeatsChange = viewModel::onRepeatsChange,
addTimer = viewModel::addTimer, addTimer = viewModel::addTimer,
onNameChange = viewModel::onNameChange, onNameChange = viewModel::onNameChange,
@ -55,7 +64,6 @@ fun getAddTimerActions(
@Composable @Composable
fun AddTimerRoute( fun AddTimerRoute(
open: (String) -> Unit, open: (String) -> Unit,
openAndPopUp: (String, String) -> Unit,
goBack: () -> Unit, goBack: () -> Unit,
viewModel: AddTimerViewModel, viewModel: AddTimerViewModel,
) { ) {
@ -63,6 +71,7 @@ fun AddTimerRoute(
AddTimerScreen( AddTimerScreen(
addTimerActions = getAddTimerActions( addTimerActions = getAddTimerActions(
open = open,
goBack = goBack, goBack = goBack,
viewModel = viewModel, viewModel = viewModel,
), ),
@ -75,6 +84,20 @@ fun AddTimerScreen(
addTimerActions: AddTimerActions, addTimerActions: AddTimerActions,
uiState: AddTimerUiState, 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( SecondaryScreenTemplate(
title = resources().getString(R.string.add_timer), title = resources().getString(R.string.add_timer),
popUp = addTimerActions.goBack popUp = addTimerActions.goBack
@ -82,52 +105,40 @@ fun AddTimerScreen(
LazyColumn( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp) .padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
item { item {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
verticalAlignment = Alignment.CenterVertically, .padding(16.dp)
horizontalArrangement = Arrangement.Center
) { ) {
Text( Text(
text = "How long do you want to study?", text = stringResource(R.string.addTimer_question),
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
} }
} }
item { item {
Text( 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 { item {
Slider( Button(
value = uiState.studyTimeHours, onClick = {
onValueChange = { mStudyTimePicker.show()
addTimerActions.onStudyTimeHoursChange(it)
}, },
steps = 8, ) {
valueRange = 1f..10f, Text(
enabled = true text = stringResource(R.string.addTimer_timepicker),
) )
} }
item {
Text(
text = "${uiState.studyTimeMinutes.toInt()} minutes"
)
}
item {
Slider(
value = uiState.studyTimeMinutes,
onValueChange = {
addTimerActions.onStudyTimeMinutesChange(it)
},
steps = 11,
valueRange = 0f..60f,
enabled = true
)
} }
item { item {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@ -135,68 +146,99 @@ fun AddTimerScreen(
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
Text( Text(
text = "With breaks?", text = stringResource(R.string.addTimer_break_question),
) )
Checkbox( Checkbox(
checked = uiState.withBreaks, 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 { item {
Text( Text(
text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", text = stringResource(R.string.addTimer_name)
)
}
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"
) )
} }
item { item {
TextField( TextField(
value = uiState.name, value = uiState.name,
onValueChange = { addTimerActions.onNameChange(it) } onValueChange = { addTimerActions.onNameChange(it) }
) )
} }
item {
if (uiState.name == "") {
Text(
text = stringResource(R.string.addTimer_name_error),
color = Color.Red
)
}
}
item { item {
Text( Text(
text = "Timer description" text = stringResource(R.string.addTimer_description)
) )
} }
item { item {
TextField( TextField(
value = uiState.description, value = uiState.description,
onValueChange = { addTimerActions.onDescriptionChange(it) } onValueChange = { addTimerActions.onDescriptionChange(it) }
) )
} }
item {
if (uiState.description == "") {
Text(
text = stringResource(R.string.addTimer_description_error),
color = Color.Red
)
}
}
item { item {
Row( Row(
modifier = Modifier modifier = Modifier
@ -208,7 +250,12 @@ fun AddTimerScreen(
BasicButton( BasicButton(
text = R.string.add_timer, text = R.string.add_timer,
modifier = Modifier, 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 @Composable
fun AddTimerScreenPreview() { StudeezTheme { fun AddTimerScreenPreview() { StudeezTheme {
AddTimerScreen( AddTimerScreen(
addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}),
uiState = AddTimerUiState() uiState = AddTimerUiState()
) )
} }
} }

View file

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

View file

@ -79,4 +79,19 @@
<!-- About --> <!-- About -->
<string name="about">About Studeez</string> <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> </resources>