commit
1d53752a30
14 changed files with 160 additions and 8 deletions
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
|
@ -1,6 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17_PREVIEW" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
@ -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.EditProfileRoute
|
||||||
import be.ugent.sel.studeez.screens.profile.ProfileRoute
|
import be.ugent.sel.studeez.screens.profile.ProfileRoute
|
||||||
import be.ugent.sel.studeez.screens.session.SessionRoute
|
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.sign_up.SignUpRoute
|
||||||
import be.ugent.sel.studeez.screens.splash.SplashRoute
|
import be.ugent.sel.studeez.screens.splash.SplashRoute
|
||||||
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute
|
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute
|
||||||
|
@ -166,6 +167,7 @@ fun StudeezNavGraph(
|
||||||
composable(StudeezDestinations.SESSION_SCREEN) {
|
composable(StudeezDestinations.SESSION_SCREEN) {
|
||||||
SessionRoute(
|
SessionRoute(
|
||||||
open,
|
open,
|
||||||
|
openAndPopUp,
|
||||||
viewModel = hiltViewModel()
|
viewModel = hiltViewModel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -189,5 +191,12 @@ fun StudeezNavGraph(
|
||||||
viewModel = hiltViewModel(),
|
viewModel = hiltViewModel(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(StudeezDestinations.SESSION_RECAP) {
|
||||||
|
SessionRecapRoute(
|
||||||
|
openAndPopUp = openAndPopUp,
|
||||||
|
viewModel = hiltViewModel()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
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.CustomSessionScreen
|
||||||
import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
|
import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) {
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
if (!hasEnded()) {
|
if (!hasEnded()) {
|
||||||
time.minOne()
|
time.minOne()
|
||||||
|
totalStudyTime++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) {
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
time.plusOne()
|
time.plusOne()
|
||||||
|
totalStudyTime++
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> accept(visitor: FunctionalTimerVisitor<T>): T {
|
override fun <T> accept(visitor: FunctionalTimerVisitor<T>): T {
|
||||||
|
|
|
@ -26,6 +26,10 @@ class FunctionalPomodoroTimer(
|
||||||
isInBreak = !isInBreak
|
isInBreak = !isInBreak
|
||||||
}
|
}
|
||||||
time.minOne()
|
time.minOne()
|
||||||
|
|
||||||
|
if (!isInBreak) {
|
||||||
|
totalStudyTime++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasEnded(): Boolean {
|
override fun hasEnded(): Boolean {
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
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) {
|
abstract class FunctionalTimer(initialValue: Int) {
|
||||||
val time: Time = Time(initialValue)
|
val time: Time = Time(initialValue)
|
||||||
|
var totalStudyTime: Int = 0
|
||||||
|
|
||||||
fun getHoursMinutesSeconds(): HoursMinutesSeconds {
|
fun getHoursMinutesSeconds(): HoursMinutesSeconds {
|
||||||
return time.getAsHMS()
|
return time.getAsHMS()
|
||||||
|
@ -13,5 +18,12 @@ abstract class FunctionalTimer(initialValue: Int) {
|
||||||
|
|
||||||
abstract fun hasCurrentCountdownEnded(): Boolean
|
abstract fun hasCurrentCountdownEnded(): Boolean
|
||||||
|
|
||||||
|
fun getSessionReport(): SessionReport {
|
||||||
|
return SessionReport(
|
||||||
|
studyTime = totalStudyTime,
|
||||||
|
endTime = Timestamp.now()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun <T> accept(visitor: FunctionalTimerVisitor<T>): T
|
abstract fun <T> accept(visitor: FunctionalTimerVisitor<T>): T
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ object StudeezDestinations {
|
||||||
const val TIMER_OVERVIEW_SCREEN = "timer_overview"
|
const val TIMER_OVERVIEW_SCREEN = "timer_overview"
|
||||||
const val TIMER_SELECTION_SCREEN = "timer_selection"
|
const val TIMER_SELECTION_SCREEN = "timer_selection"
|
||||||
const val SESSION_SCREEN = "session"
|
const val SESSION_SCREEN = "session"
|
||||||
|
const val SESSION_RECAP = "session_recap"
|
||||||
// const val TASKS_SCREEN = "tasks"
|
// const val TASKS_SCREEN = "tasks"
|
||||||
// const val SESSIONS_SCREEN = "sessions"
|
// const val SESSIONS_SCREEN = "sessions"
|
||||||
const val PROFILE_SCREEN = "profile"
|
const val PROFILE_SCREEN = "profile"
|
||||||
|
|
|
@ -14,23 +14,27 @@ data class SessionActions(
|
||||||
val getTask: () -> String,
|
val getTask: () -> String,
|
||||||
val prepareMediaPlayer: () -> Unit,
|
val prepareMediaPlayer: () -> Unit,
|
||||||
val releaseMediaPlayer: () -> Unit,
|
val releaseMediaPlayer: () -> Unit,
|
||||||
|
val endSession: () -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getSessionActions(
|
private fun getSessionActions(
|
||||||
viewModel: SessionViewModel,
|
viewModel: SessionViewModel,
|
||||||
|
openAndPopUp: (String, String) -> Unit,
|
||||||
mediaplayer: MediaPlayer,
|
mediaplayer: MediaPlayer,
|
||||||
): SessionActions {
|
): SessionActions {
|
||||||
return SessionActions(
|
return SessionActions(
|
||||||
getTimer = viewModel::getTimer,
|
getTimer = viewModel::getTimer,
|
||||||
getTask = viewModel::getTask,
|
getTask = viewModel::getTask,
|
||||||
|
endSession = { viewModel.endSession(openAndPopUp) },
|
||||||
prepareMediaPlayer = mediaplayer::prepareAsync,
|
prepareMediaPlayer = mediaplayer::prepareAsync,
|
||||||
releaseMediaPlayer = mediaplayer::release,
|
releaseMediaPlayer = mediaplayer::release
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SessionRoute(
|
fun SessionRoute(
|
||||||
open: (String) -> Unit,
|
open: (String) -> Unit,
|
||||||
|
openAndPopUp: (String, String) -> Unit,
|
||||||
viewModel: SessionViewModel,
|
viewModel: SessionViewModel,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
@ -58,6 +62,6 @@ fun SessionRoute(
|
||||||
|
|
||||||
sessionScreen(
|
sessionScreen(
|
||||||
open = open,
|
open = open,
|
||||||
sessionActions = getSessionActions(viewModel, mediaplayer)
|
sessionActions = getSessionActions(viewModel, openAndPopUp, mediaplayer)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
package be.ugent.sel.studeez.screens.session
|
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.data.local.models.timer_functional.FunctionalTimer
|
||||||
import be.ugent.sel.studeez.domain.LogService
|
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.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 dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SessionViewModel @Inject constructor(
|
class SessionViewModel @Inject constructor(
|
||||||
private val selectedTimerState: SelectedTimerState,
|
private val selectedTimerState: SelectedTimerState,
|
||||||
|
private val sessionReportState: SessionReportState,
|
||||||
logService: LogService
|
logService: LogService
|
||||||
) : StudeezViewModel(logService) {
|
) : StudeezViewModel(logService) {
|
||||||
|
|
||||||
private val timer: FunctionalTimer = FunctionalPomodoroTimer(15, 5, 3)
|
|
||||||
private val task : String = "No task selected" // placeholder for tasks implementation
|
private val task : String = "No task selected" // placeholder for tasks implementation
|
||||||
|
|
||||||
fun getTimer() : FunctionalTimer {
|
fun getTimer() : FunctionalTimer {
|
||||||
|
@ -24,4 +25,9 @@ class SessionViewModel @Inject constructor(
|
||||||
fun getTask(): String {
|
fun getTask(): String {
|
||||||
return task
|
return task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun endSession(openAndPopUp: (String, String) -> Unit) {
|
||||||
|
sessionReportState.sessionReport = getTimer().getSessionReport()
|
||||||
|
openAndPopUp(StudeezDestinations.SESSION_RECAP, StudeezDestinations.SESSION_SCREEN)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -47,8 +47,7 @@ abstract class AbstractSessionScreen {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
sessionActions.releaseMediaPlayer
|
sessionActions.releaseMediaPlayer
|
||||||
open(StudeezDestinations.HOME_SCREEN)
|
sessionActions.endSession()
|
||||||
// Vanaf hier ook naar report gaan als "end session" knop word ingedrukt
|
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 20.dp)
|
.padding(horizontal = 20.dp)
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<string name="confirm">Confirm</string>
|
<string name="confirm">Confirm</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
|
<string name="discard">Discard</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="go_back">Go back</string>
|
<string name="go_back">Go back</string>
|
||||||
<string name="next">Next</string>
|
<string name="next">Next</string>
|
||||||
|
|
Reference in a new issue