Merge pull request #120 from SELab1/abstract2composition_refactor_session_screen
Abstract2composition refactor session screen
This commit is contained in:
		
						commit
						19a073f8c6
					
				
					 14 changed files with 393 additions and 340 deletions
				
			
		|  | @ -1,6 +1,10 @@ | |||
| package be.ugent.sel.studeez.screens.session | ||||
| 
 | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Context | ||||
| import android.media.MediaPlayer | ||||
| import android.media.RingtoneManager | ||||
| import android.net.Uri | ||||
| import kotlinx.coroutines.delay | ||||
| import javax.inject.Singleton | ||||
| import kotlin.time.Duration.Companion.seconds | ||||
|  | @ -10,9 +14,11 @@ object InvisibleSessionManager { | |||
|     private var viewModel: SessionViewModel? = null | ||||
|     private lateinit var mediaPlayer: MediaPlayer | ||||
| 
 | ||||
|     fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { | ||||
|     fun setParameters(viewModel: SessionViewModel, context: Context) { | ||||
|         val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) | ||||
|         this.mediaPlayer = MediaPlayer.create(context, uri) | ||||
|         this.mediaPlayer.isLooping = false | ||||
|         this.viewModel = viewModel | ||||
|         this.mediaPlayer = mediaplayer | ||||
|     } | ||||
| 
 | ||||
|     suspend fun updateTimer() { | ||||
|  |  | |||
|  | @ -1,33 +1,24 @@ | |||
| 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 | ||||
| import be.ugent.sel.studeez.screens.session.sessionScreens.GetSessionScreenComposable | ||||
| 
 | ||||
| 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, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
|  | @ -37,20 +28,12 @@ fun SessionRoute( | |||
|     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 | ||||
|     ) | ||||
|     InvisibleSessionManager.setParameters(viewModel = viewModel, context = LocalContext.current) | ||||
| 
 | ||||
|     val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen(mediaplayer)) | ||||
|     val soundPlayer = SoundPlayer(LocalContext.current) | ||||
|     val sessionActions = getSessionActions(viewModel, openAndPopUp) | ||||
|     val sessionScreen = viewModel.getTimer().accept(GetSessionScreenComposable(soundPlayer, open, sessionActions)) | ||||
| 
 | ||||
|     sessionScreen( | ||||
|         open = open, | ||||
|         sessionActions = getSessionActions(viewModel, openAndPopUp, mediaplayer) | ||||
|     ) | ||||
|     sessionScreen() | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,29 @@ | |||
| package be.ugent.sel.studeez.screens.session | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.media.MediaPlayer | ||||
| import android.media.RingtoneManager | ||||
| 
 | ||||
| class SoundPlayer(private val context: Context) { | ||||
| 
 | ||||
|     var oldValue: Boolean = false | ||||
|     var mediaPlayer: MediaPlayer = initPlayer() | ||||
| 
 | ||||
|     fun playOn(newValue: Boolean) { | ||||
|         if (oldValue != newValue) { | ||||
|             mediaPlayer.start() | ||||
|             mediaPlayer.setOnCompletionListener { | ||||
|                 mediaPlayer = initPlayer() | ||||
|             } | ||||
|             oldValue = newValue | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private fun initPlayer(): MediaPlayer { | ||||
|         return  MediaPlayer.create( | ||||
|             context, | ||||
|             RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | @ -1,150 +0,0 @@ | |||
| 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.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.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.toString(), | ||||
|                 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 | ||||
|             ) | ||||
| 
 | ||||
|             MidSection() | ||||
| 
 | ||||
|             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 | ||||
| 
 | ||||
|     @Composable | ||||
|     open fun MidSection() { | ||||
|         // Default has no midsection, unless overwritten. | ||||
|     } | ||||
| 
 | ||||
|     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" }, {}, {}, {})) | ||||
| } | ||||
|  | @ -1,96 +0,0 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import android.media.MediaPlayer | ||||
| import androidx.compose.foundation.background | ||||
| import androidx.compose.foundation.layout.* | ||||
| import androidx.compose.foundation.shape.CircleShape | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.draw.clip | ||||
| import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.unit.dp | ||||
| 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 MidSection() { | ||||
|         Dots() | ||||
|     } | ||||
| 
 | ||||
|     @Composable | ||||
|     fun Dots() { | ||||
|         Row( | ||||
|             modifier = Modifier.fillMaxWidth(), | ||||
|             verticalAlignment = Alignment.CenterVertically, | ||||
|             horizontalArrangement = Arrangement.Center, | ||||
|         ) { | ||||
|             if (funPomoDoroTimer.hasEnded()) { | ||||
|                 repeat(funPomoDoroTimer.repeats) { | ||||
|                     Dot(Color.Green) | ||||
|                 } | ||||
|             } else { | ||||
|                 repeat(funPomoDoroTimer.repeats - funPomoDoroTimer.breaksRemaining - 1) { | ||||
|                     Dot(color = Color.DarkGray) | ||||
|                 } | ||||
|                 if (!funPomoDoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray) | ||||
|                 repeat(funPomoDoroTimer.breaksRemaining) { | ||||
|                     Dot(color = Color.Gray) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Composable | ||||
|     private fun Dot(color: Color) { | ||||
|         Box( | ||||
|             modifier = Modifier | ||||
|                 .padding(5.dp) | ||||
|                 .size(10.dp) | ||||
|                 .clip(CircleShape) | ||||
|                 .background(color) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @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().getString(AppText.state_focus) | ||||
|     } | ||||
| 
 | ||||
|     override fun callMediaPlayer() { | ||||
|         if (funPomoDoroTimer.hasEnded()) { | ||||
|             mediaplayer?.let { it: MediaPlayer -> | ||||
|                 it.setOnCompletionListener { | ||||
|                     it.release() | ||||
|                     mediaplayer = null | ||||
|                 } | ||||
|                 it.start() | ||||
|             } | ||||
|         } else if (funPomoDoroTimer.hasCurrentCountdownEnded()) { | ||||
|             mediaplayer?.start() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Preview | ||||
| @Composable | ||||
| fun MidsectionPreview() { | ||||
|     val funPomoDoroTimer = FunctionalPomodoroTimer(15, 60, 5) | ||||
|     val breakSessionScreen = BreakSessionScreen(funPomoDoroTimer, MediaPlayer()) | ||||
|     breakSessionScreen.MidSection() | ||||
| } | ||||
|  | @ -0,0 +1,79 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import androidx.compose.foundation.background | ||||
| import androidx.compose.foundation.layout.* | ||||
| import androidx.compose.foundation.shape.CircleShape | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.draw.clip | ||||
| import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.unit.dp | ||||
| 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.screens.session.SessionActions | ||||
| import be.ugent.sel.studeez.screens.session.SoundPlayer | ||||
| 
 | ||||
| @Composable | ||||
| fun BreakSessionScreenComposable( | ||||
|     open: (String) -> Unit, | ||||
|     sessionActions: SessionActions, | ||||
|     pomodoroTimer: FunctionalPomodoroTimer, | ||||
|     soundPlayer: SoundPlayer, | ||||
| ) { | ||||
|     SessionScreen( | ||||
|         open = open, | ||||
|         sessionActions = sessionActions, | ||||
|         midSection = { Dots(pomodoroTimer = pomodoroTimer) }, | ||||
|         callMediaPlayer = { soundPlayer.playOn(pomodoroTimer.hasCurrentCountdownEnded()) }, | ||||
|         motivationString = { motivationString (pomodoroTimer = pomodoroTimer) } | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| private fun Dots(pomodoroTimer: FunctionalPomodoroTimer): Int { | ||||
|     Row( | ||||
|         modifier = Modifier.fillMaxWidth(), | ||||
|         verticalAlignment = Alignment.CenterVertically, | ||||
|         horizontalArrangement = Arrangement.Center, | ||||
|     ) { | ||||
|         if (pomodoroTimer.hasEnded()) { | ||||
|             repeat(pomodoroTimer.repeats) { | ||||
|                 Dot(Color.Green) | ||||
|             } | ||||
|         } else { | ||||
|             repeat(pomodoroTimer.repeats - pomodoroTimer.breaksRemaining - 1) { | ||||
|                 Dot(color = Color.DarkGray) | ||||
|             } | ||||
|             if (!pomodoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray) | ||||
|             repeat(pomodoroTimer.breaksRemaining) { | ||||
|                 Dot(color = Color.Gray) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return pomodoroTimer.breaksRemaining | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| private fun Dot(color: Color) { | ||||
|     Box(modifier = Modifier | ||||
|         .padding(5.dp) | ||||
|         .size(10.dp) | ||||
|         .clip(CircleShape) | ||||
|         .background(color)) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @Composable | ||||
| private fun motivationString(pomodoroTimer: FunctionalPomodoroTimer): String { | ||||
|     if (pomodoroTimer.isInBreak) { | ||||
|         return resources().getString(R.string.state_take_a_break) | ||||
|     } | ||||
| 
 | ||||
|     if (pomodoroTimer.hasEnded()) { | ||||
|         return resources().getString(R.string.state_done) | ||||
|     } | ||||
| 
 | ||||
|     return resources().getString(R.string.state_focus) | ||||
| } | ||||
|  | @ -1,35 +0,0 @@ | |||
| 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() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,32 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import androidx.compose.runtime.Composable | ||||
| import be.ugent.sel.studeez.R | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer | ||||
| import be.ugent.sel.studeez.resources | ||||
| import be.ugent.sel.studeez.screens.session.SessionActions | ||||
| import be.ugent.sel.studeez.screens.session.SoundPlayer | ||||
| 
 | ||||
| @Composable | ||||
| fun CustomTimerSessionScreenComposable( | ||||
|     open: (String) -> Unit, | ||||
|     sessionActions: SessionActions, | ||||
|     customTimer: FunctionalCustomTimer, | ||||
|     soundPlayer: SoundPlayer | ||||
| ) { | ||||
|     SessionScreen( | ||||
|         open = open, | ||||
|         callMediaPlayer = { soundPlayer.playOn(customTimer.hasEnded()) }, | ||||
|         sessionActions = sessionActions | ||||
|     ) { | ||||
|         motivationString(customTimer = customTimer) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| private fun motivationString(customTimer: FunctionalCustomTimer): String { | ||||
|     if (customTimer.hasEnded()) { | ||||
|         return resources().getString(R.string.state_done) | ||||
|     } | ||||
|     return resources().getString(R.string.state_focus) | ||||
| } | ||||
|  | @ -1,16 +0,0 @@ | |||
| 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() {} | ||||
| } | ||||
|  | @ -0,0 +1,24 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import androidx.compose.runtime.Composable | ||||
| import be.ugent.sel.studeez.R | ||||
| import be.ugent.sel.studeez.resources | ||||
| import be.ugent.sel.studeez.screens.session.SessionActions | ||||
| 
 | ||||
| @Composable | ||||
| fun EndlessTimerSessionScreenComposable( | ||||
|     open: (String) -> Unit, | ||||
|     sessionActions: SessionActions, | ||||
| ) { | ||||
|     SessionScreen( | ||||
|         open = open, | ||||
|         sessionActions = sessionActions | ||||
|     ) { | ||||
|         motivationString() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| private fun motivationString(): String { | ||||
|     return resources().getString(R.string.state_focus) | ||||
| } | ||||
|  | @ -1,18 +0,0 @@ | |||
| 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<AbstractSessionScreen> { | ||||
|     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) | ||||
| } | ||||
|  | @ -0,0 +1,47 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import androidx.compose.runtime.Composable | ||||
| 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 | ||||
| import be.ugent.sel.studeez.screens.session.SessionActions | ||||
| import be.ugent.sel.studeez.screens.session.SoundPlayer | ||||
| 
 | ||||
| class GetSessionScreenComposable( | ||||
|     private val soundPlayer: SoundPlayer, | ||||
|     private val open: (String) -> Unit, | ||||
|     private val sessionActions: SessionActions | ||||
|     ) : | ||||
|     FunctionalTimerVisitor<@Composable () -> Unit> { | ||||
| 
 | ||||
|     override fun visitFunctionalCustomTimer(functionalCustomTimer: FunctionalCustomTimer): @Composable () -> Unit { | ||||
|         return { CustomTimerSessionScreenComposable( | ||||
|                 open = open, | ||||
|                 sessionActions = sessionActions, | ||||
|                 soundPlayer = soundPlayer, | ||||
|                 customTimer = functionalCustomTimer, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun visitFunctionalEndlessTimer(functionalEndlessTimer: FunctionalEndlessTimer): @Composable () -> Unit { | ||||
|         return { | ||||
|             EndlessTimerSessionScreenComposable( | ||||
|                 open = open, | ||||
|                 sessionActions = sessionActions, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun visitFunctionalBreakTimer(functionalPomodoroTimer: FunctionalPomodoroTimer): @Composable () -> Unit { | ||||
|         return { | ||||
|             BreakSessionScreenComposable( | ||||
|                 open = open, | ||||
|                 sessionActions = sessionActions, | ||||
|                 soundPlayer = soundPlayer, | ||||
|                 pomodoroTimer = functionalPomodoroTimer | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,73 @@ | |||
| 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.Composable | ||||
| 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.unit.dp | ||||
| import androidx.compose.ui.unit.sp | ||||
| import be.ugent.sel.studeez.screens.session.SessionActions | ||||
| 
 | ||||
| @Composable | ||||
| fun SessionScreen( | ||||
|     open: (String) -> Unit, | ||||
|     sessionActions: SessionActions, | ||||
|     callMediaPlayer: () -> Unit = {}, | ||||
|     midSection: @Composable () -> Int = {0}, | ||||
|     motivationString: @Composable () -> String, | ||||
| 
 | ||||
| ) { | ||||
|     Column( | ||||
|         modifier = Modifier.padding(10.dp) | ||||
|     ) { | ||||
|         Timer( | ||||
|             sessionActions = sessionActions, | ||||
|             callMediaPlayer = callMediaPlayer, | ||||
|             motivationString = motivationString, | ||||
|             MidSection = midSection | ||||
|         ) | ||||
|         Box( | ||||
|             contentAlignment = Alignment.Center, modifier = Modifier | ||||
|                 .fillMaxWidth() | ||||
|                 .padding(50.dp) | ||||
|         ) { | ||||
|             EndSessionButton(sessionActions = sessionActions) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun EndSessionButton(sessionActions: SessionActions) { | ||||
|     TextButton( | ||||
|         onClick = { | ||||
|             sessionActions.endSession() | ||||
|         }, | ||||
|         modifier = Modifier | ||||
|             .padding(horizontal = 20.dp) | ||||
|             .border(1.dp, Color.Red, RoundedCornerShape(32.dp)) | ||||
|             .background(Color.Transparent) | ||||
|     ) { | ||||
|         EndsessionText() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun EndsessionText() { | ||||
|     Text( | ||||
|         text = "End session", | ||||
|         color = Color.Red, | ||||
|         fontWeight = FontWeight.Bold, | ||||
|         fontSize = 18.sp, | ||||
|         modifier = Modifier.padding(1.dp) | ||||
|     ) | ||||
| } | ||||
|  | @ -0,0 +1,95 @@ | |||
| package be.ugent.sel.studeez.screens.session.sessionScreens | ||||
| 
 | ||||
| import androidx.compose.foundation.background | ||||
| 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.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.unit.dp | ||||
| import androidx.compose.ui.unit.sp | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds | ||||
| import be.ugent.sel.studeez.screens.session.SessionActions | ||||
| import kotlinx.coroutines.delay | ||||
| import kotlin.time.Duration.Companion.seconds | ||||
| 
 | ||||
| @Composable | ||||
| fun Timer( | ||||
|     sessionActions: SessionActions, | ||||
|     callMediaPlayer: () -> Unit, | ||||
|     motivationString: @Composable () -> String, | ||||
|     MidSection: @Composable () -> Int | ||||
| ) { | ||||
|     var tikker by remember { mutableStateOf(false) } | ||||
|     LaunchedEffect(tikker) { | ||||
|         delay(1.seconds) | ||||
|         sessionActions.getTimer().tick() | ||||
|         callMediaPlayer() | ||||
|         tikker = !tikker | ||||
|     } | ||||
| 
 | ||||
|     val hms = sessionActions.getTimer().getHoursMinutesSeconds() | ||||
|     Column { | ||||
| 
 | ||||
|         TimerClock(hms) | ||||
|         MotivationText(text = motivationString()) | ||||
|         MidSection() | ||||
| 
 | ||||
|         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)) | ||||
|             ) { | ||||
|                 TaskText(taskName = sessionActions.getTask()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun TimerClock(hms: HoursMinutesSeconds) { | ||||
|     Text( | ||||
|         text = hms.toString(), | ||||
|         modifier = Modifier | ||||
|             .fillMaxWidth() | ||||
|             .padding(50.dp), | ||||
|         textAlign = TextAlign.Center, | ||||
|         fontWeight = FontWeight.Bold, | ||||
|         fontSize = 40.sp, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun MotivationText(text: String) { | ||||
|     Text( | ||||
|         text = text, | ||||
|         modifier = Modifier.fillMaxWidth(), | ||||
|         textAlign = TextAlign.Center, | ||||
|         fontWeight = FontWeight.Light, | ||||
|         fontSize = 30.sp | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun TaskText(taskName: String) { | ||||
|     Text( | ||||
|         text = taskName, | ||||
|         color = Color.White, | ||||
|         fontSize = 18.sp, | ||||
|         fontWeight = FontWeight.Bold, | ||||
|         modifier = Modifier.padding(vertical = 4.dp, horizontal = 20.dp) | ||||
|     ) | ||||
| } | ||||
		Reference in a new issue
	
	 lbarraga
						lbarraga