merged with current dev
This commit is contained in:
		
						commit
						b30edf6538
					
				
					 22 changed files with 849 additions and 373 deletions
				
			
		
							
								
								
									
										2
									
								
								.idea/compiler.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/compiler.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,6 +1,6 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <project version="4"> | <project version="4"> | ||||||
|   <component name="CompilerConfiguration"> |   <component name="CompilerConfiguration"> | ||||||
|     <bytecodeTargetLevel target="11" /> |     <bytecodeTargetLevel target="17" /> | ||||||
|   </component> |   </component> | ||||||
| </project> | </project> | ||||||
							
								
								
									
										2
									
								
								.idea/kotlinc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/kotlinc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,6 +1,6 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <project version="4"> | <project version="4"> | ||||||
|   <component name="KotlinJpsPluginSettings"> |   <component name="KotlinJpsPluginSettings"> | ||||||
|     <option name="version" value="1.8.0-release" /> |     <option name="version" value="1.7.0" /> | ||||||
|   </component> |   </component> | ||||||
| </project> | </project> | ||||||
							
								
								
									
										3
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,7 +1,6 @@ | ||||||
| <?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_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK"> |   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" 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,7 +2,13 @@ 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.* | import androidx.compose.material.MaterialTheme | ||||||
|  | import androidx.compose.material.Scaffold | ||||||
|  | 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.Composable | ||||||
| import androidx.compose.runtime.ReadOnlyComposable | import androidx.compose.runtime.ReadOnlyComposable | ||||||
| import androidx.compose.runtime.remember | import androidx.compose.runtime.remember | ||||||
|  | @ -11,22 +17,24 @@ 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 | ||||||
| import androidx.compose.ui.unit.dp | import androidx.compose.ui.unit.dp | ||||||
| import androidx.navigation.NavGraphBuilder | import androidx.hilt.navigation.compose.hiltViewModel | ||||||
| import androidx.navigation.NavHostController | import androidx.navigation.NavHostController | ||||||
| import androidx.navigation.compose.NavHost | import androidx.navigation.compose.NavHost | ||||||
| import androidx.navigation.compose.composable | import androidx.navigation.compose.composable | ||||||
| import androidx.navigation.compose.rememberNavController | import androidx.navigation.compose.rememberNavController | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | ||||||
| import be.ugent.sel.studeez.common.snackbar.SnackbarManager | import be.ugent.sel.studeez.common.snackbar.SnackbarManager | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||||
| import be.ugent.sel.studeez.screens.home.HomeScreen | import be.ugent.sel.studeez.screens.home.HomeRoute | ||||||
| import be.ugent.sel.studeez.screens.log_in.LoginScreen | import be.ugent.sel.studeez.screens.log_in.LoginRoute | ||||||
| import be.ugent.sel.studeez.screens.session.SessionScreen | import be.ugent.sel.studeez.screens.profile.EditProfileRoute | ||||||
| import be.ugent.sel.studeez.screens.profile.EditProfileScreen | import be.ugent.sel.studeez.screens.profile.ProfileRoute | ||||||
| import be.ugent.sel.studeez.screens.profile.ProfileScreen | import be.ugent.sel.studeez.screens.session.SessionRoute | ||||||
| import be.ugent.sel.studeez.screens.sign_up.SignUpScreen | import be.ugent.sel.studeez.screens.sign_up.SignUpRoute | ||||||
| import be.ugent.sel.studeez.screens.splash.SplashScreen | import be.ugent.sel.studeez.screens.splash.SplashRoute | ||||||
| import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewScreen | import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute | ||||||
| import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionScreen | 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 | ||||||
| 
 | 
 | ||||||
|  | @ -48,13 +56,7 @@ fun StudeezApp() { | ||||||
|                 }, |                 }, | ||||||
|                 scaffoldState = appState.scaffoldState |                 scaffoldState = appState.scaffoldState | ||||||
|             ) { innerPaddingModifier -> |             ) { innerPaddingModifier -> | ||||||
|                 NavHost( |                 StudeezNavGraph(appState, Modifier.padding(innerPaddingModifier)) | ||||||
|                     navController = appState.navController, |  | ||||||
|                     startDestination = StudeezDestinations.SPLASH_SCREEN, |  | ||||||
|                     modifier = Modifier.padding(innerPaddingModifier) |  | ||||||
|                 ) { |  | ||||||
|                     studeezGraph(appState) |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -79,49 +81,73 @@ fun resources(): Resources { | ||||||
|     return LocalContext.current.resources |     return LocalContext.current.resources | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { | @Composable | ||||||
|  | fun StudeezNavGraph( | ||||||
|  |     appState: StudeezAppstate, | ||||||
|  |     modifier: Modifier, | ||||||
|  | ) { | ||||||
|  |     val drawerViewModel: DrawerViewModel = hiltViewModel() | ||||||
|  |     val navBarViewModel: NavigationBarViewModel = hiltViewModel() | ||||||
| 
 | 
 | ||||||
|  |     NavHost( | ||||||
|  |         navController = appState.navController, | ||||||
|  |         startDestination = StudeezDestinations.SPLASH_SCREEN, | ||||||
|  |         modifier = modifier, | ||||||
|  |     ) { | ||||||
|         val goBack: () -> Unit = { |         val goBack: () -> Unit = { | ||||||
|             appState.popUp() |             appState.popUp() | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     val open: (String) -> Unit = { |         val open: (String) -> Unit = { route -> | ||||||
|             route -> appState.navigate(route) |             appState.navigate(route) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     val openAndPopUp: (String, String) -> Unit = { |         val openAndPopUp: (String, String) -> Unit = { route, popUp -> | ||||||
|             route, popUp -> appState.navigateAndPopUp(route, popUp) |             appState.navigateAndPopUp(route, popUp) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         composable(StudeezDestinations.SPLASH_SCREEN) { |         composable(StudeezDestinations.SPLASH_SCREEN) { | ||||||
|         SplashScreen(openAndPopUp) |             SplashRoute(openAndPopUp, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.LOGIN_SCREEN) { |         composable(StudeezDestinations.LOGIN_SCREEN) { | ||||||
|         LoginScreen(openAndPopUp) |             LoginRoute(openAndPopUp, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.SIGN_UP_SCREEN) { |         composable(StudeezDestinations.SIGN_UP_SCREEN) { | ||||||
|         SignUpScreen(openAndPopUp) |             SignUpRoute(openAndPopUp, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.HOME_SCREEN) { |         composable(StudeezDestinations.HOME_SCREEN) { | ||||||
|         HomeScreen(open, openAndPopUp) |             HomeRoute( | ||||||
|  |                 open, | ||||||
|  |                 openAndPopUp, | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerViewModel = drawerViewModel, | ||||||
|  |                 navBarViewModel = navBarViewModel, | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // TODO Tasks screen |         // TODO Tasks screen | ||||||
|         // TODO Sessions screen |         // TODO Sessions screen | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.PROFILE_SCREEN) { |         composable(StudeezDestinations.PROFILE_SCREEN) { | ||||||
|         ProfileScreen(open, openAndPopUp) |             ProfileRoute(open, openAndPopUp, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) { |         composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) { | ||||||
|         TimerOverviewScreen(open, openAndPopUp) |             TimerOverviewRoute( | ||||||
|  |                 open, | ||||||
|  |                 openAndPopUp, | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerViewModel = drawerViewModel, | ||||||
|  |                 navBarViewModel = navBarViewModel, | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.SESSION_SCREEN) { |         composable(StudeezDestinations.SESSION_SCREEN) { | ||||||
|         SessionScreen(open, openAndPopUp) |             SessionRoute(open, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // TODO Timers screen |         // TODO Timers screen | ||||||
|  | @ -129,10 +155,17 @@ fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { | ||||||
| 
 | 
 | ||||||
|         // Edit screens |         // Edit screens | ||||||
|         composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { |         composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { | ||||||
|         EditProfileScreen(goBack, openAndPopUp) |             EditProfileRoute(goBack, openAndPopUp, viewModel = hiltViewModel()) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { |         composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { | ||||||
|         TimerSelectionScreen(open, openAndPopUp) |             TimerSelectionRoute( | ||||||
|  |                 open, | ||||||
|  |                 openAndPopUp, | ||||||
|  |                 viewModel = hiltViewModel(), | ||||||
|  |                 drawerViewModel = drawerViewModel, | ||||||
|  |                 navBarViewModel = navBarViewModel, | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1,8 +1,5 @@ | ||||||
| package be.ugent.sel.studeez.activities | package be.ugent.sel.studeez.activities | ||||||
| 
 | 
 | ||||||
| import android.media.MediaPlayer |  | ||||||
| import android.media.RingtoneManager |  | ||||||
| import android.net.Uri |  | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import androidx.activity.ComponentActivity | import androidx.activity.ComponentActivity | ||||||
| import androidx.activity.compose.setContent | import androidx.activity.compose.setContent | ||||||
|  | @ -25,13 +22,7 @@ var onTimerInvisible: Job? = null | ||||||
| 
 | 
 | ||||||
| @AndroidEntryPoint | @AndroidEntryPoint | ||||||
| class MainActivity : ComponentActivity() { | class MainActivity : ComponentActivity() { | ||||||
| 
 |  | ||||||
|     private var mediaPlayer: MediaPlayer? = null |  | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|         val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) |  | ||||||
|         mediaPlayer = MediaPlayer.create(this, uri) |  | ||||||
|         mediaPlayer?.isLooping = false |  | ||||||
| 
 |  | ||||||
|         super.onCreate(savedInstanceState) |         super.onCreate(savedInstanceState) | ||||||
|         setContent { |         setContent { | ||||||
|             StudeezTheme { |             StudeezTheme { | ||||||
|  | @ -54,16 +45,9 @@ class MainActivity : ComponentActivity() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun onStart() { |     override fun onStart() { | ||||||
|         mediaPlayer?.stop() |  | ||||||
|         onTimerInvisible?.cancel() |         onTimerInvisible?.cancel() | ||||||
|         super.onStart() |         super.onStart() | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     override fun onDestroy() { |  | ||||||
|         mediaPlayer?.stop() |  | ||||||
|         mediaPlayer?.release() |  | ||||||
|         super.onDestroy() |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
|  |  | ||||||
|  | @ -2,17 +2,26 @@ package be.ugent.sel.studeez.common.composable | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.layout.PaddingValues | import androidx.compose.foundation.layout.PaddingValues | ||||||
| import androidx.compose.foundation.layout.RowScope | import androidx.compose.foundation.layout.RowScope | ||||||
| import androidx.compose.material.* | import androidx.compose.material.FabPosition | ||||||
|  | import androidx.compose.material.Icon | ||||||
|  | import androidx.compose.material.IconButton | ||||||
|  | import androidx.compose.material.Scaffold | ||||||
|  | import androidx.compose.material.ScaffoldState | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.material.TopAppBar | ||||||
| import androidx.compose.material.icons.Icons | import androidx.compose.material.icons.Icons | ||||||
| import androidx.compose.material.icons.filled.Edit | import androidx.compose.material.icons.filled.Edit | ||||||
| import androidx.compose.material.icons.filled.Menu | import androidx.compose.material.icons.filled.Menu | ||||||
|  | import androidx.compose.material.rememberScaffoldState | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.rememberCoroutineScope | import androidx.compose.runtime.rememberCoroutineScope | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.screens.drawer.Drawer | import be.ugent.sel.studeez.common.composable.drawer.Drawer | ||||||
| import be.ugent.sel.studeez.screens.navbar.NavigationBar | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBar | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
| import be.ugent.sel.studeez.ui.theme.StudeezTheme | import be.ugent.sel.studeez.ui.theme.StudeezTheme | ||||||
| import kotlinx.coroutines.CoroutineScope | import kotlinx.coroutines.CoroutineScope | ||||||
| import kotlinx.coroutines.launch | import kotlinx.coroutines.launch | ||||||
|  | @ -20,8 +29,8 @@ import kotlinx.coroutines.launch | ||||||
| @Composable | @Composable | ||||||
| fun PrimaryScreenTemplate( | fun PrimaryScreenTemplate( | ||||||
|     title: String, |     title: String, | ||||||
|     open: (String) -> Unit, |     drawerActions: DrawerActions, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     navigationBarActions: NavigationBarActions, | ||||||
|     action: @Composable RowScope.() -> Unit = {}, |     action: @Composable RowScope.() -> Unit = {}, | ||||||
|     content: @Composable (PaddingValues) -> Unit |     content: @Composable (PaddingValues) -> Unit | ||||||
| ) { | ) { | ||||||
|  | @ -31,7 +40,8 @@ fun PrimaryScreenTemplate( | ||||||
|     Scaffold( |     Scaffold( | ||||||
|         scaffoldState = scaffoldState, |         scaffoldState = scaffoldState, | ||||||
| 
 | 
 | ||||||
|         topBar = { TopAppBar( |         topBar = { | ||||||
|  |             TopAppBar( | ||||||
|                 title = { Text(text = title) }, |                 title = { Text(text = title) }, | ||||||
|                 navigationIcon = { |                 navigationIcon = { | ||||||
|                     IconButton(onClick = { |                     IconButton(onClick = { | ||||||
|  | @ -44,13 +54,14 @@ fun PrimaryScreenTemplate( | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 actions = action |                 actions = action | ||||||
|         ) }, |             ) | ||||||
| 
 |  | ||||||
|         drawerContent = { |  | ||||||
|             Drawer(open, openAndPopUp) |  | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|         bottomBar = { NavigationBar(open) }, |         drawerContent = { | ||||||
|  |             Drawer(drawerActions) | ||||||
|  |         }, | ||||||
|  | 
 | ||||||
|  |         bottomBar = { NavigationBar(navigationBarActions) }, | ||||||
|         floatingActionButtonPosition = FabPosition.Center, |         floatingActionButtonPosition = FabPosition.Center, | ||||||
|         isFloatingActionButtonDocked = true, |         isFloatingActionButtonDocked = true, | ||||||
|         floatingActionButton = { CollapsedAddButton() } |         floatingActionButton = { CollapsedAddButton() } | ||||||
|  | @ -65,14 +76,16 @@ fun PrimaryScreenPreview() { | ||||||
|     StudeezTheme { |     StudeezTheme { | ||||||
|         PrimaryScreenTemplate( |         PrimaryScreenTemplate( | ||||||
|             "Preview screen", |             "Preview screen", | ||||||
|             { _ -> {}}, |             DrawerActions({}, {}, {}, {}, {}), | ||||||
|             { _, _ -> {}}, |             NavigationBarActions({}, {}, {}, {}), | ||||||
|             { IconButton(onClick = { /*TODO*/ }) { |             { | ||||||
|  |                 IconButton(onClick = { /*TODO*/ }) { | ||||||
|                     Icon( |                     Icon( | ||||||
|                         imageVector = Icons.Default.Edit, |                         imageVector = Icons.Default.Edit, | ||||||
|                         contentDescription = "Edit" |                         contentDescription = "Edit" | ||||||
|                     ) |                     ) | ||||||
|             }} |                 } | ||||||
|  |             }, | ||||||
|         ) {} |         ) {} | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -0,0 +1,62 @@ | ||||||
|  | package be.ugent.sel.studeez.common.composable | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.layout.Arrangement | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.fillMaxWidth | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.text.font.FontWeight | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import androidx.compose.ui.unit.sp | ||||||
|  | import be.ugent.sel.studeez.R | ||||||
|  | import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo | ||||||
|  | import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun TimerEntry( | ||||||
|  |     timerInfo: TimerInfo, | ||||||
|  |     button: @Composable () -> Unit, | ||||||
|  | ) { | ||||||
|  |     Row( | ||||||
|  |         verticalAlignment = Alignment.CenterVertically, | ||||||
|  |         modifier = Modifier.fillMaxWidth(), | ||||||
|  |         horizontalArrangement = Arrangement.SpaceBetween | ||||||
|  |     ) { | ||||||
|  |         Column( | ||||||
|  |             Modifier.padding(horizontal = 10.dp) | ||||||
|  |         ) { | ||||||
|  |             Text( | ||||||
|  |                 text = timerInfo.name, fontWeight = FontWeight.Bold, fontSize = 20.sp | ||||||
|  |             ) | ||||||
|  |             Text( | ||||||
|  |                 text = timerInfo.description, fontWeight = FontWeight.Light, fontSize = 15.sp | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |         button() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun TimerEntryPreview() { | ||||||
|  |     val timerInfo = CustomTimerInfo( | ||||||
|  |         "my preview timer", "This is the description of the timer", 60 | ||||||
|  |     ) | ||||||
|  |     TimerEntry(timerInfo = timerInfo) { | ||||||
|  |         StealthButton(text = R.string.edit) {} | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun TimerDefaultEntryPreview() { | ||||||
|  |     val timerInfo = CustomTimerInfo( | ||||||
|  |         "Default preview timer", "This is the description of the timer", 60 | ||||||
|  |     ) | ||||||
|  |     TimerEntry(timerInfo = timerInfo) {} | ||||||
|  | } | ||||||
|  | @ -1,7 +1,12 @@ | ||||||
| package be.ugent.sel.studeez.screens.drawer | package be.ugent.sel.studeez.common.composable.drawer | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.clickable | import androidx.compose.foundation.clickable | ||||||
| import androidx.compose.foundation.layout.* | import androidx.compose.foundation.layout.Arrangement | ||||||
|  | import androidx.compose.foundation.layout.Box | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.fillMaxWidth | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
| import androidx.compose.material.Icon | import androidx.compose.material.Icon | ||||||
| import androidx.compose.material.Text | import androidx.compose.material.Text | ||||||
| import androidx.compose.material.icons.Icons | import androidx.compose.material.icons.Icons | ||||||
|  | @ -14,57 +19,71 @@ import androidx.compose.ui.graphics.vector.ImageVector | ||||||
| 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 | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| import androidx.lifecycle.viewmodel.compose.viewModel |  | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| 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 | ||||||
| 
 | 
 | ||||||
|  | data class DrawerActions( | ||||||
|  |     val onHomeButtonClick: () -> Unit, | ||||||
|  |     val onTimersClick: () -> Unit, | ||||||
|  |     val onSettingsClick: () -> Unit, | ||||||
|  |     val onLogoutClick: () -> Unit, | ||||||
|  |     val onAboutClick: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getDrawerActions( | ||||||
|  |     drawerViewModel: DrawerViewModel, | ||||||
|  |     open: (String) -> Unit, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  | ): DrawerActions { | ||||||
|  |     return DrawerActions( | ||||||
|  |         onHomeButtonClick = { drawerViewModel.onHomeButtonClick(open) }, | ||||||
|  |         onTimersClick = { drawerViewModel.onTimersClick(open) }, | ||||||
|  |         onSettingsClick = { drawerViewModel.onSettingsClick(open) }, | ||||||
|  |         onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, | ||||||
|  |         onAboutClick = { drawerViewModel.onAboutClick(open) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun Drawer( | fun Drawer( | ||||||
|     open: (String) -> Unit, |     drawerActions: DrawerActions, | ||||||
|     openAndPopUp: (String, String) -> Unit, |  | ||||||
|     viewModel: DrawerViewModel = hiltViewModel() |  | ||||||
| ) { | ) { | ||||||
|     Column( |     Column( | ||||||
|         modifier = Modifier.fillMaxWidth() |         modifier = Modifier.fillMaxWidth() | ||||||
|     ) { |     ) { | ||||||
|         Column( |         Column( | ||||||
|             modifier = Modifier.fillMaxWidth().weight(1f) |             modifier = Modifier | ||||||
|  |                 .fillMaxWidth() | ||||||
|  |                 .weight(1f) | ||||||
|         ) { |         ) { | ||||||
|             DrawerEntry( |             DrawerEntry( | ||||||
|                 icon = Icons.Default.Home, |                 icon = Icons.Default.Home, | ||||||
|                 text = resources().getString(R.string.home) |                 text = resources().getString(R.string.home), | ||||||
|             ) { |                 onClick = drawerActions.onHomeButtonClick, | ||||||
|                 viewModel.onHomeButtonClick(open) |             ) | ||||||
|             } |  | ||||||
|             DrawerEntry( |             DrawerEntry( | ||||||
|                 icon = ImageVector.vectorResource(id = R.drawable.ic_timer), |                 icon = ImageVector.vectorResource(id = R.drawable.ic_timer), | ||||||
|                 text = resources().getString(R.string.timers) |                 text = resources().getString(R.string.timers), | ||||||
|             ) { |                 onClick = drawerActions.onTimersClick, | ||||||
|                 viewModel.onTimersClick(open) |             ) | ||||||
|             } |  | ||||||
|             DrawerEntry( |             DrawerEntry( | ||||||
|                 icon = Icons.Default.Settings, |                 icon = Icons.Default.Settings, | ||||||
|                 text = resources().getString(R.string.settings) |                 text = resources().getString(R.string.settings), | ||||||
|             ) { |                 onClick = drawerActions.onSettingsClick, | ||||||
|                 viewModel.onSettingsClick(open) |             ) | ||||||
|             } |  | ||||||
|             DrawerEntry( |             DrawerEntry( | ||||||
|                 icon = ImageVector.vectorResource(id = R.drawable.ic_logout), |                 icon = ImageVector.vectorResource(id = R.drawable.ic_logout), | ||||||
|                 text = resources().getString(R.string.log_out) |                 text = resources().getString(R.string.log_out), | ||||||
|             ) { |                 onClick = drawerActions.onLogoutClick, | ||||||
|                 viewModel.onLogoutClick(openAndPopUp) |             ) | ||||||
|             } |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         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, | ||||||
|             viewModel.onAboutClick(open) |         ) | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -100,11 +119,8 @@ fun DrawerEntry( | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun DrawerPreview() { | fun DrawerPreview() { | ||||||
|  |     val drawerActions = DrawerActions({}, {}, {}, {}, {}) | ||||||
|     StudeezTheme { |     StudeezTheme { | ||||||
|         Drawer( |         Drawer(drawerActions) | ||||||
|             { _, -> {} }, |  | ||||||
|             { _, _ -> {} }, |  | ||||||
|             hiltViewModel() |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package be.ugent.sel.studeez.screens.drawer | package be.ugent.sel.studeez.common.composable.drawer | ||||||
| 
 | 
 | ||||||
| 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 | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package be.ugent.sel.studeez.screens.navbar | package be.ugent.sel.studeez.common.composable.navbar | ||||||
| 
 | 
 | ||||||
| import androidx.compose.material.BottomNavigation | import androidx.compose.material.BottomNavigation | ||||||
| import androidx.compose.material.BottomNavigationItem | import androidx.compose.material.BottomNavigationItem | ||||||
|  | @ -12,16 +12,32 @@ import androidx.compose.material.icons.outlined.DateRange | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| 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 | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| 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( | ||||||
|  |     val onHomeClick: () -> Unit, | ||||||
|  |     val onTasksClick: () -> Unit, | ||||||
|  |     val onSessionsClick: () -> Unit, | ||||||
|  |     val onProfileClick: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getNavigationBarActions( | ||||||
|  |     navigationBarViewModel: NavigationBarViewModel, | ||||||
|  |     open: (String) -> Unit, | ||||||
|  | ): NavigationBarActions { | ||||||
|  |     return NavigationBarActions( | ||||||
|  |         onHomeClick = { navigationBarViewModel.onHomeClick(open) }, | ||||||
|  |         onTasksClick = { navigationBarViewModel.onTasksClick(open) }, | ||||||
|  |         onSessionsClick = { navigationBarViewModel.onSessionsClick(open) }, | ||||||
|  |         onProfileClick = { navigationBarViewModel.onProfileClick(open) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun NavigationBar( | fun NavigationBar( | ||||||
|     open: (String) -> Unit, |     navigationBarActions: NavigationBarActions, | ||||||
|     viewModel: NavigationBarViewModel = hiltViewModel() |  | ||||||
| ) { | ) { | ||||||
|     // TODO Pass functions and new screens. |     // TODO Pass functions and new screens. | ||||||
|     // TODO Pass which screen is selected. |     // TODO Pass which screen is selected. | ||||||
|  | @ -33,31 +49,43 @@ fun NavigationBar( | ||||||
|             icon = { Icon(imageVector = Icons.Default.List, resources().getString(AppText.home)) }, |             icon = { Icon(imageVector = Icons.Default.List, resources().getString(AppText.home)) }, | ||||||
|             label = { Text(text = resources().getString(AppText.home)) }, |             label = { Text(text = resources().getString(AppText.home)) }, | ||||||
|             selected = false, // TODO |             selected = false, // TODO | ||||||
|             onClick = { viewModel.onHomeClick(open) } |             onClick = navigationBarActions.onHomeClick | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         BottomNavigationItem( |         BottomNavigationItem( | ||||||
|             icon = { Icon(imageVector = Icons.Default.Check, resources().getString(AppText.tasks)) }, |             icon = { | ||||||
|  |                 Icon( | ||||||
|  |                     imageVector = Icons.Default.Check, resources().getString(AppText.tasks) | ||||||
|  |                 ) | ||||||
|  |             }, | ||||||
|             label = { Text(text = resources().getString(AppText.tasks)) }, |             label = { Text(text = resources().getString(AppText.tasks)) }, | ||||||
|             selected = false, // TODO |             selected = false, // TODO | ||||||
|             onClick = { viewModel.onTasksClick(open) } |             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) | ||||||
| 
 | 
 | ||||||
|         BottomNavigationItem( |         BottomNavigationItem( | ||||||
|             icon = { Icon(imageVector = Icons.Outlined.DateRange, resources().getString(AppText.sessions)) }, |             icon = { | ||||||
|  |                 Icon( | ||||||
|  |                     imageVector = Icons.Outlined.DateRange, resources().getString(AppText.sessions) | ||||||
|  |                 ) | ||||||
|  |             }, | ||||||
|             label = { Text(text = resources().getString(AppText.sessions)) }, |             label = { Text(text = resources().getString(AppText.sessions)) }, | ||||||
|             selected = false, // TODO |             selected = false, // TODO | ||||||
|             onClick = { viewModel.onSessionsClick(open) } |             onClick = navigationBarActions.onSessionsClick | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         BottomNavigationItem( |         BottomNavigationItem( | ||||||
|             icon = { Icon(imageVector = Icons.Default.Person, resources().getString(AppText.profile)) }, |             icon = { | ||||||
|  |                 Icon( | ||||||
|  |                     imageVector = Icons.Default.Person, resources().getString(AppText.profile) | ||||||
|  |                 ) | ||||||
|  |             }, | ||||||
|             label = { Text(text = resources().getString(AppText.profile)) }, |             label = { Text(text = resources().getString(AppText.profile)) }, | ||||||
|             selected = false, // TODO |             selected = false, // TODO | ||||||
|             onClick = { viewModel.onProfileClick(open) } |             onClick = navigationBarActions.onProfileClick | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  | @ -67,9 +95,6 @@ fun NavigationBar( | ||||||
| @Composable | @Composable | ||||||
| fun NavigationBarPreview() { | fun NavigationBarPreview() { | ||||||
|     StudeezTheme { |     StudeezTheme { | ||||||
|         NavigationBar( |         NavigationBar(NavigationBarActions({}, {}, {}, {})) | ||||||
|             { _ -> {} }, |  | ||||||
|             hiltViewModel() |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package be.ugent.sel.studeez.screens.navbar | package be.ugent.sel.studeez.common.composable.navbar | ||||||
| 
 | 
 | ||||||
| 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 | ||||||
|  | @ -6,27 +6,49 @@ import androidx.compose.material.icons.Icons | ||||||
| import androidx.compose.material.icons.filled.Person | import androidx.compose.material.icons.filled.Person | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel | 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.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
| import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun HomeScreen( | fun HomeRoute( | ||||||
|     open: (String) -> Unit, |     open: (String) -> Unit, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     openAndPopUp: (String, String) -> Unit, | ||||||
|     viewModel: HomeViewModel = hiltViewModel() |     viewModel: HomeViewModel, | ||||||
|  |     drawerViewModel: DrawerViewModel, | ||||||
|  |     navBarViewModel: NavigationBarViewModel, | ||||||
| ) { | ) { | ||||||
|  |     HomeScreen( | ||||||
|  |         onStartSessionClick = { viewModel.onStartSessionClick(open) }, | ||||||
|  |         drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), | ||||||
|  |         navigationBarActions = getNavigationBarActions(navBarViewModel, open), | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun HomeScreen( | ||||||
|  |     onStartSessionClick: () -> Unit, | ||||||
|  |     drawerActions: DrawerActions, | ||||||
|  |     navigationBarActions: NavigationBarActions, | ||||||
|  | ) { | ||||||
|  | 
 | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.home), |         title = resources().getString(R.string.home), | ||||||
|         open = open, |         drawerActions = drawerActions, | ||||||
|         openAndPopUp = openAndPopUp, |         navigationBarActions = navigationBarActions, | ||||||
|         action = { FriendsAction() } |         action = { FriendsAction() } | ||||||
|     ) { |     ) { | ||||||
|         BasicButton(R.string.start_session, Modifier.basicButton()) { |         BasicButton(R.string.start_session, Modifier.basicButton()) { | ||||||
|             viewModel.onStartSessionClick(open) |             onStartSessionClick() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -40,3 +62,13 @@ fun FriendsAction () { | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun HomeScreenPreview() { | ||||||
|  |     HomeScreen( | ||||||
|  |         onStartSessionClick = {}, | ||||||
|  |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|  |         navigationBarActions = NavigationBarActions({}, {}, {}, {}) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.common.composable.* | import be.ugent.sel.studeez.common.composable.* | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.common.ext.fieldModifier | import be.ugent.sel.studeez.common.ext.fieldModifier | ||||||
|  | @ -18,14 +18,48 @@ import be.ugent.sel.studeez.common.ext.textButton | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
|  | data class LoginScreenActions( | ||||||
|  |     val onEmailChange: (String) -> Unit, | ||||||
|  |     val onPasswordChange: (String) -> Unit, | ||||||
|  |     val onSignUpClick: () -> Unit, | ||||||
|  |     val onSignInClick: () -> Unit, | ||||||
|  |     val onForgotPasswordClick: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getLoginScreenActions( | ||||||
|  |     viewModel: LoginViewModel, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  | ): LoginScreenActions { | ||||||
|  |     return LoginScreenActions( | ||||||
|  |         onEmailChange = { viewModel.onEmailChange(it) }, | ||||||
|  |         onPasswordChange = { viewModel.onPasswordChange(it) }, | ||||||
|  |         onSignUpClick = { viewModel.onSignUpClick(openAndPopUp) }, | ||||||
|  |         onSignInClick = { viewModel.onSignInClick(openAndPopUp) }, | ||||||
|  |         onForgotPasswordClick = { viewModel.onForgotPasswordClick() } | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun LoginScreen( | fun LoginRoute( | ||||||
|     openAndPopUp: (String, String) -> Unit, |     openAndPopUp: (String, String) -> Unit, | ||||||
|     modifier: Modifier = Modifier, |     modifier: Modifier = Modifier, | ||||||
|     viewModel: LoginViewModel = hiltViewModel() |     viewModel: LoginViewModel, | ||||||
| ) { | ) { | ||||||
|     val uiState by viewModel.uiState |     val uiState by viewModel.uiState | ||||||
| 
 | 
 | ||||||
|  |     LoginScreen( | ||||||
|  |         modifier = modifier, | ||||||
|  |         uiState = uiState, | ||||||
|  |         loginScreenActions = getLoginScreenActions(viewModel = viewModel, openAndPopUp) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun LoginScreen( | ||||||
|  |     modifier: Modifier = Modifier, | ||||||
|  |     uiState: LoginUiState, | ||||||
|  |     loginScreenActions: LoginScreenActions, | ||||||
|  | ) { | ||||||
|     SimpleScreenTemplate(title = resources().getString(AppText.sign_in)) { |     SimpleScreenTemplate(title = resources().getString(AppText.sign_in)) { | ||||||
|         Column( |         Column( | ||||||
|             modifier = modifier |             modifier = modifier | ||||||
|  | @ -35,18 +69,42 @@ fun LoginScreen( | ||||||
|             verticalArrangement = Arrangement.Center, |             verticalArrangement = Arrangement.Center, | ||||||
|             horizontalAlignment = Alignment.CenterHorizontally |             horizontalAlignment = Alignment.CenterHorizontally | ||||||
|         ) { |         ) { | ||||||
|             EmailField(uiState.email, viewModel::onEmailChange, Modifier.fieldModifier()) |             EmailField( | ||||||
|             PasswordField(uiState.password, viewModel::onPasswordChange, Modifier.fieldModifier()) |                 uiState.email, | ||||||
|  |                 loginScreenActions.onEmailChange, | ||||||
|  |                 Modifier.fieldModifier() | ||||||
|  |             ) | ||||||
|  |             PasswordField( | ||||||
|  |                 uiState.password, | ||||||
|  |                 loginScreenActions.onPasswordChange, | ||||||
|  |                 Modifier.fieldModifier() | ||||||
|  |             ) | ||||||
|  |             BasicButton( | ||||||
|  |                 AppText.sign_in, | ||||||
|  |                 Modifier.basicButton(), | ||||||
|  |                 onClick = loginScreenActions.onSignInClick, | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|             BasicButton(AppText.sign_in, Modifier.basicButton()) { viewModel.onSignInClick(openAndPopUp) } |             BasicTextButton( | ||||||
|  |                 AppText.not_already_user, | ||||||
|  |                 Modifier.textButton(), | ||||||
|  |                 action = loginScreenActions.onSignUpClick, | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|             BasicTextButton(AppText.not_already_user, Modifier.textButton()) { |             BasicTextButton( | ||||||
|                 viewModel.onNotAlreadyUser(openAndPopUp) |                 AppText.forgot_password, | ||||||
|  |                 Modifier.textButton(), | ||||||
|  |                 action = loginScreenActions.onForgotPasswordClick, | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|             BasicTextButton(AppText.forgot_password, Modifier.textButton()) { | @Preview | ||||||
|                 viewModel.onForgotPasswordClick() | @Composable | ||||||
|             } | fun LoginScreenPreview() { | ||||||
|         } |     LoginScreen( | ||||||
|     } |         uiState = LoginUiState(), | ||||||
|  |         loginScreenActions = LoginScreenActions({}, {}, {}, {}, {}) | ||||||
|  |     ) | ||||||
| } | } | ||||||
|  | @ -63,7 +63,7 @@ class LoginViewModel @Inject constructor( | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onNotAlreadyUser(openAndPopUp: (String, String) -> Unit) { |     fun onSignUpClick(openAndPopUp: (String, String) -> Unit) { | ||||||
|         openAndPopUp(SIGN_UP_SCREEN, LOGIN_SCREEN) |         openAndPopUp(SIGN_UP_SCREEN, LOGIN_SCREEN) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -5,7 +5,6 @@ import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.BasicTextButton | import be.ugent.sel.studeez.common.composable.BasicTextButton | ||||||
| import be.ugent.sel.studeez.common.composable.LabelledInputField | import be.ugent.sel.studeez.common.composable.LabelledInputField | ||||||
|  | @ -14,14 +13,43 @@ import be.ugent.sel.studeez.common.ext.textButton | ||||||
| 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 | ||||||
| 
 | 
 | ||||||
|  | data class EditProfileActions( | ||||||
|  |     val onUserNameChange: (String) -> Unit, | ||||||
|  |     val onSaveClick: () -> Unit, | ||||||
|  |     val onDeleteClick: () -> Unit | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getEditProfileActions( | ||||||
|  |     viewModel: ProfileEditViewModel, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  | ): EditProfileActions { | ||||||
|  |     return EditProfileActions( | ||||||
|  |         onUserNameChange = { viewModel.onUsernameChange(it) }, | ||||||
|  |         onSaveClick = { viewModel.onSaveClick() }, | ||||||
|  |         onDeleteClick = { viewModel.onDeleteClick(openAndPopUp) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun EditProfileRoute( | ||||||
|  |     goBack: () -> Unit, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  |     viewModel: ProfileEditViewModel, | ||||||
|  | ) { | ||||||
|  |     val uiState by viewModel.uiState | ||||||
|  |     EditProfileScreen( | ||||||
|  |         goBack = goBack, | ||||||
|  |         uiState = uiState, | ||||||
|  |         editProfileActions = getEditProfileActions(viewModel, openAndPopUp) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun EditProfileScreen( | fun EditProfileScreen( | ||||||
|     goBack: () -> Unit, |     goBack: () -> Unit, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     uiState: ProfileEditUiState, | ||||||
|     viewModel: ProfileEditViewModel = hiltViewModel() |     editProfileActions: EditProfileActions, | ||||||
| ) { | ) { | ||||||
|     val uiState by viewModel.uiState |  | ||||||
| 
 |  | ||||||
|     SecondaryScreenTemplate( |     SecondaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.editing_profile), |         title = resources().getString(R.string.editing_profile), | ||||||
|         popUp = goBack |         popUp = goBack | ||||||
|  | @ -29,16 +57,19 @@ fun EditProfileScreen( | ||||||
|         Column { |         Column { | ||||||
|             LabelledInputField( |             LabelledInputField( | ||||||
|                 value = uiState.username, |                 value = uiState.username, | ||||||
|                 onNewValue = viewModel::onUsernameChange, |                 onNewValue = editProfileActions.onUserNameChange, | ||||||
|                 label = R.string.username |                 label = R.string.username | ||||||
|             ) |             ) | ||||||
| 
 |             BasicTextButton( | ||||||
|             BasicTextButton(text = R.string.save, Modifier.textButton()) { |                 text = R.string.save, | ||||||
|                 viewModel.onSaveClick() |                 Modifier.textButton(), | ||||||
|             } |                 action = editProfileActions.onSaveClick | ||||||
|             BasicTextButton(text = R.string.delete_profile, Modifier.textButton()) { |             ) | ||||||
|                 viewModel.onDeleteClick(openAndPopUp) |             BasicTextButton( | ||||||
|             } |                 text = R.string.delete_profile, | ||||||
|  |                 Modifier.textButton(), | ||||||
|  |                 action = editProfileActions.onDeleteClick | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -47,9 +78,6 @@ fun EditProfileScreen( | ||||||
| @Composable | @Composable | ||||||
| fun EditProfileScreenComposable() { | fun EditProfileScreenComposable() { | ||||||
|     StudeezTheme { |     StudeezTheme { | ||||||
|         EditProfileScreen ( |         EditProfileScreen({}, ProfileEditUiState(), EditProfileActions({}, {}, {})) | ||||||
|             {}, |  | ||||||
|             {_, _ -> {}} |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -4,30 +4,68 @@ import androidx.compose.material.Icon | ||||||
| import androidx.compose.material.IconButton | import androidx.compose.material.IconButton | ||||||
| import androidx.compose.material.icons.Icons | import androidx.compose.material.icons.Icons | ||||||
| import androidx.compose.material.icons.filled.Edit | import androidx.compose.material.icons.filled.Edit | ||||||
| import androidx.compose.runtime.* | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.LaunchedEffect | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel | import androidx.hilt.navigation.compose.hiltViewModel | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.Headline | import be.ugent.sel.studeez.common.composable.Headline | ||||||
| import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | ||||||
|  | import kotlinx.coroutines.CoroutineScope | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
|  | data class ProfileActions( | ||||||
|  |     val getUsername: suspend CoroutineScope.() -> String?, | ||||||
|  |     val onEditProfileClick: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getProfileActions( | ||||||
|  |     viewModel: ProfileViewModel, | ||||||
|  |     open: (String) -> Unit, | ||||||
|  | ): ProfileActions { | ||||||
|  |     return ProfileActions( | ||||||
|  |         getUsername = { viewModel.getUsername() }, | ||||||
|  |         onEditProfileClick = { viewModel.onEditProfileClick(open) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun ProfileRoute( | ||||||
|  |     open: (String) -> Unit, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  |     viewModel: ProfileViewModel, | ||||||
|  | ) { | ||||||
|  |     ProfileScreen( | ||||||
|  |         profileActions = getProfileActions(viewModel, open), | ||||||
|  |         drawerActions = getDrawerActions(hiltViewModel(), open, openAndPopUp), | ||||||
|  |         navigationBarActions = getNavigationBarActions(hiltViewModel(), open), | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun ProfileScreen( | fun ProfileScreen( | ||||||
|     open: (String) -> Unit, |     profileActions: ProfileActions, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     drawerActions: DrawerActions, | ||||||
|     viewModel: ProfileViewModel = hiltViewModel() |     navigationBarActions: NavigationBarActions, | ||||||
| ) { | ) { | ||||||
|     var username: String? by remember { mutableStateOf("") } |     var username: String? by remember { mutableStateOf("") } | ||||||
|     LaunchedEffect(key1 = Unit) { |     LaunchedEffect(key1 = Unit) { | ||||||
|         username = viewModel.getUsername() |         username = profileActions.getUsername(this) | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(AppText.profile), |         title = resources().getString(AppText.profile), | ||||||
|         open = open, |         drawerActions = drawerActions, | ||||||
|         openAndPopUp = openAndPopUp, |         navigationBarActions = navigationBarActions, | ||||||
|         action = { EditAction { viewModel.onEditProfileClick(open) } } |         action = { EditAction(onClick = profileActions.onEditProfileClick) } | ||||||
|     ) { |     ) { | ||||||
|         Headline(text = (username ?: resources().getString(R.string.no_username))) |         Headline(text = (username ?: resources().getString(R.string.no_username))) | ||||||
|     } |     } | ||||||
|  | @ -45,3 +83,13 @@ fun EditAction( | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun ProfileScreenPreview() { | ||||||
|  |     ProfileScreen( | ||||||
|  |         profileActions = ProfileActions({ null }, {}), | ||||||
|  |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|  |         navigationBarActions = NavigationBarActions({}, {}, {}, {}) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | @ -24,34 +24,71 @@ import androidx.compose.ui.graphics.Color | ||||||
| import androidx.compose.ui.platform.LocalContext | import androidx.compose.ui.platform.LocalContext | ||||||
| import androidx.compose.ui.text.font.FontWeight | import androidx.compose.ui.text.font.FontWeight | ||||||
| import androidx.compose.ui.text.style.TextAlign | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | 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 | import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||||
| import androidx.compose.ui.unit.sp | import androidx.compose.ui.unit.sp | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
|  | 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 | ||||||
|  | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer.StudyState | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer.StudyState | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import kotlinx.coroutines.delay | import kotlinx.coroutines.delay | ||||||
|  | import javax.inject.Singleton | ||||||
| import kotlin.time.Duration.Companion.seconds | import kotlin.time.Duration.Companion.seconds | ||||||
| 
 | 
 | ||||||
|  | data class SessionActions( | ||||||
|  |     val getTimer: () -> FunctionalTimer, | ||||||
|  |     val getTask: () -> String, | ||||||
|  |     val releaseMediaPlayer: () -> Unit, | ||||||
|  |     val startMediaPlayer: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getSessionActions( | ||||||
|  |     viewModel: SessionViewModel, | ||||||
|  |     mediaplayer: MediaPlayer, | ||||||
|  | ): SessionActions { | ||||||
|  |     return SessionActions( | ||||||
|  |         getTimer = viewModel::getTimer, | ||||||
|  |         getTask = viewModel::getTask, | ||||||
|  |         releaseMediaPlayer = mediaplayer::release, | ||||||
|  |         startMediaPlayer = mediaplayer::start, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun SessionScreen( | fun SessionRoute( | ||||||
|     open: (String) -> Unit, |     open: (String) -> Unit, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     viewModel: SessionViewModel, | ||||||
|     viewModel: SessionViewModel = hiltViewModel() |  | ||||||
| ) { | ) { | ||||||
|     val context = LocalContext.current |     val context = LocalContext.current | ||||||
|     val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) |     val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) | ||||||
|     val mediaplayer = MediaPlayer.create(context, uri) |     val mediaplayer = MediaPlayer.create(context, uri) | ||||||
|     mediaplayer.isLooping = false |     mediaplayer.isLooping = false | ||||||
| 
 | 
 | ||||||
|     InvisibleSessionManager.setParameters(viewModel = viewModel, mediaplayer = mediaplayer) |     InvisibleSessionManager.setParameters( | ||||||
|  |         viewModel = viewModel, | ||||||
|  |         mediaplayer = mediaplayer | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
|  |     SessionScreen( | ||||||
|  |         open = open, | ||||||
|  |         sessionActions = getSessionActions(viewModel, mediaplayer) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SessionScreen( | ||||||
|  |     open: (String) -> Unit, | ||||||
|  |     sessionActions: SessionActions | ||||||
|  | ) { | ||||||
|     Column( |     Column( | ||||||
|         modifier = Modifier.padding(10.dp) |         modifier = Modifier.padding(10.dp) | ||||||
|     ) { |     ) { | ||||||
|         Timer(viewModel, mediaplayer) |         Timer( | ||||||
|  |             sessionActions = sessionActions | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|         Box( |         Box( | ||||||
|             contentAlignment = Alignment.Center, |             contentAlignment = Alignment.Center, | ||||||
|  | @ -61,10 +98,9 @@ fun SessionScreen( | ||||||
|         ) { |         ) { | ||||||
|             TextButton( |             TextButton( | ||||||
|                 onClick = { |                 onClick = { | ||||||
|                     mediaplayer.stop() |                     sessionActions.releaseMediaPlayer | ||||||
|                     mediaplayer.release() | 
 | ||||||
|                     open(StudeezDestinations.HOME_SCREEN) |                     open(StudeezDestinations.HOME_SCREEN) | ||||||
|                     InvisibleSessionManager.isSession = false |  | ||||||
|                     // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt |                     // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt | ||||||
|                 }, |                 }, | ||||||
|                 modifier = Modifier |                 modifier = Modifier | ||||||
|  | @ -77,7 +113,8 @@ fun SessionScreen( | ||||||
|                     color = Color.Red, |                     color = Color.Red, | ||||||
|                     fontWeight = FontWeight.Bold, |                     fontWeight = FontWeight.Bold, | ||||||
|                     fontSize = 18.sp, |                     fontSize = 18.sp, | ||||||
|                     modifier = Modifier.padding(1.dp) |                     modifier = Modifier | ||||||
|  |                         .padding(1.dp) | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -85,19 +122,21 @@ fun SessionScreen( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: MediaPlayer) { | private fun Timer( | ||||||
|  |     sessionActions: SessionActions | ||||||
|  | ) { | ||||||
|     var tikker by remember { mutableStateOf(false) } |     var tikker by remember { mutableStateOf(false) } | ||||||
|     LaunchedEffect(tikker) { |     LaunchedEffect(tikker) { | ||||||
|         delay(1.seconds) |         delay(1.seconds) | ||||||
|         viewModel.getTimer().tick() |         sessionActions.getTimer().tick() | ||||||
|         tikker = !tikker |         tikker = !tikker | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { |     if (sessionActions.getTimer().hasCurrentCountdownEnded() && !sessionActions.getTimer().hasEnded()) { | ||||||
|         mediaplayer.start() |         sessionActions.startMediaPlayer | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     val hms = viewModel.getTimer().getHoursMinutesSeconds() |     val hms = sessionActions.getTimer().getHoursMinutesSeconds() | ||||||
|     Column { |     Column { | ||||||
|         Text( |         Text( | ||||||
|             text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}", |             text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}", | ||||||
|  | @ -108,12 +147,12 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me | ||||||
|             fontWeight = FontWeight.Bold, |             fontWeight = FontWeight.Bold, | ||||||
|             fontSize = 40.sp, |             fontSize = 40.sp, | ||||||
|         ) |         ) | ||||||
|         val stateString: String = when (viewModel.getTimer().view) { |         val stateString: String = when (sessionActions.getTimer().view) { | ||||||
|             StudyState.DONE -> resources().getString(R.string.state_done) |             StudyState.DONE -> resources().getString(R.string.state_done) | ||||||
|             StudyState.FOCUS -> resources().getString(R.string.state_focus) |             StudyState.FOCUS -> resources().getString(R.string.state_focus) | ||||||
|             StudyState.BREAK -> resources().getString(R.string.state_take_a_break) |             StudyState.BREAK -> resources().getString(R.string.state_take_a_break) | ||||||
|             StudyState.FOCUS_REMAINING -> |             StudyState.FOCUS_REMAINING -> | ||||||
|                 (viewModel.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let { |                 (sessionActions.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let { | ||||||
|                     resources().getQuantityString(R.plurals.state_focus_remaining, it, it) |                     resources().getQuantityString(R.plurals.state_focus_remaining, it, it) | ||||||
|                 }.toString() |                 }.toString() | ||||||
|         } |         } | ||||||
|  | @ -139,7 +178,7 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me | ||||||
|                     .background(Color.Blue, RoundedCornerShape(32.dp)) |                     .background(Color.Blue, RoundedCornerShape(32.dp)) | ||||||
|             ) { |             ) { | ||||||
|                 Text( |                 Text( | ||||||
|                     text = viewModel.getTask(), |                     text = sessionActions.getTask(), | ||||||
|                     color = Color.White, |                     color = Color.White, | ||||||
|                     fontSize = 18.sp, |                     fontSize = 18.sp, | ||||||
|                     fontWeight = FontWeight.Bold, |                     fontWeight = FontWeight.Bold, | ||||||
|  | @ -151,6 +190,8 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | @Singleton | ||||||
| object InvisibleSessionManager { | object InvisibleSessionManager { | ||||||
|     private lateinit var viewModel: SessionViewModel |     private lateinit var viewModel: SessionViewModel | ||||||
|     private lateinit var mediaplayer: MediaPlayer |     private lateinit var mediaplayer: MediaPlayer | ||||||
|  | @ -174,3 +215,19 @@ object InvisibleSessionManager { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun TimerPreview() { | ||||||
|  |     Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {})) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun SessionPreview() { | ||||||
|  |     SessionScreen( | ||||||
|  |         open = {}, | ||||||
|  |         sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {}) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -10,23 +10,64 @@ import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.common.composable.* | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.BasicTextButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.EmailField | ||||||
|  | import be.ugent.sel.studeez.common.composable.PasswordField | ||||||
|  | import be.ugent.sel.studeez.common.composable.RepeatPasswordField | ||||||
|  | import be.ugent.sel.studeez.common.composable.SimpleScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.UsernameField | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.common.ext.fieldModifier | import be.ugent.sel.studeez.common.ext.fieldModifier | ||||||
| import be.ugent.sel.studeez.common.ext.textButton | import be.ugent.sel.studeez.common.ext.textButton | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
|  | data class SignUpActions( | ||||||
|  |     val onUserNameChange: (String) -> Unit, | ||||||
|  |     val onEmailChange: (String) -> Unit, | ||||||
|  |     val onPasswordChange: (String) -> Unit, | ||||||
|  |     val onRepeatPasswordChange: (String) -> Unit, | ||||||
|  |     val onSignUpClick: () -> Unit, | ||||||
|  |     val onLoginClick: () -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getSignUpActions( | ||||||
|  |     viewModel: SignUpViewModel, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  | ): SignUpActions { | ||||||
|  |     return SignUpActions( | ||||||
|  |         onUserNameChange = { viewModel.onUsernameChange(it) }, | ||||||
|  |         onEmailChange = { viewModel.onEmailChange(it) }, | ||||||
|  |         onPasswordChange = { viewModel.onPasswordChange(it) }, | ||||||
|  |         onRepeatPasswordChange = { viewModel.onRepeatPasswordChange(it) }, | ||||||
|  |         onSignUpClick = { viewModel.onSignUpClick(openAndPopUp) }, | ||||||
|  |         onLoginClick = { viewModel.onLoginClick(openAndPopUp) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Composable | @Composable | ||||||
| fun SignUpScreen( | fun SignUpRoute( | ||||||
|     openAndPopUp: (String, String) -> Unit, |     openAndPopUp: (String, String) -> Unit, | ||||||
|     modifier: Modifier = Modifier, |     modifier: Modifier = Modifier, | ||||||
|     viewModel: SignUpViewModel = hiltViewModel() |     viewModel: SignUpViewModel, | ||||||
| ) { | ) { | ||||||
|     val uiState by viewModel.uiState |     val uiState by viewModel.uiState | ||||||
|     val fieldModifier = Modifier.fieldModifier() |     SignUpScreen( | ||||||
|  |         modifier = modifier, | ||||||
|  |         uiState, | ||||||
|  |         getSignUpActions(viewModel, openAndPopUp) | ||||||
|  |     ) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | @Composable | ||||||
|  | fun SignUpScreen( | ||||||
|  |     modifier: Modifier = Modifier, | ||||||
|  |     uiState: SignUpUiState, | ||||||
|  |     signUpActions: SignUpActions, | ||||||
|  | ) { | ||||||
|  |     val fieldModifier = Modifier.fieldModifier() | ||||||
|     SimpleScreenTemplate(title = resources().getString(AppText.create_account)) { |     SimpleScreenTemplate(title = resources().getString(AppText.create_account)) { | ||||||
|         Column( |         Column( | ||||||
|             modifier = modifier |             modifier = modifier | ||||||
|  | @ -36,40 +77,45 @@ fun SignUpScreen( | ||||||
|             verticalArrangement = Arrangement.Center, |             verticalArrangement = Arrangement.Center, | ||||||
|             horizontalAlignment = Alignment.CenterHorizontally |             horizontalAlignment = Alignment.CenterHorizontally | ||||||
|         ) { |         ) { | ||||||
| 
 |  | ||||||
|             UsernameField( |             UsernameField( | ||||||
|                 uiState.username, |                 uiState.username, | ||||||
|                 viewModel::onUsernameChange, |                 signUpActions.onUserNameChange, | ||||||
|                 fieldModifier |                 fieldModifier | ||||||
|             ) |             ) | ||||||
| 
 |  | ||||||
|             EmailField( |             EmailField( | ||||||
|                 uiState.email, |                 uiState.email, | ||||||
|                 viewModel::onEmailChange, |                 signUpActions.onEmailChange, | ||||||
|                 fieldModifier |                 fieldModifier | ||||||
|             ) |             ) | ||||||
| 
 |  | ||||||
|             PasswordField( |             PasswordField( | ||||||
|                 uiState.password, |                 uiState.password, | ||||||
|                 viewModel::onPasswordChange, |                 signUpActions.onPasswordChange, | ||||||
|                 fieldModifier |                 fieldModifier | ||||||
|             ) |             ) | ||||||
| 
 |  | ||||||
|             RepeatPasswordField( |             RepeatPasswordField( | ||||||
|                 uiState.repeatPassword, |                 uiState.repeatPassword, | ||||||
|                 viewModel::onRepeatPasswordChange, |                 signUpActions.onRepeatPasswordChange, | ||||||
|                 fieldModifier |                 fieldModifier | ||||||
|             ) |             ) | ||||||
| 
 |             BasicButton( | ||||||
|             BasicButton(AppText.create_account, Modifier.basicButton()) { |                 AppText.create_account, | ||||||
|                 viewModel.onSignUpClick(openAndPopUp) |                 Modifier.basicButton(), | ||||||
|             } |                 onClick = signUpActions.onSignUpClick | ||||||
| 
 |             ) | ||||||
|             BasicTextButton(AppText.already_user, Modifier.textButton()) { |             BasicTextButton( | ||||||
|                 viewModel.onLoginScreenClick(openAndPopUp) |                 AppText.already_user, | ||||||
|  |                 Modifier.textButton(), | ||||||
|  |                 action = signUpActions.onLoginClick | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | @Preview | ||||||
|  | @Composable | ||||||
|  | fun SignUpPreview() { | ||||||
|  |     SignUpScreen( | ||||||
|  |         uiState = SignUpUiState(), | ||||||
|  |         signUpActions = SignUpActions({}, {}, {}, {}, {}, {}) | ||||||
|  |     ) | ||||||
| } | } | ||||||
|  | @ -71,7 +71,7 @@ class SignUpViewModel @Inject constructor( | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onLoginScreenClick(openAndPopUp: (String, String) -> Unit) { |     fun onLoginClick(openAndPopUp: (String, String) -> Unit) { | ||||||
|         openAndPopUp(LOGIN_SCREEN, SIGN_UP_SCREEN) |         openAndPopUp(LOGIN_SCREEN, SIGN_UP_SCREEN) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -15,7 +15,7 @@ import androidx.compose.runtime.LaunchedEffect | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.res.stringResource | import androidx.compose.ui.res.stringResource | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.common.composable.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import kotlinx.coroutines.delay | import kotlinx.coroutines.delay | ||||||
|  | @ -24,14 +24,26 @@ import be.ugent.sel.studeez.R.string as AppText | ||||||
| private const val SPLASH_TIMEOUT = 500L | private const val SPLASH_TIMEOUT = 500L | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun SplashScreen( | fun SplashRoute( | ||||||
|     openAndPopUp: (String, String) -> Unit, |     openAndPopUp: (String, String) -> Unit, | ||||||
|     modifier: Modifier = Modifier, |     modifier: Modifier = Modifier, | ||||||
|     viewModel: SplashViewModel = hiltViewModel() |     viewModel: SplashViewModel, | ||||||
|  | ) { | ||||||
|  |     SplashScreen( | ||||||
|  |         modifier = modifier, | ||||||
|  |         onAppStart = { viewModel.onAppStart(openAndPopUp) }, | ||||||
|  |         showError = viewModel.showError.value | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun SplashScreen( | ||||||
|  |     modifier: Modifier = Modifier, | ||||||
|  |     onAppStart: () -> Unit, | ||||||
|  |     showError: Boolean, | ||||||
| ) { | ) { | ||||||
|     Column( |     Column( | ||||||
|         modifier = |         modifier = modifier | ||||||
|         modifier |  | ||||||
|             .fillMaxWidth() |             .fillMaxWidth() | ||||||
|             .fillMaxHeight() |             .fillMaxHeight() | ||||||
|             .background(color = MaterialTheme.colors.background) |             .background(color = MaterialTheme.colors.background) | ||||||
|  | @ -39,17 +51,37 @@ fun SplashScreen( | ||||||
|         verticalArrangement = Arrangement.Center, |         verticalArrangement = Arrangement.Center, | ||||||
|         horizontalAlignment = Alignment.CenterHorizontally |         horizontalAlignment = Alignment.CenterHorizontally | ||||||
|     ) { |     ) { | ||||||
|         if (viewModel.showError.value) { |         if (showError) { | ||||||
|             Text(text = stringResource(AppText.generic_error)) |             Text(text = stringResource(AppText.generic_error)) | ||||||
| 
 |             BasicButton( | ||||||
|             BasicButton(AppText.try_again, Modifier.basicButton()) { viewModel.onAppStart(openAndPopUp) } |                 AppText.try_again, | ||||||
|  |                 Modifier.basicButton(), | ||||||
|  |                 onClick = onAppStart, | ||||||
|  |             ) | ||||||
|         } else { |         } else { | ||||||
|             CircularProgressIndicator(color = MaterialTheme.colors.onBackground) |             CircularProgressIndicator(color = MaterialTheme.colors.onBackground) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     LaunchedEffect(true) { |     LaunchedEffect(true) { | ||||||
|         delay(SPLASH_TIMEOUT) |         delay(SPLASH_TIMEOUT) | ||||||
|         viewModel.onAppStart(openAndPopUp) |         onAppStart() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun SplashPreview() { | ||||||
|  |     SplashScreen( | ||||||
|  |         onAppStart = {}, | ||||||
|  |         showError = false, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun SplashErrorPreview() { | ||||||
|  |     SplashScreen( | ||||||
|  |         onAppStart = {}, | ||||||
|  |         showError = true, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | @ -1,122 +1,118 @@ | ||||||
| package be.ugent.sel.studeez.screens.timer_overview | package be.ugent.sel.studeez.screens.timer_overview | ||||||
| 
 | 
 | ||||||
| import android.annotation.SuppressLint |  | ||||||
| import androidx.annotation.StringRes |  | ||||||
| import androidx.compose.foundation.layout.Arrangement | import androidx.compose.foundation.layout.Arrangement | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.foundation.layout.Column | ||||||
| import androidx.compose.foundation.layout.Row |  | ||||||
| import androidx.compose.foundation.layout.fillMaxWidth |  | ||||||
| import androidx.compose.foundation.layout.padding |  | ||||||
| import androidx.compose.foundation.lazy.LazyColumn | import androidx.compose.foundation.lazy.LazyColumn | ||||||
| import androidx.compose.foundation.lazy.items | import androidx.compose.foundation.lazy.items | ||||||
| import androidx.compose.material.Scaffold |  | ||||||
| import androidx.compose.material.Text |  | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.collectAsState | import androidx.compose.runtime.collectAsState | ||||||
| import androidx.compose.ui.Alignment |  | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.text.font.FontWeight |  | ||||||
| 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 | ||||||
| import androidx.compose.ui.unit.sp |  | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
| import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
| import be.ugent.sel.studeez.common.composable.StealthButton | import be.ugent.sel.studeez.common.composable.StealthButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.TimerEntry | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | ||||||
| import be.ugent.sel.studeez.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.resources | import be.ugent.sel.studeez.resources | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.flowOf | ||||||
|  | 
 | ||||||
|  | data class TimerOverviewActions( | ||||||
|  |     val getUserTimers: () -> Flow<List<TimerInfo>>, | ||||||
|  |     val getDefaultTimers: () -> List<TimerInfo>, | ||||||
|  |     val onEditClick: (TimerInfo) -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getTimerOverviewActions( | ||||||
|  |     viewModel: TimerOverviewViewModel, | ||||||
|  | ): TimerOverviewActions { | ||||||
|  |     return TimerOverviewActions( | ||||||
|  |         getUserTimers = viewModel::getUserTimers, | ||||||
|  |         getDefaultTimers = viewModel::getDefaultTimers, | ||||||
|  |         onEditClick = { viewModel.update(it) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun TimerOverviewRoute( | ||||||
|  |     open: (String) -> Unit, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  |     viewModel: TimerOverviewViewModel, | ||||||
|  |     drawerViewModel: DrawerViewModel, | ||||||
|  |     navBarViewModel: NavigationBarViewModel, | ||||||
|  | ) { | ||||||
|  |     TimerOverviewScreen( | ||||||
|  |         timerOverviewActions = getTimerOverviewActions(viewModel), | ||||||
|  |         drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), | ||||||
|  |         navigationBarActions = getNavigationBarActions(navBarViewModel, open), | ||||||
|  |     ) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun TimerOverviewScreen( | fun TimerOverviewScreen( | ||||||
|     open: (String) -> Unit, |     timerOverviewActions: TimerOverviewActions, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     drawerActions: DrawerActions, | ||||||
|     viewModel: TimerOverviewViewModel = hiltViewModel() |     navigationBarActions: NavigationBarActions, | ||||||
| ) { | ) { | ||||||
| 
 | 
 | ||||||
|     val timers = viewModel.getUserTimers().collectAsState(initial = emptyList()) |     val timers = timerOverviewActions.getUserTimers().collectAsState(initial = emptyList()) | ||||||
| 
 | 
 | ||||||
|  |     // TODO moet geen primary screen zijn: geen navbar nodig | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.timers), |         title = resources().getString(R.string.timers), | ||||||
|         open = open, |         drawerActions = drawerActions, | ||||||
|         openAndPopUp = openAndPopUp |         navigationBarActions = navigationBarActions, | ||||||
|     ) { |     ) { | ||||||
| 
 |  | ||||||
|         Column { |         Column { | ||||||
|             LazyColumn( |             LazyColumn( | ||||||
|                 verticalArrangement = Arrangement.spacedBy(7.dp) |                 verticalArrangement = Arrangement.spacedBy(7.dp) | ||||||
|             ) { |             ) { | ||||||
|                 // Default Timers, cannot be edited |                 // Default Timers, cannot be edited | ||||||
|                 items(viewModel.getDefaultTimers()) { |                 items(timerOverviewActions.getDefaultTimers()) { | ||||||
|                     TimerEntry(timerInfo = it, canDisplay = false) |                     TimerEntry(timerInfo = it) {} | ||||||
|  |                 } | ||||||
|  |                 // User timers, can be edited | ||||||
|  |                 items(timers.value) { timerInfo -> | ||||||
|  |                     TimerEntry( | ||||||
|  |                         timerInfo = timerInfo, | ||||||
|  |                     ) { | ||||||
|  |                         StealthButton( | ||||||
|  |                             text = R.string.edit, | ||||||
|  |                             onClick = { timerOverviewActions.onEditClick(timerInfo) } | ||||||
|  |                         ) | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                 // User timers, can be edited |  | ||||||
|                 items(timers.value) { |  | ||||||
|                     TimerEntry(timerInfo = it, true, R.string.edit) { timerInfo -> |  | ||||||
|                         viewModel.update(timerInfo) |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             BasicButton(R.string.add_timer, Modifier.basicButton()) { |             BasicButton(R.string.add_timer, Modifier.basicButton()) { | ||||||
|                 // TODO |                 // TODO | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable |  | ||||||
| fun TimerEntry( |  | ||||||
|     timerInfo: TimerInfo, |  | ||||||
|     canDisplay: Boolean, |  | ||||||
|     @StringRes buttonName: Int = -1, |  | ||||||
|     buttonFunction: (TimerInfo) -> Unit = {} |  | ||||||
| ) { |  | ||||||
|     Row( |  | ||||||
|         verticalAlignment = Alignment.CenterVertically, |  | ||||||
|         modifier = Modifier.fillMaxWidth(), |  | ||||||
|         horizontalArrangement = Arrangement.SpaceBetween |  | ||||||
|     ) { |  | ||||||
|         Column( |  | ||||||
|             Modifier.padding(horizontal = 10.dp) |  | ||||||
|         ) { |  | ||||||
|             Text( |  | ||||||
|                 text = timerInfo.name, |  | ||||||
|                 fontWeight = FontWeight.Bold, |  | ||||||
|                 fontSize = 20.sp |  | ||||||
|             ) |  | ||||||
|             Text( |  | ||||||
|                 text = timerInfo.description, |  | ||||||
|                 fontWeight = FontWeight.Light, |  | ||||||
|                 fontSize = 15.sp |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|         if (canDisplay) { |  | ||||||
|             StealthButton(buttonName) { |  | ||||||
|                 buttonFunction(timerInfo) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @SuppressLint("UnusedMaterialScaffoldPaddingParameter") |  | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun TimerEntryPreview() { | fun TimerOverviewPreview() { | ||||||
|     val timerInfo = CustomTimerInfo( |     val customTimer = CustomTimerInfo( | ||||||
|         "my preview timer", |         "my preview timer", "This is the description of the timer", 60 | ||||||
|         "This is the description of the timer", |     ) | ||||||
|         60 |     TimerOverviewScreen( | ||||||
|  |         timerOverviewActions = TimerOverviewActions( | ||||||
|  |             { flowOf() }, | ||||||
|  |             { listOf(customTimer, customTimer) }, | ||||||
|  |             {}), | ||||||
|  |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|  |         navigationBarActions = NavigationBarActions({}, {}, {}, {}) | ||||||
|     ) |     ) | ||||||
|     Scaffold() { |  | ||||||
|         Column() { |  | ||||||
|             TimerEntry(timerInfo = timerInfo, true, buttonName = R.string.edit) { } |  | ||||||
|             TimerEntry(timerInfo = timerInfo, true, buttonName = R.string.edit) { } |  | ||||||
|             TimerEntry(timerInfo = timerInfo, true, buttonName = R.string.edit) { } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | @ -3,42 +3,89 @@ package be.ugent.sel.studeez.screens.timer_selection | ||||||
| import androidx.compose.foundation.layout.Arrangement | import androidx.compose.foundation.layout.Arrangement | ||||||
| import androidx.compose.foundation.lazy.LazyColumn | import androidx.compose.foundation.lazy.LazyColumn | ||||||
| import androidx.compose.foundation.lazy.items | import androidx.compose.foundation.lazy.items | ||||||
| import androidx.compose.runtime.* | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.collectAsState | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.compose.ui.unit.dp | import androidx.compose.ui.unit.dp | ||||||
| import androidx.hilt.navigation.compose.hiltViewModel |  | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.StealthButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.TimerEntry | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | ||||||
|  | import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | ||||||
|  | import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.screens.timer_overview.TimerEntry | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.flowOf | ||||||
|  | 
 | ||||||
|  | data class TimerSelectionActions( | ||||||
|  |     val getAllTimers: () -> Flow<List<TimerInfo>>, | ||||||
|  |     val startSession: (TimerInfo) -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getTimerSelectionActions( | ||||||
|  |     viewModel: TimerSelectionViewModel, | ||||||
|  |     open: (String) -> Unit, | ||||||
|  | ): TimerSelectionActions { | ||||||
|  |     return TimerSelectionActions( | ||||||
|  |         getAllTimers = viewModel::getAllTimers, | ||||||
|  |         startSession = { viewModel.startSession(open, it) }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun TimerSelectionRoute( | ||||||
|  |     open: (String) -> Unit, | ||||||
|  |     openAndPopUp: (String, String) -> Unit, | ||||||
|  |     viewModel: TimerSelectionViewModel, | ||||||
|  |     drawerViewModel: DrawerViewModel, | ||||||
|  |     navBarViewModel: NavigationBarViewModel, | ||||||
|  | ) { | ||||||
|  |     TimerSelectionScreen( | ||||||
|  |         timerSelectionActions = getTimerSelectionActions(viewModel, open), | ||||||
|  |         drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), | ||||||
|  |         navigationBarActions = getNavigationBarActions(navBarViewModel, open), | ||||||
|  |     ) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun TimerSelectionScreen( | fun TimerSelectionScreen( | ||||||
|     open: (String) -> Unit, |     timerSelectionActions: TimerSelectionActions, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     drawerActions: DrawerActions, | ||||||
|     viewModel: TimerSelectionViewModel = hiltViewModel() |     navigationBarActions: NavigationBarActions, | ||||||
| ) { | ) { | ||||||
| 
 |     val timers = timerSelectionActions.getAllTimers().collectAsState(initial = emptyList()) | ||||||
|     val timers = viewModel.getAllTimers().collectAsState(initial = emptyList()) |  | ||||||
| 
 |  | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.timers), |         title = resources().getString(R.string.timers), | ||||||
|         open = open, |         drawerActions = drawerActions, | ||||||
|         openAndPopUp = openAndPopUp, |         navigationBarActions = navigationBarActions, | ||||||
|     ) { |     ) { | ||||||
| 
 |  | ||||||
|         LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) { |         LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) { | ||||||
| 
 |  | ||||||
|             // All timers |             // All timers | ||||||
|             items(timers.value) { |             items(timers.value) { timerInfo -> | ||||||
|                 TimerEntry( |                 TimerEntry( | ||||||
|                     timerInfo = it, |                     timerInfo = timerInfo, | ||||||
|                     canDisplay = true, |                 ) { | ||||||
|                     buttonName = R.string.start |                     StealthButton( | ||||||
|                 ) { timerInfo -> |                         text = R.string.start, | ||||||
|                     viewModel.startSession(open, timerInfo) |                         onClick = { timerSelectionActions.startSession(timerInfo) } | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     } | @Preview | ||||||
|  | @Composable | ||||||
|  | fun TimerSelectionPreview() { | ||||||
|  |     TimerSelectionScreen( | ||||||
|  |         timerSelectionActions = TimerSelectionActions({ flowOf() }, {}), | ||||||
|  |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|  |         navigationBarActions = NavigationBarActions({}, {}, {}, {}), | ||||||
|  |     ) | ||||||
| } | } | ||||||
		Reference in a new issue
	
	 Rune Dyselinck
						Rune Dyselinck