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"> | ||||
|   <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" /> | ||||
|   </component> | ||||
|   <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.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() | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
| 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++ | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) { | |||
| 
 | ||||
|     override fun tick() { | ||||
|         time.plusOne() | ||||
|         totalStudyTime++ | ||||
|     } | ||||
| 
 | ||||
|     override fun <T> accept(visitor: FunctionalTimerVisitor<T>): T { | ||||
|  |  | |||
|  | @ -26,6 +26,10 @@ class FunctionalPomodoroTimer( | |||
|             isInBreak = !isInBreak | ||||
|         } | ||||
|         time.minOne() | ||||
| 
 | ||||
|         if (!isInBreak) { | ||||
|             totalStudyTime++ | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun hasEnded(): Boolean { | ||||
|  |  | |||
|  | @ -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 <T> accept(visitor: FunctionalTimerVisitor<T>): T | ||||
| } | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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) | ||||
|     ) | ||||
| } | ||||
|  |  | |||
|  | @ -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) | ||||
|     } | ||||
| } | ||||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 --> | ||||
|         <string name="confirm">Confirm</string> | ||||
|         <string name="save">Save</string> | ||||
|         <string name="discard">Discard</string> | ||||
|         <string name="cancel">Cancel</string> | ||||
|         <string name="go_back">Go back</string> | ||||
|         <string name="next">Next</string> | ||||
|  |  | |||
		Reference in a new issue
	
	 GitHub Enterprise
							GitHub Enterprise