diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt index 47dbb0b..aadcee3 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt @@ -1,11 +1,11 @@ package be.ugent.sel.studeez.common.composable import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Email import androidx.compose.material.icons.filled.Lock @@ -14,10 +14,15 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.common.ext.fieldModifier +import be.ugent.sel.studeez.resources +import kotlin.math.sin import be.ugent.sel.studeez.R.drawable as AppIcon import be.ugent.sel.studeez.R.string as AppText @@ -85,6 +90,86 @@ fun EmailField( ) } +@Composable +fun LabeledNumberInputField( + value: Int, + onNewValue: (Int) -> Unit, + @StringRes label: Int, + singleLine: Boolean = false +) { + var number by remember { mutableStateOf(value) } + OutlinedTextField( + value = number.toString(), + singleLine = singleLine, + label = { Text(resources().getString(label)) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + onValueChange = {typedInt -> + val isNumber = typedInt.matches(Regex("[1-9]+\\d*]")) + if (isNumber) { + number = typedInt.toInt() + onNewValue(typedInt.toInt()) + } + } + ) +} + +@Composable +fun LabeledErrorTextField( + modifier: Modifier = Modifier, + initialValue: String, + @StringRes label: Int, + singleLine: Boolean = false, + errorText: Int, + keyboardType: KeyboardType, + predicate: (String) -> Boolean, + onNewCorrectValue: (String) -> Unit +) { + var value by remember { + mutableStateOf(initialValue) + } + + var isValid by remember { + mutableStateOf(predicate(value)) + } + + Column { + OutlinedTextField( + modifier = modifier.fieldModifier(), + value = value, + onValueChange = { newText -> + value = newText + isValid = predicate(value) + if (isValid) { + onNewCorrectValue(newText) + } + }, + singleLine = singleLine, + label = { Text(text = stringResource(id = label)) }, + isError = !isValid, + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType, + imeAction = ImeAction.Done + ) + ) + + if (!isValid) { + Text( + modifier = Modifier.padding(start = 16.dp), + text = stringResource(id = errorText), + color = MaterialTheme.colors.error + ) + } + } +} + + + + @Preview(showBackground = true) + @Composable + fun IntInputPreview() { + LabeledNumberInputField(value = 1, onNewValue = {}, label = AppText.email) + } + @Composable fun PasswordField( value: String, diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt index 6dd6797..7316630 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt @@ -9,7 +9,7 @@ class PomodoroTimerInfo( description: String, var studyTime: Int, var breakTime: Int, - val repeats: Int, + var repeats: Int, id: String = "" ): TimerInfo(id, name, description) { diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index 966b4a1..49856c9 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -19,6 +19,7 @@ object StudeezDestinations { // Studying flow const val TIMER_SELECTION_SCREEN = "timer_selection" const val TIMER_EDIT_SCREEN = "timer_edit" + const val TIMER_TYPE_CHOOSING_SCREEN = "timer_type_choosing_screen" const val SESSION_SCREEN = "session" const val SESSION_RECAP = "session_recap" diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt index 8ac135e..a09846a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt @@ -30,9 +30,10 @@ import be.ugent.sel.studeez.screens.tasks.forms.SubjectAddRoute import be.ugent.sel.studeez.screens.tasks.forms.SubjectEditRoute import be.ugent.sel.studeez.screens.tasks.forms.TaskAddRoute import be.ugent.sel.studeez.screens.tasks.forms.TaskEditRoute -import be.ugent.sel.studeez.screens.timer_edit.TimerEditRoute +import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute +import be.ugent.sel.studeez.screens.timer_form.TimerEditRoute +import be.ugent.sel.studeez.screens.timer_form.timer_type_select.TimerTypeSelectScreen import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute -import be.ugent.sel.studeez.screens.timer_overview.add_timer.AddTimerRoute import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionRoute @Composable @@ -182,6 +183,13 @@ fun StudeezNavGraph( ) } + composable(StudeezDestinations.TIMER_TYPE_CHOOSING_SCREEN) { + TimerTypeSelectScreen( + open = open, + popUp = goBack + ) + } + composable(StudeezDestinations.SESSION_SCREEN) { SessionRoute( open, @@ -198,16 +206,14 @@ fun StudeezNavGraph( } composable(StudeezDestinations.ADD_TIMER_SCREEN) { - AddTimerRoute( - open = open, - goBack = goBack, + TimerAddRoute( + popUp = goBack, viewModel = hiltViewModel() ) } composable(StudeezDestinations.TIMER_EDIT_SCREEN) { TimerEditRoute( - open = open, popUp = goBack, viewModel = hiltViewModel() ) @@ -236,3 +242,4 @@ fun StudeezNavGraph( } } } + diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt deleted file mode 100644 index 7cb6a8f..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt +++ /dev/null @@ -1,44 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_add - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.tooling.preview.Preview -import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate -import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo -import be.ugent.sel.studeez.screens.timer_edit.GetTimerEditScreen -import be.ugent.sel.studeez.screens.timer_edit.TimerEditViewModel -import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen -import be.ugent.sel.studeez.ui.theme.StudeezTheme - -data class TimerEditActions( - val getTimerInfo: () -> TimerInfo, - val saveTimer: (TimerInfo, () -> Unit) -> Unit -) - -fun getTimerEditActions( - viewModel: TimerEditViewModel, - open: (String) -> Unit -): TimerEditActions { - return TimerEditActions( - getTimerInfo = viewModel::getTimerInfo, - saveTimer = viewModel::saveTimer - ) -} - -@Composable -fun TimerEditRoute( - open: (String) -> Unit, - popUp: () -> Unit, - viewModel: TimerEditViewModel, -) { - - val timerEditActions = getTimerEditActions(viewModel, open) - - SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { - - val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen()) - timerEditScreen { timerInfo -> - timerEditActions.saveTimer(timerInfo, popUp) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt deleted file mode 100644 index 9ab766c..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt +++ /dev/null @@ -1,29 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_add - -import be.ugent.sel.studeez.data.EditTimerState -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 -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class TimerAddViewModel @Inject constructor( - private val editTimerState: EditTimerState, - private val timerDAO: TimerDAO, - logService: LogService -) : StudeezViewModel(logService) { - - private val timerInfo: TimerInfo = editTimerState.timerInfo - - fun getTimerInfo(): TimerInfo { - return timerInfo - } - - fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) { - timerDAO.updateTimer(timerInfo) - goBack() - } - -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt deleted file mode 100644 index b22b775..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt +++ /dev/null @@ -1,27 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_edit - -import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo -import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo -import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo -import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor -import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen -import be.ugent.sel.studeez.screens.timer_edit.editScreens.BreakTimerEditScreen -import be.ugent.sel.studeez.screens.timer_edit.editScreens.CustomTimerEditScreen -import be.ugent.sel.studeez.screens.timer_edit.editScreens.EndlessTimerEditScreen - -class GetTimerEditScreen: TimerInfoVisitor { - - override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen { - return CustomTimerEditScreen(customTimerInfo) - } - - override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen { - return EndlessTimerEditScreen(endlessTimerInfo) - } - - override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerEditScreen { - return BreakTimerEditScreen(pomodoroTimerInfo) - } - - -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt deleted file mode 100644 index 649caf6..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt +++ /dev/null @@ -1,65 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_edit - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.tooling.preview.Preview -import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate -import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo -import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen -import be.ugent.sel.studeez.ui.theme.StudeezTheme - -data class TimerEditActions( - val getTimerInfo: () -> TimerInfo, - val saveTimer: (TimerInfo, () -> Unit) -> Unit -) - -fun getTimerEditActions( - viewModel: TimerEditViewModel, - open: (String) -> Unit -): TimerEditActions { - return TimerEditActions( - getTimerInfo = viewModel::getTimerInfo, - saveTimer = viewModel::saveTimer - ) -} - -@Composable -fun TimerEditRoute( - open: (String) -> Unit, - popUp: () -> Unit, - viewModel: TimerEditViewModel, -) { - - val timerEditActions = getTimerEditActions(viewModel, open) - - SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { - - val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen()) - timerEditScreen { timerInfo -> - timerEditActions.saveTimer(timerInfo, popUp) - } - } -} - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/GetTimerFormScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/GetTimerFormScreen.kt new file mode 100644 index 0000000..99426e4 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/GetTimerFormScreen.kt @@ -0,0 +1,27 @@ +package be.ugent.sel.studeez.screens.timer_form + +import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor +import be.ugent.sel.studeez.screens.timer_form.form_screens.AbstractTimerFormScreen +import be.ugent.sel.studeez.screens.timer_form.form_screens.BreakTimerFormScreen +import be.ugent.sel.studeez.screens.timer_form.form_screens.CustomTimerFormScreen +import be.ugent.sel.studeez.screens.timer_form.form_screens.EndlessTimerFormScreen + +class GetTimerFormScreen: TimerInfoVisitor { + + override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerFormScreen { + return CustomTimerFormScreen(customTimerInfo) + } + + override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerFormScreen { + return EndlessTimerFormScreen(endlessTimerInfo) + } + + override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerFormScreen { + return BreakTimerFormScreen(pomodoroTimerInfo) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormRoute.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormRoute.kt new file mode 100644 index 0000000..0323dc2 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormRoute.kt @@ -0,0 +1,42 @@ +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.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun TimerAddRoute( + popUp: () -> Unit, + viewModel: TimerFormViewModel +) { + TimerFormScreen(popUp = popUp, getTimerInfo = viewModel::getTimerInfo, AppText.add_timer) { + viewModel.saveTimer(it, goBack = popUp) + } +} + +@Composable +fun TimerEditRoute( + popUp: () -> Unit, + viewModel: TimerFormViewModel +) { + TimerFormScreen(popUp = popUp, getTimerInfo = viewModel::getTimerInfo, AppText.edit_timer) { + viewModel.editTimer(it, goBack = popUp) + } +} + +@Composable +fun TimerFormScreen( + popUp: () -> Unit, + getTimerInfo: () -> TimerInfo, + @StringRes label: Int, + onConfirmClick: (TimerInfo) -> Unit +) { + val timerFormScreen = getTimerInfo().accept(GetTimerFormScreen()) + + SecondaryScreenTemplate(title = stringResource(id = label), popUp = popUp) { + timerFormScreen(onConfirmClick) + } +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormViewModel.kt similarity index 77% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormViewModel.kt index 3258f24..4c2079c 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/TimerFormViewModel.kt @@ -1,4 +1,4 @@ -package be.ugent.sel.studeez.screens.timer_edit +package be.ugent.sel.studeez.screens.timer_form import be.ugent.sel.studeez.data.EditTimerState import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo @@ -9,7 +9,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel -class TimerEditViewModel @Inject constructor( +class TimerFormViewModel @Inject constructor( private val editTimerState: EditTimerState, private val timerDAO: TimerDAO, logService: LogService @@ -21,9 +21,13 @@ class TimerEditViewModel @Inject constructor( return timerInfo } - fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) { + fun editTimer(timerInfo: TimerInfo, goBack: () -> Unit) { timerDAO.updateTimer(timerInfo) goBack() } + fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) { + timerDAO.saveTimer(timerInfo) + goBack() + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/AbstractTimerFormScreen.kt similarity index 91% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/AbstractTimerFormScreen.kt index 420d734..5f4a17b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/AbstractTimerFormScreen.kt @@ -1,4 +1,4 @@ -package be.ugent.sel.studeez.screens.timer_edit.editScreens +package be.ugent.sel.studeez.screens.timer_form.form_screens import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -18,8 +18,9 @@ import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.LabelledInputField import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.R.string as AppText -abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) { +abstract class AbstractTimerFormScreen(private val timerInfo: TimerInfo) { @Composable operator fun invoke(onSaveClick: (TimerInfo) -> Unit) { @@ -50,7 +51,7 @@ abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) { LabelledInputField( value = description, onNewValue = { description = it }, - label = R.string.description, + label = AppText.description, singleLine = false ) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/BreakTimerFormScreen.kt similarity index 57% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/BreakTimerFormScreen.kt index b6104b6..12d07a4 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/BreakTimerFormScreen.kt @@ -1,20 +1,19 @@ -package be.ugent.sel.studeez.screens.timer_edit.editScreens +package be.ugent.sel.studeez.screens.timer_form.form_screens import androidx.compose.runtime.* +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.R -import be.ugent.sel.studeez.common.composable.TimePickerButton +import be.ugent.sel.studeez.common.composable.LabeledErrorTextField import be.ugent.sel.studeez.common.composable.TimePickerCard -import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds -import be.ugent.sel.studeez.data.local.models.timer_functional.Time -import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo -import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo import be.ugent.sel.studeez.ui.theme.StudeezTheme +import be.ugent.sel.studeez.R.string as AppText -class BreakTimerEditScreen( + +class BreakTimerFormScreen( private val breakTimerInfo: PomodoroTimerInfo -): AbstractTimerEditScreen(breakTimerInfo) { +): AbstractTimerFormScreen(breakTimerInfo) { @Composable override fun ExtraFields() { @@ -26,8 +25,18 @@ class BreakTimerEditScreen( TimePickerCard(R.string.breakTime, breakTimerInfo.breakTime) { newTime -> breakTimerInfo.breakTime = newTime } - } + LabeledErrorTextField( + initialValue = breakTimerInfo.repeats.toString(), + label = R.string.repeats, + errorText = AppText.repeats_error, + keyboardType = KeyboardType.Decimal, + predicate = { it.matches(Regex("[1-9]+\\d*")) } + ) { correctlyTypedInt -> + breakTimerInfo.repeats = correctlyTypedInt.toInt() + } + + } } @Preview @@ -41,6 +50,6 @@ fun BreakEditScreenPreview() { 5 ) StudeezTheme { - BreakTimerEditScreen(pomodoroTimerInfo).invoke(onSaveClick = {}) + BreakTimerFormScreen(pomodoroTimerInfo).invoke(onSaveClick = {}) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/CustomTimerFormScreen.kt similarity index 79% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/CustomTimerFormScreen.kt index f3278d5..27c0657 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/CustomTimerFormScreen.kt @@ -1,4 +1,4 @@ -package be.ugent.sel.studeez.screens.timer_edit.editScreens +package be.ugent.sel.studeez.screens.timer_form.form_screens import androidx.compose.runtime.* import androidx.compose.ui.tooling.preview.Preview @@ -7,9 +7,9 @@ import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.ui.theme.StudeezTheme import be.ugent.sel.studeez.R.string as AppText -class CustomTimerEditScreen( +class CustomTimerFormScreen( private val customTimerInfo: CustomTimerInfo - ): AbstractTimerEditScreen(customTimerInfo) { + ): AbstractTimerFormScreen(customTimerInfo) { @Composable override fun ExtraFields() { @@ -29,6 +29,6 @@ class CustomTimerEditScreen( fun CustomEditScreenPreview() { val customTimerInfo = CustomTimerInfo("custom", "my description", 25) StudeezTheme { - CustomTimerEditScreen(customTimerInfo).invoke(onSaveClick = {}) + CustomTimerFormScreen(customTimerInfo).invoke(onSaveClick = {}) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/EndlessTimerFormScreen.kt similarity index 70% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/EndlessTimerFormScreen.kt index 0e26209..9009fff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/form_screens/EndlessTimerFormScreen.kt @@ -1,13 +1,13 @@ -package be.ugent.sel.studeez.screens.timer_edit.editScreens +package be.ugent.sel.studeez.screens.timer_form.form_screens import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo import be.ugent.sel.studeez.ui.theme.StudeezTheme -class EndlessTimerEditScreen( +class EndlessTimerFormScreen( endlessTimerInfo: EndlessTimerInfo -): AbstractTimerEditScreen(endlessTimerInfo) { +): AbstractTimerFormScreen(endlessTimerInfo) { } @Preview @@ -18,6 +18,6 @@ fun EndlessEditScreenPreview() { "My endless timer description", ) StudeezTheme { - EndlessTimerEditScreen(endlessTimerInfo).invoke(onSaveClick = {}) + EndlessTimerFormScreen(endlessTimerInfo).invoke(onSaveClick = {}) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectScreen.kt similarity index 76% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectScreen.kt index d14bb86..fa8d650 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectScreen.kt @@ -1,4 +1,4 @@ -package be.ugent.sel.studeez.screens.timer_add +package be.ugent.sel.studeez.screens.timer_form.timer_type_select import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -7,16 +7,18 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.data.local.models.timer_info.* +import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.CUSTOM import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.BREAK import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.ENDLESS val defaultTimerInfo: Map = mapOf( CUSTOM to CustomTimerInfo("", "", 0), - BREAK to PomodoroTimerInfo("", "", 0, 0, 0), + BREAK to PomodoroTimerInfo("", "", 0, 0, 1), ENDLESS to EndlessTimerInfo("", ""), ) @@ -28,13 +30,14 @@ fun TimerTypeSelectScreen( viewModel: TimerTypeSelectViewModel = hiltViewModel() ) { - SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { + SecondaryScreenTemplate(title = stringResource(id = AppText.timer_type_select), popUp = popUp) { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() ) { TimerType.values().forEach { timerType -> - Button(onClick = { viewModel.onTimerTypeChosen(defaultTimerInfo[timerType]!!, open) }) { + val default: TimerInfo = defaultTimerInfo.getValue(timerType) + Button(onClick = { viewModel.onTimerTypeChosen(default, open) }) { Text(text = timerType.name) } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectViewModel.kt similarity index 75% rename from app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt rename to app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectViewModel.kt index 1892833..569a36c 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_form/timer_type_select/TimerTypeSelectViewModel.kt @@ -1,25 +1,22 @@ -package be.ugent.sel.studeez.screens.timer_add +package be.ugent.sel.studeez.screens.timer_form.timer_type_select import be.ugent.sel.studeez.data.EditTimerState 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.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 TimerTypeSelectViewModel @Inject constructor( private val editTimerState: EditTimerState, - private val timerDAO: TimerDAO, logService: LogService ) : StudeezViewModel(logService) { fun onTimerTypeChosen(timerInfo: TimerInfo, open: (String) -> Unit) { editTimerState.timerInfo = timerInfo - open(StudeezDestinations.TIMER_EDIT_SCREEN) + open(StudeezDestinations.ADD_TIMER_SCREEN) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt index dd3f062..a07dd67 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt @@ -25,7 +25,7 @@ data class TimerOverviewActions( val getUserTimers: () -> Flow>, val getDefaultTimers: () -> List, val onEditClick: (TimerInfo) -> Unit, - val onAddClick: () -> Unit, + val onAddClick: () -> Unit ) fun getTimerOverviewActions( @@ -36,7 +36,7 @@ fun getTimerOverviewActions( getUserTimers = viewModel::getUserTimers, getDefaultTimers = viewModel::getDefaultTimers, onEditClick = { viewModel.update(it, open) }, - onAddClick = { viewModel.create(open) } + onAddClick = { viewModel.onAddClick(open) } ) } @@ -48,14 +48,14 @@ fun TimerOverviewRoute( ) { TimerOverviewScreen( timerOverviewActions = getTimerOverviewActions(viewModel, open), - drawerActions = drawerActions + drawerActions = drawerActions, ) } @Composable fun TimerOverviewScreen( timerOverviewActions: TimerOverviewActions, - drawerActions: DrawerActions + drawerActions: DrawerActions, ) { val timers = timerOverviewActions.getUserTimers().collectAsState(initial = emptyList()) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt index 77a5a6e..3e10053 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt @@ -32,8 +32,8 @@ class TimerOverviewViewModel @Inject constructor( open(StudeezDestinations.TIMER_EDIT_SCREEN) } - fun create(open: (String) -> Unit) { - open(StudeezDestinations.ADD_TIMER_SCREEN) + fun onAddClick(open: (String) -> Unit) { + open(StudeezDestinations.TIMER_TYPE_CHOOSING_SCREEN) } fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt deleted file mode 100644 index fcfa79a..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt +++ /dev/null @@ -1,12 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_overview.add_timer - -data class AddTimerUiState( - val studyTimeHours: Int = 1, - val studyTimeMinutes: Int = 0, - val withBreaks: Boolean = false, - val breakTimeMinutes: Int = 5, - val breakTimeHours: Int = 0, - val repeats: Int = 1, - val name: String = "Timer", - val description: String = "Long study session", -) \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt deleted file mode 100644 index d507974..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt +++ /dev/null @@ -1,91 +0,0 @@ -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.domain.LogService -import be.ugent.sel.studeez.domain.TimerDAO -import be.ugent.sel.studeez.screens.StudeezViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class AddTimerViewModel @Inject constructor( - logService: LogService, - private val timerDAO: TimerDAO, -): StudeezViewModel(logService) { - var uiState = mutableStateOf(AddTimerUiState()) - private set - - private val studyTimeHours - get() = uiState.value.studyTimeHours - - private val studyTimeMinutes - get() = uiState.value.studyTimeMinutes - - private val breakTimeHours - get() = uiState.value.breakTimeHours - - private val breakTimeMinutes - get() = uiState.value.breakTimeMinutes - - private val repeats - get() = uiState.value.repeats - - private val name - get() = uiState.value.name - - private val description - get() = uiState.value.description - - fun onStudyTimeHoursChange(newValue: Int) { - uiState.value = uiState.value.copy(studyTimeHours = newValue) - - } - - fun onStudyTimeMinutesChange(newValue: Int) { - uiState.value = uiState.value.copy(studyTimeMinutes = newValue) - } - - fun onWithBreaksChange() { - uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks) - } - - fun onBreakTimeHourChange(newValue: Int) { - uiState.value = uiState.value.copy(breakTimeHours = newValue) - } - - fun onBreakTimeMinutesChange(newValue: Int) { - uiState.value = uiState.value.copy(breakTimeMinutes = newValue) - } - - fun onRepeatsChange(newValue: Int) { - uiState.value = uiState.value.copy(repeats = newValue) - } - - fun addTimer() { - if (uiState.value.withBreaks) { - timerDAO.saveTimer(PomodoroTimerInfo( - name = uiState.value.name, - description = uiState.value.description, - 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 * 60 * 60 + studyTimeMinutes * 60 - )) - } - } - - fun onNameChange(newValue: String) { - uiState.value = uiState.value.copy(name = newValue) - } - - fun onDescriptionChange(newValue: String) { - uiState.value = uiState.value.copy(description = newValue) - } -} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt deleted file mode 100644 index dc7bbda..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt +++ /dev/null @@ -1,274 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_overview.add_timer - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -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.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: (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, - onBreakTimeHourChange = viewModel::onBreakTimeHourChange, - onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange, - onRepeatsChange = viewModel::onRepeatsChange, - addTimer = viewModel::addTimer, - onNameChange = viewModel::onNameChange, - onDescriptionChange = viewModel::onDescriptionChange - ) -} - -@Composable -fun AddTimerRoute( - open: (String) -> Unit, - goBack: () -> Unit, - viewModel: AddTimerViewModel, -) { - val uiState by viewModel.uiState - - AddTimerScreen( - addTimerActions = getAddTimerActions( - open = open, - goBack = goBack, - viewModel = viewModel, - ), - uiState = uiState - ) -} - -@Composable -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 - ) { - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - item { - Row( - modifier = Modifier - .padding(16.dp) - ) { - Text( - text = stringResource(R.string.addTimer_question), - textAlign = TextAlign.Center - ) - } - } - - item { - Text( - text = uiState.studyTimeHours.toString() + stringResource(R.string.addTimer_studytime_1) + uiState.studyTimeMinutes + stringResource( - R.string.addTimer_studytime_2) - ) - } - - item { - Button( - onClick = { - mStudyTimePicker.show() - }, - ) { - Text( - text = stringResource(R.string.addTimer_timepicker), - ) - } - } - - item { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Text( - text = stringResource(R.string.addTimer_break_question), - ) - Checkbox( - checked = uiState.withBreaks, - 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 = 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 = 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 - .fillMaxWidth() - .fillMaxHeight(), - verticalAlignment = Alignment.Bottom, - horizontalArrangement = Arrangement.Center - ) { - BasicButton( - text = R.string.add_timer, - modifier = Modifier, - onClick = { - if (uiState.description != "" && uiState.name != "") { - addTimerActions.addTimer() - addTimerActions.open(StudeezDestinations.TIMER_SCREEN) - } - } - ) - } - } - } - } -} - -@Preview -@Composable -fun AddTimerScreenPreview() { StudeezTheme { - AddTimerScreen( - addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}), - uiState = AddTimerUiState() - ) - } -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ec0e9d..d51259c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -131,8 +131,13 @@ " minutes of studytime" How long do you want to study? + + Select Timer Type + Name + Edit Timer + Repeats must be a positive non-zero number Description Study Time Break Time