From 601740f258fe5f63d9412ea1316e9bc747b635ee Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Wed, 26 Apr 2023 11:38:09 +0200 Subject: [PATCH 1/4] secondaryscreentemplate error --- .idea/misc.xml | 3 +- .../studeez/navigation/StudeezDestinations.kt | 2 + .../add_timer/AddTimerViewModel.kt | 13 ++++++ .../add_timer/addTimerScreen.kt | 42 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..704c883 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + 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 760c814..63f9d64 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 @@ -18,4 +18,6 @@ object StudeezDestinations { // Edit screens const val EDIT_PROFILE_SCREEN = "edit_profile" + + const val ADD_TIMER_SCREEN = "add_timer" } \ 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 new file mode 100644 index 0000000..a209f49 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt @@ -0,0 +1,13 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class AddTimerViewModel @Inject constructor( + logService: LogService +): StudeezViewModel(logService) { + +} 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 new file mode 100644 index 0000000..a26826c --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt @@ -0,0 +1,42 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +import androidx.compose.runtime.Composable +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel +import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel +import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions + +@Composable +fun AddTimerRoute( + open: (String) -> Unit, + openAndPopUp: (String, String) -> Unit + viewModel: AddTimerViewModel, + drawerViewModel: DrawerViewModel, + navBarViewModel: NavigationBarViewModel, +) { + addTimerScreen( + drawerActions = getDrawerActions( + drawerViewModel = drawerViewModel, + open = open, + openAndPopUp = openAndPopUp + ), + navigationBarActions = getNavigationBarActions( + navigationBarViewModel = navBarViewModel, + open = open + ) + ) +} + +fun addTimerScreen( + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions +) { + SecondaryScreenTemplate( + title = , + popUp = { /*TODO*/ }) { + + } +} \ No newline at end of file From 2ca112ee0e66547dd8ed8a3ecb96643061033eca Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Thu, 27 Apr 2023 17:01:39 +0200 Subject: [PATCH 2/4] LazyColumn not fixed --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 10 + .../common/composable/ButtonComposable.kt | 9 +- .../timer_overview/TimerOverviewScreen.kt | 12 +- .../add_timer/AddTimerUiState.kt | 11 + .../add_timer/AddTimerViewModel.kt | 74 +++++- .../add_timer/addTimerScreen.kt | 215 ++++++++++++++++-- 6 files changed, 303 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index a6830a5..be8ad00 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -34,6 +34,7 @@ import be.ugent.sel.studeez.screens.session.SessionRoute import be.ugent.sel.studeez.screens.sign_up.SignUpRoute import be.ugent.sel.studeez.screens.splash.SplashRoute 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 import be.ugent.sel.studeez.ui.theme.StudeezTheme import kotlinx.coroutines.CoroutineScope @@ -167,5 +168,14 @@ fun StudeezNavGraph( navBarViewModel = navBarViewModel, ) } + + composable(StudeezDestinations.ADD_TIMER_SCREEN) { + AddTimerRoute( + open = open, + openAndPopUp = openAndPopUp, + goBack = goBack, + viewModel = hiltViewModel() + ) + } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index b2568aa..79845ec 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -23,7 +23,14 @@ import be.ugent.sel.studeez.common.ext.card @Composable fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { - TextButton(onClick = action, modifier = modifier) { Text(text = stringResource(text)) } + TextButton( + onClick = action, + modifier = modifier + ) { + Text( + text = stringResource(text) + ) + } } @Composable 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 fafdf02..3bc6ca7 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 @@ -23,6 +23,7 @@ import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.resources import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -31,15 +32,18 @@ data class TimerOverviewActions( val getUserTimers: () -> Flow>, val getDefaultTimers: () -> List, val onEditClick: (TimerInfo) -> Unit, + val open: (String) -> Unit, ) fun getTimerOverviewActions( viewModel: TimerOverviewViewModel, + open: (String) -> Unit, ): TimerOverviewActions { return TimerOverviewActions( getUserTimers = viewModel::getUserTimers, getDefaultTimers = viewModel::getDefaultTimers, onEditClick = { viewModel.update(it) }, + open = open ) } @@ -52,7 +56,7 @@ fun TimerOverviewRoute( navBarViewModel: NavigationBarViewModel, ) { TimerOverviewScreen( - timerOverviewActions = getTimerOverviewActions(viewModel), + timerOverviewActions = getTimerOverviewActions(viewModel, open), drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), navigationBarActions = getNavigationBarActions(navBarViewModel, open), ) @@ -95,7 +99,7 @@ fun TimerOverviewScreen( } } BasicButton(R.string.add_timer, Modifier.basicButton()) { - // TODO + timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN) } } } @@ -111,7 +115,9 @@ fun TimerOverviewPreview() { timerOverviewActions = TimerOverviewActions( { flowOf() }, { listOf(customTimer, customTimer) }, - {}), + {}, + {} + ), drawerActions = DrawerActions({}, {}, {}, {}, {}), navigationBarActions = NavigationBarActions({}, {}, {}, {}) ) 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 new file mode 100644 index 0000000..9b17121 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt @@ -0,0 +1,11 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +data class AddTimerUiState( + val studyTimeHours: Float = 1f, + val studyTimeMinutes: Float = 0f, + val withBreaks: Boolean = false, + val breakTime: Float = 5f, + val repeats: Float = 1f, + val name: String = "", + val description: String = "", +) \ 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 index a209f49..7e79e1e 100644 --- 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 @@ -1,13 +1,85 @@ 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 import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class AddTimerViewModel @Inject constructor( - logService: LogService + 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 breakTime + get() = uiState.value.breakTime + + private val repeats + get() = uiState.value.repeats + + private val name + get() = uiState.value.name + + private val description + get() = uiState.value.description + + fun onStudyTimeHoursChange(newValue: Float) { + uiState.value = uiState.value.copy(studyTimeHours = newValue) + + } + + fun onStudyTimeMinutesChange(newValue: Float) { + uiState.value = uiState.value.copy(studyTimeMinutes = newValue) + } + + fun onWithBreaksChange(newValue: Boolean) { + uiState.value = uiState.value.copy(withBreaks = newValue) + } + + fun onBreakTimeChange(newValue: Float) { + uiState.value = uiState.value.copy(breakTime = newValue) + } + + fun onRepeatsChange(newValue: Float) { + 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.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60, + breakTime = breakTime.toInt() * 60, + repeats = repeats.toInt() + )) + } else { + timerDAO.saveTimer(CustomTimerInfo( + name = uiState.value.name, + description = uiState.value.description, + studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 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 index a26826c..6941a05 100644 --- 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 @@ -1,42 +1,211 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +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.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.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.drawer.DrawerActions -import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel -import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions -import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions -import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel -import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions +import be.ugent.sel.studeez.resources + +data class AddTimerActions( + val goBack: () -> Unit, + val onStudyTimeHoursChange: (Float) -> Unit, + val onStudyTimeMinutesChange: (Float) -> Unit, + val onBreakTimeChange: (Float) -> Unit, + val onRepeatsChange: (Float) -> Unit, + val onWithBreaksChange: (Boolean) -> Unit, + val addTimer: () -> Unit, + val onNameChange: (String) -> Unit, + val onDescriptionChange: (String) -> Unit, +) + +fun getAddTimerActions( + goBack: () -> Unit, + viewModel: AddTimerViewModel, +): AddTimerActions { + return AddTimerActions( + goBack = goBack, + onWithBreaksChange = viewModel::onWithBreaksChange, + onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange, + onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange, + onBreakTimeChange = viewModel::onBreakTimeChange, + onRepeatsChange = viewModel::onRepeatsChange, + addTimer = viewModel::addTimer, + onNameChange = viewModel::onNameChange, + onDescriptionChange = viewModel::onDescriptionChange + ) +} @Composable fun AddTimerRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit + openAndPopUp: (String, String) -> Unit, + goBack: () -> Unit, viewModel: AddTimerViewModel, - drawerViewModel: DrawerViewModel, - navBarViewModel: NavigationBarViewModel, ) { - addTimerScreen( - drawerActions = getDrawerActions( - drawerViewModel = drawerViewModel, - open = open, - openAndPopUp = openAndPopUp + val uiState by viewModel.uiState + + AddTimerScreen( + addTimerActions = getAddTimerActions( + goBack = goBack, + viewModel = viewModel, ), - navigationBarActions = getNavigationBarActions( - navigationBarViewModel = navBarViewModel, - open = open - ) + uiState = uiState ) } -fun addTimerScreen( - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions +@Composable +fun AddTimerScreen( + addTimerActions: AddTimerActions, + uiState: AddTimerUiState, ) { SecondaryScreenTemplate( - title = , - popUp = { /*TODO*/ }) { + title = resources().getString(R.string.add_timer), + popUp = addTimerActions.goBack + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "How long do you want to study?", + textAlign = TextAlign.Center + ) + } + LazyColumn( + modifier = Modifier + .padding(16.dp) + ) { + item{ + Text( + text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" + ) + Slider( + value = uiState.studyTimeHours, + onValueChange = { + addTimerActions.onStudyTimeHoursChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = true + ) + + Text( + text = "${uiState.studyTimeMinutes.toInt()} minutes" + ) + Slider( + value = uiState.studyTimeMinutes, + onValueChange = { + addTimerActions.onStudyTimeMinutesChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = true + ) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "With breaks?", + ) + Checkbox( + checked = uiState.withBreaks, + onCheckedChange = { addTimerActions.onWithBreaksChange(it) } + ) + } + + Text( + text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", + ) + Slider( + value = uiState.breakTime, + onValueChange = { + addTimerActions.onBreakTimeChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = uiState.withBreaks + ) + + Text( + text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" + ) + Slider( + value = uiState.repeats, + onValueChange = { + addTimerActions.onRepeatsChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = uiState.withBreaks + ) + + Text( + text = "Timer name" + ) + TextField( + value = uiState.name, + onValueChange = { addTimerActions.onNameChange(it) } + ) + + Text( + text = "Timer description" + ) + TextField( + value = uiState.description, + onValueChange = { addTimerActions.onDescriptionChange(it) } + ) + + Row( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.Center + ) { + BasicButton( + text = R.string.add_timer, + modifier = Modifier, + onClick = addTimerActions.addTimer + ) + } + } + } + } } +} + +@Preview +@Composable +fun AddTimerScreenPreview() { + AddTimerScreen( + addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), + uiState = AddTimerUiState() + ) } \ No newline at end of file From 535ef85c6d0a908388833929407df03eecdff245 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Fri, 28 Apr 2023 11:42:03 +0200 Subject: [PATCH 3/4] LazyColumn in progress of being fixed --- .../add_timer/addTimerScreen.kt | 232 ++++++++++-------- 1 file changed, 124 insertions(+), 108 deletions(-) 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 index 6941a05..772917d 100644 --- 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 @@ -1,7 +1,6 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth @@ -22,6 +21,7 @@ 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.resources +import be.ugent.sel.studeez.ui.theme.StudeezTheme data class AddTimerActions( val goBack: () -> Unit, @@ -79,122 +79,137 @@ fun AddTimerScreen( title = resources().getString(R.string.add_timer), popUp = addTimerActions.goBack ) { - Column( + LazyColumn( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { + item { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "How long do you want to study?", + textAlign = TextAlign.Center + ) + } + } + item { Text( - text = "How long do you want to study?", - textAlign = TextAlign.Center + text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" ) } - - LazyColumn( - modifier = Modifier - .padding(16.dp) - ) { - item{ + item { + Slider( + value = uiState.studyTimeHours, + onValueChange = { + addTimerActions.onStudyTimeHoursChange(it) + }, + 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 + ) + } + item { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { Text( - text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" + text = "With breaks?", ) - Slider( - value = uiState.studyTimeHours, - onValueChange = { - addTimerActions.onStudyTimeHoursChange(it) - }, - steps = 8, - valueRange = 1f..10f, - enabled = true + Checkbox( + checked = uiState.withBreaks, + onCheckedChange = { addTimerActions.onWithBreaksChange(it) } ) - - Text( - text = "${uiState.studyTimeMinutes.toInt()} minutes" + } + } + 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" + ) + } + item { + TextField( + value = uiState.name, + onValueChange = { addTimerActions.onNameChange(it) } + ) + } + item { + Text( + text = "Timer description" + ) + } + item { + TextField( + value = uiState.description, + onValueChange = { addTimerActions.onDescriptionChange(it) } + ) + } + item { + Row( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.Center + ) { + BasicButton( + text = R.string.add_timer, + modifier = Modifier, + onClick = addTimerActions.addTimer ) - Slider( - value = uiState.studyTimeMinutes, - onValueChange = { - addTimerActions.onStudyTimeMinutesChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = true - ) - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Text( - text = "With breaks?", - ) - Checkbox( - checked = uiState.withBreaks, - onCheckedChange = { addTimerActions.onWithBreaksChange(it) } - ) - } - - Text( - text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", - ) - Slider( - value = uiState.breakTime, - onValueChange = { - addTimerActions.onBreakTimeChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = uiState.withBreaks - ) - - Text( - text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" - ) - Slider( - value = uiState.repeats, - onValueChange = { - addTimerActions.onRepeatsChange(it) - }, - steps = 8, - valueRange = 1f..10f, - enabled = uiState.withBreaks - ) - - Text( - text = "Timer name" - ) - TextField( - value = uiState.name, - onValueChange = { addTimerActions.onNameChange(it) } - ) - - Text( - text = "Timer description" - ) - TextField( - value = uiState.description, - onValueChange = { addTimerActions.onDescriptionChange(it) } - ) - - Row( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight(), - verticalAlignment = Alignment.Bottom, - horizontalArrangement = Arrangement.Center - ) { - BasicButton( - text = R.string.add_timer, - modifier = Modifier, - onClick = addTimerActions.addTimer - ) - } } } } @@ -203,9 +218,10 @@ fun AddTimerScreen( @Preview @Composable -fun AddTimerScreenPreview() { +fun AddTimerScreenPreview() { StudeezTheme { AddTimerScreen( addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), uiState = AddTimerUiState() - ) + ) + } } \ No newline at end of file From 4b4c9539f83f5ac92fd959f35a715847d7655222 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 2 May 2023 13:57:03 +0200 Subject: [PATCH 4/4] addTimer finished --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 1 - .../composable/navbar/TimePickerComposable.kt | 24 +++ .../add_timer/AddTimerUiState.kt | 13 +- .../add_timer/AddTimerViewModel.kt | 34 +-- .../add_timer/addTimerScreen.kt | 201 +++++++++++------- .../timer_selection/TimerSelectionScreen.kt | 4 +- app/src/main/res/values/strings.xml | 15 ++ 7 files changed, 193 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index be8ad00..d7465b0 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -172,7 +172,6 @@ fun StudeezNavGraph( composable(StudeezDestinations.ADD_TIMER_SCREEN) { AddTimerRoute( open = open, - openAndPopUp = openAndPopUp, goBack = goBack, viewModel = hiltViewModel() ) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt new file mode 100644 index 0000000..3a59519 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt @@ -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 + ) +} 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 index 9b17121..fcfa79a 100644 --- 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 @@ -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", ) \ 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 index 7e79e1e..d507974 100644 --- 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 @@ -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 )) } } 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 index 772917d..77bdeda 100644 --- 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 @@ -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() ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index 47e7f91..a3318bc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -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( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39abda6..50df45b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,4 +79,19 @@ About Studeez + + Timer description cannot be empty! + Timer description + Timer name cannot be empty! + Timer name + Open Time Picker + " hours and " + " minutes of breaktime" + " break" + " breaks" + With breaks? + " hours and " + " minutes of studytime" + How long do you want to study? +