LazyColumn not fixed
This commit is contained in:
		
							parent
							
								
									601740f258
								
							
						
					
					
						commit
						2ca112ee0e
					
				
					 6 changed files with 303 additions and 28 deletions
				
			
		|  | @ -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() | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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<List<TimerInfo>>, | ||||
|     val getDefaultTimers: () -> List<TimerInfo>, | ||||
|     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({}, {}, {}, {}) | ||||
|     ) | ||||
|  |  | |||
|  | @ -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 = "", | ||||
| ) | ||||
|  | @ -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) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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() | ||||
|     ) | ||||
| } | ||||
		Reference in a new issue
	
	 Rune Dyselinck
						Rune Dyselinck