Resolved merge conflicts (call with friends)
This commit is contained in:
		
						commit
						46109ac4ff
					
				
					 31 changed files with 1011 additions and 205 deletions
				
			
		
							
								
								
									
										2
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,7 +1,7 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <project version="4"> | <project version="4"> | ||||||
|   <component name="ExternalStorageConfigurationManager" enabled="true" /> |   <component name="ExternalStorageConfigurationManager" enabled="true" /> | ||||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> |   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK"> | ||||||
|     <output url="file://$PROJECT_DIR$/build/classes" /> |     <output url="file://$PROJECT_DIR$/build/classes" /> | ||||||
|   </component> |   </component> | ||||||
|   <component name="ProjectType"> |   <component name="ProjectType"> | ||||||
|  |  | ||||||
|  | @ -2,18 +2,8 @@ package be.ugent.sel.studeez | ||||||
| 
 | 
 | ||||||
| import android.content.res.Resources | import android.content.res.Resources | ||||||
| import androidx.compose.foundation.layout.padding | import androidx.compose.foundation.layout.padding | ||||||
| import androidx.compose.material.MaterialTheme | import androidx.compose.material.* | ||||||
| import androidx.compose.material.Scaffold | import androidx.compose.runtime.* | ||||||
| import androidx.compose.material.ScaffoldState |  | ||||||
| import androidx.compose.material.Snackbar |  | ||||||
| import androidx.compose.material.SnackbarHost |  | ||||||
| import androidx.compose.material.Surface |  | ||||||
| import androidx.compose.material.rememberScaffoldState |  | ||||||
| import androidx.compose.runtime.Composable |  | ||||||
| import androidx.compose.runtime.ReadOnlyComposable |  | ||||||
| import androidx.compose.runtime.getValue |  | ||||||
| import androidx.compose.runtime.remember |  | ||||||
| import androidx.compose.runtime.rememberCoroutineScope |  | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.platform.LocalConfiguration | import androidx.compose.ui.platform.LocalConfiguration | ||||||
| import androidx.compose.ui.platform.LocalContext | import androidx.compose.ui.platform.LocalContext | ||||||
|  | @ -38,10 +28,13 @@ import be.ugent.sel.studeez.screens.profile.EditProfileRoute | ||||||
| import be.ugent.sel.studeez.screens.profile.ProfileRoute | import be.ugent.sel.studeez.screens.profile.ProfileRoute | ||||||
| import be.ugent.sel.studeez.screens.session.SessionRoute | import be.ugent.sel.studeez.screens.session.SessionRoute | ||||||
| import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute | import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute | ||||||
|  | import be.ugent.sel.studeez.screens.sessions.SessionsRoute | ||||||
|  | import be.ugent.sel.studeez.screens.settings.SettingsRoute | ||||||
| import be.ugent.sel.studeez.screens.sign_up.SignUpRoute | import be.ugent.sel.studeez.screens.sign_up.SignUpRoute | ||||||
| import be.ugent.sel.studeez.screens.splash.SplashRoute | import be.ugent.sel.studeez.screens.splash.SplashRoute | ||||||
| import be.ugent.sel.studeez.screens.timer_edit.TimerEditRoute | import be.ugent.sel.studeez.screens.timer_edit.TimerEditRoute | ||||||
| import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute | 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.screens.timer_selection.TimerSelectionRoute | ||||||
| import be.ugent.sel.studeez.ui.theme.StudeezTheme | import be.ugent.sel.studeez.ui.theme.StudeezTheme | ||||||
| import kotlinx.coroutines.CoroutineScope | import kotlinx.coroutines.CoroutineScope | ||||||
|  | @ -92,7 +85,7 @@ fun resources(): Resources { | ||||||
| @Composable | @Composable | ||||||
| fun StudeezNavGraph( | fun StudeezNavGraph( | ||||||
|     appState: StudeezAppstate, |     appState: StudeezAppstate, | ||||||
|     modifier: Modifier, |     modifier: Modifier = Modifier, | ||||||
| ) { | ) { | ||||||
|     val drawerViewModel: DrawerViewModel = hiltViewModel() |     val drawerViewModel: DrawerViewModel = hiltViewModel() | ||||||
|     val navBarViewModel: NavigationBarViewModel = hiltViewModel() |     val navBarViewModel: NavigationBarViewModel = hiltViewModel() | ||||||
|  | @ -114,8 +107,52 @@ fun StudeezNavGraph( | ||||||
|         startDestination = StudeezDestinations.SPLASH_SCREEN, |         startDestination = StudeezDestinations.SPLASH_SCREEN, | ||||||
|         modifier = modifier, |         modifier = modifier, | ||||||
|     ) { |     ) { | ||||||
|  |         // NavBar | ||||||
|  |         composable(StudeezDestinations.HOME_SCREEN) { | ||||||
|  |             HomeRoute( | ||||||
|  |                 open, | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerActions = drawerActions, | ||||||
|  |                 navigationBarActions = navigationBarActions | ||||||
|  |             ) | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|  |         composable(StudeezDestinations.TASKS_SCREEN) { | ||||||
|  |             // TODO | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|  |         composable(StudeezDestinations.SESSIONS_SCREEN) { | ||||||
|  |             SessionsRoute( | ||||||
|  |                 drawerActions = drawerActions, | ||||||
|  |                 navigationBarActions = navigationBarActions | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         composable(StudeezDestinations.PROFILE_SCREEN) { | ||||||
|  |             ProfileRoute( | ||||||
|  |                 open, | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerActions = drawerActions, | ||||||
|  |                 navigationBarActions = navigationBarActions | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Drawer | ||||||
|  |         composable(StudeezDestinations.TIMER_SCREEN) { | ||||||
|  |             TimerOverviewRoute( | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerActions = drawerActions, | ||||||
|  |                 open = open | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         composable(StudeezDestinations.SETTINGS_SCREEN) { | ||||||
|  |             SettingsRoute( | ||||||
|  |                 drawerActions = drawerActions | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Login flow | ||||||
|         composable(StudeezDestinations.SPLASH_SCREEN) { |         composable(StudeezDestinations.SPLASH_SCREEN) { | ||||||
|             SplashRoute( |             SplashRoute( | ||||||
|                 openAndPopUp, |                 openAndPopUp, | ||||||
|  | @ -137,40 +174,12 @@ fun StudeezNavGraph( | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.HOME_SCREEN) { |         // Studying flow | ||||||
|             HomeRoute( |         composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { | ||||||
|  |             TimerSelectionRoute( | ||||||
|                 open, |                 open, | ||||||
|  |                 goBack, | ||||||
|                 viewModel = hiltViewModel(), |                 viewModel = hiltViewModel(), | ||||||
|                 drawerActions = drawerActions, |  | ||||||
|                 navigationBarActions = navigationBarActions, |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // TODO Tasks screen |  | ||||||
|         // TODO Sessions screen |  | ||||||
| 
 |  | ||||||
|         composable(StudeezDestinations.PROFILE_SCREEN) { |  | ||||||
|             ProfileRoute( |  | ||||||
|                 open, |  | ||||||
|                 viewModel = hiltViewModel(), |  | ||||||
|                 drawerActions = drawerActions, |  | ||||||
|                 navigationBarActions = navigationBarActions, |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) { |  | ||||||
|             TimerOverviewRoute( |  | ||||||
|                 viewModel = hiltViewModel(), |  | ||||||
|                 drawerActions = drawerActions, |  | ||||||
|                 open = open |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         composable(StudeezDestinations.TIMER_EDIT_SCREEN) { |  | ||||||
|             TimerEditRoute( |  | ||||||
|                 open = open, |  | ||||||
|                 popUp = goBack, |  | ||||||
|                 viewModel = hiltViewModel() |  | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -182,10 +191,43 @@ fun StudeezNavGraph( | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // TODO Timers screen |         composable(StudeezDestinations.SESSION_RECAP) { | ||||||
|         // TODO Settings screen |             SessionRecapRoute( | ||||||
|  |                 openAndPopUp = openAndPopUp, | ||||||
|  |                 viewModel = hiltViewModel() | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         composable(StudeezDestinations.ADD_TIMER_SCREEN) { | ||||||
|  |             AddTimerRoute( | ||||||
|  |                 open = open, | ||||||
|  |                 goBack = goBack, | ||||||
|  |                 viewModel = hiltViewModel() | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         composable(StudeezDestinations.TIMER_EDIT_SCREEN) { | ||||||
|  |             TimerEditRoute( | ||||||
|  |                 open = open, | ||||||
|  |                 popUp = goBack, | ||||||
|  |                 viewModel = hiltViewModel() | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Friends flow | ||||||
|  |         composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) { | ||||||
|  |             // TODO | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Create & edit screens | ||||||
|  |         composable(StudeezDestinations.CREATE_TASK_SCREEN) { | ||||||
|  |             // TODO | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         composable(StudeezDestinations.CREATE_SESSION_SCREEN) { | ||||||
|  |             // TODO | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         // Edit screens |  | ||||||
|         composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { |         composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { | ||||||
|             EditProfileRoute( |             EditProfileRoute( | ||||||
|                 goBack, |                 goBack, | ||||||
|  | @ -193,20 +235,5 @@ fun StudeezNavGraph( | ||||||
|                 viewModel = hiltViewModel(), |                 viewModel = hiltViewModel(), | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { |  | ||||||
|             TimerSelectionRoute( |  | ||||||
|                 open, |  | ||||||
|                 goBack, |  | ||||||
|                 viewModel = hiltViewModel(), |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         composable(StudeezDestinations.SESSION_RECAP) { |  | ||||||
|             SessionRecapRoute( |  | ||||||
|                 openAndPopUp = openAndPopUp, |  | ||||||
|                 viewModel = hiltViewModel() |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ package be.ugent.sel.studeez.common.composable | ||||||
| 
 | 
 | ||||||
| import androidx.annotation.StringRes | import androidx.annotation.StringRes | ||||||
| import androidx.compose.foundation.BorderStroke | import androidx.compose.foundation.BorderStroke | ||||||
| import androidx.compose.foundation.shape.RoundedCornerShape |  | ||||||
| import androidx.compose.material.* | import androidx.compose.material.* | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
|  | @ -13,10 +12,18 @@ import androidx.compose.ui.unit.sp | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.common.ext.card | import be.ugent.sel.studeez.common.ext.card | ||||||
|  | import be.ugent.sel.studeez.common.ext.defaultButtonShape | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { | 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 | @Composable | ||||||
|  | @ -30,7 +37,7 @@ fun BasicButton( | ||||||
|     Button( |     Button( | ||||||
|         onClick = onClick, |         onClick = onClick, | ||||||
|         modifier = modifier, |         modifier = modifier, | ||||||
|         shape = RoundedCornerShape(20.dp), |         shape = defaultButtonShape(), | ||||||
|         colors = colors, |         colors = colors, | ||||||
|         border = border, |         border = border, | ||||||
|     ) { |     ) { | ||||||
|  | @ -47,6 +54,25 @@ fun BasicButtonPreview() { | ||||||
|     BasicButton(text = R.string.add_timer, modifier = Modifier.basicButton()) {} |     BasicButton(text = R.string.add_timer, modifier = Modifier.basicButton()) {} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Composable | ||||||
|  | fun NotInternationalisedButton( | ||||||
|  |     text: String, | ||||||
|  |     modifier: Modifier = Modifier, | ||||||
|  |     colors: ButtonColors = ButtonDefaults.buttonColors(), | ||||||
|  |     border: BorderStroke? = null, | ||||||
|  |     onClick: () -> Unit | ||||||
|  | ) { | ||||||
|  |     Button( | ||||||
|  |         onClick = onClick, | ||||||
|  |         modifier = modifier, | ||||||
|  |         shape = defaultButtonShape(), | ||||||
|  |         colors = colors, | ||||||
|  |         border = border | ||||||
|  |     ) { | ||||||
|  |         Text(text = text) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun StealthButton( | fun StealthButton( | ||||||
|     @StringRes text: Int, |     @StringRes text: Int, | ||||||
|  |  | ||||||
|  | @ -1,7 +1,9 @@ | ||||||
| package be.ugent.sel.studeez.common.composable | package be.ugent.sel.studeez.common.composable | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.animation.core.animateFloat | ||||||
| import androidx.compose.foundation.layout.Row | import androidx.compose.animation.core.updateTransition | ||||||
|  | import androidx.compose.foundation.border | ||||||
|  | import androidx.compose.foundation.layout.* | ||||||
| import androidx.compose.material.FloatingActionButton | import androidx.compose.material.FloatingActionButton | ||||||
| import androidx.compose.material.Icon | import androidx.compose.material.Icon | ||||||
| import androidx.compose.material.IconButton | import androidx.compose.material.IconButton | ||||||
|  | @ -11,52 +13,134 @@ import androidx.compose.material.icons.filled.Add | ||||||
| import androidx.compose.material.icons.filled.Check | import androidx.compose.material.icons.filled.Check | ||||||
| import androidx.compose.material.icons.filled.DateRange | import androidx.compose.material.icons.filled.DateRange | ||||||
| import androidx.compose.material.icons.filled.Person | import androidx.compose.material.icons.filled.Person | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.* | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.draw.rotate | ||||||
|  | import androidx.compose.ui.graphics.vector.ImageVector | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.ui.theme.StudeezTheme | import be.ugent.sel.studeez.ui.theme.StudeezTheme | ||||||
|  | import be.ugent.sel.studeez.R.string as AppText | ||||||
|  | 
 | ||||||
|  | const val TRANSITION = "transition" | ||||||
|  | val HEIGHT_DIFFERENCE = 30.dp | ||||||
|  | 
 | ||||||
|  | data class AddButtonActions( | ||||||
|  |     val onTaskClick: () -> Unit, | ||||||
|  |     val onFriendClick: () -> Unit, | ||||||
|  |     val onSessionClick: () -> Unit | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun CollapsedAddButton() { | fun AddButton( | ||||||
|     FloatingActionButton( |     addButtonActions: AddButtonActions | ||||||
|         onClick = { /* TODO popup add options */ } | ) { | ||||||
|  |     var isExpanded by remember { mutableStateOf(false) } | ||||||
|  | 
 | ||||||
|  |     // Rotate the button when expanded, normal when collapsed. | ||||||
|  |     val transition = updateTransition(targetState = isExpanded, label = TRANSITION) | ||||||
|  |     val rotate by transition.animateFloat(label = TRANSITION) { expanded -> if (expanded) 315f else 0f } | ||||||
|  | 
 | ||||||
|  |     Column( | ||||||
|  |         horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|  |         verticalArrangement = Arrangement.Top | ||||||
|     ) { |     ) { | ||||||
|         Icon(imageVector = Icons.Default.Add, contentDescription = "fab") |         Box { | ||||||
|  |             // Show minis when expanded. | ||||||
|  |             if (isExpanded) { | ||||||
|  |                 ExpandedAddButton( | ||||||
|  |                     addButtonActions = addButtonActions | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // The base add button | ||||||
|  |         FloatingActionButton( | ||||||
|  |             onClick = { | ||||||
|  |                 // Toggle expanded/collapsed. | ||||||
|  |                 isExpanded = !isExpanded | ||||||
|  |             }, | ||||||
|  |             modifier = Modifier.padding(bottom = if (isExpanded) 78.dp else 0.dp) | ||||||
|  |         ) { | ||||||
|  |             Icon( | ||||||
|  |                 imageVector = Icons.Default.Add, | ||||||
|  |                 contentDescription = "fab", | ||||||
|  |                 modifier = Modifier.rotate(rotate) // The rotation | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun ExpandedAddButton() { | fun ExpandedAddButton( | ||||||
|     Row() { |     addButtonActions: AddButtonActions | ||||||
|         IconButton(onClick = { /* TODO Go to next step */ }) { | ) { | ||||||
|             Column (horizontalAlignment = Alignment.CenterHorizontally) { |     Row { | ||||||
|                 Icon(imageVector = Icons.Default.Check, contentDescription = "Task") |         ExpandedEntry( | ||||||
|                 Text(text = "Task") |             name = AppText.task, | ||||||
|             } |             imageVector = Icons.Default.Check, | ||||||
|         } |             onClick = addButtonActions.onTaskClick, | ||||||
|         IconButton(onClick = { /* TODO Go to next step */ }) { |             modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) | ||||||
|             Column (horizontalAlignment = Alignment.CenterHorizontally) { |         ) | ||||||
|                 Icon(imageVector = Icons.Default.Person, contentDescription = "Friend") | 
 | ||||||
|                 Text(text = "Friend") |         ExpandedEntry( | ||||||
|             } |             name = AppText.friend, | ||||||
|         } |             imageVector = Icons.Default.Person, | ||||||
|         IconButton(onClick = { /* TODO Go to next step */ }) { |             onClick = addButtonActions.onFriendClick | ||||||
|             Column (horizontalAlignment = Alignment.CenterHorizontally) { |         ) | ||||||
|                 Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session") | 
 | ||||||
|                 Text(text = "Session") |         ExpandedEntry( | ||||||
|             } |             name = AppText.session, | ||||||
|         } |             imageVector = Icons.Default.DateRange, | ||||||
|  |             onClick = addButtonActions.onSessionClick, | ||||||
|  |             modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Composable | ||||||
|  | fun ExpandedEntry( | ||||||
|  |     name: Int, | ||||||
|  |     imageVector: ImageVector, | ||||||
|  |     onClick: () -> Unit, | ||||||
|  |     modifier: Modifier = Modifier | ||||||
|  | ) { | ||||||
|  |     IconButton( | ||||||
|  |         onClick = onClick, | ||||||
|  |         modifier = modifier | ||||||
|  |     ) { | ||||||
|  |         Column(horizontalAlignment = Alignment.CenterHorizontally) { | ||||||
|  |             Icon( | ||||||
|  |                 imageVector = imageVector, | ||||||
|  |                 contentDescription = resources().getString(name), | ||||||
|  |                 // TODO Dark overlay | ||||||
|  |                 //  tint = colors.surface | ||||||
|  |             ) | ||||||
|  |             Text( | ||||||
|  |                 text = resources().getString(name), | ||||||
|  |                 // TODO Dark overlay | ||||||
|  |                 //  color = colors.surface | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun CollapsedAddButtonPreview() { | fun AddButtonPreview() { | ||||||
|     StudeezTheme { CollapsedAddButton() } |     StudeezTheme { AddButton( | ||||||
|  |         addButtonActions = AddButtonActions({}, {}, {}) | ||||||
|  |     )} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun ExpandedAddButtonPreview() { | fun ExpandedAddButtonPreview() { | ||||||
|     StudeezTheme { ExpandedAddButton() } |     StudeezTheme { ExpandedAddButton ( | ||||||
|  |         addButtonActions = AddButtonActions({}, {}, {}) | ||||||
|  |     ) } | ||||||
| } | } | ||||||
|  | @ -57,7 +57,11 @@ fun PrimaryScreenTemplate( | ||||||
|         bottomBar = { NavigationBar(navigationBarActions) }, |         bottomBar = { NavigationBar(navigationBarActions) }, | ||||||
|         floatingActionButtonPosition = FabPosition.Center, |         floatingActionButtonPosition = FabPosition.Center, | ||||||
|         isFloatingActionButtonDocked = true, |         isFloatingActionButtonDocked = true, | ||||||
|         floatingActionButton = { CollapsedAddButton() } |         floatingActionButton = { AddButton(AddButtonActions( | ||||||
|  |             onTaskClick = navigationBarActions.onAddTaskClick, | ||||||
|  |             onFriendClick = navigationBarActions.onAddFriendClick, | ||||||
|  |             onSessionClick = navigationBarActions.onAddSessionClick | ||||||
|  |         )) } | ||||||
|     ) { |     ) { | ||||||
|         content(it) |         content(it) | ||||||
|     } |     } | ||||||
|  | @ -70,7 +74,7 @@ fun PrimaryScreenPreview() { | ||||||
|         PrimaryScreenTemplate( |         PrimaryScreenTemplate( | ||||||
|             "Preview screen", |             "Preview screen", | ||||||
|             DrawerActions({}, {}, {}, {}, {}), |             DrawerActions({}, {}, {}, {}, {}), | ||||||
|             NavigationBarActions({ false }, {}, {}, {}, {}), |             NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), | ||||||
|             { |             { | ||||||
|                 IconButton(onClick = { /*TODO*/ }) { |                 IconButton(onClick = { /*TODO*/ }) { | ||||||
|                     Icon( |                     Icon( | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| package be.ugent.sel.studeez.common.composable.drawer | package be.ugent.sel.studeez.common.composable.drawer | ||||||
| 
 | 
 | ||||||
|  | import android.content.Context | ||||||
| import androidx.compose.foundation.clickable | import androidx.compose.foundation.clickable | ||||||
| import androidx.compose.foundation.layout.Arrangement | import androidx.compose.foundation.layout.Arrangement | ||||||
| import androidx.compose.foundation.layout.Box | import androidx.compose.foundation.layout.Box | ||||||
|  | @ -16,6 +17,7 @@ import androidx.compose.material.icons.outlined.Info | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.graphics.vector.ImageVector | import androidx.compose.ui.graphics.vector.ImageVector | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
| import androidx.compose.ui.res.vectorResource | import androidx.compose.ui.res.vectorResource | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.compose.ui.unit.dp | import androidx.compose.ui.unit.dp | ||||||
|  | @ -28,7 +30,7 @@ data class DrawerActions( | ||||||
|     val onTimersClick: () -> Unit, |     val onTimersClick: () -> Unit, | ||||||
|     val onSettingsClick: () -> Unit, |     val onSettingsClick: () -> Unit, | ||||||
|     val onLogoutClick: () -> Unit, |     val onLogoutClick: () -> Unit, | ||||||
|     val onAboutClick: () -> Unit, |     val onAboutClick: (Context) -> Unit, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| fun getDrawerActions( | fun getDrawerActions( | ||||||
|  | @ -41,7 +43,7 @@ fun getDrawerActions( | ||||||
|         onTimersClick = { drawerViewModel.onTimersClick(open) }, |         onTimersClick = { drawerViewModel.onTimersClick(open) }, | ||||||
|         onSettingsClick = { drawerViewModel.onSettingsClick(open) }, |         onSettingsClick = { drawerViewModel.onSettingsClick(open) }, | ||||||
|         onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, |         onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, | ||||||
|         onAboutClick = { drawerViewModel.onAboutClick(open) }, |         onAboutClick = { context -> drawerViewModel.onAboutClick(open, context = context) }, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -79,10 +81,11 @@ fun Drawer( | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         val context = LocalContext.current | ||||||
|         DrawerEntry( |         DrawerEntry( | ||||||
|             icon = Icons.Outlined.Info, |             icon = Icons.Outlined.Info, | ||||||
|             text = resources().getString(R.string.about), |             text = resources().getString(R.string.about), | ||||||
|             onClick = drawerActions.onAboutClick, |             onClick = { drawerActions.onAboutClick(context) }, | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -96,7 +99,7 @@ fun DrawerEntry( | ||||||
|     Row( |     Row( | ||||||
|         horizontalArrangement = Arrangement.Center, |         horizontalArrangement = Arrangement.Center, | ||||||
|         modifier = Modifier |         modifier = Modifier | ||||||
|             .clickable(onClick = { onClick() }) |             .clickable(onClick = onClick) | ||||||
|             .fillMaxWidth() |             .fillMaxWidth() | ||||||
|     ) { |     ) { | ||||||
|         Box( |         Box( | ||||||
|  |  | ||||||
|  | @ -1,5 +1,10 @@ | ||||||
| package be.ugent.sel.studeez.common.composable.drawer | package be.ugent.sel.studeez.common.composable.drawer | ||||||
| 
 | 
 | ||||||
|  | import android.content.Context | ||||||
|  | import android.content.Intent | ||||||
|  | import android.net.Uri | ||||||
|  | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.ui.platform.LocalContext | ||||||
| import be.ugent.sel.studeez.domain.AccountDAO | import be.ugent.sel.studeez.domain.AccountDAO | ||||||
| import be.ugent.sel.studeez.domain.LogService | import be.ugent.sel.studeez.domain.LogService | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||||
|  | @ -9,6 +14,8 @@ import be.ugent.sel.studeez.screens.StudeezViewModel | ||||||
| import dagger.hilt.android.lifecycle.HiltViewModel | import dagger.hilt.android.lifecycle.HiltViewModel | ||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
| 
 | 
 | ||||||
|  | const val REPO_URL: String = "https://github.ugent.be/SELab1/project2023-groep14/" | ||||||
|  | 
 | ||||||
| @HiltViewModel | @HiltViewModel | ||||||
| class DrawerViewModel @Inject constructor( | class DrawerViewModel @Inject constructor( | ||||||
|     private val accountDAO: AccountDAO, |     private val accountDAO: AccountDAO, | ||||||
|  | @ -20,11 +27,11 @@ class DrawerViewModel @Inject constructor( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onTimersClick(openAndPopup: (String) -> Unit) { |     fun onTimersClick(openAndPopup: (String) -> Unit) { | ||||||
|         openAndPopup(StudeezDestinations.TIMER_OVERVIEW_SCREEN) |         openAndPopup(StudeezDestinations.TIMER_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onSettingsClick(open: (String) -> Unit) { |     fun onSettingsClick(open: (String) -> Unit) { | ||||||
|         // TODO |         open(StudeezDestinations.SETTINGS_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onLogoutClick(openAndPopUp: (String, String) -> Unit) { |     fun onLogoutClick(openAndPopUp: (String, String) -> Unit) { | ||||||
|  | @ -34,7 +41,8 @@ class DrawerViewModel @Inject constructor( | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onAboutClick(open: (String) -> Unit) { |     fun onAboutClick(open: (String) -> Unit, context: Context) { | ||||||
|         // TODO |         val intent = Intent(Intent.ACTION_VIEW, Uri.parse(REPO_URL)) | ||||||
|  |         context.startActivity(intent) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,16 +14,24 @@ import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.compose.ui.unit.dp | import androidx.compose.ui.unit.dp | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN | import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN | import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN | ||||||
|  | import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN | ||||||
|  | import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.ui.theme.StudeezTheme | import be.ugent.sel.studeez.ui.theme.StudeezTheme | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
| data class NavigationBarActions( | data class NavigationBarActions( | ||||||
|     val isSelectedTab: (String) -> Boolean, |     val isSelectedTab: (String) -> Boolean, | ||||||
|  | 
 | ||||||
|     val onHomeClick: () -> Unit, |     val onHomeClick: () -> Unit, | ||||||
|     val onTasksClick: () -> Unit, |     val onTasksClick: () -> Unit, | ||||||
|     val onSessionsClick: () -> Unit, |     val onSessionsClick: () -> Unit, | ||||||
|     val onProfileClick: () -> Unit, |     val onProfileClick: () -> Unit, | ||||||
|  | 
 | ||||||
|  |     // AddButton | ||||||
|  |     val onAddTaskClick: () -> Unit, | ||||||
|  |     val onAddFriendClick: () -> Unit, | ||||||
|  |     val onAddSessionClick: () -> Unit | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| fun getNavigationBarActions( | fun getNavigationBarActions( | ||||||
|  | @ -35,6 +43,7 @@ fun getNavigationBarActions( | ||||||
|         isSelectedTab = { screen -> |         isSelectedTab = { screen -> | ||||||
|             screen == getCurrentScreen() |             screen == getCurrentScreen() | ||||||
|         }, |         }, | ||||||
|  | 
 | ||||||
|         onHomeClick = { |         onHomeClick = { | ||||||
|             navigationBarViewModel.onHomeClick(open) |             navigationBarViewModel.onHomeClick(open) | ||||||
|         }, |         }, | ||||||
|  | @ -47,6 +56,16 @@ fun getNavigationBarActions( | ||||||
|         onProfileClick = { |         onProfileClick = { | ||||||
|             navigationBarViewModel.onProfileClick(open) |             navigationBarViewModel.onProfileClick(open) | ||||||
|         }, |         }, | ||||||
|  | 
 | ||||||
|  |         onAddTaskClick = { | ||||||
|  |             navigationBarViewModel.onAddTaskClick(open) | ||||||
|  |         }, | ||||||
|  |         onAddFriendClick = { | ||||||
|  |             navigationBarViewModel.onAddFriendClick(open) | ||||||
|  |         }, | ||||||
|  |         onAddSessionClick = { | ||||||
|  |             navigationBarViewModel.onAddSessionClick(open) | ||||||
|  |         } | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -71,13 +90,12 @@ fun NavigationBar( | ||||||
|                 ) |                 ) | ||||||
|             }, |             }, | ||||||
|             label = { Text(text = resources().getString(AppText.tasks)) }, |             label = { Text(text = resources().getString(AppText.tasks)) }, | ||||||
|             // TODO selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), |             selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), | ||||||
|             selected = false, |  | ||||||
|             onClick = navigationBarActions.onTasksClick |             onClick = navigationBarActions.onTasksClick | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         // Hack to space the entries in the navigation bar, make space for fab |         // Hack to space the entries in the navigation bar, make space for fab | ||||||
|         BottomNavigationItem(icon = {}, onClick = {}, selected = false) |         BottomNavigationItem(icon = {}, onClick = {}, selected = false, enabled = false) | ||||||
| 
 | 
 | ||||||
|         BottomNavigationItem( |         BottomNavigationItem( | ||||||
|             icon = { |             icon = { | ||||||
|  | @ -86,8 +104,7 @@ fun NavigationBar( | ||||||
|                 ) |                 ) | ||||||
|             }, |             }, | ||||||
|             label = { Text(text = resources().getString(AppText.sessions)) }, |             label = { Text(text = resources().getString(AppText.sessions)) }, | ||||||
|             // TODO selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), |             selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), | ||||||
|             selected = false, |  | ||||||
|             onClick = navigationBarActions.onSessionsClick |             onClick = navigationBarActions.onSessionsClick | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  | @ -110,7 +127,7 @@ fun NavigationBar( | ||||||
| fun NavigationBarPreview() { | fun NavigationBarPreview() { | ||||||
|     StudeezTheme { |     StudeezTheme { | ||||||
|         NavigationBar( |         NavigationBar( | ||||||
|             navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}), |             navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1,12 +1,16 @@ | ||||||
| package be.ugent.sel.studeez.common.composable.navbar | package be.ugent.sel.studeez.common.composable.navbar | ||||||
| 
 | 
 | ||||||
|  | import be.ugent.sel.studeez.common.snackbar.SnackbarManager | ||||||
| import be.ugent.sel.studeez.domain.AccountDAO | import be.ugent.sel.studeez.domain.AccountDAO | ||||||
| import be.ugent.sel.studeez.domain.LogService | import be.ugent.sel.studeez.domain.LogService | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN | import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN | import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN | ||||||
|  | import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN | ||||||
|  | import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN | ||||||
| import be.ugent.sel.studeez.screens.StudeezViewModel | import be.ugent.sel.studeez.screens.StudeezViewModel | ||||||
| import dagger.hilt.android.lifecycle.HiltViewModel | import dagger.hilt.android.lifecycle.HiltViewModel | ||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
|  | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
| @HiltViewModel | @HiltViewModel | ||||||
| class NavigationBarViewModel @Inject constructor( | class NavigationBarViewModel @Inject constructor( | ||||||
|  | @ -19,14 +23,29 @@ class NavigationBarViewModel @Inject constructor( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onTasksClick(open: (String) -> Unit) { |     fun onTasksClick(open: (String) -> Unit) { | ||||||
|         // TODO |         open(TASKS_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onSessionsClick(open: (String) -> Unit) { |     fun onSessionsClick(open: (String) -> Unit) { | ||||||
|         // TODO |         open(SESSIONS_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onProfileClick(open: (String) -> Unit) { |     fun onProfileClick(open: (String) -> Unit) { | ||||||
|         open(PROFILE_SCREEN) |         open(PROFILE_SCREEN) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fun onAddTaskClick(open: (String) -> Unit) { | ||||||
|  |         // TODO open(CREATE_TASK_SCREEN) | ||||||
|  |         SnackbarManager.showMessage(AppText.create_task_not_possible_yet) // TODO Remove | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun onAddFriendClick(open: (String) -> Unit) { | ||||||
|  |         // TODO open(SEARCH_FRIENDS_SCREEN) | ||||||
|  |         SnackbarManager.showMessage(AppText.add_friend_not_possible_yet) // TODO Remove | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun onAddSessionClick(open: (String) -> Unit) { | ||||||
|  |         // TODO open(CREATE_SESSION_SCREEN) | ||||||
|  |         SnackbarManager.showMessage(AppText.create_session_not_possible_yet) // TODO Remove | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | @ -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 | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | package be.ugent.sel.studeez.common.ext | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.shape.RoundedCornerShape | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | 
 | ||||||
|  | fun defaultButtonShape(): RoundedCornerShape { | ||||||
|  |     return RoundedCornerShape(20.dp) | ||||||
|  | } | ||||||
|  | @ -4,7 +4,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) { | ||||||
| 
 | 
 | ||||||
|     override fun tick() { |     override fun tick() { | ||||||
|         if (!hasEnded()) { |         if (!hasEnded()) { | ||||||
|             time++ |             time-- | ||||||
|             totalStudyTime++ |             totalStudyTime++ | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,23 +1,34 @@ | ||||||
| package be.ugent.sel.studeez.navigation | package be.ugent.sel.studeez.navigation | ||||||
| 
 | 
 | ||||||
| object StudeezDestinations { | object StudeezDestinations { | ||||||
|     const val SPLASH_SCREEN = "splash" |     // NavBar | ||||||
|     const val SIGN_UP_SCREEN = "signup" |  | ||||||
|     const val LOGIN_SCREEN = "login" |  | ||||||
| 
 |  | ||||||
|     const val HOME_SCREEN = "home" |     const val HOME_SCREEN = "home" | ||||||
|     const val TIMER_OVERVIEW_SCREEN = "timer_overview" |     const val TASKS_SCREEN = "tasks" | ||||||
|  |     const val SESSIONS_SCREEN = "sessions" | ||||||
|  |     const val PROFILE_SCREEN = "profile" | ||||||
|  | 
 | ||||||
|  |     // Drawer | ||||||
|  |     const val TIMER_SCREEN = "timer_overview" | ||||||
|  |     const val SETTINGS_SCREEN = "settings" | ||||||
|  | 
 | ||||||
|  |     // Login flow | ||||||
|  |     const val SPLASH_SCREEN = "splash" | ||||||
|  |     const val LOGIN_SCREEN = "login" | ||||||
|  |     const val SIGN_UP_SCREEN = "signup" | ||||||
|  | 
 | ||||||
|  |     // Studying flow | ||||||
|     const val TIMER_SELECTION_SCREEN = "timer_selection" |     const val TIMER_SELECTION_SCREEN = "timer_selection" | ||||||
|     const val TIMER_EDIT_SCREEN = "timer_edit" |     const val TIMER_EDIT_SCREEN = "timer_edit" | ||||||
|     const val SESSION_SCREEN = "session" |     const val SESSION_SCREEN = "session" | ||||||
|     const val SESSION_RECAP = "session_recap" |     const val SESSION_RECAP = "session_recap" | ||||||
|  //    const val TASKS_SCREEN = "tasks" |  | ||||||
|  //    const val SESSIONS_SCREEN = "sessions" |  | ||||||
|     const val PROFILE_SCREEN = "profile" |  | ||||||
| 
 | 
 | ||||||
| //    const val TIMERS_SCREEN = "timers" |     // Friends flow | ||||||
| //    const val SETTINGS_SCREEN = "settings" |     const val SEARCH_FRIENDS_SCREEN = "search_friends" | ||||||
| 
 | 
 | ||||||
|     // Edit screens |     // Create & edit screens | ||||||
|  |     const val CREATE_TASK_SCREEN = "create_task" | ||||||
|  |     const val CREATE_SESSION_SCREEN = "create_session" | ||||||
|     const val EDIT_PROFILE_SCREEN = "edit_profile" |     const val EDIT_PROFILE_SCREEN = "edit_profile" | ||||||
|  | 
 | ||||||
|  |     const val ADD_TIMER_SCREEN = "add_timer" | ||||||
| } | } | ||||||
|  | @ -33,13 +33,13 @@ fun HomeRoute( | ||||||
| fun HomeScreen( | fun HomeScreen( | ||||||
|     onStartSessionClick: () -> Unit, |     onStartSessionClick: () -> Unit, | ||||||
|     drawerActions: DrawerActions, |     drawerActions: DrawerActions, | ||||||
|     navigationBarActions: NavigationBarActions, |     navigationBarActions: NavigationBarActions | ||||||
| ) { | ) { | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.home), |         title = resources().getString(R.string.home), | ||||||
|         drawerActions = drawerActions, |         drawerActions = drawerActions, | ||||||
|         navigationBarActions = navigationBarActions, |         navigationBarActions = navigationBarActions, | ||||||
|         barAction = { FriendsAction() } |         // TODO barAction = { FriendsAction() } | ||||||
|     ) { |     ) { | ||||||
|         BasicButton(R.string.start_session, Modifier.basicButton()) { |         BasicButton(R.string.start_session, Modifier.basicButton()) { | ||||||
|             onStartSessionClick() |             onStartSessionClick() | ||||||
|  | @ -63,6 +63,6 @@ fun HomeScreenPreview() { | ||||||
|     HomeScreen( |     HomeScreen( | ||||||
|         onStartSessionClick = {}, |         onStartSessionClick = {}, | ||||||
|         drawerActions = DrawerActions({}, {}, {}, {}, {}), |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) |         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}) | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -63,7 +63,10 @@ fun EditProfileScreen( | ||||||
|             BasicTextButton( |             BasicTextButton( | ||||||
|                 text = R.string.save, |                 text = R.string.save, | ||||||
|                 Modifier.textButton(), |                 Modifier.textButton(), | ||||||
|                 action = editProfileActions.onSaveClick |                 action = { | ||||||
|  |                     editProfileActions.onSaveClick() | ||||||
|  |                     goBack() | ||||||
|  |                 } | ||||||
|             ) |             ) | ||||||
|             BasicTextButton( |             BasicTextButton( | ||||||
|                 text = R.string.delete_profile, |                 text = R.string.delete_profile, | ||||||
|  |  | ||||||
|  | @ -88,6 +88,6 @@ fun ProfileScreenPreview() { | ||||||
|     ProfileScreen( |     ProfileScreen( | ||||||
|         profileActions = ProfileActions({ null }, {}), |         profileActions = ProfileActions({ null }, {}), | ||||||
|         drawerActions = DrawerActions({}, {}, {}, {}, {}), |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) |         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}) | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | @ -47,8 +47,11 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi | ||||||
|     val sessionReport: SessionReport = sessionRecapActions.getSessionReport() |     val sessionReport: SessionReport = sessionRecapActions.getSessionReport() | ||||||
|     val studyTime: Int = sessionReport.studyTime |     val studyTime: Int = sessionReport.studyTime | ||||||
|     val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() |     val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() | ||||||
|     Column { |     Column( | ||||||
|  |         modifier = modifier | ||||||
|  |     ) { | ||||||
|         Text(text = "You studied: $hms") |         Text(text = "You studied: $hms") | ||||||
|  | 
 | ||||||
|         BasicButton( |         BasicButton( | ||||||
|             R.string.save, Modifier.basicButton() |             R.string.save, Modifier.basicButton() | ||||||
|         ) { |         ) { | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ import javax.inject.Inject | ||||||
| 
 | 
 | ||||||
| @HiltViewModel | @HiltViewModel | ||||||
| class SessionRecapViewModel @Inject constructor( | class SessionRecapViewModel @Inject constructor( | ||||||
|     private val sessionReportState: SessionReportState, |     sessionReportState: SessionReportState, | ||||||
|     private val sessionDAO: SessionDAO, |     private val sessionDAO: SessionDAO, | ||||||
|     logService: LogService |     logService: LogService | ||||||
| ) : StudeezViewModel(logService) { | ) : StudeezViewModel(logService) { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | package be.ugent.sel.studeez.screens.sessions | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.layout.fillMaxSize | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.resources | ||||||
|  | import be.ugent.sel.studeez.R.string as AppText | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SessionsRoute( | ||||||
|  |     // viewModel: SessionsViewModel, | ||||||
|  |     drawerActions: DrawerActions, | ||||||
|  |     navigationBarActions: NavigationBarActions | ||||||
|  | ) { | ||||||
|  |     SessionsScreen( | ||||||
|  |         drawerActions = drawerActions, | ||||||
|  |         navigationBarActions = navigationBarActions | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SessionsScreen( | ||||||
|  |     drawerActions: DrawerActions, | ||||||
|  |     navigationBarActions: NavigationBarActions | ||||||
|  | ) { | ||||||
|  |     PrimaryScreenTemplate( | ||||||
|  |         title = resources().getString(AppText.upcoming_sessions), | ||||||
|  |         drawerActions = drawerActions, | ||||||
|  |         navigationBarActions = navigationBarActions | ||||||
|  |     ) { | ||||||
|  |         Text( | ||||||
|  |             text = resources().getString(AppText.sessions_temp_description), | ||||||
|  |             modifier = Modifier.fillMaxSize(), | ||||||
|  |             textAlign = TextAlign.Center | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | package be.ugent.sel.studeez.screens.settings | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.layout.fillMaxSize | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | import be.ugent.sel.studeez.common.composable.DrawerScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.resources | ||||||
|  | import be.ugent.sel.studeez.R.string as AppText | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SettingsRoute( | ||||||
|  |     // viewModel: SettingsViewModel, | ||||||
|  |     drawerActions: DrawerActions | ||||||
|  | ) { | ||||||
|  |     SettingsScreen( | ||||||
|  |         drawerActions = drawerActions | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SettingsScreen( | ||||||
|  |     drawerActions: DrawerActions | ||||||
|  | ) { | ||||||
|  |     DrawerScreenTemplate( | ||||||
|  |         title = resources().getString(AppText.settings), | ||||||
|  |         drawerActions = drawerActions | ||||||
|  |     ) { | ||||||
|  |         Text( | ||||||
|  |             text = resources().getString(AppText.settings_temp_description), | ||||||
|  |             modifier = Modifier.fillMaxSize(), | ||||||
|  |             textAlign = TextAlign.Center | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -42,12 +42,16 @@ abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) { | ||||||
|                     onNewValue = { name = it }, |                     onNewValue = { name = it }, | ||||||
|                     label = R.string.name |                     label = R.string.name | ||||||
|                 ) |                 ) | ||||||
|                 LabelledInputField( | 
 | ||||||
|                     value = description, |                 repeat(20) { | ||||||
|                     onNewValue = { description = it }, |                     LabelledInputField( | ||||||
|                     label = R.string.description, |                         value = description, | ||||||
|                     singleLine = false |                         onNewValue = { description = it }, | ||||||
|                 ) |                         label = R.string.description, | ||||||
|  |                         singleLine = false | ||||||
|  |                     ) | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 ExtraFields() |                 ExtraFields() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | 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.CustomTimerInfo | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | 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 be.ugent.sel.studeez.resources | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.flowOf | import kotlinx.coroutines.flow.flowOf | ||||||
|  | @ -24,6 +25,7 @@ data class TimerOverviewActions( | ||||||
|     val getUserTimers: () -> Flow<List<TimerInfo>>, |     val getUserTimers: () -> Flow<List<TimerInfo>>, | ||||||
|     val getDefaultTimers: () -> List<TimerInfo>, |     val getDefaultTimers: () -> List<TimerInfo>, | ||||||
|     val onEditClick: (TimerInfo) -> Unit, |     val onEditClick: (TimerInfo) -> Unit, | ||||||
|  |     val onAddClick: () -> Unit, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| fun getTimerOverviewActions( | fun getTimerOverviewActions( | ||||||
|  | @ -34,6 +36,7 @@ fun getTimerOverviewActions( | ||||||
|         getUserTimers = viewModel::getUserTimers, |         getUserTimers = viewModel::getUserTimers, | ||||||
|         getDefaultTimers = viewModel::getDefaultTimers, |         getDefaultTimers = viewModel::getDefaultTimers, | ||||||
|         onEditClick = { viewModel.update(it, open) }, |         onEditClick = { viewModel.update(it, open) }, | ||||||
|  |         onAddClick = { viewModel.create(open) } | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -61,8 +64,16 @@ fun TimerOverviewScreen( | ||||||
|         title = resources().getString(R.string.timers), |         title = resources().getString(R.string.timers), | ||||||
|         drawerActions = drawerActions |         drawerActions = drawerActions | ||||||
|     ) { |     ) { | ||||||
|         Column { |         Column { // TODO knop beneden | ||||||
|             LazyColumn { |             LazyColumn { | ||||||
|  |                 // Custom timer, select new duration each time | ||||||
|  |                 item { | ||||||
|  |                     TimerEntry(timerInfo = CustomTimerInfo( | ||||||
|  |                         name = resources().getString(R.string.custom_name), | ||||||
|  |                         description = resources().getString(R.string.custom_name), | ||||||
|  |                         studyTime = 0 | ||||||
|  |                     )) | ||||||
|  |                 } | ||||||
|                 // Default Timers, cannot be edited |                 // Default Timers, cannot be edited | ||||||
|                 items(timerOverviewActions.getDefaultTimers()) { |                 items(timerOverviewActions.getDefaultTimers()) { | ||||||
|                     TimerEntry(timerInfo = it) {} |                     TimerEntry(timerInfo = it) {} | ||||||
|  | @ -79,9 +90,13 @@ fun TimerOverviewScreen( | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                 } |                 } | ||||||
|             } | 
 | ||||||
|             BasicButton(R.string.add_timer, Modifier.basicButton()) { |                 // TODO uit lazy column | ||||||
|                 // TODO |                 item { | ||||||
|  |                     BasicButton(R.string.add_timer, Modifier.basicButton()) { | ||||||
|  |                         timerOverviewActions.onAddClick() | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -97,7 +112,9 @@ fun TimerOverviewPreview() { | ||||||
|         timerOverviewActions = TimerOverviewActions( |         timerOverviewActions = TimerOverviewActions( | ||||||
|             { flowOf() }, |             { flowOf() }, | ||||||
|             { listOf(customTimer, customTimer) }, |             { listOf(customTimer, customTimer) }, | ||||||
|             {}), |             {}, | ||||||
|  |             {} | ||||||
|  |         ), | ||||||
|         drawerActions = DrawerActions({}, {}, {}, {}, {}) |         drawerActions = DrawerActions({}, {}, {}, {}, {}) | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -32,6 +32,10 @@ class TimerOverviewViewModel @Inject constructor( | ||||||
|         open(StudeezDestinations.TIMER_EDIT_SCREEN) |         open(StudeezDestinations.TIMER_EDIT_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fun create(open: (String) -> Unit) { | ||||||
|  |         open(StudeezDestinations.ADD_TIMER_SCREEN) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo) |     fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo) | ||||||
| 
 | 
 | ||||||
|     fun save(timerInfo: TimerInfo) = timerDAO.saveTimer(timerInfo) |     fun save(timerInfo: TimerInfo) = timerDAO.saveTimer(timerInfo) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | 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", | ||||||
|  | ) | ||||||
|  | @ -0,0 +1,91 @@ | ||||||
|  | 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) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,274 @@ | ||||||
|  | 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() | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -8,7 +8,11 @@ import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | ||||||
| import be.ugent.sel.studeez.common.composable.StealthButton | import be.ugent.sel.studeez.common.composable.StealthButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.TimePickerButton | ||||||
| import be.ugent.sel.studeez.common.composable.TimerEntry | import be.ugent.sel.studeez.common.composable.TimerEntry | ||||||
|  | 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.TimerInfo | import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
|  | @ -17,6 +21,7 @@ import kotlinx.coroutines.flow.flowOf | ||||||
| data class TimerSelectionActions( | data class TimerSelectionActions( | ||||||
|     val getAllTimers: () -> Flow<List<TimerInfo>>, |     val getAllTimers: () -> Flow<List<TimerInfo>>, | ||||||
|     val startSession: (TimerInfo) -> Unit, |     val startSession: (TimerInfo) -> Unit, | ||||||
|  |     val customTimeStudyTime: Int | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| fun getTimerSelectionActions( | fun getTimerSelectionActions( | ||||||
|  | @ -26,6 +31,7 @@ fun getTimerSelectionActions( | ||||||
|     return TimerSelectionActions( |     return TimerSelectionActions( | ||||||
|         getAllTimers = viewModel::getAllTimers, |         getAllTimers = viewModel::getAllTimers, | ||||||
|         startSession = { viewModel.startSession(open, it) }, |         startSession = { viewModel.startSession(open, it) }, | ||||||
|  |         customTimeStudyTime = viewModel.customTimerStudyTime.value | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -52,6 +58,11 @@ fun TimerSelectionScreen( | ||||||
|         popUp = popUp |         popUp = popUp | ||||||
|     ) { |     ) { | ||||||
|         LazyColumn { |         LazyColumn { | ||||||
|  |             // Custom timer with duration selection button | ||||||
|  |             item { | ||||||
|  |                 CustomTimerEntry(timerSelectionActions) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             // All timers |             // All timers | ||||||
|             items(timers.value) { timerInfo -> |             items(timers.value) { timerInfo -> | ||||||
|                 TimerEntry( |                 TimerEntry( | ||||||
|  | @ -68,11 +79,38 @@ fun TimerSelectionScreen( | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Composable | ||||||
|  | fun CustomTimerEntry( | ||||||
|  |     timerSelectionActions: TimerSelectionActions | ||||||
|  | ) { | ||||||
|  |     val timerInfo = CustomTimerInfo( | ||||||
|  |         name = resources().getString(R.string.custom_name), | ||||||
|  |         description = resources().getString(R.string.custom_description), | ||||||
|  |         studyTime = timerSelectionActions.customTimeStudyTime | ||||||
|  |     ) | ||||||
|  |     val hms: HoursMinutesSeconds = Time(timerInfo.studyTime).getAsHMS() | ||||||
|  | 
 | ||||||
|  |     TimerEntry( | ||||||
|  |         timerInfo = timerInfo, | ||||||
|  |         leftButton = { | ||||||
|  |             StealthButton( | ||||||
|  |                 text = R.string.start, | ||||||
|  |                 onClick = { timerSelectionActions.startSession(timerInfo) } | ||||||
|  |             ) | ||||||
|  |         }, | ||||||
|  |         rightButton = { | ||||||
|  |             TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime -> | ||||||
|  |                 timerInfo.studyTime = chosenTime | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun TimerSelectionPreview() { | fun TimerSelectionPreview() { | ||||||
|     TimerSelectionScreen( |     TimerSelectionScreen( | ||||||
|         timerSelectionActions = TimerSelectionActions({ flowOf() }, {}), |         timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, 0), | ||||||
|         popUp = {} |         popUp = {} | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | @ -1,5 +1,9 @@ | ||||||
| package be.ugent.sel.studeez.screens.timer_selection | package be.ugent.sel.studeez.screens.timer_selection | ||||||
| 
 | 
 | ||||||
|  | import androidx.compose.runtime.MutableState | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.remember | ||||||
| import be.ugent.sel.studeez.data.SelectedTimerState | import be.ugent.sel.studeez.data.SelectedTimerState | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||||
| import be.ugent.sel.studeez.domain.LogService | import be.ugent.sel.studeez.domain.LogService | ||||||
|  | @ -17,6 +21,8 @@ class TimerSelectionViewModel @Inject constructor( | ||||||
|     logService: LogService |     logService: LogService | ||||||
| ) : StudeezViewModel(logService) { | ) : StudeezViewModel(logService) { | ||||||
| 
 | 
 | ||||||
|  |     var customTimerStudyTime: MutableState<Int> = mutableStateOf(0) | ||||||
|  | 
 | ||||||
|     fun getAllTimers() : Flow<List<TimerInfo>> { |     fun getAllTimers() : Flow<List<TimerInfo>> { | ||||||
|         return timerDAO.getAllTimers() |         return timerDAO.getAllTimers() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,9 @@ import androidx.compose.ui.graphics.Color | ||||||
| private val DarkColorPalette = darkColors( | private val DarkColorPalette = darkColors( | ||||||
|     primary = Blue100, |     primary = Blue100, | ||||||
|     primaryVariant = Blue120, |     primaryVariant = Blue120, | ||||||
|     secondary = Yellow100 |     secondary = Yellow100, | ||||||
|  | 
 | ||||||
|  |     onPrimary = Color.White | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| private val LightColorPalette = lightColors( | private val LightColorPalette = lightColors( | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| <resources> | <resources> | ||||||
|     <!-- Common --> |     <!-- ========== Common ========== --> | ||||||
|  | 
 | ||||||
|     <string name="app_name">Studeez</string> |     <string name="app_name">Studeez</string> | ||||||
|     <string name="username">Username</string> |     <string name="username">Username</string> | ||||||
|     <string name="email">Email</string> |     <string name="email">Email</string> | ||||||
|  | @ -7,20 +8,75 @@ | ||||||
|     <string name="repeat_password">Repeat password</string> |     <string name="repeat_password">Repeat password</string> | ||||||
|     <string name="menu">Menu</string> |     <string name="menu">Menu</string> | ||||||
| 
 | 
 | ||||||
|         <!-- Actions --> |     <!-- Actions --> | ||||||
|         <string name="confirm">Confirm</string> |     <string name="confirm">Confirm</string> | ||||||
|         <string name="save">Save</string> |     <string name="save">Save</string> | ||||||
|         <string name="discard">Discard</string> |     <string name="discard">Discard</string> | ||||||
|         <string name="cancel">Cancel</string> |     <string name="cancel">Cancel</string> | ||||||
|         <string name="go_back">Go back</string> |     <string name="go_back">Go back</string> | ||||||
|         <string name="next">Next</string> |     <string name="next">Next</string> | ||||||
|         <string name="start">Start</string> |     <string name="start">Start</string> | ||||||
| 
 | 
 | ||||||
|         <!-- Messages --> |     <!-- Messages --> | ||||||
|         <string name="success">Success!</string> |     <string name="success">Success!</string> | ||||||
|         <string name="try_again">Try again</string> |     <string name="try_again">Try again</string> | ||||||
|         <string name="generic_error">Something wrong happened. Please try again.</string> |     <string name="generic_error">Something wrong happened. Please try again.</string> | ||||||
|         <string name="email_error">Please insert a valid email.</string> |     <string name="email_error">Please insert a valid email.</string> | ||||||
|  | 
 | ||||||
|  |     <!-- ========== NavBar ========== --> | ||||||
|  | 
 | ||||||
|  |     <!-- HomeScreen --> | ||||||
|  |     <string name="home">Home</string> | ||||||
|  |     <string name="start_session">Start session</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Tasks --> | ||||||
|  |     <string name="tasks">Tasks</string> | ||||||
|  |     <string name="task">Task</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Sessions --> | ||||||
|  |     <string name="sessions_temp_description">Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own.</string> <!-- TODO Remove this description line once implemented. --> | ||||||
|  |     <string name="sessions">Sessions</string> | ||||||
|  |     <string name="session">Session</string> | ||||||
|  |     <string name="end_session">End session</string> | ||||||
|  |     <string name="upcoming_sessions">Upcoming sessions</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Profile --> | ||||||
|  |     <string name="profile">Profile</string> | ||||||
|  |     <string name="no_username">Unknown username</string> | ||||||
|  |     <string name="edit_profile">Edit profile</string> | ||||||
|  |     <string name="editing_profile">Editing profile</string> | ||||||
|  |     <string name="delete_profile">Delete profile</string> | ||||||
|  | 
 | ||||||
|  |     <!-- ========== Drawer ========== --> | ||||||
|  | 
 | ||||||
|  |     <string name="log_out">Log out</string> | ||||||
|  |     <string name="profile_picture_description">Profile Picture</string> | ||||||
|  |     <string name="user_description">Normal user</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Timers --> | ||||||
|  |     <string name="timers">Timers</string> | ||||||
|  |     <string name="edit">Edit</string> | ||||||
|  |     <string name="add_timer">Add timer</string> | ||||||
|  |     <string name="pick_time">Select time</string> | ||||||
|  |     <string name="state_focus">Focus!</string> | ||||||
|  |     <plurals name="state_focus_remaining"> | ||||||
|  |         <item quantity="zero">Focus one more time!</item> | ||||||
|  |         <item quantity="one">Focus! (%d break remaining)</item> | ||||||
|  |         <item quantity="other">Focus! (%d breaks remaining)</item> | ||||||
|  |     </plurals> | ||||||
|  |     <string name="state_done">Done!</string> | ||||||
|  |     <string name="state_take_a_break">Take a break!</string> | ||||||
|  |     <string name="custom_name">Custom</string> | ||||||
|  |     <string name="custom_description">Select how long you want to study</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Settings --> | ||||||
|  |     <string name="settings_temp_description">Looks like you found the settings screen! In the future, this will enable you to edit your preferenes such as light/dark mode, end sessions automatically when we detect you are gone etc.</string> <!-- TODO Remove this description line once implemented. --> | ||||||
|  |     <string name="settings">Settings</string> | ||||||
|  | 
 | ||||||
|  |     <!-- About --> | ||||||
|  |     <string name="about">About Studeez</string> | ||||||
|  | 
 | ||||||
|  |     <!-- ========== Login flow ========== --> | ||||||
| 
 | 
 | ||||||
|     <!-- SignUpScreen --> |     <!-- SignUpScreen --> | ||||||
|     <string name="create_account">Create account</string> |     <string name="create_account">Create account</string> | ||||||
|  | @ -36,57 +92,42 @@ | ||||||
|     <string name="recovery_email_sent">Check your inbox for the recovery email.</string> |     <string name="recovery_email_sent">Check your inbox for the recovery email.</string> | ||||||
|     <string name="empty_password_error">Password cannot be empty.</string> |     <string name="empty_password_error">Password cannot be empty.</string> | ||||||
| 
 | 
 | ||||||
|     <!-- HomeScreen --> |     <!-- ========== Studying flow ========== --> | ||||||
|     <string name="home">Home</string> |  | ||||||
|     <string name="start_session">Start session</string> |  | ||||||
| 
 | 
 | ||||||
|     <!-- Tasks --> |     <!-- ========== Friends flow ========== --> | ||||||
|     <string name="tasks">Tasks</string> |  | ||||||
| 
 | 
 | ||||||
|     <!-- Sessions --> |  | ||||||
|     <string name="sessions">Sessions</string> |  | ||||||
|     <string name="end_session">End session</string> |  | ||||||
| 
 |  | ||||||
|     <!-- Profile --> |  | ||||||
|     <string name="profile">Profile</string> |  | ||||||
|     <string name="no_username">Unknown username</string> |  | ||||||
|     <string name="edit_profile">Edit profile</string> |  | ||||||
|     <string name="editing_profile">Editing profile</string> |  | ||||||
|     <string name="delete_profile">Delete profile</string> |  | ||||||
| 
 |  | ||||||
|     <!-- Friends --> |  | ||||||
|     <string name="friends">Friends</string> |     <string name="friends">Friends</string> | ||||||
|  |     <string name="friend">Friend</string> | ||||||
|  |     <string name="add_friend_not_possible_yet">Adding friends still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. --> | ||||||
| 
 | 
 | ||||||
|     <!-- Drawer / SideMenu --> |     <!-- ========== Create & edit screens ========== --> | ||||||
|     <string name="log_out">Log out</string> |  | ||||||
|     <string name="profile_picture_description">Profile Picture</string> |  | ||||||
|     <string name="user_description">Normal user</string> |  | ||||||
| 
 | 
 | ||||||
|     <!-- Timers --> |     <!-- Task --> | ||||||
|     <string name="timers">Timers</string> |     <string name="create_task_not_possible_yet">Creating tasks still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. --> | ||||||
|     <string name="edit">Edit</string> |  | ||||||
|     <string name="add_timer">Add timer</string> |  | ||||||
|     <string name="state_focus">Focus!</string> |  | ||||||
|     <plurals name="state_focus_remaining"> |  | ||||||
|         <item quantity="zero">Focus one more time!</item> |  | ||||||
|         <item quantity="one">Focus! (%d break remaining)</item> |  | ||||||
|         <item quantity="other">Focus! (%d breaks remaining)</item> |  | ||||||
|     </plurals> |  | ||||||
|     <string name="state_done">Done!</string> |  | ||||||
|     <string name="state_take_a_break">Take a break!</string> |  | ||||||
| 
 | 
 | ||||||
|     <!--    Edit Timer--> |     <!-- Session --> | ||||||
|  |     <string name="create_session_not_possible_yet">Creating sessions still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. --> | ||||||
|  | 
 | ||||||
|  |     <!-- Add Timer --> | ||||||
|  |     <string name="addTimer_description_error">Timer description cannot be empty!</string> | ||||||
|  |     <string name="addTimer_description">Timer description</string> | ||||||
|  |     <string name="addTimer_name_error">Timer name cannot be empty!</string> | ||||||
|  |     <string name="addTimer_name">Timer name</string> | ||||||
|  |     <string name="addTimer_timepicker">Open Time Picker</string> | ||||||
|  |     <string name="breakTime_1">" hours and "</string> | ||||||
|  |     <string name="breakTime_2">" minutes of breaktime"</string> | ||||||
|  |     <string name="addTimer_break_1">" break"</string> | ||||||
|  |     <string name="addTimer_break_s">" breaks"</string> | ||||||
|  |     <string name="addTimer_break_question">With breaks?</string> | ||||||
|  |     <string name="addTimer_studytime_1">" hours and "</string> | ||||||
|  |     <string name="addTimer_studytime_2">" minutes of studytime"</string> | ||||||
|  |     <string name="addTimer_question">How long do you want to study?</string> | ||||||
|  | 
 | ||||||
|  |     <!-- Edit Timer--> | ||||||
|     <string name="name">Name</string> |     <string name="name">Name</string> | ||||||
|     <string name="description">Description</string> |     <string name="description">Description</string> | ||||||
|     <string name="studyTime">Study Time</string> |     <string name="studyTime">Study Time</string> | ||||||
|     <string name="breakTime">Break Time</string> |     <string name="breakTime">Break Time</string> | ||||||
|     <string name="repeats">Number of Repeats</string> |     <string name="repeats">Number of Repeats</string> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     <!-- Settings --> |  | ||||||
|     <string name="settings">Settings</string> |  | ||||||
| 
 |  | ||||||
|     <!-- About --> |  | ||||||
|     <string name="about">About Studeez</string> |  | ||||||
| 
 |  | ||||||
| </resources> | </resources> | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ package be.ugent.sel.studeez.timer_functional | ||||||
| 
 | 
 | ||||||
| import android.media.MediaPlayer | import android.media.MediaPlayer | ||||||
| import be.ugent.sel.studeez.data.SelectedTimerState | import be.ugent.sel.studeez.data.SelectedTimerState | ||||||
|  | import be.ugent.sel.studeez.data.SessionReportState | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||||
|  | @ -24,7 +25,7 @@ class InvisibleSessionManagerTest { | ||||||
|     @Test |     @Test | ||||||
|     fun InvisibleEndlessTimerTest() = runTest { |     fun InvisibleEndlessTimerTest() = runTest { | ||||||
|         timerState.selectedTimer = FunctionalEndlessTimer() |         timerState.selectedTimer = FunctionalEndlessTimer() | ||||||
|         viewModel = SessionViewModel(timerState, mock()) |         viewModel = SessionViewModel(timerState, SessionReportState(), mock()) | ||||||
|         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) |         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) | ||||||
| 
 | 
 | ||||||
|         val test = launch { |         val test = launch { | ||||||
|  | @ -46,7 +47,7 @@ class InvisibleSessionManagerTest { | ||||||
|         val breakTime = 5 |         val breakTime = 5 | ||||||
|         val repeats = 1 |         val repeats = 1 | ||||||
|         timerState.selectedTimer = FunctionalPomodoroTimer(studyTime, breakTime, repeats) |         timerState.selectedTimer = FunctionalPomodoroTimer(studyTime, breakTime, repeats) | ||||||
|         viewModel = SessionViewModel(timerState, mock()) |         viewModel = SessionViewModel(timerState, SessionReportState(), mock()) | ||||||
|         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) |         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) | ||||||
| 
 | 
 | ||||||
|         val test = launch { |         val test = launch { | ||||||
|  | @ -79,7 +80,7 @@ class InvisibleSessionManagerTest { | ||||||
|     @Test |     @Test | ||||||
|     fun InvisibleCustomTimerTest() = runTest { |     fun InvisibleCustomTimerTest() = runTest { | ||||||
|         timerState.selectedTimer = FunctionalCustomTimer(5) |         timerState.selectedTimer = FunctionalCustomTimer(5) | ||||||
|         viewModel = SessionViewModel(timerState, mock()) |         viewModel = SessionViewModel(timerState, SessionReportState(), mock()) | ||||||
|         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) |         InvisibleSessionManager.setParameters(viewModel, mediaPlayer) | ||||||
| 
 | 
 | ||||||
|         val test = launch { |         val test = launch { | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 lbarraga
						lbarraga