diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 53a1745..cd54531 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -42,5 +42,6 @@
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index bca9a30..6489d31 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -66,6 +66,7 @@ dependencies {
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.compose.material:material:1.2.0'
+
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
// ViewModel
@@ -97,6 +98,9 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ // Coroutine testing
+ testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
+
// Mocking
testImplementation 'org.mockito.kotlin:mockito-kotlin:3.2.0'
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 d7465b0..673058e 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
@@ -90,43 +97,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,
)
}
@@ -134,21 +150,28 @@ 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,
+ open = open
)
}
composable(StudeezDestinations.SESSION_SCREEN) {
- SessionRoute(open, viewModel = hiltViewModel())
+ SessionRoute(
+ open,
+ openAndPopUp,
+ viewModel = hiltViewModel()
+ )
}
// TODO Timers screen
@@ -156,16 +179,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/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt
index 318fe7a..b020cc8 100644
--- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt
+++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt
@@ -10,9 +10,15 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.lifecycleScope
import be.ugent.sel.studeez.StudeezApp
+import be.ugent.sel.studeez.screens.session.InvisibleSessionManager
import be.ugent.sel.studeez.ui.theme.StudeezTheme
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+var onTimerInvisible: Job? = null
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@@ -30,6 +36,18 @@ class MainActivity : ComponentActivity() {
}
}
}
+
+ override fun onStop() {
+ onTimerInvisible = lifecycleScope.launch {
+ InvisibleSessionManager.updateTimer()
+ }
+ super.onStop()
+ }
+
+ override fun onStart() {
+ onTimerInvisible?.cancel()
+ super.onStart()
+ }
}
@Composable
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 79845ec..86464f9 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,
@@ -71,10 +64,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 ab533dd..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
@@ -3,19 +3,22 @@ package be.ugent.sel.studeez.data.local.models.timer_functional
class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) {
override fun tick() {
- if (time.time == 0) {
- view = StudyState.DONE
- } else {
+ if (!hasEnded()) {
time.minOne()
+ totalStudyTime++
}
}
override fun hasEnded(): Boolean {
- return view == StudyState.DONE
- }
-
- override fun hasCurrentCountdownEnded(): Boolean {
return time.time == 0
}
+ override fun hasCurrentCountdownEnded(): Boolean {
+ return hasEnded()
+ }
+
+ override fun accept(visitor: FunctionalTimerVisitor): T {
+ return visitor.visitFunctionalCustomTimer(this)
+ }
+
}
\ No newline at end of file
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 70fcf7d..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
@@ -1,6 +1,6 @@
package be.ugent.sel.studeez.data.local.models.timer_functional
-class FunctionalEndlessTimer() : FunctionalTimer(0) {
+class FunctionalEndlessTimer : FunctionalTimer(0) {
override fun hasEnded(): Boolean {
return false
@@ -12,5 +12,10 @@ class FunctionalEndlessTimer() : FunctionalTimer(0) {
override fun tick() {
time.plusOne()
+ totalStudyTime++
+ }
+
+ override fun accept(visitor: FunctionalTimerVisitor): T {
+ return visitor.visitFunctionalEndlessTimer(this)
}
}
\ No newline at end of file
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 3e2b97e..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
@@ -9,30 +9,39 @@ class FunctionalPomodoroTimer(
var isInBreak = false
override fun tick() {
- if (time.time == 0 && breaksRemaining == 0) {
- view = StudyState.DONE
+ if (hasEnded()) {
return
}
- if (time.time == 0) {
+ if (hasCurrentCountdownEnded()) {
if (isInBreak) {
breaksRemaining--
- view = StudyState.FOCUS_REMAINING
time.time = studyTime
} else {
- view = StudyState.BREAK
time.time = breakTime
}
isInBreak = !isInBreak
}
time.minOne()
+
+ if (!isInBreak) {
+ totalStudyTime++
+ }
}
override fun hasEnded(): Boolean {
- return breaksRemaining == 0 && time.time == 0
+ return !hasBreaksRemaining() && hasCurrentCountdownEnded()
+ }
+
+ private fun hasBreaksRemaining(): Boolean {
+ return breaksRemaining > 0
}
override fun hasCurrentCountdownEnded(): Boolean {
return time.time == 0
}
+
+ override fun accept(visitor: FunctionalTimerVisitor): T {
+ return visitor.visitFunctionalBreakTimer(this)
+ }
}
\ No newline at end of file
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 dae27c6..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,8 +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 view: StudyState = StudyState.FOCUS
+ var totalStudyTime: Int = 0
fun getHoursMinutesSeconds(): HoursMinutesSeconds {
return time.getAsHMS()
@@ -14,8 +17,12 @@ abstract class FunctionalTimer(initialValue: Int) {
abstract fun hasCurrentCountdownEnded(): Boolean
- enum class StudyState {
- FOCUS, DONE, BREAK, FOCUS_REMAINING
+ 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/data/local/models/timer_functional/FunctionalTimerVisitor.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimerVisitor.kt
new file mode 100644
index 0000000..3acc805
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimerVisitor.kt
@@ -0,0 +1,11 @@
+package be.ugent.sel.studeez.data.local.models.timer_functional
+
+interface FunctionalTimerVisitor {
+
+ fun visitFunctionalCustomTimer(functionalCustomTimer: FunctionalCustomTimer): T
+
+ fun visitFunctionalEndlessTimer(functionalEndlessTimer: FunctionalEndlessTimer): T
+
+ fun visitFunctionalBreakTimer(functionalPomodoroTimer: FunctionalPomodoroTimer): 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 63f9d64..4e95243 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/ProfileEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt
index 116a5fb..3dbe270 100644
--- a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt
@@ -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
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/InvisibleSessionManager.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt
new file mode 100644
index 0000000..9051fa8
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt
@@ -0,0 +1,29 @@
+package be.ugent.sel.studeez.screens.session
+
+import android.media.MediaPlayer
+import kotlinx.coroutines.delay
+import javax.inject.Singleton
+import kotlin.time.Duration.Companion.seconds
+
+@Singleton
+object InvisibleSessionManager {
+ private var viewModel: SessionViewModel? = null
+ private lateinit var mediaPlayer: MediaPlayer
+
+ fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) {
+ this.viewModel = viewModel
+ this.mediaPlayer = mediaplayer
+ }
+
+ suspend fun updateTimer() {
+ viewModel?.let {
+ while (!it.getTimer().hasEnded()) {
+ delay(1.seconds)
+ it.getTimer().tick()
+ if (it.getTimer().hasCurrentCountdownEnded()) {
+ mediaPlayer.start()
+ }
+ }
+ }
+ }
+}
\ 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
new file mode 100644
index 0000000..084ff43
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt
@@ -0,0 +1,56 @@
+package be.ugent.sel.studeez.screens.session
+
+import android.media.MediaPlayer
+import android.media.RingtoneManager
+import android.net.Uri
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
+import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
+import be.ugent.sel.studeez.screens.session.sessionScreens.GetSessionScreen
+
+data class SessionActions(
+ val getTimer: () -> FunctionalTimer,
+ 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,
+ )
+}
+
+@Composable
+fun SessionRoute(
+ open: (String) -> Unit,
+ openAndPopUp: (String, String) -> Unit,
+ 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
+ )
+
+ val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen(mediaplayer))
+
+ sessionScreen(
+ open = open,
+ sessionActions = getSessionActions(viewModel, openAndPopUp, mediaplayer)
+ )
+}
diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt
deleted file mode 100644
index 3db95c1..0000000
--- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt
+++ /dev/null
@@ -1,212 +0,0 @@
-package be.ugent.sel.studeez.screens.session
-
-import android.media.MediaPlayer
-import android.media.RingtoneManager
-import android.net.Uri
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.Text
-import androidx.compose.material.TextButton
-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.Alignment
-import androidx.compose.ui.Modifier
-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 androidx.compose.ui.unit.sp
-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.navigation.StudeezDestinations
-import be.ugent.sel.studeez.resources
-import kotlinx.coroutines.delay
-import kotlin.time.Duration.Companion.seconds
-
-var timerEnd = false
-
-data class SessionActions(
- val getTimer: () -> FunctionalTimer,
- val getTask: () -> String,
- val prepareMediaPlayer: () -> Unit,
- val releaseMediaPlayer: () -> Unit,
-)
-
-fun getSessionActions(
- viewModel: SessionViewModel,
- mediaplayer: MediaPlayer,
-): SessionActions {
- return SessionActions(
- getTimer = viewModel::getTimer,
- getTask = viewModel::getTask,
- prepareMediaPlayer = mediaplayer::prepareAsync,
- releaseMediaPlayer = mediaplayer::release,
- )
-}
-
-@Composable
-fun SessionRoute(
- open: (String) -> Unit,
- viewModel: SessionViewModel,
-) {
- val context = LocalContext.current
- val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
- val mediaplayer = MediaPlayer()
- mediaplayer.setDataSource(context, uri)
- mediaplayer.setOnCompletionListener {
- mediaplayer.stop()
- if (timerEnd) {
-// mediaplayer.release()
- }
- }
- mediaplayer.setOnPreparedListener {
-// mediaplayer.start()
- }
- SessionScreen(
- open = open,
- sessionActions = getSessionActions(viewModel, mediaplayer),
- )
-}
-
-@Composable
-fun SessionScreen(
- open: (String) -> Unit,
- sessionActions: SessionActions,
-) {
- Column(
- modifier = Modifier.padding(10.dp)
- ) {
- Timer(
- sessionActions = sessionActions,
- )
- Box(
- contentAlignment = Alignment.Center, modifier = Modifier
- .fillMaxWidth()
- .padding(50.dp)
- ) {
- TextButton(
- onClick = {
- sessionActions.releaseMediaPlayer
- open(StudeezDestinations.HOME_SCREEN)
- // 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))
- .background(Color.Transparent)
- ) {
- Text(
- text = "End session",
- color = Color.Red,
- fontWeight = FontWeight.Bold,
- fontSize = 18.sp,
- modifier = Modifier.padding(1.dp)
- )
- }
- }
- }
-}
-
-@Composable
-private fun Timer(
- sessionActions: SessionActions,
-) {
- var tikker by remember { mutableStateOf(false) }
- LaunchedEffect(tikker) {
- delay(1.seconds)
- sessionActions.getTimer().tick()
- tikker = !tikker
- }
-
- if (
- sessionActions.getTimer().hasCurrentCountdownEnded() && !sessionActions.getTimer()
- .hasEnded()
- ) {
-// sessionActions.prepareMediaPlayer()
- }
-
- if (!timerEnd && sessionActions.getTimer().hasEnded()) {
-// sessionActions.prepareMediaPlayer()
- timerEnd =
- true // Placeholder, vanaf hier moet het report opgestart worden en de sessie afgesloten
- }
-
- val hms = sessionActions.getTimer().getHoursMinutesSeconds()
- Column {
- Text(
- text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}",
- modifier = Modifier
- .fillMaxWidth()
- .padding(50.dp),
- textAlign = TextAlign.Center,
- fontWeight = FontWeight.Bold,
- fontSize = 40.sp,
- )
- 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 -> (sessionActions.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let {
- resources().getQuantityString(R.plurals.state_focus_remaining, it, it)
- }.toString()
- }
-
- Text(
- text = stateString,
- modifier = Modifier.fillMaxWidth(),
- textAlign = TextAlign.Center,
- fontWeight = FontWeight.Light,
- fontSize = 30.sp
- )
-
- Box(
- contentAlignment = Alignment.Center, modifier = Modifier
- .fillMaxWidth()
- .padding(50.dp)
- ) {
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .padding(16.dp)
- .background(Color.Blue, RoundedCornerShape(32.dp))
- ) {
- Text(
- text = sessionActions.getTask(),
- color = Color.White,
- fontSize = 18.sp,
- fontWeight = FontWeight.Bold,
- modifier = Modifier.padding(vertical = 4.dp, horizontal = 20.dp)
- )
- }
- }
- }
-}
-
-@Preview
-@Composable
-fun TimerPreview() {
- Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {}))
-}
-
-@Preview
-@Composable
-fun SessionPreview() {
- SessionScreen(
- open = {},
- sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {})
- )
-}
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
new file mode 100644
index 0000000..4c0cc3e
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt
@@ -0,0 +1,138 @@
+package be.ugent.sel.studeez.screens.session.sessionScreens
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Text
+import androidx.compose.material.TextButton
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+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 androidx.compose.ui.unit.sp
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
+import be.ugent.sel.studeez.screens.session.SessionActions
+import kotlinx.coroutines.delay
+import kotlin.time.Duration.Companion.seconds
+
+abstract class AbstractSessionScreen {
+
+ @Composable
+ operator fun invoke(
+ open: (String) -> Unit,
+ sessionActions: SessionActions,
+ ) {
+ Column(
+ modifier = Modifier.padding(10.dp)
+ ) {
+ Timer(
+ sessionActions = sessionActions,
+ )
+ Box(
+ contentAlignment = Alignment.Center, modifier = Modifier
+ .fillMaxWidth()
+ .padding(50.dp)
+ ) {
+ TextButton(
+ onClick = {
+ sessionActions.releaseMediaPlayer
+ sessionActions.endSession()
+ },
+ modifier = Modifier
+ .padding(horizontal = 20.dp)
+ .border(1.dp, Color.Red, RoundedCornerShape(32.dp))
+ .background(Color.Transparent)
+ ) {
+ Text(
+ text = "End session",
+ color = Color.Red,
+ fontWeight = FontWeight.Bold,
+ fontSize = 18.sp,
+ modifier = Modifier.padding(1.dp)
+ )
+ }
+ }
+ }
+ }
+
+ @Composable
+ fun Timer(
+ sessionActions: SessionActions,
+ ) {
+ var tikker by remember { mutableStateOf(false) }
+ LaunchedEffect(tikker) {
+ delay(1.seconds)
+ sessionActions.getTimer().tick()
+ callMediaPlayer()
+ tikker = !tikker
+ }
+
+ val hms = sessionActions.getTimer().getHoursMinutesSeconds()
+ Column {
+ Text(
+ text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}",
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(50.dp),
+ textAlign = TextAlign.Center,
+ fontWeight = FontWeight.Bold,
+ fontSize = 40.sp,
+ )
+
+ Text(
+ text = motivationString(),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center,
+ fontWeight = FontWeight.Light,
+ fontSize = 30.sp
+ )
+
+ Box(
+ contentAlignment = Alignment.Center, modifier = Modifier
+ .fillMaxWidth()
+ .padding(50.dp)
+ ) {
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .padding(16.dp)
+ .background(Color.Blue, RoundedCornerShape(32.dp))
+ ) {
+ Text(
+ text = sessionActions.getTask(),
+ color = Color.White,
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(vertical = 4.dp, horizontal = 20.dp)
+ )
+ }
+ }
+ }
+ }
+
+ @Composable
+ abstract fun motivationString(): String
+
+ abstract fun callMediaPlayer()
+
+}
+
+@Preview
+@Composable
+fun TimerPreview() {
+ val sessionScreen = object : AbstractSessionScreen() {
+ @Composable
+ override fun motivationString(): String = "Test"
+ override fun callMediaPlayer() {}
+
+ }
+ 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/sessionScreens/BreakSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt
new file mode 100644
index 0000000..8fa45ff
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt
@@ -0,0 +1,45 @@
+package be.ugent.sel.studeez.screens.session.sessionScreens
+
+import android.media.MediaPlayer
+import androidx.compose.runtime.Composable
+import be.ugent.sel.studeez.R
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
+import be.ugent.sel.studeez.resources
+import be.ugent.sel.studeez.R.string as AppText
+
+class BreakSessionScreen(
+ private val funPomoDoroTimer: FunctionalPomodoroTimer,
+ private var mediaplayer: MediaPlayer?
+): AbstractSessionScreen() {
+
+ @Composable
+ override fun motivationString(): String {
+ if (funPomoDoroTimer.isInBreak) {
+ return resources().getString(AppText.state_take_a_break)
+ }
+
+ if (funPomoDoroTimer.hasEnded()) {
+ return resources().getString(AppText.state_done)
+ }
+
+ return resources().getQuantityString(
+ R.plurals.state_focus_remaining,
+ funPomoDoroTimer.breaksRemaining,
+ funPomoDoroTimer.breaksRemaining
+ )
+ }
+
+ override fun callMediaPlayer() {
+ if (funPomoDoroTimer.hasEnded()) {
+ mediaplayer?.let { it: MediaPlayer ->
+ it.setOnCompletionListener {
+ it.release()
+ mediaplayer = null
+ }
+ it.start()
+ }
+ } else if (funPomoDoroTimer.hasCurrentCountdownEnded()) {
+ mediaplayer?.start()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt
new file mode 100644
index 0000000..7fc60bc
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt
@@ -0,0 +1,35 @@
+package be.ugent.sel.studeez.screens.session.sessionScreens
+
+import android.media.MediaPlayer
+import androidx.compose.runtime.Composable
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
+import be.ugent.sel.studeez.resources
+import be.ugent.sel.studeez.R.string as AppText
+
+
+class CustomSessionScreen(
+ private val functionalTimer: FunctionalCustomTimer,
+ private var mediaplayer: MediaPlayer?
+): AbstractSessionScreen() {
+
+ @Composable
+ override fun motivationString(): String {
+ if (functionalTimer.hasEnded()) {
+ return resources().getString(AppText.state_done)
+ }
+ return resources().getString(AppText.state_focus)
+ }
+
+ override fun callMediaPlayer() {
+ if (functionalTimer.hasEnded()) {
+ mediaplayer?.let { it: MediaPlayer ->
+ it.setOnCompletionListener {
+ it.release()
+ mediaplayer = null
+ }
+ it.start()
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt
new file mode 100644
index 0000000..be67cff
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt
@@ -0,0 +1,16 @@
+package be.ugent.sel.studeez.screens.session.sessionScreens
+
+import androidx.compose.runtime.Composable
+import be.ugent.sel.studeez.resources
+import be.ugent.sel.studeez.R.string as AppText
+
+
+class EndlessSessionScreen : AbstractSessionScreen() {
+
+ @Composable
+ override fun motivationString(): String {
+ return resources().getString(AppText.state_focus)
+ }
+
+ override fun callMediaPlayer() {}
+}
\ No newline at end of file
diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt
new file mode 100644
index 0000000..98b2d5e
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt
@@ -0,0 +1,18 @@
+package be.ugent.sel.studeez.screens.session.sessionScreens
+
+import android.media.MediaPlayer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor
+
+class GetSessionScreen(private val mediaplayer: MediaPlayer?) : FunctionalTimerVisitor {
+ override fun visitFunctionalCustomTimer(functionalCustomTimer: FunctionalCustomTimer): AbstractSessionScreen =
+ CustomSessionScreen(functionalCustomTimer, mediaplayer)
+
+ override fun visitFunctionalEndlessTimer(functionalEndlessTimer: FunctionalEndlessTimer): AbstractSessionScreen =
+ EndlessSessionScreen()
+
+ override fun visitFunctionalBreakTimer(functionalPomodoroTimer: FunctionalPomodoroTimer): AbstractSessionScreen =
+ BreakSessionScreen(functionalPomodoroTimer, mediaplayer)
+}
\ 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..477d174
--- /dev/null
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt
@@ -0,0 +1,67 @@
+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(
+ modifier = modifier
+ ) {
+ 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..5fb4943
--- /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(
+ 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/splash/SplashScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt
index a5b0e81..e70c67b 100644
--- a/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt
+++ b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashScreen.kt
@@ -1,6 +1,5 @@
package be.ugent.sel.studeez.screens.splash
-import android.window.SplashScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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 3bc6ca7..0d48594 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,25 +1,17 @@
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
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
@@ -50,56 +42,48 @@ fun getTimerOverviewActions(
@Composable
fun TimerOverviewRoute(
open: (String) -> Unit,
- openAndPopUp: (String, String) -> Unit,
viewModel: TimerOverviewViewModel,
- drawerViewModel: DrawerViewModel,
- navBarViewModel: NavigationBarViewModel,
+ drawerActions: DrawerActions,
) {
TimerOverviewScreen(
timerOverviewActions = getTimerOverviewActions(viewModel, open),
- 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)
- ) {
- // Default Timers, cannot be edited
- items(timerOverviewActions.getDefaultTimers()) {
- TimerEntry(timerInfo = it) {}
- }
- // User timers, can be edited
- items(timers.value) { timerInfo ->
- TimerEntry(
- timerInfo = timerInfo,
- ) {
- StealthButton(
- text = R.string.edit,
- onClick = { timerOverviewActions.onEditClick(timerInfo) }
- )
- }
-
- }
+ LazyColumn {
+ // Default Timers, cannot be edited
+ items(timerOverviewActions.getDefaultTimers()) {
+ TimerEntry(timerInfo = it) {}
}
- BasicButton(R.string.add_timer, Modifier.basicButton()) {
- timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN)
+ // User timers, can be edited
+ items(timers.value) { timerInfo ->
+ TimerEntry(
+ timerInfo = timerInfo,
+ ) {
+ StealthButton(
+ text = R.string.edit,
+ onClick = { timerOverviewActions.onEditClick(timerInfo) }
+ )
+ }
+
+ }
+ item {
+ BasicButton(R.string.add_timer, Modifier.basicButton()) {
+ timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN)
+ }
}
}
}
@@ -118,7 +102,6 @@ fun TimerOverviewPreview() {
{},
{}
),
- 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 a3318bc..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,43 +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) }
+ )
+ }
+ )
}
}
}
@@ -87,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 50df45b..9e98592 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
@@ -44,6 +45,7 @@
Sessions
+ End session
Profile
diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalCustomTimerUnitTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalCustomTimerUnitTest.kt
index 2daa61e..548fe9d 100644
--- a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalCustomTimerUnitTest.kt
+++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalCustomTimerUnitTest.kt
@@ -1,7 +1,6 @@
package be.ugent.sel.studeez.timer_functional
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
-import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
import org.junit.Assert
import org.junit.Test
@@ -36,9 +35,6 @@ class FunctionalCustomTimerUnitTest : FunctionalTimerUnitTest() {
timer = FunctionalCustomTimer(0)
timer.tick()
Assert.assertTrue(timer.hasEnded())
- Assert.assertEquals(
- FunctionalTimer.StudyState.DONE,
- timer.view
- )
+ Assert.assertTrue(timer.hasEnded())
}
}
\ No newline at end of file
diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalEndlessTimerUnitTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalEndlessTimerUnitTest.kt
index b83d436..17733bc 100644
--- a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalEndlessTimerUnitTest.kt
+++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalEndlessTimerUnitTest.kt
@@ -1,7 +1,6 @@
package be.ugent.sel.studeez.timer_functional
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
-import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
import org.junit.Assert
import org.junit.Test
@@ -37,10 +36,6 @@ class FunctionalEndlessTimerUnitTest : FunctionalTimerUnitTest() {
for (i in 1..n) {
timer.tick()
Assert.assertFalse(timer.hasEnded())
- Assert.assertEquals(
- FunctionalTimer.StudyState.FOCUS,
- timer.view
- )
}
}
}
\ No newline at end of file
diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalPomodoroTimerUnitTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalPomodoroTimerUnitTest.kt
index a49d2f7..4b259c8 100644
--- a/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalPomodoroTimerUnitTest.kt
+++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/FunctionalPomodoroTimerUnitTest.kt
@@ -1,7 +1,6 @@
package be.ugent.sel.studeez.timer_functional
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
-import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
import org.junit.Assert
import org.junit.Test
@@ -29,10 +28,6 @@ class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
breaks,
pomodoroTimer.breaksRemaining,
)
- Assert.assertEquals(
- FunctionalTimer.StudyState.FOCUS,
- pomodoroTimer.view,
- )
}
@Test
@@ -52,10 +47,6 @@ class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
pomodoroTimer = FunctionalPomodoroTimer(0, 0, 0)
pomodoroTimer.tick()
Assert.assertTrue(pomodoroTimer.hasEnded())
- Assert.assertEquals(
- FunctionalTimer.StudyState.DONE,
- pomodoroTimer.view,
- )
}
@Test
@@ -65,10 +56,6 @@ class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
}
Assert.assertFalse(pomodoroTimer.hasEnded())
Assert.assertTrue(pomodoroTimer.isInBreak)
- Assert.assertEquals(
- FunctionalTimer.StudyState.BREAK,
- pomodoroTimer.view
- )
}
@Test
@@ -77,10 +64,6 @@ class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
pomodoroTimer.tick()
}
Assert.assertTrue(pomodoroTimer.isInBreak)
- Assert.assertEquals(
- FunctionalTimer.StudyState.BREAK,
- pomodoroTimer.view
- )
for (i in 0..breakTime) {
pomodoroTimer.tick()
}
@@ -90,9 +73,5 @@ class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
breaksRemaining,
pomodoroTimer.breaksRemaining
)
- Assert.assertEquals(
- FunctionalTimer.StudyState.FOCUS_REMAINING,
- pomodoroTimer.view
- )
}
}
\ No newline at end of file
diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt
new file mode 100644
index 0000000..f9e34c3
--- /dev/null
+++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt
@@ -0,0 +1,100 @@
+package be.ugent.sel.studeez.timer_functional
+
+import android.media.MediaPlayer
+import be.ugent.sel.studeez.data.SelectedTimerState
+import be.ugent.sel.studeez.data.SessionReportState
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
+import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
+import be.ugent.sel.studeez.screens.session.InvisibleSessionManager
+import be.ugent.sel.studeez.screens.session.SessionViewModel
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert
+import org.junit.Test
+import org.mockito.kotlin.mock
+
+@ExperimentalCoroutinesApi
+class InvisibleSessionManagerTest {
+ private var timerState: SelectedTimerState = SelectedTimerState()
+ private lateinit var viewModel: SessionViewModel
+ private var mediaPlayer: MediaPlayer = mock()
+
+ @Test
+ fun InvisibleEndlessTimerTest() = runTest {
+ timerState.selectedTimer = FunctionalEndlessTimer()
+ viewModel = SessionViewModel(timerState, SessionReportState(), mock())
+ InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
+
+ val test = launch {
+ InvisibleSessionManager.updateTimer()
+ }
+
+ Assert.assertEquals(viewModel.getTimer().time.time, 0)
+ advanceTimeBy(1_000) // Start tikker
+ advanceTimeBy(10_000_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 10000)
+
+ test.cancel()
+ return@runTest
+ }
+
+ @Test
+ fun InvisiblePomodoroTimerTest() = runTest {
+ val studyTime = 10
+ val breakTime = 5
+ val repeats = 1
+ timerState.selectedTimer = FunctionalPomodoroTimer(studyTime, breakTime, repeats)
+ viewModel = SessionViewModel(timerState, SessionReportState(), mock())
+ InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
+
+ val test = launch {
+ InvisibleSessionManager.updateTimer()
+ }
+
+ Assert.assertEquals(viewModel.getTimer().time.time, 10)
+ advanceTimeBy(1_000) // start tikker
+
+ advanceTimeBy(9_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 1)
+ // focus, 9 sec, 1 sec nog
+
+ advanceTimeBy(2_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 4)
+ // pauze, 11 sec bezig, 4 seconden nog pauze
+
+ advanceTimeBy(5_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 9)
+ // 2e focus, 16 sec, 9 sec in 2e focus nog
+
+ advanceTimeBy(13_000)
+ Assert.assertTrue(viewModel.getTimer().hasEnded())
+ // Done
+
+ test.cancel()
+ return@runTest
+ }
+
+ @Test
+ fun InvisibleCustomTimerTest() = runTest {
+ timerState.selectedTimer = FunctionalCustomTimer(5)
+ viewModel = SessionViewModel(timerState, SessionReportState(), mock())
+ InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
+
+ val test = launch {
+ InvisibleSessionManager.updateTimer()
+ }
+
+ Assert.assertEquals(viewModel.getTimer().time.time, 5)
+ advanceTimeBy(1_000) // Start tikker
+ advanceTimeBy(4_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 1)
+ advanceTimeBy(1_000)
+ Assert.assertEquals(viewModel.getTimer().time.time, 0)
+
+ test.cancel()
+ return@runTest
+ }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 3c5031e..edf11ef 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,6 +7,8 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.daemon=true
+org.gradle.parallel=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects