merged with current dev
This commit is contained in:
		
						commit
						b30edf6538
					
				
					 22 changed files with 849 additions and 373 deletions
				
			
		| 
						 | 
				
			
			@ -2,7 +2,13 @@ package be.ugent.sel.studeez
 | 
			
		|||
 | 
			
		||||
import android.content.res.Resources
 | 
			
		||||
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.ReadOnlyComposable
 | 
			
		||||
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.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.navigation.NavGraphBuilder
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import androidx.navigation.NavHostController
 | 
			
		||||
import androidx.navigation.compose.NavHost
 | 
			
		||||
import androidx.navigation.compose.composable
 | 
			
		||||
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.navigation.StudeezDestinations
 | 
			
		||||
import be.ugent.sel.studeez.screens.home.HomeScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.log_in.LoginScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.session.SessionScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.profile.EditProfileScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.profile.ProfileScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.sign_up.SignUpScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.splash.SplashScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionScreen
 | 
			
		||||
import be.ugent.sel.studeez.screens.home.HomeRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.log_in.LoginRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.profile.EditProfileRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.profile.ProfileRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.session.SessionRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.sign_up.SignUpRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.splash.SplashRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionRoute
 | 
			
		||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,13 +56,7 @@ fun StudeezApp() {
 | 
			
		|||
                },
 | 
			
		||||
                scaffoldState = appState.scaffoldState
 | 
			
		||||
            ) { innerPaddingModifier ->
 | 
			
		||||
                NavHost(
 | 
			
		||||
                    navController = appState.navController,
 | 
			
		||||
                    startDestination = StudeezDestinations.SPLASH_SCREEN,
 | 
			
		||||
                    modifier = Modifier.padding(innerPaddingModifier)
 | 
			
		||||
                ) {
 | 
			
		||||
                    studeezGraph(appState)
 | 
			
		||||
                }
 | 
			
		||||
                StudeezNavGraph(appState, Modifier.padding(innerPaddingModifier))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -79,60 +81,91 @@ fun resources(): 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()
 | 
			
		||||
 | 
			
		||||
    val goBack: () -> Unit = {
 | 
			
		||||
        appState.popUp()
 | 
			
		||||
    NavHost(
 | 
			
		||||
        navController = appState.navController,
 | 
			
		||||
        startDestination = StudeezDestinations.SPLASH_SCREEN,
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
    ) {
 | 
			
		||||
        val goBack: () -> Unit = {
 | 
			
		||||
            appState.popUp()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val open: (String) -> Unit = { route ->
 | 
			
		||||
            appState.navigate(route)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val openAndPopUp: (String, String) -> Unit = { route, popUp ->
 | 
			
		||||
            appState.navigateAndPopUp(route, popUp)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.SPLASH_SCREEN) {
 | 
			
		||||
            SplashRoute(openAndPopUp, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.LOGIN_SCREEN) {
 | 
			
		||||
            LoginRoute(openAndPopUp, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.SIGN_UP_SCREEN) {
 | 
			
		||||
            SignUpRoute(openAndPopUp, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.HOME_SCREEN) {
 | 
			
		||||
            HomeRoute(
 | 
			
		||||
                open,
 | 
			
		||||
                openAndPopUp,
 | 
			
		||||
                viewModel = hiltViewModel(),
 | 
			
		||||
                drawerViewModel = drawerViewModel,
 | 
			
		||||
                navBarViewModel = navBarViewModel,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO Tasks screen
 | 
			
		||||
        // TODO Sessions screen
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.PROFILE_SCREEN) {
 | 
			
		||||
            ProfileRoute(open, openAndPopUp, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) {
 | 
			
		||||
            TimerOverviewRoute(
 | 
			
		||||
                open,
 | 
			
		||||
                openAndPopUp,
 | 
			
		||||
                viewModel = hiltViewModel(),
 | 
			
		||||
                drawerViewModel = drawerViewModel,
 | 
			
		||||
                navBarViewModel = navBarViewModel,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.SESSION_SCREEN) {
 | 
			
		||||
            SessionRoute(open, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // TODO Timers screen
 | 
			
		||||
        // TODO Settings screen
 | 
			
		||||
 | 
			
		||||
        // Edit screens
 | 
			
		||||
        composable(StudeezDestinations.EDIT_PROFILE_SCREEN) {
 | 
			
		||||
            EditProfileRoute(goBack, openAndPopUp, viewModel = hiltViewModel())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
 | 
			
		||||
            TimerSelectionRoute(
 | 
			
		||||
                open,
 | 
			
		||||
                openAndPopUp,
 | 
			
		||||
                viewModel = hiltViewModel(),
 | 
			
		||||
                drawerViewModel = drawerViewModel,
 | 
			
		||||
                navBarViewModel = navBarViewModel,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val open: (String) -> Unit = {
 | 
			
		||||
            route -> appState.navigate(route)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val openAndPopUp: (String, String) -> Unit = {
 | 
			
		||||
            route, popUp -> appState.navigateAndPopUp(route, popUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.SPLASH_SCREEN) {
 | 
			
		||||
        SplashScreen(openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.LOGIN_SCREEN) {
 | 
			
		||||
        LoginScreen(openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.SIGN_UP_SCREEN) {
 | 
			
		||||
        SignUpScreen(openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.HOME_SCREEN) {
 | 
			
		||||
        HomeScreen(open, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO Tasks screen
 | 
			
		||||
    // TODO Sessions screen
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.PROFILE_SCREEN) {
 | 
			
		||||
        ProfileScreen(open, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) {
 | 
			
		||||
        TimerOverviewScreen(open, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.SESSION_SCREEN) {
 | 
			
		||||
        SessionScreen(open, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // TODO Timers screen
 | 
			
		||||
    // TODO Settings screen
 | 
			
		||||
 | 
			
		||||
    // Edit screens
 | 
			
		||||
    composable(StudeezDestinations.EDIT_PROFILE_SCREEN) {
 | 
			
		||||
        EditProfileScreen(goBack, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
 | 
			
		||||
        TimerSelectionScreen(open, openAndPopUp)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,5 @@
 | 
			
		|||
package be.ugent.sel.studeez.activities
 | 
			
		||||
 | 
			
		||||
import android.media.MediaPlayer
 | 
			
		||||
import android.media.RingtoneManager
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import androidx.activity.ComponentActivity
 | 
			
		||||
import androidx.activity.compose.setContent
 | 
			
		||||
| 
						 | 
				
			
			@ -25,13 +22,7 @@ var onTimerInvisible: Job? = null
 | 
			
		|||
 | 
			
		||||
@AndroidEntryPoint
 | 
			
		||||
class MainActivity : ComponentActivity() {
 | 
			
		||||
 | 
			
		||||
    private var mediaPlayer: MediaPlayer? = null
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
 | 
			
		||||
        mediaPlayer = MediaPlayer.create(this, uri)
 | 
			
		||||
        mediaPlayer?.isLooping = false
 | 
			
		||||
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        setContent {
 | 
			
		||||
            StudeezTheme {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,16 +45,9 @@ class MainActivity : ComponentActivity() {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStart() {
 | 
			
		||||
        mediaPlayer?.stop()
 | 
			
		||||
        onTimerInvisible?.cancel()
 | 
			
		||||
        super.onStart()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroy() {
 | 
			
		||||
        mediaPlayer?.stop()
 | 
			
		||||
        mediaPlayer?.release()
 | 
			
		||||
        super.onDestroy()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,17 +2,26 @@ package be.ugent.sel.studeez.common.composable
 | 
			
		|||
 | 
			
		||||
import androidx.compose.foundation.layout.PaddingValues
 | 
			
		||||
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.filled.Edit
 | 
			
		||||
import androidx.compose.material.icons.filled.Menu
 | 
			
		||||
import androidx.compose.material.rememberScaffoldState
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import be.ugent.sel.studeez.R
 | 
			
		||||
import be.ugent.sel.studeez.resources
 | 
			
		||||
import be.ugent.sel.studeez.screens.drawer.Drawer
 | 
			
		||||
import be.ugent.sel.studeez.screens.navbar.NavigationBar
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.drawer.Drawer
 | 
			
		||||
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 kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
| 
						 | 
				
			
			@ -20,8 +29,8 @@ import kotlinx.coroutines.launch
 | 
			
		|||
@Composable
 | 
			
		||||
fun PrimaryScreenTemplate(
 | 
			
		||||
    title: String,
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
    action: @Composable RowScope.() -> Unit = {},
 | 
			
		||||
    content: @Composable (PaddingValues) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
| 
						 | 
				
			
			@ -31,26 +40,28 @@ fun PrimaryScreenTemplate(
 | 
			
		|||
    Scaffold(
 | 
			
		||||
        scaffoldState = scaffoldState,
 | 
			
		||||
 | 
			
		||||
        topBar = { TopAppBar(
 | 
			
		||||
            title = { Text(text = title) },
 | 
			
		||||
            navigationIcon = {
 | 
			
		||||
                IconButton(onClick = {
 | 
			
		||||
                    coroutineScope.launch { scaffoldState.drawerState.open() }
 | 
			
		||||
                }) {
 | 
			
		||||
                    Icon(
 | 
			
		||||
                        imageVector = Icons.Default.Menu,
 | 
			
		||||
                        contentDescription = resources().getString(R.string.menu)
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            actions = action
 | 
			
		||||
        ) },
 | 
			
		||||
 | 
			
		||||
        drawerContent = {
 | 
			
		||||
            Drawer(open, openAndPopUp)
 | 
			
		||||
        topBar = {
 | 
			
		||||
            TopAppBar(
 | 
			
		||||
                title = { Text(text = title) },
 | 
			
		||||
                navigationIcon = {
 | 
			
		||||
                    IconButton(onClick = {
 | 
			
		||||
                        coroutineScope.launch { scaffoldState.drawerState.open() }
 | 
			
		||||
                    }) {
 | 
			
		||||
                        Icon(
 | 
			
		||||
                            imageVector = Icons.Default.Menu,
 | 
			
		||||
                            contentDescription = resources().getString(R.string.menu)
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                actions = action
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        bottomBar = { NavigationBar(open) },
 | 
			
		||||
        drawerContent = {
 | 
			
		||||
            Drawer(drawerActions)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        bottomBar = { NavigationBar(navigationBarActions) },
 | 
			
		||||
        floatingActionButtonPosition = FabPosition.Center,
 | 
			
		||||
        isFloatingActionButtonDocked = true,
 | 
			
		||||
        floatingActionButton = { CollapsedAddButton() }
 | 
			
		||||
| 
						 | 
				
			
			@ -65,14 +76,16 @@ fun PrimaryScreenPreview() {
 | 
			
		|||
    StudeezTheme {
 | 
			
		||||
        PrimaryScreenTemplate(
 | 
			
		||||
            "Preview screen",
 | 
			
		||||
            { _ -> {}},
 | 
			
		||||
            { _, _ -> {}},
 | 
			
		||||
            { IconButton(onClick = { /*TODO*/ }) {
 | 
			
		||||
                Icon(
 | 
			
		||||
                    imageVector = Icons.Default.Edit,
 | 
			
		||||
                    contentDescription = "Edit"
 | 
			
		||||
                )
 | 
			
		||||
            }}
 | 
			
		||||
            DrawerActions({}, {}, {}, {}, {}),
 | 
			
		||||
            NavigationBarActions({}, {}, {}, {}),
 | 
			
		||||
            {
 | 
			
		||||
                IconButton(onClick = { /*TODO*/ }) {
 | 
			
		||||
                    Icon(
 | 
			
		||||
                        imageVector = Icons.Default.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.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.Text
 | 
			
		||||
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.tooling.preview.Preview
 | 
			
		||||
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.resources
 | 
			
		||||
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
 | 
			
		||||
fun Drawer(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: DrawerViewModel = hiltViewModel()
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
) {
 | 
			
		||||
    Column (
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = Modifier.fillMaxWidth()
 | 
			
		||||
    ) {
 | 
			
		||||
        Column (
 | 
			
		||||
            modifier = Modifier.fillMaxWidth().weight(1f)
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .fillMaxWidth()
 | 
			
		||||
                .weight(1f)
 | 
			
		||||
        ) {
 | 
			
		||||
            DrawerEntry(
 | 
			
		||||
                icon = Icons.Default.Home,
 | 
			
		||||
                text = resources().getString(R.string.home)
 | 
			
		||||
            ) {
 | 
			
		||||
                viewModel.onHomeButtonClick(open)
 | 
			
		||||
            }
 | 
			
		||||
                text = resources().getString(R.string.home),
 | 
			
		||||
                onClick = drawerActions.onHomeButtonClick,
 | 
			
		||||
            )
 | 
			
		||||
            DrawerEntry(
 | 
			
		||||
                icon = ImageVector.vectorResource(id = R.drawable.ic_timer),
 | 
			
		||||
                text = resources().getString(R.string.timers)
 | 
			
		||||
            ) {
 | 
			
		||||
                viewModel.onTimersClick(open)
 | 
			
		||||
            }
 | 
			
		||||
                text = resources().getString(R.string.timers),
 | 
			
		||||
                onClick = drawerActions.onTimersClick,
 | 
			
		||||
            )
 | 
			
		||||
            DrawerEntry(
 | 
			
		||||
                icon = Icons.Default.Settings,
 | 
			
		||||
                text = resources().getString(R.string.settings)
 | 
			
		||||
            ) {
 | 
			
		||||
                viewModel.onSettingsClick(open)
 | 
			
		||||
            }
 | 
			
		||||
                text = resources().getString(R.string.settings),
 | 
			
		||||
                onClick = drawerActions.onSettingsClick,
 | 
			
		||||
            )
 | 
			
		||||
            DrawerEntry(
 | 
			
		||||
                icon = ImageVector.vectorResource(id = R.drawable.ic_logout),
 | 
			
		||||
                text = resources().getString(R.string.log_out)
 | 
			
		||||
            ) {
 | 
			
		||||
                viewModel.onLogoutClick(openAndPopUp)
 | 
			
		||||
            }
 | 
			
		||||
                text = resources().getString(R.string.log_out),
 | 
			
		||||
                onClick = drawerActions.onLogoutClick,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DrawerEntry(
 | 
			
		||||
            icon = Icons.Outlined.Info,
 | 
			
		||||
            text = resources().getString(R.string.about)
 | 
			
		||||
        ) {
 | 
			
		||||
            viewModel.onAboutClick(open)
 | 
			
		||||
        }
 | 
			
		||||
            text = resources().getString(R.string.about),
 | 
			
		||||
            onClick = drawerActions.onAboutClick,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,11 +119,8 @@ fun DrawerEntry(
 | 
			
		|||
@Preview
 | 
			
		||||
@Composable
 | 
			
		||||
fun DrawerPreview() {
 | 
			
		||||
    val drawerActions = DrawerActions({}, {}, {}, {}, {})
 | 
			
		||||
    StudeezTheme {
 | 
			
		||||
        Drawer(
 | 
			
		||||
            { _, -> {} },
 | 
			
		||||
            { _, _ -> {} },
 | 
			
		||||
            hiltViewModel()
 | 
			
		||||
        )
 | 
			
		||||
        Drawer(drawerActions)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.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.BottomNavigationItem
 | 
			
		||||
| 
						 | 
				
			
			@ -12,16 +12,32 @@ import androidx.compose.material.icons.outlined.DateRange
 | 
			
		|||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import be.ugent.sel.studeez.resources
 | 
			
		||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
 | 
			
		||||
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
 | 
			
		||||
fun NavigationBar(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    viewModel: NavigationBarViewModel = hiltViewModel()
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
) {
 | 
			
		||||
    // TODO Pass functions and new screens.
 | 
			
		||||
    // TODO Pass which screen is selected.
 | 
			
		||||
| 
						 | 
				
			
			@ -33,31 +49,43 @@ fun NavigationBar(
 | 
			
		|||
            icon = { Icon(imageVector = Icons.Default.List, resources().getString(AppText.home)) },
 | 
			
		||||
            label = { Text(text = resources().getString(AppText.home)) },
 | 
			
		||||
            selected = false, // TODO
 | 
			
		||||
            onClick = { viewModel.onHomeClick(open) }
 | 
			
		||||
            onClick = navigationBarActions.onHomeClick
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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)) },
 | 
			
		||||
            selected = false, // TODO
 | 
			
		||||
            onClick = { viewModel.onTasksClick(open) }
 | 
			
		||||
            onClick = navigationBarActions.onTasksClick
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // Hack to space the entries in the navigation bar, make space for fab
 | 
			
		||||
        BottomNavigationItem(icon = {}, onClick = {}, selected = false)
 | 
			
		||||
 | 
			
		||||
        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)) },
 | 
			
		||||
            selected = false, // TODO
 | 
			
		||||
            onClick = { viewModel.onSessionsClick(open) }
 | 
			
		||||
            onClick = navigationBarActions.onSessionsClick
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        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)) },
 | 
			
		||||
            selected = false, // TODO
 | 
			
		||||
            onClick = { viewModel.onProfileClick(open) }
 | 
			
		||||
            onClick = navigationBarActions.onProfileClick
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -67,9 +95,6 @@ fun NavigationBar(
 | 
			
		|||
@Composable
 | 
			
		||||
fun NavigationBarPreview() {
 | 
			
		||||
    StudeezTheme {
 | 
			
		||||
        NavigationBar(
 | 
			
		||||
            { _ -> {} },
 | 
			
		||||
            hiltViewModel()
 | 
			
		||||
        )
 | 
			
		||||
        NavigationBar(NavigationBarActions({}, {}, {}, {}))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.LogService
 | 
			
		||||
| 
						 | 
				
			
			@ -6,37 +6,69 @@ import androidx.compose.material.icons.Icons
 | 
			
		|||
import androidx.compose.material.icons.filled.Person
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
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.common.composable.BasicButton
 | 
			
		||||
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.resources
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun HomeScreen(
 | 
			
		||||
fun HomeRoute(
 | 
			
		||||
    open: (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(
 | 
			
		||||
        title = resources().getString(R.string.home),
 | 
			
		||||
        open = open,
 | 
			
		||||
        openAndPopUp = openAndPopUp,
 | 
			
		||||
        drawerActions = drawerActions,
 | 
			
		||||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
        action = { FriendsAction() }
 | 
			
		||||
    ) {
 | 
			
		||||
        BasicButton(R.string.start_session, Modifier.basicButton()) {
 | 
			
		||||
            viewModel.onStartSessionClick(open)
 | 
			
		||||
            onStartSessionClick()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun FriendsAction () {
 | 
			
		||||
fun FriendsAction() {
 | 
			
		||||
    IconButton(onClick = { /*TODO*/ }) {
 | 
			
		||||
        Icon(
 | 
			
		||||
            imageVector = Icons.Default.Person,
 | 
			
		||||
            contentDescription = resources().getString(R.string.friends)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@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.ui.Alignment
 | 
			
		||||
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.ext.basicButton
 | 
			
		||||
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.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
 | 
			
		||||
fun LoginScreen(
 | 
			
		||||
fun LoginRoute(
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    viewModel: LoginViewModel = hiltViewModel()
 | 
			
		||||
    viewModel: LoginViewModel,
 | 
			
		||||
) {
 | 
			
		||||
    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)) {
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = modifier
 | 
			
		||||
| 
						 | 
				
			
			@ -35,18 +69,42 @@ fun LoginScreen(
 | 
			
		|||
            verticalArrangement = Arrangement.Center,
 | 
			
		||||
            horizontalAlignment = Alignment.CenterHorizontally
 | 
			
		||||
        ) {
 | 
			
		||||
            EmailField(uiState.email, viewModel::onEmailChange, Modifier.fieldModifier())
 | 
			
		||||
            PasswordField(uiState.password, viewModel::onPasswordChange, Modifier.fieldModifier())
 | 
			
		||||
            EmailField(
 | 
			
		||||
                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()) {
 | 
			
		||||
                viewModel.onNotAlreadyUser(openAndPopUp)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            BasicTextButton(AppText.forgot_password, Modifier.textButton()) {
 | 
			
		||||
                viewModel.onForgotPasswordClick()
 | 
			
		||||
            }
 | 
			
		||||
            BasicTextButton(
 | 
			
		||||
                AppText.forgot_password,
 | 
			
		||||
                Modifier.textButton(),
 | 
			
		||||
                action = loginScreenActions.onForgotPasswordClick,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Preview
 | 
			
		||||
@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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable
 | 
			
		|||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import be.ugent.sel.studeez.R
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.BasicTextButton
 | 
			
		||||
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.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
 | 
			
		||||
fun EditProfileScreen(
 | 
			
		||||
    goBack: () -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: ProfileEditViewModel = hiltViewModel()
 | 
			
		||||
    uiState: ProfileEditUiState,
 | 
			
		||||
    editProfileActions: EditProfileActions,
 | 
			
		||||
) {
 | 
			
		||||
    val uiState by viewModel.uiState
 | 
			
		||||
 | 
			
		||||
    SecondaryScreenTemplate(
 | 
			
		||||
        title = resources().getString(R.string.editing_profile),
 | 
			
		||||
        popUp = goBack
 | 
			
		||||
| 
						 | 
				
			
			@ -29,16 +57,19 @@ fun EditProfileScreen(
 | 
			
		|||
        Column {
 | 
			
		||||
            LabelledInputField(
 | 
			
		||||
                value = uiState.username,
 | 
			
		||||
                onNewValue = viewModel::onUsernameChange,
 | 
			
		||||
                onNewValue = editProfileActions.onUserNameChange,
 | 
			
		||||
                label = R.string.username
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            BasicTextButton(text = R.string.save, Modifier.textButton()) {
 | 
			
		||||
                viewModel.onSaveClick()
 | 
			
		||||
            }
 | 
			
		||||
            BasicTextButton(text = R.string.delete_profile, Modifier.textButton()) {
 | 
			
		||||
                viewModel.onDeleteClick(openAndPopUp)
 | 
			
		||||
            }
 | 
			
		||||
            BasicTextButton(
 | 
			
		||||
                text = R.string.save,
 | 
			
		||||
                Modifier.textButton(),
 | 
			
		||||
                action = editProfileActions.onSaveClick
 | 
			
		||||
            )
 | 
			
		||||
            BasicTextButton(
 | 
			
		||||
                text = R.string.delete_profile,
 | 
			
		||||
                Modifier.textButton(),
 | 
			
		||||
                action = editProfileActions.onDeleteClick
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +78,6 @@ fun EditProfileScreen(
 | 
			
		|||
@Composable
 | 
			
		||||
fun EditProfileScreenComposable() {
 | 
			
		||||
    StudeezTheme {
 | 
			
		||||
        EditProfileScreen (
 | 
			
		||||
            {},
 | 
			
		||||
            {_, _ -> {}}
 | 
			
		||||
        )
 | 
			
		||||
        EditProfileScreen({}, ProfileEditUiState(), EditProfileActions({}, {}, {}))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,30 +4,68 @@ import androidx.compose.material.Icon
 | 
			
		|||
import androidx.compose.material.IconButton
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
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 be.ugent.sel.studeez.R
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.Headline
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
fun ProfileScreen(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: ProfileViewModel = hiltViewModel()
 | 
			
		||||
    profileActions: ProfileActions,
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
) {
 | 
			
		||||
    var username: String? by remember { mutableStateOf("") }
 | 
			
		||||
    LaunchedEffect(key1 = Unit) {
 | 
			
		||||
        username = viewModel.getUsername()
 | 
			
		||||
        username = profileActions.getUsername(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PrimaryScreenTemplate(
 | 
			
		||||
        title = resources().getString(AppText.profile),
 | 
			
		||||
        open = open,
 | 
			
		||||
        openAndPopUp = openAndPopUp,
 | 
			
		||||
        action = { EditAction { viewModel.onEditProfileClick(open) } }
 | 
			
		||||
        drawerActions = drawerActions,
 | 
			
		||||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
        action = { EditAction(onClick = profileActions.onEditProfileClick) }
 | 
			
		||||
    ) {
 | 
			
		||||
        Headline(text = (username ?: resources().getString(R.string.no_username)))
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +82,14 @@ 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.text.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.text.style.TextAlign
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
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.FunctionalTimer
 | 
			
		||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer.StudyState
 | 
			
		||||
import be.ugent.sel.studeez.resources
 | 
			
		||||
import kotlinx.coroutines.delay
 | 
			
		||||
import javax.inject.Singleton
 | 
			
		||||
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
 | 
			
		||||
fun SessionScreen(
 | 
			
		||||
fun SessionRoute(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: SessionViewModel = hiltViewModel()
 | 
			
		||||
    viewModel: SessionViewModel,
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
 | 
			
		||||
    val mediaplayer = MediaPlayer.create(context, uri)
 | 
			
		||||
    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(
 | 
			
		||||
       modifier = Modifier.padding(10.dp)
 | 
			
		||||
   ) {
 | 
			
		||||
        Timer(viewModel, mediaplayer)
 | 
			
		||||
        modifier = Modifier.padding(10.dp)
 | 
			
		||||
    ) {
 | 
			
		||||
        Timer(
 | 
			
		||||
            sessionActions = sessionActions
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        Box(
 | 
			
		||||
            contentAlignment = Alignment.Center,
 | 
			
		||||
| 
						 | 
				
			
			@ -61,12 +98,11 @@ fun SessionScreen(
 | 
			
		|||
        ) {
 | 
			
		||||
            TextButton(
 | 
			
		||||
                onClick = {
 | 
			
		||||
                    mediaplayer.stop()
 | 
			
		||||
                    mediaplayer.release()
 | 
			
		||||
                    sessionActions.releaseMediaPlayer
 | 
			
		||||
 | 
			
		||||
                    open(StudeezDestinations.HOME_SCREEN)
 | 
			
		||||
                    InvisibleSessionManager.isSession = false
 | 
			
		||||
                    // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(horizontal = 20.dp)
 | 
			
		||||
                    .border(1.dp, Color.Red, RoundedCornerShape(32.dp))
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +113,8 @@ fun SessionScreen(
 | 
			
		|||
                    color = Color.Red,
 | 
			
		||||
                    fontWeight = FontWeight.Bold,
 | 
			
		||||
                    fontSize = 18.sp,
 | 
			
		||||
                    modifier = Modifier.padding(1.dp)
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .padding(1.dp)
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -85,19 +122,21 @@ fun SessionScreen(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: MediaPlayer) {
 | 
			
		||||
private fun Timer(
 | 
			
		||||
    sessionActions: SessionActions
 | 
			
		||||
) {
 | 
			
		||||
    var tikker by remember { mutableStateOf(false) }
 | 
			
		||||
    LaunchedEffect(tikker) {
 | 
			
		||||
        delay(1.seconds)
 | 
			
		||||
        viewModel.getTimer().tick()
 | 
			
		||||
        sessionActions.getTimer().tick()
 | 
			
		||||
        tikker = !tikker
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) {
 | 
			
		||||
        mediaplayer.start()
 | 
			
		||||
    if (sessionActions.getTimer().hasCurrentCountdownEnded() && !sessionActions.getTimer().hasEnded()) {
 | 
			
		||||
        sessionActions.startMediaPlayer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val hms = viewModel.getTimer().getHoursMinutesSeconds()
 | 
			
		||||
    val hms = sessionActions.getTimer().getHoursMinutesSeconds()
 | 
			
		||||
    Column {
 | 
			
		||||
        Text(
 | 
			
		||||
            text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}",
 | 
			
		||||
| 
						 | 
				
			
			@ -108,14 +147,14 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me
 | 
			
		|||
            fontWeight = FontWeight.Bold,
 | 
			
		||||
            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.FOCUS -> resources().getString(R.string.state_focus)
 | 
			
		||||
            StudyState.BREAK -> resources().getString(R.string.state_take_a_break)
 | 
			
		||||
            StudyState.FOCUS_REMAINING ->
 | 
			
		||||
                (viewModel.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let {
 | 
			
		||||
                (sessionActions.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let {
 | 
			
		||||
                    resources().getQuantityString(R.plurals.state_focus_remaining, it, it)
 | 
			
		||||
            }.toString()
 | 
			
		||||
                }.toString()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Text(
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +178,7 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me
 | 
			
		|||
                    .background(Color.Blue, RoundedCornerShape(32.dp))
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(
 | 
			
		||||
                    text = viewModel.getTask(),
 | 
			
		||||
                    text = sessionActions.getTask(),
 | 
			
		||||
                    color = Color.White,
 | 
			
		||||
                    fontSize = 18.sp,
 | 
			
		||||
                    fontWeight = FontWeight.Bold,
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +190,8 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Singleton
 | 
			
		||||
object InvisibleSessionManager {
 | 
			
		||||
    private lateinit var viewModel: SessionViewModel
 | 
			
		||||
    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.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.*
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
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.fieldModifier
 | 
			
		||||
import be.ugent.sel.studeez.common.ext.textButton
 | 
			
		||||
import be.ugent.sel.studeez.resources
 | 
			
		||||
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
 | 
			
		||||
fun SignUpScreen(
 | 
			
		||||
fun SignUpRoute(
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    viewModel: SignUpViewModel = hiltViewModel()
 | 
			
		||||
    viewModel: SignUpViewModel,
 | 
			
		||||
) {
 | 
			
		||||
    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)) {
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = modifier
 | 
			
		||||
| 
						 | 
				
			
			@ -36,40 +77,45 @@ fun SignUpScreen(
 | 
			
		|||
            verticalArrangement = Arrangement.Center,
 | 
			
		||||
            horizontalAlignment = Alignment.CenterHorizontally
 | 
			
		||||
        ) {
 | 
			
		||||
 | 
			
		||||
            UsernameField(
 | 
			
		||||
                uiState.username,
 | 
			
		||||
                viewModel::onUsernameChange,
 | 
			
		||||
                signUpActions.onUserNameChange,
 | 
			
		||||
                fieldModifier
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            EmailField(
 | 
			
		||||
                uiState.email,
 | 
			
		||||
                viewModel::onEmailChange,
 | 
			
		||||
                signUpActions.onEmailChange,
 | 
			
		||||
                fieldModifier
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            PasswordField(
 | 
			
		||||
                uiState.password,
 | 
			
		||||
                viewModel::onPasswordChange,
 | 
			
		||||
                signUpActions.onPasswordChange,
 | 
			
		||||
                fieldModifier
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            RepeatPasswordField(
 | 
			
		||||
                uiState.repeatPassword,
 | 
			
		||||
                viewModel::onRepeatPasswordChange,
 | 
			
		||||
                signUpActions.onRepeatPasswordChange,
 | 
			
		||||
                fieldModifier
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            BasicButton(AppText.create_account, Modifier.basicButton()) {
 | 
			
		||||
                viewModel.onSignUpClick(openAndPopUp)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            BasicTextButton(AppText.already_user, Modifier.textButton()) {
 | 
			
		||||
                viewModel.onLoginScreenClick(openAndPopUp)
 | 
			
		||||
            }
 | 
			
		||||
            BasicButton(
 | 
			
		||||
                AppText.create_account,
 | 
			
		||||
                Modifier.basicButton(),
 | 
			
		||||
                onClick = signUpActions.onSignUpClick
 | 
			
		||||
            )
 | 
			
		||||
            BasicTextButton(
 | 
			
		||||
                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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ import androidx.compose.runtime.LaunchedEffect
 | 
			
		|||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
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.ext.basicButton
 | 
			
		||||
import kotlinx.coroutines.delay
 | 
			
		||||
| 
						 | 
				
			
			@ -24,14 +24,26 @@ import be.ugent.sel.studeez.R.string as AppText
 | 
			
		|||
private const val SPLASH_TIMEOUT = 500L
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun SplashScreen(
 | 
			
		||||
fun SplashRoute(
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    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(
 | 
			
		||||
        modifier =
 | 
			
		||||
        modifier
 | 
			
		||||
        modifier = modifier
 | 
			
		||||
            .fillMaxWidth()
 | 
			
		||||
            .fillMaxHeight()
 | 
			
		||||
            .background(color = MaterialTheme.colors.background)
 | 
			
		||||
| 
						 | 
				
			
			@ -39,17 +51,37 @@ fun SplashScreen(
 | 
			
		|||
        verticalArrangement = Arrangement.Center,
 | 
			
		||||
        horizontalAlignment = Alignment.CenterHorizontally
 | 
			
		||||
    ) {
 | 
			
		||||
        if (viewModel.showError.value) {
 | 
			
		||||
        if (showError) {
 | 
			
		||||
            Text(text = stringResource(AppText.generic_error))
 | 
			
		||||
 | 
			
		||||
            BasicButton(AppText.try_again, Modifier.basicButton()) { viewModel.onAppStart(openAndPopUp) }
 | 
			
		||||
            BasicButton(
 | 
			
		||||
                AppText.try_again,
 | 
			
		||||
                Modifier.basicButton(),
 | 
			
		||||
                onClick = onAppStart,
 | 
			
		||||
            )
 | 
			
		||||
        } else {
 | 
			
		||||
            CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LaunchedEffect(true) {
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
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.foundation.lazy.LazyColumn
 | 
			
		||||
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.collectAsState
 | 
			
		||||
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 androidx.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import be.ugent.sel.studeez.R
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.BasicButton
 | 
			
		||||
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.common.ext.basicButton
 | 
			
		||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
 | 
			
		||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
 | 
			
		||||
import be.ugent.sel.studeez.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
 | 
			
		||||
fun TimerOverviewScreen(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: TimerOverviewViewModel = hiltViewModel()
 | 
			
		||||
    timerOverviewActions: TimerOverviewActions,
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
    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(
 | 
			
		||||
        title = resources().getString(R.string.timers),
 | 
			
		||||
        open = open,
 | 
			
		||||
        openAndPopUp = openAndPopUp
 | 
			
		||||
        drawerActions = drawerActions,
 | 
			
		||||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        Column {
 | 
			
		||||
            LazyColumn(
 | 
			
		||||
                verticalArrangement = Arrangement.spacedBy(7.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                // Default Timers, cannot be edited
 | 
			
		||||
                items(viewModel.getDefaultTimers()) {
 | 
			
		||||
                    TimerEntry(timerInfo = it, canDisplay = false)
 | 
			
		||||
                items(timerOverviewActions.getDefaultTimers()) {
 | 
			
		||||
                    TimerEntry(timerInfo = it) {}
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // User timers, can be edited
 | 
			
		||||
                items(timers.value) {
 | 
			
		||||
                    TimerEntry(timerInfo = it, true, R.string.edit) { timerInfo ->
 | 
			
		||||
                        viewModel.update(timerInfo)
 | 
			
		||||
                items(timers.value) { timerInfo ->
 | 
			
		||||
                    TimerEntry(
 | 
			
		||||
                        timerInfo = timerInfo,
 | 
			
		||||
                    ) {
 | 
			
		||||
                        StealthButton(
 | 
			
		||||
                            text = R.string.edit,
 | 
			
		||||
                            onClick = { timerOverviewActions.onEditClick(timerInfo) }
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            BasicButton(R.string.add_timer, Modifier.basicButton()) {
 | 
			
		||||
                // 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
 | 
			
		||||
@Composable
 | 
			
		||||
fun TimerEntryPreview() {
 | 
			
		||||
    val timerInfo = CustomTimerInfo(
 | 
			
		||||
        "my preview timer",
 | 
			
		||||
        "This is the description of the timer",
 | 
			
		||||
        60
 | 
			
		||||
fun TimerOverviewPreview() {
 | 
			
		||||
    val customTimer = CustomTimerInfo(
 | 
			
		||||
        "my preview timer", "This is the description of the timer", 60
 | 
			
		||||
    )
 | 
			
		||||
    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) { }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    TimerOverviewScreen(
 | 
			
		||||
        timerOverviewActions = TimerOverviewActions(
 | 
			
		||||
            { flowOf() },
 | 
			
		||||
            { listOf(customTimer, customTimer) },
 | 
			
		||||
            {}),
 | 
			
		||||
        drawerActions = DrawerActions({}, {}, {}, {}, {}),
 | 
			
		||||
        navigationBarActions = NavigationBarActions({}, {}, {}, {})
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,42 +3,89 @@ package be.ugent.sel.studeez.screens.timer_selection
 | 
			
		|||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
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.hilt.navigation.compose.hiltViewModel
 | 
			
		||||
import be.ugent.sel.studeez.R
 | 
			
		||||
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.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
 | 
			
		||||
fun TimerSelectionScreen(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    openAndPopUp: (String, String) -> Unit,
 | 
			
		||||
    viewModel: TimerSelectionViewModel = hiltViewModel()
 | 
			
		||||
    timerSelectionActions: TimerSelectionActions,
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    val timers = viewModel.getAllTimers().collectAsState(initial = emptyList())
 | 
			
		||||
 | 
			
		||||
    val timers = timerSelectionActions.getAllTimers().collectAsState(initial = emptyList())
 | 
			
		||||
    PrimaryScreenTemplate(
 | 
			
		||||
        title = resources().getString(R.string.timers),
 | 
			
		||||
        open = open,
 | 
			
		||||
        openAndPopUp = openAndPopUp,
 | 
			
		||||
        drawerActions = drawerActions,
 | 
			
		||||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) {
 | 
			
		||||
 | 
			
		||||
            // All timers
 | 
			
		||||
            items(timers.value) {
 | 
			
		||||
            items(timers.value) { timerInfo ->
 | 
			
		||||
                TimerEntry(
 | 
			
		||||
                    timerInfo = it,
 | 
			
		||||
                    canDisplay = true,
 | 
			
		||||
                    buttonName = R.string.start
 | 
			
		||||
                ) { timerInfo ->
 | 
			
		||||
                    viewModel.startSession(open, timerInfo)
 | 
			
		||||
                    timerInfo = timerInfo,
 | 
			
		||||
                ) {
 | 
			
		||||
                    StealthButton(
 | 
			
		||||
                        text = R.string.start,
 | 
			
		||||
                        onClick = { timerSelectionActions.startSession(timerInfo) }
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Preview
 | 
			
		||||
@Composable
 | 
			
		||||
fun TimerSelectionPreview() {
 | 
			
		||||
    TimerSelectionScreen(
 | 
			
		||||
        timerSelectionActions = TimerSelectionActions({ flowOf() }, {}),
 | 
			
		||||
        drawerActions = DrawerActions({}, {}, {}, {}, {}),
 | 
			
		||||
        navigationBarActions = NavigationBarActions({}, {}, {}, {}),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
		Reference in a new issue