diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..4412b1a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + 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 28e3785..c8a133b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -37,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 @@ -166,6 +167,7 @@ fun StudeezNavGraph( composable(StudeezDestinations.SESSION_SCREEN) { SessionRoute( open, + openAndPopUp, viewModel = hiltViewModel() ) } @@ -189,5 +191,12 @@ fun StudeezNavGraph( viewModel = hiltViewModel(), ) } + + composable(StudeezDestinations.SESSION_RECAP) { + SessionRecapRoute( + openAndPopUp = openAndPopUp, + viewModel = hiltViewModel() + ) + } } } 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 412432b..1a2e099 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 @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.data.local.models.timer_functional +import be.ugent.sel.studeez.data.local.models.SessionReport import be.ugent.sel.studeez.screens.session.sessionScreens.CustomSessionScreen import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen @@ -8,6 +9,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 07f9a39..40660e2 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 @@ -26,6 +26,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..760d656 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,12 @@ package be.ugent.sel.studeez.data.local.models.timer_functional +import be.ugent.sel.studeez.data.local.models.SessionReport +import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen +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 +18,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/session/SessionRoute.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt index 57dd7af..a503067 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,23 +14,27 @@ data class SessionActions( val getTask: () -> String, val prepareMediaPlayer: () -> 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) }, prepareMediaPlayer = mediaplayer::prepareAsync, - releaseMediaPlayer = mediaplayer::release, + releaseMediaPlayer = mediaplayer::release ) } @Composable fun SessionRoute( open: (String) -> Unit, + openAndPopUp: (String, String) -> Unit, viewModel: SessionViewModel, ) { val context = LocalContext.current @@ -58,6 +62,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 98a5871..273e5dc 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 @@ -47,8 +47,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) 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..63878f7 --- /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.saveSession(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/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39abda6..bb643d3 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