From 2ca112ee0e66547dd8ed8a3ecb96643061033eca Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Thu, 27 Apr 2023 17:01:39 +0200 Subject: [PATCH] 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