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
	
	 GitHub Enterprise
							GitHub Enterprise