Merge branch 'development' into sessionscreen_ui
This commit is contained in:
		
						commit
						9d2c53d4e6
					
				
					 26 changed files with 477 additions and 79 deletions
				
			
		|  | @ -26,6 +26,7 @@ import be.ugent.sel.studeez.screens.profile.ProfileScreen | |||
| import be.ugent.sel.studeez.screens.sign_up.SignUpScreen | ||||
| import be.ugent.sel.studeez.screens.splash.SplashScreen | ||||
| import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewScreen | ||||
| import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionScreen | ||||
| import be.ugent.sel.studeez.ui.theme.StudeezTheme | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| 
 | ||||
|  | @ -130,4 +131,8 @@ fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { | |||
|     composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { | ||||
|         EditProfileScreen(goBack, openAndPopUp) | ||||
|     } | ||||
| 
 | ||||
|     composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { | ||||
|         TimerSelectionScreen(open, openAndPopUp) | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| package be.ugent.sel.studeez.data | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| 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 SelectedTimerState @Inject constructor(){ | ||||
|     var selectedTimer: FunctionalTimer? = null | ||||
| } | ||||
|  | @ -1,3 +1,3 @@ | |||
| package be.ugent.sel.studeez.data.local.models | ||||
| 
 | ||||
| data class User(val id: String = "", val isAnonymous: Boolean = true) | ||||
| data class User(val id: String = "") | ||||
|  |  | |||
|  | @ -1,16 +1,16 @@ | |||
| package be.ugent.sel.studeez.data.local.models.timer_functional | ||||
| 
 | ||||
| class FunctionalCustomTimer(studyTime: Int): FunctionalTimer(studyTime) { | ||||
| class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) { | ||||
| 
 | ||||
|     override fun tick() { | ||||
|         if (time.getTime() == 0) { | ||||
|             view = "Done!" | ||||
|         if (time.time == 0) { | ||||
|             view = StudyState.DONE | ||||
|         } else { | ||||
|             time.minOne() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun hasEnded(): Boolean { | ||||
|         return time.getTime() == 0 | ||||
|         return time.time == 0 | ||||
|     } | ||||
| } | ||||
|  | @ -1,6 +1,6 @@ | |||
| package be.ugent.sel.studeez.data.local.models.timer_functional | ||||
| 
 | ||||
| class FunctionalEndlessTimer() : FunctionalTimer(0){ | ||||
| class FunctionalEndlessTimer() : FunctionalTimer(0) { | ||||
| 
 | ||||
|     override fun hasEnded(): Boolean { | ||||
|         return false | ||||
|  |  | |||
|  | @ -3,25 +3,25 @@ package be.ugent.sel.studeez.data.local.models.timer_functional | |||
| class FunctionalPomodoroTimer( | ||||
|     private var studyTime: Int, | ||||
|     private var breakTime: Int, repeats: Int | ||||
| ): FunctionalTimer(studyTime) { | ||||
| ) : FunctionalTimer(studyTime) { | ||||
| 
 | ||||
|     private var breaksRemaining = repeats | ||||
|     private var isInBreak = false | ||||
|     var breaksRemaining = repeats | ||||
|     var isInBreak = false | ||||
| 
 | ||||
|     override fun tick() { | ||||
|         if (time.getTime() == 0 && breaksRemaining == 0){ | ||||
|             view = "Done!" | ||||
|         if (time.time == 0 && breaksRemaining == 0) { | ||||
|             view = StudyState.DONE | ||||
|             return | ||||
|         } | ||||
| 
 | ||||
|         if (time.getTime() == 0) { | ||||
|         if (time.time == 0) { | ||||
|             if (isInBreak) { | ||||
|                 breaksRemaining-- | ||||
|                 view = "Focus! ($breaksRemaining breaks remaining)" | ||||
|                 time.setTime(studyTime) | ||||
|                 view = StudyState.FOCUS_REMAINING | ||||
|                 time.time = studyTime | ||||
|             } else { | ||||
|                 view = "Take a break!" | ||||
|                 time.setTime(breakTime) | ||||
|                 view = StudyState.BREAK | ||||
|                 time.time = breakTime | ||||
|             } | ||||
|             isInBreak = !isInBreak | ||||
|         } | ||||
|  | @ -29,6 +29,6 @@ class FunctionalPomodoroTimer( | |||
|     } | ||||
| 
 | ||||
|     override fun hasEnded(): Boolean { | ||||
|         return breaksRemaining == 0 && time.getTime() == 0 | ||||
|         return breaksRemaining == 0 && time.time == 0 | ||||
|     } | ||||
| } | ||||
|  | @ -1,17 +1,13 @@ | |||
| package be.ugent.sel.studeez.data.local.models.timer_functional | ||||
| 
 | ||||
| abstract class FunctionalTimer(initialValue: Int) { | ||||
|     protected val time: Time = Time(initialValue) | ||||
|     protected var view: String = "Focus" | ||||
|     val time: Time = Time(initialValue) | ||||
|     var view: StudyState = StudyState.FOCUS | ||||
| 
 | ||||
|     fun getHoursMinutesSeconds(): HoursMinutesSeconds { | ||||
|         return time.getAsHMS() | ||||
|     } | ||||
| 
 | ||||
|     fun getViewString(): String { | ||||
|         return view | ||||
|     } | ||||
| 
 | ||||
|     abstract fun tick() | ||||
| 
 | ||||
|     abstract fun hasEnded(): Boolean | ||||
|  | @ -19,4 +15,9 @@ abstract class FunctionalTimer(initialValue: Int) { | |||
|     fun hasCurrentCountdownEnded(): Boolean { | ||||
|         return time.getTime() == 0 | ||||
|     } | ||||
| 
 | ||||
|     enum class StudyState { | ||||
|         FOCUS, DONE, BREAK, FOCUS_REMAINING | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -2,7 +2,7 @@ package be.ugent.sel.studeez.data.local.models.timer_functional | |||
| 
 | ||||
| class Time(initialTime: Int) { | ||||
| 
 | ||||
|     private var time = initialTime | ||||
|     var time = initialTime | ||||
| 
 | ||||
|     fun minOne() { | ||||
|         time-- | ||||
|  | @ -12,14 +12,6 @@ class Time(initialTime: Int) { | |||
|         time++ | ||||
|     } | ||||
| 
 | ||||
|     fun setTime(newTime: Int) { | ||||
|         time = newTime | ||||
|     } | ||||
| 
 | ||||
|     fun getTime(): Int { | ||||
|         return time | ||||
|     } | ||||
| 
 | ||||
|     fun getAsHMS(): HoursMinutesSeconds { | ||||
|         val hours: Int = time / (60 * 60) | ||||
|         val minutes: Int = (time / (60)) % 60 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ package be.ugent.sel.studeez.data.local.models.timer_info | |||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| 
 | ||||
| class BreakTimerInfo( | ||||
| class PomodoroTimerInfo( | ||||
|     name: String, | ||||
|     description: String, | ||||
|     private val studyTime: Int, | ||||
|  | @ -39,7 +39,7 @@ class FirebaseAccountDAO @Inject constructor( | |||
|         get() = callbackFlow { | ||||
|             val listener = | ||||
|                 FirebaseAuth.AuthStateListener { auth -> | ||||
|                     this.trySend(auth.currentUser?.let { User(it.uid, it.isAnonymous) } ?: User()) | ||||
|                     this.trySend(auth.currentUser?.let { User(it.uid) } ?: User()) | ||||
|                 } | ||||
|             auth.addAuthStateListener(listener) | ||||
|             awaitClose { auth.removeAuthStateListener(listener) } | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ class ToTimerConverter { | |||
|             it.studyTime, | ||||
|             it.id | ||||
|         ) }, | ||||
|         TimerType.BREAK to TimerFactory { BreakTimerInfo( | ||||
|         TimerType.BREAK to TimerFactory { PomodoroTimerInfo( | ||||
|             it.name, | ||||
|             it.description, | ||||
|             it.studyTime, | ||||
|  |  | |||
|  | @ -5,8 +5,9 @@ object StudeezDestinations { | |||
|     const val SIGN_UP_SCREEN = "signup" | ||||
|     const val LOGIN_SCREEN = "login" | ||||
| 
 | ||||
|      const val HOME_SCREEN = "home" | ||||
|     const val HOME_SCREEN = "home" | ||||
|     const val TIMER_OVERVIEW_SCREEN = "timer_overview" | ||||
|     const val TIMER_SELECTION_SCREEN = "timer_selection" | ||||
|     const val SESSION_SCREEN = "session" | ||||
|  //    const val TASKS_SCREEN = "tasks" | ||||
|  //    const val SESSIONS_SCREEN = "sessions" | ||||
|  |  | |||
|  | @ -15,14 +15,7 @@ class HomeViewModel @Inject constructor( | |||
|     logService: LogService | ||||
| ) : StudeezViewModel(logService) { | ||||
| 
 | ||||
|     fun onStartSessionClick(openAndPopUp: (String) -> Unit) { | ||||
|         openAndPopUp(StudeezDestinations.SESSION_SCREEN) | ||||
|     } | ||||
| 
 | ||||
|     fun onLogoutClick(openAndPopup: (String, String) -> Unit) { | ||||
|         launchCatching { | ||||
|             accountDAO.signOut() | ||||
|             openAndPopup(LOGIN_SCREEN, HOME_SCREEN) | ||||
|         } | ||||
|     fun onStartSessionClick(open: (String) -> Unit) { | ||||
|         open(StudeezDestinations.TIMER_SELECTION_SCREEN) | ||||
|     } | ||||
| } | ||||
|  | @ -14,16 +14,28 @@ import androidx.compose.material.Text | |||
| import androidx.compose.material.TextButton | ||||
| import androidx.compose.runtime.* | ||||
| import androidx.compose.ui.Alignment | ||||
| 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.Modifier | ||||
| import androidx.compose.ui.graphics.Color | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.text.font.FontWeight | ||||
| import androidx.compose.ui.text.style.TextAlign | ||||
| import androidx.compose.ui.unit.dp | ||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||
| import androidx.compose.ui.unit.sp | ||||
| import androidx.hilt.navigation.compose.hiltViewModel | ||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||
| import be.ugent.sel.studeez.R | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer.StudyState | ||||
| import be.ugent.sel.studeez.resources | ||||
| import kotlinx.coroutines.delay | ||||
| import kotlin.time.Duration.Companion.seconds | ||||
| 
 | ||||
| var timerEnd = false | ||||
| 
 | ||||
|  | @ -31,7 +43,6 @@ var timerEnd = false | |||
| fun SessionScreen( | ||||
|     open: (String) -> Unit, | ||||
|     openAndPopUp: (String, String) -> Unit, | ||||
|     viewModel: SessionViewModel = hiltViewModel() | ||||
| ) { | ||||
|     val context = LocalContext.current | ||||
|     val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) | ||||
|  | @ -86,9 +97,9 @@ fun SessionScreen( | |||
| private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: MediaPlayer) { | ||||
|     var tikker by remember { mutableStateOf(false) } | ||||
|     LaunchedEffect(tikker) { | ||||
|         delay(1000) | ||||
|         delay(1.seconds) | ||||
|         viewModel.getTimer().tick() | ||||
|         tikker = !tikker | ||||
|         ticker = !ticker | ||||
|     } | ||||
| 
 | ||||
|     if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { | ||||
|  | @ -111,8 +122,18 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me | |||
|             fontWeight = FontWeight.Bold, | ||||
|             fontSize = 40.sp, | ||||
|         ) | ||||
|         val stateString: String = when (viewModel.getTimer().view) { | ||||
|             StudyState.DONE -> resources().getString(R.string.state_done) | ||||
|             StudyState.FOCUS -> resources().getString(R.string.state_focus) | ||||
|             StudyState.BREAK -> resources().getString(R.string.state_take_a_break) | ||||
|             StudyState.FOCUS_REMAINING -> | ||||
|                 (viewModel.getTimer() as FunctionalPomodoroTimer?)?.breaksRemaining?.let { | ||||
|                     resources().getQuantityString(R.plurals.state_focus_remaining, it, it) | ||||
|             }.toString() | ||||
|         } | ||||
| 
 | ||||
|         Text( | ||||
|             text = viewModel.getTimer().getViewString(), | ||||
|             text = stateString, | ||||
|             modifier = Modifier.fillMaxWidth(), | ||||
|             textAlign = TextAlign.Center, | ||||
|             fontWeight = FontWeight.Light, | ||||
|  | @ -142,4 +163,6 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me | |||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -1,14 +1,15 @@ | |||
| package be.ugent.sel.studeez.screens.session | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import be.ugent.sel.studeez.domain.LogService | ||||
| import be.ugent.sel.studeez.screens.StudeezViewModel | ||||
| import be.ugent.sel.studeez.data.SelectedTimerState | ||||
| import dagger.hilt.android.lifecycle.HiltViewModel | ||||
| import javax.inject.Inject | ||||
| 
 | ||||
| @HiltViewModel | ||||
| class SessionViewModel @Inject constructor( | ||||
|     private val selectedTimerState: SelectedTimerState, | ||||
|     logService: LogService | ||||
| ) : StudeezViewModel(logService) { | ||||
| 
 | ||||
|  | @ -16,7 +17,7 @@ class SessionViewModel @Inject constructor( | |||
|     private val task : String = "No task selected" // placeholder for tasks implementation | ||||
| 
 | ||||
|     fun getTimer() : FunctionalTimer { | ||||
|         return timer | ||||
|         return selectedTimerState.selectedTimer!! | ||||
|     } | ||||
| 
 | ||||
|     fun getTask(): String { | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| package be.ugent.sel.studeez.screens.timer_overview | ||||
| 
 | ||||
| import androidx.annotation.StringRes | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.Row | ||||
|  | @ -46,12 +47,12 @@ fun TimerOverviewScreen( | |||
|             ) { | ||||
|                 // Default Timers, cannot be edited | ||||
|                 items(viewModel.getDefaultTimers()) { | ||||
|                     TimerEntry(timerInfo = it, canEdit = false) | ||||
|                     TimerEntry(timerInfo = it, canDisplay = false) | ||||
|                 } | ||||
| 
 | ||||
|                 // User timers, can be edited | ||||
|                 items(timers.value) { | ||||
|                     TimerEntry(timerInfo = it, true) { timerInfo -> | ||||
|                     TimerEntry(timerInfo = it, true, R.string.edit) { timerInfo -> | ||||
|                         viewModel.update(timerInfo) | ||||
|                     } | ||||
|                 } | ||||
|  | @ -65,7 +66,12 @@ fun TimerOverviewScreen( | |||
| } | ||||
| 
 | ||||
| @Composable | ||||
| fun TimerEntry(timerInfo: TimerInfo, canEdit: Boolean, update: (TimerInfo) -> Unit = {}) { | ||||
| fun TimerEntry( | ||||
|     timerInfo: TimerInfo, | ||||
|     canDisplay: Boolean, | ||||
|     @StringRes buttonName: Int = -1, | ||||
|     buttonFunction: (TimerInfo) -> Unit = {} | ||||
| ) { | ||||
|     Row( | ||||
|         verticalAlignment = Alignment.CenterVertically, | ||||
|         modifier = Modifier.fillMaxWidth(), | ||||
|  | @ -83,9 +89,9 @@ fun TimerEntry(timerInfo: TimerInfo, canEdit: Boolean, update: (TimerInfo) -> Un | |||
|                 fontSize = 15.sp | ||||
|             ) | ||||
|         } | ||||
|         if (canEdit) { | ||||
|             BasicButton(R.string.edit, Modifier.card()) { | ||||
|                 // TODO | ||||
|         if (canDisplay) { | ||||
|             BasicButton(buttonName, Modifier.card()) { | ||||
|                 buttonFunction(timerInfo) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,44 @@ | |||
| package be.ugent.sel.studeez.screens.timer_selection | ||||
| 
 | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.lazy.LazyColumn | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.runtime.* | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.hilt.navigation.compose.hiltViewModel | ||||
| import be.ugent.sel.studeez.R | ||||
| import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||
| import be.ugent.sel.studeez.resources | ||||
| import be.ugent.sel.studeez.screens.timer_overview.TimerEntry | ||||
| 
 | ||||
| @Composable | ||||
| fun TimerSelectionScreen( | ||||
|     open: (String) -> Unit, | ||||
|     openAndPopUp: (String, String) -> Unit, | ||||
|     viewModel: TimerSelectionViewModel = hiltViewModel() | ||||
| ) { | ||||
| 
 | ||||
|     val timers = viewModel.getAllTimers().collectAsState(initial = emptyList()) | ||||
| 
 | ||||
|     PrimaryScreenTemplate( | ||||
|         title = resources().getString(R.string.timers), | ||||
|         open = open, | ||||
|         openAndPopUp = openAndPopUp, | ||||
|     ) { | ||||
| 
 | ||||
|         LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) { | ||||
| 
 | ||||
|             // All timers | ||||
|             items(timers.value) { | ||||
|                 TimerEntry( | ||||
|                     timerInfo = it, | ||||
|                     canDisplay = true, | ||||
|                     buttonName = R.string.start | ||||
|                 ) { timerInfo -> | ||||
|                     viewModel.startSession(open, timerInfo) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,28 @@ | |||
| package be.ugent.sel.studeez.screens.timer_selection | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.SelectedTimerState | ||||
| import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||
| import be.ugent.sel.studeez.domain.LogService | ||||
| import be.ugent.sel.studeez.domain.TimerDAO | ||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||
| import be.ugent.sel.studeez.screens.StudeezViewModel | ||||
| import dagger.hilt.android.lifecycle.HiltViewModel | ||||
| import kotlinx.coroutines.flow.Flow | ||||
| import javax.inject.Inject | ||||
| 
 | ||||
| @HiltViewModel | ||||
| class TimerSelectionViewModel @Inject constructor( | ||||
|     private val timerDAO: TimerDAO, | ||||
|     private val selectedTimerState: SelectedTimerState, | ||||
|     logService: LogService | ||||
| ) : StudeezViewModel(logService) { | ||||
| 
 | ||||
|     fun getAllTimers() : Flow<List<TimerInfo>> { | ||||
|         return timerDAO.getAllTimers() | ||||
|     } | ||||
| 
 | ||||
|     fun startSession(open: (String) -> Unit, timerInfo: TimerInfo) { | ||||
|         selectedTimerState.selectedTimer = timerInfo.getFunctionalTimer() | ||||
|         open(StudeezDestinations.SESSION_SCREEN) | ||||
|     } | ||||
| } | ||||
|  | @ -1,4 +0,0 @@ | |||
| package be.ugent.sel.studeez.screens.timers | ||||
| 
 | ||||
| class TimerScreen { | ||||
| } | ||||
|  | @ -13,6 +13,7 @@ | |||
|         <string name="cancel">Cancel</string> | ||||
|         <string name="go_back">Go back</string> | ||||
|         <string name="next">Next</string> | ||||
|         <string name="start">Start</string> | ||||
| 
 | ||||
|         <!-- Messages --> | ||||
|         <string name="success">Success!</string> | ||||
|  | @ -63,6 +64,14 @@ | |||
|     <string name="timers">Timers</string> | ||||
|     <string name="edit">Edit</string> | ||||
|     <string name="add_timer">Add timer</string> | ||||
|     <string name="state_focus">Focus!</string> | ||||
|     <plurals name="state_focus_remaining"> | ||||
|         <item quantity="zero">Focus one more time!</item> | ||||
|         <item quantity="one">Focus! (%d break remaining)</item> | ||||
|         <item quantity="other">Focus! (%d breaks remaining)</item> | ||||
|     </plurals> | ||||
|     <string name="state_done">Done!</string> | ||||
|     <string name="state_take_a_break">Take a break!</string> | ||||
| 
 | ||||
|     <!-- Settings --> | ||||
|     <string name="settings">Settings</string> | ||||
|  |  | |||
|  | @ -1,17 +0,0 @@ | |||
| package be.ugent.sel.studeez | ||||
| 
 | ||||
| import org.junit.Test | ||||
| 
 | ||||
| import org.junit.Assert.* | ||||
| 
 | ||||
| /** | ||||
|  * Example local unit test, which will execute on the development machine (host). | ||||
|  * | ||||
|  * See [testing documentation](http://d.android.com/tools/testing). | ||||
|  */ | ||||
| class ExampleUnitTest { | ||||
|     @Test | ||||
|     fun addition_isCorrect() { | ||||
|         assertEquals(4, 2 + 2) | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,44 @@ | |||
| package be.ugent.sel.studeez.timer_functional | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalCustomTimerUnitTest : FunctionalTimerUnitTest() { | ||||
|     override fun setTimer() { | ||||
|         timer = FunctionalCustomTimer(time) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testOneTick() { | ||||
|         timer.tick() | ||||
|         Assert.assertEquals( | ||||
|             time - 1, | ||||
|             timer.time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun multipleTicks() { | ||||
|         val n = 10 | ||||
|         for (i in 1..n) { | ||||
|             timer.tick() | ||||
|         } | ||||
|         Assert.assertEquals( | ||||
|             time - n, | ||||
|             timer.time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testEnded() { | ||||
|         timer = FunctionalCustomTimer(0) | ||||
|         timer.tick() | ||||
|         Assert.assertTrue(timer.hasEnded()) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.DONE, | ||||
|             timer.view | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,46 @@ | |||
| package be.ugent.sel.studeez.timer_functional | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalEndlessTimerUnitTest : FunctionalTimerUnitTest() { | ||||
|     override fun setTimer() { | ||||
|         timer = FunctionalEndlessTimer() | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testOneTick() { | ||||
|         timer.tick() | ||||
|         Assert.assertEquals( | ||||
|             1, | ||||
|             timer.time.time | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun multipleTicks() { | ||||
|         val n = 10 | ||||
|         for (i in 1..n) { | ||||
|             timer.tick() | ||||
|         } | ||||
|         Assert.assertEquals( | ||||
|             n, | ||||
|             timer.time.time | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testEnded() { | ||||
|         val n = 1000 | ||||
|         for (i in 1..n) { | ||||
|             timer.tick() | ||||
|             Assert.assertFalse(timer.hasEnded()) | ||||
|             Assert.assertEquals( | ||||
|                 FunctionalTimer.StudyState.FOCUS, | ||||
|                 timer.view | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,98 @@ | |||
| package be.ugent.sel.studeez.timer_functional | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import org.junit.Assert | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() { | ||||
|     private val breakTime = 10 | ||||
|     private val breaks = 2 | ||||
|     override val hours = 0 | ||||
|     override val minutes = 0 | ||||
|     override val seconds = 10 | ||||
|     private lateinit var pomodoroTimer: FunctionalPomodoroTimer | ||||
| 
 | ||||
|     override fun setTimer() { | ||||
|         pomodoroTimer = FunctionalPomodoroTimer(time, breakTime, breaks) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testOneTick() { | ||||
|         pomodoroTimer.tick() | ||||
|         Assert.assertEquals( | ||||
|             time - 1, | ||||
|             pomodoroTimer.time.time, | ||||
|         ) | ||||
|         Assert.assertFalse(pomodoroTimer.isInBreak) | ||||
|         Assert.assertEquals( | ||||
|             breaks, | ||||
|             pomodoroTimer.breaksRemaining, | ||||
|         ) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.FOCUS, | ||||
|             pomodoroTimer.view, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun multipleTicks() { | ||||
|         val n = 10 | ||||
|         for (i in 1..n) { | ||||
|             pomodoroTimer.tick() | ||||
|         } | ||||
|         Assert.assertEquals( | ||||
|             time - n, | ||||
|             pomodoroTimer.time.time | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     override fun testEnded() { | ||||
|         pomodoroTimer = FunctionalPomodoroTimer(0, 0, 0) | ||||
|         pomodoroTimer.tick() | ||||
|         Assert.assertTrue(pomodoroTimer.hasEnded()) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.DONE, | ||||
|             pomodoroTimer.view, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun switchToBreak() { | ||||
|         for (i in 0..10) { | ||||
|             pomodoroTimer.tick() | ||||
|         } | ||||
|         Assert.assertFalse(pomodoroTimer.hasEnded()) | ||||
|         Assert.assertTrue(pomodoroTimer.isInBreak) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.BREAK, | ||||
|             pomodoroTimer.view | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun switchToStudying() { | ||||
|         for (i in 0..time) { | ||||
|             pomodoroTimer.tick() | ||||
|         } | ||||
|         Assert.assertTrue(pomodoroTimer.isInBreak) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.BREAK, | ||||
|             pomodoroTimer.view | ||||
|         ) | ||||
|         for (i in 0..breakTime) { | ||||
|             pomodoroTimer.tick() | ||||
|         } | ||||
|         Assert.assertFalse(pomodoroTimer.isInBreak) | ||||
|         val breaksRemaining = breaks - 1 | ||||
|         Assert.assertEquals( | ||||
|             breaksRemaining, | ||||
|             pomodoroTimer.breaksRemaining | ||||
|         ) | ||||
|         Assert.assertEquals( | ||||
|             FunctionalTimer.StudyState.FOCUS_REMAINING, | ||||
|             pomodoroTimer.view | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,33 @@ | |||
| package be.ugent.sel.studeez.timer_functional | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer | ||||
| import org.junit.Before | ||||
| import org.junit.Test | ||||
| 
 | ||||
| abstract class FunctionalTimerUnitTest { | ||||
|     protected lateinit var timer: FunctionalTimer | ||||
|     protected open val hours = 4 | ||||
|     protected open val minutes = 20 | ||||
|     protected open val seconds = 39 | ||||
|     protected var time: Int = 0 | ||||
| 
 | ||||
|     @Before | ||||
|     fun setup() { | ||||
|         time = seconds + minutes * 60 + hours * 60 * 60 | ||||
|         setTimer() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The timer-property should be set to the right implementation in this method. | ||||
|      */ | ||||
|     abstract fun setTimer() | ||||
| 
 | ||||
|     @Test | ||||
|     abstract fun testOneTick() | ||||
| 
 | ||||
|     @Test | ||||
|     abstract fun multipleTicks() | ||||
| 
 | ||||
|     @Test | ||||
|     abstract fun testEnded() | ||||
| } | ||||
|  | @ -0,0 +1,81 @@ | |||
| package be.ugent.sel.studeez.timer_functional | ||||
| 
 | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds | ||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.Time | ||||
| import org.junit.Assert | ||||
| import org.junit.Before | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class TimeUnitTest { | ||||
|     private val hours = 4 | ||||
|     private val minutes = 20 | ||||
|     private val seconds = 39 | ||||
|     private val time: Time = Time(seconds + minutes * 60 + hours * 60 * 60) | ||||
| 
 | ||||
|     @Before | ||||
|     fun setup() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun formatTime() { | ||||
|         Assert.assertEquals( | ||||
|             HoursMinutesSeconds( | ||||
|                 hours.toString().padStart(2, '0'), | ||||
|                 minutes.toString().padStart(2, '0'), | ||||
|                 seconds.toString().padStart(2, '0'), | ||||
|             ), | ||||
|             time.getAsHMS(), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun getTime() { | ||||
|         Assert.assertEquals( | ||||
|             seconds + minutes * 60 + hours * 60 * 60, | ||||
|             time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun minOne() { | ||||
|         time.minOne() | ||||
|         Assert.assertEquals( | ||||
|             (seconds + minutes * 60 + hours * 60 * 60) - 1, | ||||
|             time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun plusOne() { | ||||
|         time.plusOne() | ||||
|         Assert.assertEquals( | ||||
|             (seconds + minutes * 60 + hours * 60 * 60) + 1, | ||||
|             time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun minMultiple() { | ||||
|         val n = 10 | ||||
|         for (i in 1 .. n) { | ||||
|             time.minOne() | ||||
|         } | ||||
|         Assert.assertEquals( | ||||
|             (seconds + minutes * 60 + hours * 60 * 60) - n, | ||||
|             time.time, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun plusMultiple() { | ||||
|         val n = 10 | ||||
|         for (i in 1 .. n) { | ||||
|             time.plusOne() | ||||
|         } | ||||
|         Assert.assertEquals( | ||||
|             (seconds + minutes * 60 + hours * 60 * 60) + n, | ||||
|             time.time, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
		Reference in a new issue
	
	 rdyselin
						rdyselin