diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..0ad17cb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index a6830a5..c8a133b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -11,6 +11,7 @@ import androidx.compose.material.Surface import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier @@ -21,9 +22,14 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +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.snackbar.SnackbarManager import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.screens.home.HomeRoute @@ -31,6 +37,7 @@ 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.session_recap.SessionRecapRoute 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 @@ -89,43 +96,52 @@ fun StudeezNavGraph( val drawerViewModel: DrawerViewModel = hiltViewModel() val navBarViewModel: NavigationBarViewModel = hiltViewModel() + val backStackEntry by appState.navController.currentBackStackEntryAsState() + val getCurrentScreen: () -> String? = { backStackEntry?.destination?.route } + + val goBack: () -> Unit = { appState.popUp() } + val open: (String) -> Unit = { appState.navigate(it) } + val openAndPopUp: (String, String) -> Unit = + { route, popUp -> appState.navigateAndPopUp(route, popUp) } + + val drawerActions: DrawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp) + val navigationBarActions: NavigationBarActions = + getNavigationBarActions(navBarViewModel, open, getCurrentScreen) + 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()) + SplashRoute( + openAndPopUp, + viewModel = hiltViewModel(), + ) } composable(StudeezDestinations.LOGIN_SCREEN) { - LoginRoute(openAndPopUp, viewModel = hiltViewModel()) + LoginRoute( + openAndPopUp, + viewModel = hiltViewModel(), + ) } composable(StudeezDestinations.SIGN_UP_SCREEN) { - SignUpRoute(openAndPopUp, viewModel = hiltViewModel()) + SignUpRoute( + openAndPopUp, + viewModel = hiltViewModel(), + ) } composable(StudeezDestinations.HOME_SCREEN) { HomeRoute( open, - openAndPopUp, viewModel = hiltViewModel(), - drawerViewModel = drawerViewModel, - navBarViewModel = navBarViewModel, + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, ) } @@ -133,21 +149,27 @@ fun StudeezNavGraph( // TODO Sessions screen composable(StudeezDestinations.PROFILE_SCREEN) { - ProfileRoute(open, openAndPopUp, viewModel = hiltViewModel()) + ProfileRoute( + open, + viewModel = hiltViewModel(), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, + ) } composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) { TimerOverviewRoute( - open, - openAndPopUp, viewModel = hiltViewModel(), - drawerViewModel = drawerViewModel, - navBarViewModel = navBarViewModel, + drawerActions = drawerActions, ) } composable(StudeezDestinations.SESSION_SCREEN) { - SessionRoute(open, viewModel = hiltViewModel()) + SessionRoute( + open, + openAndPopUp, + viewModel = hiltViewModel() + ) } // TODO Timers screen @@ -155,16 +177,25 @@ fun StudeezNavGraph( // Edit screens composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { - EditProfileRoute(goBack, openAndPopUp, viewModel = hiltViewModel()) + EditProfileRoute( + goBack, + openAndPopUp, + viewModel = hiltViewModel(), + ) } composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { TimerSelectionRoute( open, - openAndPopUp, + goBack, viewModel = hiltViewModel(), - drawerViewModel = drawerViewModel, - navBarViewModel = navBarViewModel, + ) + } + + composable(StudeezDestinations.SESSION_RECAP) { + SessionRecapRoute( + openAndPopUp = openAndPopUp, + viewModel = hiltViewModel() ) } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index b2568aa..3fa9bd2 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -3,15 +3,9 @@ package be.ugent.sel.studeez.common.composable import androidx.annotation.StringRes import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Button -import androidx.compose.material.ButtonColors -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.material.TextButton +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -21,7 +15,6 @@ import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.common.ext.card @Composable - fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { TextButton(onClick = action, modifier = modifier) { Text(text = stringResource(text)) } } @@ -64,10 +57,10 @@ fun StealthButton( onClick = onClick, modifier = Modifier.card(), colors = ButtonDefaults.buttonColors( - backgroundColor = Color.Transparent, - contentColor = Color.DarkGray, + backgroundColor = MaterialTheme.colors.surface, + contentColor = MaterialTheme.colors.onSurface ), - border = BorderStroke(3.dp, Color.DarkGray), + border = BorderStroke(1.dp, MaterialTheme.colors.onSurface) ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/DrawerScreenComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/DrawerScreenComposable.kt new file mode 100644 index 0000000..b0b1829 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/DrawerScreenComposable.kt @@ -0,0 +1,64 @@ +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.icons.Icons +import androidx.compose.material.icons.filled.Menu +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.common.composable.drawer.Drawer +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.ui.theme.StudeezTheme +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun DrawerScreenTemplate( + title: String, + drawerActions: DrawerActions, + barAction: @Composable RowScope.() -> Unit = {}, + content: @Composable (PaddingValues) -> Unit +) { + val scaffoldState: ScaffoldState = rememberScaffoldState() + val coroutineScope: CoroutineScope = rememberCoroutineScope() + + 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(AppText.menu) + ) + } + }, + actions = barAction + )}, + + drawerContent = { + Drawer(drawerActions) + } + ) { + content(it) + } +} + +@Preview +@Composable +fun DrawerScreenPreview() { + StudeezTheme { DrawerScreenTemplate( + title = "Drawer screen preview", + drawerActions =DrawerActions({}, {}, {}, {}, {}) + ) { + Text(text = "Preview content") + } } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt index 5af2788..79dec41 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt @@ -2,26 +2,19 @@ package be.ugent.sel.studeez.common.composable import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope -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.* 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.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.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -31,7 +24,7 @@ fun PrimaryScreenTemplate( title: String, drawerActions: DrawerActions, navigationBarActions: NavigationBarActions, - action: @Composable RowScope.() -> Unit = {}, + barAction: @Composable RowScope.() -> Unit = {}, content: @Composable (PaddingValues) -> Unit ) { val scaffoldState: ScaffoldState = rememberScaffoldState() @@ -53,7 +46,7 @@ fun PrimaryScreenTemplate( ) } }, - actions = action + actions = barAction ) }, @@ -77,7 +70,7 @@ fun PrimaryScreenPreview() { PrimaryScreenTemplate( "Preview screen", DrawerActions({}, {}, {}, {}, {}), - NavigationBarActions({}, {}, {}, {}), + NavigationBarActions({ false }, {}, {}, {}, {}), { IconButton(onClick = { /*TODO*/ }) { Icon( diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/SecondaryScreenComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/SecondaryScreenComposable.kt index 5470566..5999072 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/SecondaryScreenComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/SecondaryScreenComposable.kt @@ -1,6 +1,7 @@ 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.icons.Icons import androidx.compose.material.icons.filled.ArrowBack @@ -10,13 +11,12 @@ import be.ugent.sel.studeez.R import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme -// TODO Add option for button in top right corner as extra button - @Composable // Does not contain floatingActionButton and bottom bar, used in all the other screens fun SecondaryScreenTemplate( title: String, popUp: () -> Unit, + barAction: @Composable RowScope.() -> Unit = {}, content: @Composable (PaddingValues) -> Unit ) { Scaffold( @@ -30,7 +30,8 @@ fun SecondaryScreenTemplate( contentDescription = resources().getString(R.string.go_back) ) } - } + }, + actions = barAction ) }, ) { paddingValues -> content(paddingValues) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimerEntry.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimerEntry.kt index bfa2711..7dc105b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimerEntry.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimerEntry.kt @@ -1,10 +1,6 @@ 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.foundation.layout.* import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -20,24 +16,39 @@ import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo @Composable fun TimerEntry( timerInfo: TimerInfo, - button: @Composable () -> Unit, + rightButton: @Composable () -> Unit = {}, + leftButton: @Composable () -> Unit = {} ) { Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween + modifier = Modifier.fillMaxWidth() ) { - Column( - Modifier.padding(horizontal = 10.dp) + Row( + modifier = Modifier.weight(1f) ) { - Text( - text = timerInfo.name, fontWeight = FontWeight.Bold, fontSize = 20.sp - ) - Text( - text = timerInfo.description, fontWeight = FontWeight.Light, fontSize = 15.sp - ) + Box(modifier = Modifier.align(alignment = Alignment.CenterVertically)) { + leftButton() + } + + Column( + Modifier.padding( + horizontal = 20.dp, + vertical = 11.dp + ) + ) { + Text( + text = timerInfo.name, + fontWeight = FontWeight.Medium, + fontSize = 20.sp + ) + Text( + text = timerInfo.description, fontWeight = FontWeight.Light, fontSize = 14.sp + ) + } + } + + Box(modifier = Modifier.align(alignment = Alignment.CenterVertically)) { + rightButton() } - button() } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index 21311ef..79186b5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -12,11 +12,14 @@ 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 be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN 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 isSelectedTab: (String) -> Boolean, val onHomeClick: () -> Unit, val onTasksClick: () -> Unit, val onSessionsClick: () -> Unit, @@ -26,29 +29,38 @@ data class NavigationBarActions( fun getNavigationBarActions( navigationBarViewModel: NavigationBarViewModel, open: (String) -> Unit, + getCurrentScreen: () -> String? ): NavigationBarActions { return NavigationBarActions( - onHomeClick = { navigationBarViewModel.onHomeClick(open) }, - onTasksClick = { navigationBarViewModel.onTasksClick(open) }, - onSessionsClick = { navigationBarViewModel.onSessionsClick(open) }, - onProfileClick = { navigationBarViewModel.onProfileClick(open) }, + isSelectedTab = { screen -> + screen == getCurrentScreen() + }, + onHomeClick = { + navigationBarViewModel.onHomeClick(open) + }, + onTasksClick = { + navigationBarViewModel.onTasksClick(open) + }, + onSessionsClick = { + navigationBarViewModel.onSessionsClick(open) + }, + onProfileClick = { + navigationBarViewModel.onProfileClick(open) + }, ) } @Composable fun NavigationBar( - navigationBarActions: NavigationBarActions, + navigationBarActions: NavigationBarActions ) { - // TODO Pass functions and new screens. - // TODO Pass which screen is selected. - // TODO Disabled -> HIGH/MEDIUM_EMPHASIS if the page is implemented BottomNavigation( elevation = 10.dp ) { BottomNavigationItem( icon = { Icon(imageVector = Icons.Default.List, resources().getString(AppText.home)) }, label = { Text(text = resources().getString(AppText.home)) }, - selected = false, // TODO + selected = navigationBarActions.isSelectedTab(HOME_SCREEN), onClick = navigationBarActions.onHomeClick ) @@ -59,7 +71,8 @@ fun NavigationBar( ) }, label = { Text(text = resources().getString(AppText.tasks)) }, - selected = false, // TODO + // TODO selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), + selected = false, onClick = navigationBarActions.onTasksClick ) @@ -73,7 +86,8 @@ fun NavigationBar( ) }, label = { Text(text = resources().getString(AppText.sessions)) }, - selected = false, // TODO + // TODO selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), + selected = false, onClick = navigationBarActions.onSessionsClick ) @@ -84,7 +98,7 @@ fun NavigationBar( ) }, label = { Text(text = resources().getString(AppText.profile)) }, - selected = false, // TODO + selected = navigationBarActions.isSelectedTab(PROFILE_SCREEN), onClick = navigationBarActions.onProfileClick ) @@ -95,6 +109,8 @@ fun NavigationBar( @Composable fun NavigationBarPreview() { StudeezTheme { - NavigationBar(NavigationBarActions({}, {}, {}, {})) + NavigationBar( + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}), + ) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/SessionReportState.kt b/app/src/main/java/be/ugent/sel/studeez/data/SessionReportState.kt new file mode 100644 index 0000000..47770d0 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/SessionReportState.kt @@ -0,0 +1,14 @@ +package be.ugent.sel.studeez.data + +import be.ugent.sel.studeez.data.local.models.SessionReport +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Used to communicate the SelectedTimer from the selection screen to the session screen. + * Because this is a singleton-class the view-models of both screens observe the same data. + */ +@Singleton +class SessionReportState @Inject constructor(){ + var sessionReport: SessionReport? = null +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt index 94871ee..7038c7d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt @@ -5,6 +5,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) { override fun tick() { if (!hasEnded()) { time.minOne() + totalStudyTime++ } } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt index 67ed4e1..41be874 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt @@ -12,6 +12,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) { override fun tick() { time.plusOne() + totalStudyTime++ } override fun accept(visitor: FunctionalTimerVisitor): T { diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt index 6dac7c6..8eeb1c6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt @@ -23,6 +23,10 @@ class FunctionalPomodoroTimer( isInBreak = !isInBreak } time.minOne() + + if (!isInBreak) { + totalStudyTime++ + } } override fun hasEnded(): Boolean { diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt index 2d904d8..e95bbfb 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt @@ -1,7 +1,11 @@ package be.ugent.sel.studeez.data.local.models.timer_functional +import be.ugent.sel.studeez.data.local.models.SessionReport +import com.google.firebase.Timestamp + abstract class FunctionalTimer(initialValue: Int) { val time: Time = Time(initialValue) + var totalStudyTime: Int = 0 fun getHoursMinutesSeconds(): HoursMinutesSeconds { return time.getAsHMS() @@ -13,5 +17,12 @@ abstract class FunctionalTimer(initialValue: Int) { abstract fun hasCurrentCountdownEnded(): Boolean + fun getSessionReport(): SessionReport { + return SessionReport( + studyTime = totalStudyTime, + endTime = Timestamp.now() + ) + } + abstract fun accept(visitor: FunctionalTimerVisitor): T } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index 760c814..ab10c22 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -9,6 +9,7 @@ object StudeezDestinations { const val TIMER_OVERVIEW_SCREEN = "timer_overview" const val TIMER_SELECTION_SCREEN = "timer_selection" const val SESSION_SCREEN = "session" + const val SESSION_RECAP = "session_recap" // const val TASKS_SCREEN = "tasks" // const val SESSIONS_SCREEN = "sessions" const val PROFILE_SCREEN = "profile" diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt index e318655..1f760e5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt @@ -11,26 +11,21 @@ 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 HomeRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit, viewModel: HomeViewModel, - drawerViewModel: DrawerViewModel, - navBarViewModel: NavigationBarViewModel, + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions, ) { HomeScreen( onStartSessionClick = { viewModel.onStartSessionClick(open) }, - drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), - navigationBarActions = getNavigationBarActions(navBarViewModel, open), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, ) } @@ -40,12 +35,11 @@ fun HomeScreen( drawerActions: DrawerActions, navigationBarActions: NavigationBarActions, ) { - PrimaryScreenTemplate( title = resources().getString(R.string.home), drawerActions = drawerActions, navigationBarActions = navigationBarActions, - action = { FriendsAction() } + barAction = { FriendsAction() } ) { BasicButton(R.string.start_session, Modifier.basicButton()) { onStartSessionClick() @@ -69,6 +63,6 @@ fun HomeScreenPreview() { HomeScreen( onStartSessionClick = {}, drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({}, {}, {}, {}) + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt index a12dd08..0b4a67f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt @@ -11,15 +11,12 @@ 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 be.ugent.sel.studeez.resources import kotlinx.coroutines.CoroutineScope import be.ugent.sel.studeez.R.string as AppText @@ -41,13 +38,14 @@ fun getProfileActions( @Composable fun ProfileRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit, viewModel: ProfileViewModel, + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions, ) { ProfileScreen( profileActions = getProfileActions(viewModel, open), - drawerActions = getDrawerActions(hiltViewModel(), open, openAndPopUp), - navigationBarActions = getNavigationBarActions(hiltViewModel(), open), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, ) } @@ -65,7 +63,7 @@ fun ProfileScreen( title = resources().getString(AppText.profile), drawerActions = drawerActions, navigationBarActions = navigationBarActions, - action = { EditAction(onClick = profileActions.onEditProfileClick) } + barAction = { EditAction(onClick = profileActions.onEditProfileClick) } ) { Headline(text = (username ?: resources().getString(R.string.no_username))) } @@ -90,6 +88,6 @@ fun ProfileScreenPreview() { ProfileScreen( profileActions = ProfileActions({ null }, {}), drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({}, {}, {}, {}) + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) ) } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt index 680212d..084ff43 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt @@ -14,15 +14,18 @@ data class SessionActions( val getTask: () -> String, val startMediaPlayer: () -> Unit, val releaseMediaPlayer: () -> Unit, + val endSession: () -> Unit ) private fun getSessionActions( viewModel: SessionViewModel, + openAndPopUp: (String, String) -> Unit, mediaplayer: MediaPlayer, ): SessionActions { return SessionActions( getTimer = viewModel::getTimer, getTask = viewModel::getTask, + endSession = { viewModel.endSession(openAndPopUp) }, startMediaPlayer = mediaplayer::start, releaseMediaPlayer = mediaplayer::release, ) @@ -31,6 +34,7 @@ private fun getSessionActions( @Composable fun SessionRoute( open: (String) -> Unit, + openAndPopUp: (String, String) -> Unit, viewModel: SessionViewModel, ) { val context = LocalContext.current @@ -47,6 +51,6 @@ fun SessionRoute( sessionScreen( open = open, - sessionActions = getSessionActions(viewModel, mediaplayer) + sessionActions = getSessionActions(viewModel, openAndPopUp, mediaplayer) ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionViewModel.kt index b45364e..d5e2bab 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionViewModel.kt @@ -1,20 +1,21 @@ package be.ugent.sel.studeez.screens.session +import be.ugent.sel.studeez.data.SelectedTimerState +import be.ugent.sel.studeez.data.SessionReportState import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.screens.StudeezViewModel -import be.ugent.sel.studeez.data.SelectedTimerState -import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class SessionViewModel @Inject constructor( private val selectedTimerState: SelectedTimerState, + private val sessionReportState: SessionReportState, logService: LogService ) : StudeezViewModel(logService) { - private val timer: FunctionalTimer = FunctionalPomodoroTimer(15, 5, 3) private val task : String = "No task selected" // placeholder for tasks implementation fun getTimer() : FunctionalTimer { @@ -24,4 +25,9 @@ class SessionViewModel @Inject constructor( fun getTask(): String { return task } + + fun endSession(openAndPopUp: (String, String) -> Unit) { + sessionReportState.sessionReport = getTimer().getSessionReport() + openAndPopUp(StudeezDestinations.SESSION_RECAP, StudeezDestinations.SESSION_SCREEN) + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt index f268edb..4c0cc3e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer -import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.screens.session.SessionActions import kotlinx.coroutines.delay import kotlin.time.Duration.Companion.seconds @@ -45,8 +44,7 @@ abstract class AbstractSessionScreen { TextButton( onClick = { sessionActions.releaseMediaPlayer - open(StudeezDestinations.HOME_SCREEN) - // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt + sessionActions.endSession() }, modifier = Modifier .padding(horizontal = 20.dp) @@ -136,5 +134,5 @@ fun TimerPreview() { override fun callMediaPlayer() {} } - sessionScreen.Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {})) + sessionScreen.Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {}, {})) } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt new file mode 100644 index 0000000..2ddbc32 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt @@ -0,0 +1,65 @@ +package be.ugent.sel.studeez.screens.session_recap + +import androidx.compose.foundation.layout.Column +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.composable.BasicButton +import be.ugent.sel.studeez.common.ext.basicButton +import be.ugent.sel.studeez.data.local.models.SessionReport +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.data.local.models.timer_functional.Time + +data class SessionRecapActions( + val getSessionReport: () -> SessionReport, + val saveSession: () -> Unit, + val discardSession: () -> Unit +) + +fun getSessionRecapActions( + viewModel: SessionRecapViewModel, + openAndPopUp: (String, String) -> Unit, +): SessionRecapActions { + return SessionRecapActions( + viewModel::getSessionReport, + {viewModel.saveSession(openAndPopUp)}, + {viewModel.discardSession(openAndPopUp)} + ) +} + +@Composable +fun SessionRecapRoute( + openAndPopUp: (String, String) -> Unit, + modifier: Modifier = Modifier, + viewModel: SessionRecapViewModel, +) { + SessionRecapScreen( + modifier = modifier, + getSessionRecapActions(viewModel, openAndPopUp) + ) +} + +@Composable +fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActions) { + val sessionReport: SessionReport = sessionRecapActions.getSessionReport() + val studyTime: Int = sessionReport.studyTime + val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() + Column { + Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}") + + BasicButton( + R.string.save, Modifier.basicButton() + ) { + sessionRecapActions.saveSession() + } + BasicButton( + R.string.discard, Modifier.basicButton(), + colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red) + ) { + sessionRecapActions.discardSession() + } + } +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapViewModel.kt new file mode 100644 index 0000000..e9ad6b1 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapViewModel.kt @@ -0,0 +1,33 @@ +package be.ugent.sel.studeez.screens.session_recap + +import be.ugent.sel.studeez.data.SessionReportState +import be.ugent.sel.studeez.data.local.models.SessionReport +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.domain.SessionDAO +import be.ugent.sel.studeez.navigation.StudeezDestinations +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class SessionRecapViewModel @Inject constructor( + private val sessionReportState: SessionReportState, + private val sessionDAO: SessionDAO, + logService: LogService +) : StudeezViewModel(logService) { + + private val report: SessionReport = sessionReportState.sessionReport!! + + fun getSessionReport(): SessionReport { + return report + } + + fun saveSession(open: (String, String) -> Unit) { + sessionDAO.saveSession(getSessionReport()) + open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP) + } + + fun discardSession(open: (String, String) -> Unit) { + open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP) + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt index fafdf02..9489a30 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt @@ -1,6 +1,5 @@ package be.ugent.sel.studeez.screens.timer_overview -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -8,18 +7,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.BasicButton -import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate +import be.ugent.sel.studeez.common.composable.DrawerScreenTemplate 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 @@ -45,38 +38,29 @@ fun getTimerOverviewActions( @Composable fun TimerOverviewRoute( - open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit, viewModel: TimerOverviewViewModel, - drawerViewModel: DrawerViewModel, - navBarViewModel: NavigationBarViewModel, + drawerActions: DrawerActions, ) { TimerOverviewScreen( timerOverviewActions = getTimerOverviewActions(viewModel), - drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), - navigationBarActions = getNavigationBarActions(navBarViewModel, open), + drawerActions = drawerActions, ) } @Composable fun TimerOverviewScreen( timerOverviewActions: TimerOverviewActions, - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions, + drawerActions: DrawerActions ) { val timers = timerOverviewActions.getUserTimers().collectAsState(initial = emptyList()) - // TODO moet geen primary screen zijn: geen navbar nodig - PrimaryScreenTemplate( + DrawerScreenTemplate( title = resources().getString(R.string.timers), - drawerActions = drawerActions, - navigationBarActions = navigationBarActions, + drawerActions = drawerActions ) { Column { - LazyColumn( - verticalArrangement = Arrangement.spacedBy(7.dp) - ) { + LazyColumn { // Default Timers, cannot be edited items(timerOverviewActions.getDefaultTimers()) { TimerEntry(timerInfo = it) {} @@ -112,7 +96,6 @@ fun TimerOverviewPreview() { { flowOf() }, { listOf(customTimer, customTimer) }, {}), - drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({}, {}, {}, {}) + drawerActions = DrawerActions({}, {}, {}, {}, {}) ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index 47e7f91..ac46b5c 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -1,22 +1,14 @@ 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.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.R -import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate 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 kotlinx.coroutines.flow.Flow @@ -40,41 +32,37 @@ fun getTimerSelectionActions( @Composable fun TimerSelectionRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit, + popUp: () -> Unit, viewModel: TimerSelectionViewModel, - drawerViewModel: DrawerViewModel, - navBarViewModel: NavigationBarViewModel, ) { TimerSelectionScreen( timerSelectionActions = getTimerSelectionActions(viewModel, open), - drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), - navigationBarActions = getNavigationBarActions(navBarViewModel, open), + popUp = popUp ) } @Composable fun TimerSelectionScreen( timerSelectionActions: TimerSelectionActions, - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions, + popUp: () -> Unit ) { val timers = timerSelectionActions.getAllTimers().collectAsState(initial = emptyList()) - PrimaryScreenTemplate( + SecondaryScreenTemplate( title = resources().getString(R.string.timers), - drawerActions = drawerActions, - navigationBarActions = navigationBarActions, + popUp = popUp ) { - LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) { + LazyColumn { // All timers items(timers.value) { timerInfo -> TimerEntry( timerInfo = timerInfo, - ) { - StealthButton( - text = R.string.start, - onClick = { timerSelectionActions.startSession(timerInfo) } - ) - } + leftButton = { + StealthButton( + text = R.string.start, + onClick = { timerSelectionActions.startSession(timerInfo) } + ) + } + ) } } } @@ -85,7 +73,6 @@ fun TimerSelectionScreen( fun TimerSelectionPreview() { TimerSelectionScreen( timerSelectionActions = TimerSelectionActions({ flowOf() }, {}), - drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({}, {}, {}, {}), + popUp = {} ) } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 03900b3..5b9f561 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ Confirm Save + Discard Cancel Go back Next