From dc43b26dc025d354e87feef31cb68cde41ac84ba Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Mon, 24 Apr 2023 12:17:43 +0200 Subject: [PATCH 01/59] timerstates fixed --- .../studeez/screens/session/SessionScreen.kt | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 451f705..0559291 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -35,8 +35,6 @@ import be.ugent.sel.studeez.resources import kotlinx.coroutines.delay import kotlin.time.Duration.Companion.seconds -var timerEnd = false - @Composable fun SessionScreen( open: (String) -> Unit, @@ -46,17 +44,7 @@ fun SessionScreen( val context = LocalContext.current val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val mediaplayer = MediaPlayer.create(context, uri) - mediaplayer.setOnCompletionListener { - if (!mediaplayer.isPlaying) { - mediaplayer.stop() - } - if (timerEnd) { - mediaplayer.release() - } - } - mediaplayer.setOnPreparedListener { - mediaplayer.start() - } + mediaplayer.isLooping = false Column( modifier = Modifier.padding(10.dp) @@ -71,6 +59,7 @@ fun SessionScreen( ) { TextButton( onClick = { + mediaplayer.stop() mediaplayer.release() open(StudeezDestinations.HOME_SCREEN) // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt @@ -102,12 +91,7 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me } if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { - mediaplayer.prepare() - } - - if (!timerEnd && viewModel.getTimer().hasEnded()) { - mediaplayer.prepare() - timerEnd = true // Placeholder, vanaf hier moet het report opgestart worden en de sessie afgesloten + mediaplayer.start() } val hms = viewModel.getTimer().getHoursMinutesSeconds() From e20e972b88d9d778953ee4df6b00ac4cf81e7d7a Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Mon, 24 Apr 2023 19:52:36 +0200 Subject: [PATCH 02/59] localdatetime version --- .idea/misc.xml | 2 +- .../sel/studeez/activities/MainActivity.kt | 13 ++++++ .../timer_functional/FunctionalTimer.kt | 2 +- .../local/models/timer_functional/Time.kt | 4 ++ .../studeez/screens/session/SessionScreen.kt | 45 +++++++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 704c883..bdd9278 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - + diff --git a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt index 318fe7a..6829e7f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt +++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt @@ -1,6 +1,7 @@ package be.ugent.sel.studeez.activities import android.os.Bundle +import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize @@ -11,6 +12,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.StudeezApp +import be.ugent.sel.studeez.screens.session.SessionTest +import be.ugent.sel.studeez.screens.session.test import be.ugent.sel.studeez.ui.theme.StudeezTheme import dagger.hilt.android.AndroidEntryPoint @@ -30,6 +33,16 @@ class MainActivity : ComponentActivity() { } } } + + override fun onStop() { + test() + super.onStop() + } + + override fun onStart() { + SessionTest.updateTimer() + super.onStart() + } } @Composable diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt index dae27c6..bb7423e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt @@ -1,7 +1,7 @@ package be.ugent.sel.studeez.data.local.models.timer_functional abstract class FunctionalTimer(initialValue: Int) { - val time: Time = Time(initialValue) + var time: Time = Time(initialValue) var view: StudyState = StudyState.FOCUS fun getHoursMinutesSeconds(): HoursMinutesSeconds { diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index ec7702d..83be75d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -4,6 +4,10 @@ class Time(initialTime: Int) { var time = initialTime + fun min(i: Int) { + time -= i + } + fun minOne() { time-- } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 0559291..dee4f12 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -3,6 +3,7 @@ package be.ugent.sel.studeez.screens.session import android.media.MediaPlayer import android.media.RingtoneManager import android.net.Uri +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box @@ -31,10 +32,20 @@ import androidx.hilt.navigation.compose.hiltViewModel 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.StudyState +import be.ugent.sel.studeez.data.local.models.timer_functional.Time import be.ugent.sel.studeez.resources import kotlinx.coroutines.delay +import java.time.Duration +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.* +import kotlin.properties.Delegates +import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds +var start: LocalDateTime = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() + @Composable fun SessionScreen( open: (String) -> Unit, @@ -46,6 +57,8 @@ fun SessionScreen( val mediaplayer = MediaPlayer.create(context, uri) mediaplayer.isLooping = false + SessionTest.setNewViewModel(viewModel = viewModel) + Column( modifier = Modifier.padding(10.dp) ) { @@ -81,6 +94,11 @@ fun SessionScreen( } } +private operator fun Time.minus(time: Time): Time { + return Time(this.time - time.time) + +} + @Composable private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: MediaPlayer) { var tikker by remember { mutableStateOf(false) } @@ -146,6 +164,33 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me } } } +} + +fun test() { + start = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() +} + +object SessionTest { + lateinit var viewModel: SessionViewModel + private var isSession: Boolean = false + + fun setNewViewModel(viewModel: SessionViewModel) { + isSession = true + this.viewModel = viewModel + } + + fun updateTimer() { + if (isSession) { + val end = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() + + val duration = Duration.between(start, end) + + val hours = duration.toHours() + val minutes = duration.toMinutes() % 60 + val seconds = duration.seconds % 60 + viewModel.getTimer().time.min((hours + minutes + seconds).toInt()) + } + } } \ No newline at end of file From ea4e7a4790e43751c75d0ae0ad9a67f234d6db74 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Mon, 24 Apr 2023 21:35:48 +0200 Subject: [PATCH 03/59] timer can run when invisible (but no sound) --- .../sel/studeez/activities/MainActivity.kt | 17 +++++++--- .../local/models/timer_functional/Time.kt | 4 --- .../studeez/screens/session/SessionScreen.kt | 32 ++++++------------- 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt index 6829e7f..734908b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt +++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt @@ -1,7 +1,6 @@ package be.ugent.sel.studeez.activities import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize @@ -11,11 +10,15 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.lifecycleScope import be.ugent.sel.studeez.StudeezApp -import be.ugent.sel.studeez.screens.session.SessionTest -import be.ugent.sel.studeez.screens.session.test +import be.ugent.sel.studeez.screens.session.InvisibleSessionManager import be.ugent.sel.studeez.ui.theme.StudeezTheme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +var onTimerInvisible: Job? = null @AndroidEntryPoint class MainActivity : ComponentActivity() { @@ -34,13 +37,17 @@ class MainActivity : ComponentActivity() { } } + + override fun onStop() { - test() + onTimerInvisible = lifecycleScope.launch { + InvisibleSessionManager.updateTimer() + } super.onStop() } override fun onStart() { - SessionTest.updateTimer() + onTimerInvisible?.cancel() super.onStart() } } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index 83be75d..ec7702d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -4,10 +4,6 @@ class Time(initialTime: Int) { var time = initialTime - fun min(i: Int) { - time -= i - } - fun minOne() { time-- } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index dee4f12..48cf209 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -3,7 +3,6 @@ package be.ugent.sel.studeez.screens.session import android.media.MediaPlayer import android.media.RingtoneManager import android.net.Uri -import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box @@ -35,17 +34,11 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer.S import be.ugent.sel.studeez.data.local.models.timer_functional.Time import be.ugent.sel.studeez.resources import kotlinx.coroutines.delay -import java.time.Duration import java.time.LocalDateTime import java.time.ZoneId import java.util.* -import kotlin.properties.Delegates -import kotlin.time.Duration.Companion.hours -import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds -var start: LocalDateTime = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() - @Composable fun SessionScreen( open: (String) -> Unit, @@ -57,7 +50,7 @@ fun SessionScreen( val mediaplayer = MediaPlayer.create(context, uri) mediaplayer.isLooping = false - SessionTest.setNewViewModel(viewModel = viewModel) + InvisibleSessionManager.setNewViewModel(viewModel = viewModel) Column( modifier = Modifier.padding(10.dp) @@ -75,6 +68,7 @@ fun SessionScreen( mediaplayer.stop() mediaplayer.release() open(StudeezDestinations.HOME_SCREEN) + InvisibleSessionManager.isSession = false // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt }, modifier = Modifier @@ -166,29 +160,21 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me } } -fun test() { - start = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() -} - -object SessionTest { +object InvisibleSessionManager { lateinit var viewModel: SessionViewModel - private var isSession: Boolean = false + var isSession: Boolean = false fun setNewViewModel(viewModel: SessionViewModel) { isSession = true this.viewModel = viewModel } - fun updateTimer() { + suspend fun updateTimer() { if (isSession) { - val end = Calendar.getInstance().time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() - - val duration = Duration.between(start, end) - - val hours = duration.toHours() - val minutes = duration.toMinutes() % 60 - val seconds = duration.seconds % 60 - viewModel.getTimer().time.min((hours + minutes + seconds).toInt()) + while (true) { + delay(1.seconds) + viewModel.getTimer().tick() + } } } From addfb7e12650c3bf02ebe09e502b811ea926a561 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 25 Apr 2023 08:44:24 +0200 Subject: [PATCH 04/59] temporary solution to notification when app is in background --- .../sel/studeez/activities/MainActivity.kt | 20 ++++++++++++++++--- .../studeez/screens/session/SessionScreen.kt | 15 +++++--------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt index 734908b..96868f1 100644 --- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt +++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt @@ -1,5 +1,8 @@ package be.ugent.sel.studeez.activities +import android.media.MediaPlayer +import android.media.RingtoneManager +import android.net.Uri import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -22,7 +25,13 @@ var onTimerInvisible: Job? = null @AndroidEntryPoint class MainActivity : ComponentActivity() { + + private var mediaPlayer: MediaPlayer? = null override fun onCreate(savedInstanceState: Bundle?) { + val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) + mediaPlayer = MediaPlayer.create(this, uri) + mediaPlayer?.isLooping = false + super.onCreate(savedInstanceState) setContent { StudeezTheme { @@ -37,19 +46,24 @@ class MainActivity : ComponentActivity() { } } - - override fun onStop() { onTimerInvisible = lifecycleScope.launch { - InvisibleSessionManager.updateTimer() + InvisibleSessionManager.updateTimer(mediaPlayer) } super.onStop() } override fun onStart() { + mediaPlayer?.stop() onTimerInvisible?.cancel() super.onStart() } + + override fun onDestroy() { + mediaPlayer?.stop() + mediaPlayer?.release() + super.onDestroy() + } } @Composable diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 48cf209..9f009f4 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -31,12 +31,8 @@ import androidx.hilt.navigation.compose.hiltViewModel 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.StudyState -import be.ugent.sel.studeez.data.local.models.timer_functional.Time import be.ugent.sel.studeez.resources import kotlinx.coroutines.delay -import java.time.LocalDateTime -import java.time.ZoneId -import java.util.* import kotlin.time.Duration.Companion.seconds @Composable @@ -50,6 +46,7 @@ fun SessionScreen( val mediaplayer = MediaPlayer.create(context, uri) mediaplayer.isLooping = false + // evt mediaplayer meegeven vanaf hier als reserve oplossing InvisibleSessionManager.setNewViewModel(viewModel = viewModel) Column( @@ -88,11 +85,6 @@ fun SessionScreen( } } -private operator fun Time.minus(time: Time): Time { - return Time(this.time - time.time) - -} - @Composable private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: MediaPlayer) { var tikker by remember { mutableStateOf(false) } @@ -169,11 +161,14 @@ object InvisibleSessionManager { this.viewModel = viewModel } - suspend fun updateTimer() { + suspend fun updateTimer(mediaPlayer: MediaPlayer?) { if (isSession) { while (true) { delay(1.seconds) viewModel.getTimer().tick() + if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { + mediaPlayer?.start() + } } } } From 9c105f96a97fe33cab50af12d235142eb326b418 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 25 Apr 2023 09:37:50 +0200 Subject: [PATCH 05/59] mediaplayer from SessionScreen.kt instead of MainActivity.kt --- .../ugent/sel/studeez/activities/MainActivity.kt | 2 +- .../sel/studeez/screens/session/SessionScreen.kt | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt index 96868f1..02656bd 100644 --- a/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt +++ b/app/src/main/java/be/ugent/sel/studeez/activities/MainActivity.kt @@ -48,7 +48,7 @@ class MainActivity : ComponentActivity() { override fun onStop() { onTimerInvisible = lifecycleScope.launch { - InvisibleSessionManager.updateTimer(mediaPlayer) + InvisibleSessionManager.updateTimer() } super.onStop() } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 9f009f4..7b0ad3c 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -47,7 +47,7 @@ fun SessionScreen( mediaplayer.isLooping = false // evt mediaplayer meegeven vanaf hier als reserve oplossing - InvisibleSessionManager.setNewViewModel(viewModel = viewModel) + InvisibleSessionManager.setParameters(viewModel = viewModel, mediaplayer = mediaplayer) Column( modifier = Modifier.padding(10.dp) @@ -153,25 +153,25 @@ private fun Timer(viewModel: SessionViewModel = hiltViewModel(), mediaplayer: Me } object InvisibleSessionManager { - lateinit var viewModel: SessionViewModel + private lateinit var viewModel: SessionViewModel + private lateinit var mediaplayer: MediaPlayer var isSession: Boolean = false - fun setNewViewModel(viewModel: SessionViewModel) { + fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { isSession = true this.viewModel = viewModel + this.mediaplayer = mediaplayer } - suspend fun updateTimer(mediaPlayer: MediaPlayer?) { + suspend fun updateTimer() { if (isSession) { while (true) { delay(1.seconds) viewModel.getTimer().tick() if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { - mediaPlayer?.start() + mediaplayer.start() } } } } - - -} \ No newline at end of file +} From d5f3962afe86d5acb741e3e4442d95c8eb693202 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 25 Apr 2023 15:46:13 +0200 Subject: [PATCH 06/59] tests added --- .idea/inspectionProfiles/Project_Default.xml | 1 + app/build.gradle | 4 + .../studeez/screens/session/SessionScreen.kt | 1 - .../InvisibleSessionManagerTest.kt | 83 +++++++++++++++++++ gradle.properties | 2 + 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 53a1745..cd54531 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -42,5 +42,6 @@ \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index bca9a30..6489d31 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,6 +66,7 @@ dependencies { implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.compose.material:material:1.2.0' + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" // ViewModel @@ -97,6 +98,9 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' + // Coroutine testing + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' + // Mocking testImplementation 'org.mockito.kotlin:mockito-kotlin:3.2.0' diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 7b0ad3c..ac2d225 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -46,7 +46,6 @@ fun SessionScreen( val mediaplayer = MediaPlayer.create(context, uri) mediaplayer.isLooping = false - // evt mediaplayer meegeven vanaf hier als reserve oplossing InvisibleSessionManager.setParameters(viewModel = viewModel, mediaplayer = mediaplayer) Column( diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt new file mode 100644 index 0000000..5649f46 --- /dev/null +++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt @@ -0,0 +1,83 @@ +package be.ugent.sel.studeez.timer_functional + +import android.media.MediaPlayer +import be.ugent.sel.studeez.data.SelectedTimerState +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.FunctionalTimer +import be.ugent.sel.studeez.screens.session.InvisibleSessionManager +import be.ugent.sel.studeez.screens.session.SessionViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +import org.junit.Assert +import org.junit.Test +import org.mockito.kotlin.mock + +@ExperimentalCoroutinesApi +class InvisibleSessionManagerTest { + private var timerState: SelectedTimerState = SelectedTimerState() + private lateinit var viewModel: SessionViewModel + private val mediaPlayer = mock() + + @Test + fun InvisibleEndlessTimerTest() = runTest { + timerState.selectedTimer = FunctionalEndlessTimer() + viewModel = SessionViewModel(timerState, mock()) + InvisibleSessionManager.setParameters(viewModel, mediaPlayer) + + val test = launch { + InvisibleSessionManager.updateTimer() + } + + Assert.assertEquals(viewModel.getTimer().time.time, 0) + advanceTimeBy(1_000) // Start tikker + advanceTimeBy(10_000_000) + Assert.assertEquals(viewModel.getTimer().time.time, 10000) + + test.cancel() + return@runTest + } + + @Test + fun InvisiblePomodoroTimerTest() = runTest { + val studyTime = 10 + val breakTime = 5 + val repeats = 1 + timerState.selectedTimer = FunctionalPomodoroTimer(studyTime, breakTime, repeats) + viewModel = SessionViewModel(timerState, mock()) + InvisibleSessionManager.setParameters(viewModel, mediaPlayer) + + val test = launch { + InvisibleSessionManager.updateTimer() + } + + Assert.assertEquals(viewModel.getTimer().time.time, 10) + advanceTimeBy(1_000) // start tikker + + advanceTimeBy(9_000) + Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.FOCUS) // Tijdens het focussen + + advanceTimeBy(1_000) + Assert.assertEquals(viewModel.getTimer().time.time, 0) // Focussen gedaan + + advanceTimeBy(4_000) + Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.BREAK) // Tijdens pauze + + advanceTimeBy(1_000) + Assert.assertEquals(viewModel.getTimer().time.time, 0) // Pauze gedaan + + advanceTimeBy(9_000) + Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.FOCUS_REMAINING) // Tijdens 2e focus + + advanceTimeBy(1_000) + Assert.assertEquals(viewModel.getTimer().time.time, 0) // 2e focus gedaan + + advanceTimeBy(4_000) + Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.DONE) // Done + + test.cancel() + return@runTest + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3c5031e..edf11ef 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,6 +7,8 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.daemon=true +org.gradle.parallel=true # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects From f46063eba1f660f4bf5af1f43714abb60eea8baa Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 25 Apr 2023 20:58:14 +0200 Subject: [PATCH 07/59] isSession vervangend door null waaarden --- .../session/InvisibleSessionManager.kt | 34 +++++++++++++++++++ .../studeez/screens/session/SessionScreen.kt | 31 ++--------------- app/src/main/res/values/strings.xml | 1 + 3 files changed, 37 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt new file mode 100644 index 0000000..c6def28 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt @@ -0,0 +1,34 @@ +package be.ugent.sel.studeez.screens.session + +import android.media.MediaPlayer +import kotlinx.coroutines.delay +import javax.inject.Singleton +import kotlin.time.Duration.Companion.seconds + +@Singleton +object InvisibleSessionManager { + private var viewModel: SessionViewModel? = null + private var mediaplayer: MediaPlayer? = null + + fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { + this.viewModel = viewModel + this.mediaplayer = mediaplayer + } + + suspend fun updateTimer() { + if (viewModel != null) { + while (true) { + delay(1.seconds) + viewModel!!.getTimer().tick() + if (viewModel!!.getTimer().hasCurrentCountdownEnded() && !viewModel!!.getTimer().hasEnded()) { + mediaplayer?.start() + } + } + } + } + + fun removeParameters() { + viewModel = null + mediaplayer = null + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt index 3a32b37..4f9ada5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionScreen.kt @@ -35,7 +35,6 @@ 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 javax.inject.Singleton import kotlin.time.Duration.Companion.seconds data class SessionActions( @@ -99,7 +98,7 @@ fun SessionScreen( TextButton( onClick = { sessionActions.releaseMediaPlayer - + InvisibleSessionManager.removeParameters() open(StudeezDestinations.HOME_SCREEN) // Vanaf hier ook naar report gaan als "end session" knop word ingedrukt }, @@ -109,7 +108,7 @@ fun SessionScreen( .background(Color.Transparent) ) { Text( - text = "End session", + text = resources().getString(R.string.end_session), color = Color.Red, fontWeight = FontWeight.Bold, fontSize = 18.sp, @@ -190,32 +189,6 @@ private fun Timer( } } - -@Singleton -object InvisibleSessionManager { - private lateinit var viewModel: SessionViewModel - private lateinit var mediaplayer: MediaPlayer - var isSession: Boolean = false - - fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { - isSession = true - this.viewModel = viewModel - this.mediaplayer = mediaplayer - } - - suspend fun updateTimer() { - if (isSession) { - while (true) { - delay(1.seconds) - viewModel.getTimer().tick() - if (viewModel.getTimer().hasCurrentCountdownEnded() && !viewModel.getTimer().hasEnded()) { - mediaplayer.start() - } - } - } - } -} - @Preview @Composable fun TimerPreview() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39abda6..03900b3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,6 +44,7 @@ Sessions + End session Profile From 04f61c751634fbc228f950e909831b209b05fce7 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Wed, 26 Apr 2023 11:00:06 +0200 Subject: [PATCH 08/59] Added test for CustomTimer when app isn't visible --- .../InvisibleSessionManagerTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt index 5649f46..fe0d1c2 100644 --- a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt +++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt @@ -2,6 +2,7 @@ package be.ugent.sel.studeez.timer_functional import android.media.MediaPlayer import be.ugent.sel.studeez.data.SelectedTimerState +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.FunctionalTimer @@ -80,4 +81,25 @@ class InvisibleSessionManagerTest { test.cancel() return@runTest } + + @Test + fun InvisibleCustomTimerTest() = runTest { + timerState.selectedTimer = FunctionalCustomTimer(5) + viewModel = SessionViewModel(timerState, mock()) + InvisibleSessionManager.setParameters(viewModel, mediaPlayer) + + val test = launch { + InvisibleSessionManager.updateTimer() + } + + Assert.assertEquals(viewModel.getTimer().time.time, 5) + advanceTimeBy(1_000) // Start tikker + advanceTimeBy(4_000) + Assert.assertEquals(viewModel.getTimer().time.time, 1) + advanceTimeBy(1_000) + Assert.assertEquals(viewModel.getTimer().time.time, 0) + + test.cancel() + return@runTest + } } \ No newline at end of file From 601740f258fe5f63d9412ea1316e9bc747b635ee Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Wed, 26 Apr 2023 11:38:09 +0200 Subject: [PATCH 09/59] secondaryscreentemplate error --- .idea/misc.xml | 3 +- .../studeez/navigation/StudeezDestinations.kt | 2 + .../add_timer/AddTimerViewModel.kt | 13 ++++++ .../add_timer/addTimerScreen.kt | 42 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..704c883 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ + - + diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index 760c814..63f9d64 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -18,4 +18,6 @@ object StudeezDestinations { // Edit screens const val EDIT_PROFILE_SCREEN = "edit_profile" + + const val ADD_TIMER_SCREEN = "add_timer" } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt new file mode 100644 index 0000000..a209f49 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt @@ -0,0 +1,13 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class AddTimerViewModel @Inject constructor( + logService: LogService +): StudeezViewModel(logService) { + +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt new file mode 100644 index 0000000..a26826c --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt @@ -0,0 +1,42 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +import androidx.compose.runtime.Composable +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel +import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel +import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions + +@Composable +fun AddTimerRoute( + open: (String) -> Unit, + openAndPopUp: (String, String) -> Unit + viewModel: AddTimerViewModel, + drawerViewModel: DrawerViewModel, + navBarViewModel: NavigationBarViewModel, +) { + addTimerScreen( + drawerActions = getDrawerActions( + drawerViewModel = drawerViewModel, + open = open, + openAndPopUp = openAndPopUp + ), + navigationBarActions = getNavigationBarActions( + navigationBarViewModel = navBarViewModel, + open = open + ) + ) +} + +fun addTimerScreen( + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions +) { + SecondaryScreenTemplate( + title = , + popUp = { /*TODO*/ }) { + + } +} \ No newline at end of file From 2ca112ee0e66547dd8ed8a3ecb96643061033eca Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Thu, 27 Apr 2023 17:01:39 +0200 Subject: [PATCH 10/59] LazyColumn not fixed --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 10 + .../common/composable/ButtonComposable.kt | 9 +- .../timer_overview/TimerOverviewScreen.kt | 12 +- .../add_timer/AddTimerUiState.kt | 11 + .../add_timer/AddTimerViewModel.kt | 74 +++++- .../add_timer/addTimerScreen.kt | 215 ++++++++++++++++-- 6 files changed, 303 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index a6830a5..be8ad00 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -34,6 +34,7 @@ import be.ugent.sel.studeez.screens.session.SessionRoute 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 +import be.ugent.sel.studeez.screens.timer_overview.add_timer.AddTimerRoute import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionRoute import be.ugent.sel.studeez.ui.theme.StudeezTheme import kotlinx.coroutines.CoroutineScope @@ -167,5 +168,14 @@ fun StudeezNavGraph( navBarViewModel = navBarViewModel, ) } + + composable(StudeezDestinations.ADD_TIMER_SCREEN) { + AddTimerRoute( + open = open, + openAndPopUp = openAndPopUp, + goBack = goBack, + viewModel = hiltViewModel() + ) + } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index b2568aa..79845ec 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -23,7 +23,14 @@ import be.ugent.sel.studeez.common.ext.card @Composable fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { - TextButton(onClick = action, modifier = modifier) { Text(text = stringResource(text)) } + TextButton( + onClick = action, + modifier = modifier + ) { + Text( + text = stringResource(text) + ) + } } @Composable diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt index fafdf02..3bc6ca7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt @@ -23,6 +23,7 @@ import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.resources import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -31,15 +32,18 @@ data class TimerOverviewActions( val getUserTimers: () -> Flow>, val getDefaultTimers: () -> List, val onEditClick: (TimerInfo) -> Unit, + val open: (String) -> Unit, ) fun getTimerOverviewActions( viewModel: TimerOverviewViewModel, + open: (String) -> Unit, ): TimerOverviewActions { return TimerOverviewActions( getUserTimers = viewModel::getUserTimers, getDefaultTimers = viewModel::getDefaultTimers, onEditClick = { viewModel.update(it) }, + open = open ) } @@ -52,7 +56,7 @@ fun TimerOverviewRoute( navBarViewModel: NavigationBarViewModel, ) { TimerOverviewScreen( - timerOverviewActions = getTimerOverviewActions(viewModel), + timerOverviewActions = getTimerOverviewActions(viewModel, open), drawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp), navigationBarActions = getNavigationBarActions(navBarViewModel, open), ) @@ -95,7 +99,7 @@ fun TimerOverviewScreen( } } BasicButton(R.string.add_timer, Modifier.basicButton()) { - // TODO + timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN) } } } @@ -111,7 +115,9 @@ fun TimerOverviewPreview() { timerOverviewActions = TimerOverviewActions( { flowOf() }, { listOf(customTimer, customTimer) }, - {}), + {}, + {} + ), drawerActions = DrawerActions({}, {}, {}, {}, {}), navigationBarActions = NavigationBarActions({}, {}, {}, {}) ) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt new file mode 100644 index 0000000..9b17121 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt @@ -0,0 +1,11 @@ +package be.ugent.sel.studeez.screens.timer_overview.add_timer + +data class AddTimerUiState( + val studyTimeHours: Float = 1f, + val studyTimeMinutes: Float = 0f, + val withBreaks: Boolean = false, + val breakTime: Float = 5f, + val repeats: Float = 1f, + val name: String = "", + val description: String = "", +) \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt index a209f49..7e79e1e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt @@ -1,13 +1,85 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer +import androidx.compose.runtime.mutableStateOf +import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo +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.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel class AddTimerViewModel @Inject constructor( - logService: LogService + logService: LogService, + private val timerDAO: TimerDAO, ): StudeezViewModel(logService) { + var uiState = mutableStateOf(AddTimerUiState()) + private set + private val studyTimeHours + get() = uiState.value.studyTimeHours + + private val studyTimeMinutes + get() = uiState.value.studyTimeMinutes + + private val breakTime + get() = uiState.value.breakTime + + private val repeats + get() = uiState.value.repeats + + private val name + get() = uiState.value.name + + private val description + get() = uiState.value.description + + fun onStudyTimeHoursChange(newValue: Float) { + uiState.value = uiState.value.copy(studyTimeHours = newValue) + + } + + fun onStudyTimeMinutesChange(newValue: Float) { + uiState.value = uiState.value.copy(studyTimeMinutes = newValue) + } + + fun onWithBreaksChange(newValue: Boolean) { + uiState.value = uiState.value.copy(withBreaks = newValue) + } + + fun onBreakTimeChange(newValue: Float) { + uiState.value = uiState.value.copy(breakTime = newValue) + } + + fun onRepeatsChange(newValue: Float) { + uiState.value = uiState.value.copy(repeats = newValue) + } + + fun addTimer() { + if (uiState.value.withBreaks) { + timerDAO.saveTimer(PomodoroTimerInfo( + name = uiState.value.name, + description = uiState.value.description, + studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60, + breakTime = breakTime.toInt() * 60, + repeats = repeats.toInt() + )) + } else { + timerDAO.saveTimer(CustomTimerInfo( + name = uiState.value.name, + description = uiState.value.description, + studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60 + )) + } + } + + fun onNameChange(newValue: String) { + uiState.value = uiState.value.copy(name = newValue) + } + + fun onDescriptionChange(newValue: String) { + uiState.value = uiState.value.copy(description = newValue) + } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt index a26826c..6941a05 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt @@ -1,42 +1,211 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Checkbox +import androidx.compose.material.Slider +import androidx.compose.material.Text +import androidx.compose.material.TextField import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate -import be.ugent.sel.studeez.common.composable.drawer.DrawerActions -import be.ugent.sel.studeez.common.composable.drawer.DrawerViewModel -import be.ugent.sel.studeez.common.composable.drawer.getDrawerActions -import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions -import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel -import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions +import be.ugent.sel.studeez.resources + +data class AddTimerActions( + val goBack: () -> Unit, + val onStudyTimeHoursChange: (Float) -> Unit, + val onStudyTimeMinutesChange: (Float) -> Unit, + val onBreakTimeChange: (Float) -> Unit, + val onRepeatsChange: (Float) -> Unit, + val onWithBreaksChange: (Boolean) -> Unit, + val addTimer: () -> Unit, + val onNameChange: (String) -> Unit, + val onDescriptionChange: (String) -> Unit, +) + +fun getAddTimerActions( + goBack: () -> Unit, + viewModel: AddTimerViewModel, +): AddTimerActions { + return AddTimerActions( + goBack = goBack, + onWithBreaksChange = viewModel::onWithBreaksChange, + onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange, + onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange, + onBreakTimeChange = viewModel::onBreakTimeChange, + onRepeatsChange = viewModel::onRepeatsChange, + addTimer = viewModel::addTimer, + onNameChange = viewModel::onNameChange, + onDescriptionChange = viewModel::onDescriptionChange + ) +} @Composable fun AddTimerRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit + openAndPopUp: (String, String) -> Unit, + goBack: () -> Unit, viewModel: AddTimerViewModel, - drawerViewModel: DrawerViewModel, - navBarViewModel: NavigationBarViewModel, ) { - addTimerScreen( - drawerActions = getDrawerActions( - drawerViewModel = drawerViewModel, - open = open, - openAndPopUp = openAndPopUp + val uiState by viewModel.uiState + + AddTimerScreen( + addTimerActions = getAddTimerActions( + goBack = goBack, + viewModel = viewModel, ), - navigationBarActions = getNavigationBarActions( - navigationBarViewModel = navBarViewModel, - open = open - ) + uiState = uiState ) } -fun addTimerScreen( - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions +@Composable +fun AddTimerScreen( + addTimerActions: AddTimerActions, + uiState: AddTimerUiState, ) { SecondaryScreenTemplate( - title = , - popUp = { /*TODO*/ }) { + title = resources().getString(R.string.add_timer), + popUp = addTimerActions.goBack + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "How long do you want to study?", + textAlign = TextAlign.Center + ) + } + LazyColumn( + modifier = Modifier + .padding(16.dp) + ) { + item{ + Text( + text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" + ) + Slider( + value = uiState.studyTimeHours, + onValueChange = { + addTimerActions.onStudyTimeHoursChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = true + ) + + Text( + text = "${uiState.studyTimeMinutes.toInt()} minutes" + ) + Slider( + value = uiState.studyTimeMinutes, + onValueChange = { + addTimerActions.onStudyTimeMinutesChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = true + ) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "With breaks?", + ) + Checkbox( + checked = uiState.withBreaks, + onCheckedChange = { addTimerActions.onWithBreaksChange(it) } + ) + } + + Text( + text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", + ) + Slider( + value = uiState.breakTime, + onValueChange = { + addTimerActions.onBreakTimeChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = uiState.withBreaks + ) + + Text( + text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" + ) + Slider( + value = uiState.repeats, + onValueChange = { + addTimerActions.onRepeatsChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = uiState.withBreaks + ) + + Text( + text = "Timer name" + ) + TextField( + value = uiState.name, + onValueChange = { addTimerActions.onNameChange(it) } + ) + + Text( + text = "Timer description" + ) + TextField( + value = uiState.description, + onValueChange = { addTimerActions.onDescriptionChange(it) } + ) + + Row( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.Center + ) { + BasicButton( + text = R.string.add_timer, + modifier = Modifier, + onClick = addTimerActions.addTimer + ) + } + } + } + } } +} + +@Preview +@Composable +fun AddTimerScreenPreview() { + AddTimerScreen( + addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), + uiState = AddTimerUiState() + ) } \ No newline at end of file From 535ef85c6d0a908388833929407df03eecdff245 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Fri, 28 Apr 2023 11:42:03 +0200 Subject: [PATCH 11/59] LazyColumn in progress of being fixed --- .../add_timer/addTimerScreen.kt | 232 ++++++++++-------- 1 file changed, 124 insertions(+), 108 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt index 6941a05..772917d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt @@ -1,7 +1,6 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth @@ -22,6 +21,7 @@ import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.ui.theme.StudeezTheme data class AddTimerActions( val goBack: () -> Unit, @@ -79,122 +79,137 @@ fun AddTimerScreen( title = resources().getString(R.string.add_timer), popUp = addTimerActions.goBack ) { - Column( + LazyColumn( modifier = Modifier .fillMaxWidth() .padding(16.dp) ) { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { + item { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Text( + text = "How long do you want to study?", + textAlign = TextAlign.Center + ) + } + } + item { Text( - text = "How long do you want to study?", - textAlign = TextAlign.Center + text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" ) } - - LazyColumn( - modifier = Modifier - .padding(16.dp) - ) { - item{ + item { + Slider( + value = uiState.studyTimeHours, + onValueChange = { + addTimerActions.onStudyTimeHoursChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = true + ) + } + item { + Text( + text = "${uiState.studyTimeMinutes.toInt()} minutes" + ) + } + item { + Slider( + value = uiState.studyTimeMinutes, + onValueChange = { + addTimerActions.onStudyTimeMinutesChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = true + ) + } + item { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { Text( - text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" + text = "With breaks?", ) - Slider( - value = uiState.studyTimeHours, - onValueChange = { - addTimerActions.onStudyTimeHoursChange(it) - }, - steps = 8, - valueRange = 1f..10f, - enabled = true + Checkbox( + checked = uiState.withBreaks, + onCheckedChange = { addTimerActions.onWithBreaksChange(it) } ) - - Text( - text = "${uiState.studyTimeMinutes.toInt()} minutes" + } + } + item { + Text( + text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", + ) + } + item { + Slider( + value = uiState.breakTime, + onValueChange = { + addTimerActions.onBreakTimeChange(it) + }, + steps = 11, + valueRange = 0f..60f, + enabled = uiState.withBreaks + ) + } + item { + Text( + text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" + ) + } + item { + Slider( + value = uiState.repeats, + onValueChange = { + addTimerActions.onRepeatsChange(it) + }, + steps = 8, + valueRange = 1f..10f, + enabled = uiState.withBreaks + ) + } + item { + Text( + text = "Timer name" + ) + } + item { + TextField( + value = uiState.name, + onValueChange = { addTimerActions.onNameChange(it) } + ) + } + item { + Text( + text = "Timer description" + ) + } + item { + TextField( + value = uiState.description, + onValueChange = { addTimerActions.onDescriptionChange(it) } + ) + } + item { + Row( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.Center + ) { + BasicButton( + text = R.string.add_timer, + modifier = Modifier, + onClick = addTimerActions.addTimer ) - Slider( - value = uiState.studyTimeMinutes, - onValueChange = { - addTimerActions.onStudyTimeMinutesChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = true - ) - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - Text( - text = "With breaks?", - ) - Checkbox( - checked = uiState.withBreaks, - onCheckedChange = { addTimerActions.onWithBreaksChange(it) } - ) - } - - Text( - text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", - ) - Slider( - value = uiState.breakTime, - onValueChange = { - addTimerActions.onBreakTimeChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = uiState.withBreaks - ) - - Text( - text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" - ) - Slider( - value = uiState.repeats, - onValueChange = { - addTimerActions.onRepeatsChange(it) - }, - steps = 8, - valueRange = 1f..10f, - enabled = uiState.withBreaks - ) - - Text( - text = "Timer name" - ) - TextField( - value = uiState.name, - onValueChange = { addTimerActions.onNameChange(it) } - ) - - Text( - text = "Timer description" - ) - TextField( - value = uiState.description, - onValueChange = { addTimerActions.onDescriptionChange(it) } - ) - - Row( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight(), - verticalAlignment = Alignment.Bottom, - horizontalArrangement = Arrangement.Center - ) { - BasicButton( - text = R.string.add_timer, - modifier = Modifier, - onClick = addTimerActions.addTimer - ) - } } } } @@ -203,9 +218,10 @@ fun AddTimerScreen( @Preview @Composable -fun AddTimerScreenPreview() { +fun AddTimerScreenPreview() { StudeezTheme { AddTimerScreen( addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), uiState = AddTimerUiState() - ) + ) + } } \ No newline at end of file From e421430f0bb9442b2507722af1739d51f9ae201f Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Fri, 28 Apr 2023 14:42:37 +0200 Subject: [PATCH 12/59] mediaplayer in AbstractSessionScreen + InvisibleSessionManagerTest.kt fixed --- .../timer_functional/FunctionalCustomTimer.kt | 6 ---- .../FunctionalPomodoroTimer.kt | 10 ++----- .../timer_functional/FunctionalTimer.kt | 3 -- .../session/InvisibleSessionManager.kt | 5 +++- .../studeez/screens/session/SessionRoute.kt | 7 ++--- .../sessionScreens/AbstractSessionScreen.kt | 4 +++ .../sessionScreens/BreakSessionScreen.kt | 15 +++++++++- .../sessionScreens/CustomSessionScreen.kt | 14 ++++++++- .../sessionScreens/EndlessSessionScreen.kt | 2 ++ .../sessionScreens/GetSessionScreen.kt | 7 +++-- .../InvisibleSessionManagerTest.kt | 30 ++++++++----------- 11 files changed, 59 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt index 0d1c4f5..94871ee 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt @@ -5,12 +5,6 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) { override fun tick() { if (!hasEnded()) { time.minOne() - } else { - mediaPlayer?.setOnCompletionListener { - mediaPlayer!!.release() - mediaPlayer = null - } - mediaPlayer?.start() } } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt index 8189559..6dac7c6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt @@ -10,14 +10,10 @@ class FunctionalPomodoroTimer( override fun tick() { if (hasEnded()) { - mediaPlayer?.setOnCompletionListener { - mediaPlayer!!.release() - mediaPlayer = null - } - mediaPlayer?.start() return - } else if (hasCurrentCountdownEnded()) { - mediaPlayer?.start() + } + + if (hasCurrentCountdownEnded()) { if (isInBreak) { breaksRemaining-- time.time = studyTime diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt index daec359..2d904d8 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt @@ -1,10 +1,7 @@ package be.ugent.sel.studeez.data.local.models.timer_functional -import android.media.MediaPlayer - abstract class FunctionalTimer(initialValue: Int) { val time: Time = Time(initialValue) - var mediaPlayer: MediaPlayer? = null fun getHoursMinutesSeconds(): HoursMinutesSeconds { return time.getAsHMS() diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt index 4c43d13..68fe703 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.screens.session +import android.media.MediaPlayer import kotlinx.coroutines.delay import javax.inject.Singleton import kotlin.time.Duration.Companion.seconds @@ -7,8 +8,9 @@ import kotlin.time.Duration.Companion.seconds @Singleton object InvisibleSessionManager { private var viewModel: SessionViewModel? = null + private var mediaPlayer: MediaPlayer? = null - fun setParameters(viewModel: SessionViewModel) { + fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { this.viewModel = viewModel } @@ -17,6 +19,7 @@ object InvisibleSessionManager { while (true) { delay(1.seconds) viewModel!!.getTimer().tick() + } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt index d13c6c1..680212d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/SessionRoute.kt @@ -38,13 +38,12 @@ fun SessionRoute( val mediaplayer = MediaPlayer.create(context, uri) mediaplayer.isLooping = false - viewModel.getTimer().mediaPlayer = mediaplayer - InvisibleSessionManager.setParameters( - viewModel = viewModel + viewModel = viewModel, + mediaplayer = mediaplayer ) - val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen()) + val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen(mediaplayer)) sessionScreen( open = open, diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt index 0804abf..f268edb 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt @@ -73,6 +73,7 @@ abstract class AbstractSessionScreen { LaunchedEffect(tikker) { delay(1.seconds) sessionActions.getTimer().tick() + callMediaPlayer() tikker = !tikker } @@ -122,6 +123,8 @@ abstract class AbstractSessionScreen { @Composable abstract fun motivationString(): String + abstract fun callMediaPlayer() + } @Preview @@ -130,6 +133,7 @@ fun TimerPreview() { val sessionScreen = object : AbstractSessionScreen() { @Composable override fun motivationString(): String = "Test" + override fun callMediaPlayer() {} } sessionScreen.Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {})) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt index edc8475..34927bc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.screens.session.sessionScreens +import android.media.MediaPlayer import androidx.compose.runtime.Composable import be.ugent.sel.studeez.R import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer @@ -7,7 +8,8 @@ import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.R.string as AppText class BreakSessionScreen( - private val funPomoDoroTimer: FunctionalPomodoroTimer + private val funPomoDoroTimer: FunctionalPomodoroTimer, + private var mediaplayer: MediaPlayer? ): AbstractSessionScreen() { @Composable @@ -27,4 +29,15 @@ class BreakSessionScreen( ) } + override fun callMediaPlayer() { + if (funPomoDoroTimer.hasEnded()) { + mediaplayer?.setOnCompletionListener { + mediaplayer!!.release() + mediaplayer = null + } + mediaplayer?.start() + } else if (funPomoDoroTimer.hasCurrentCountdownEnded()) { + mediaplayer?.start() + } + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt index 36ee492..e998645 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt @@ -1,5 +1,6 @@ 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 @@ -7,7 +8,8 @@ import be.ugent.sel.studeez.R.string as AppText class CustomSessionScreen( - private val functionalTimer: FunctionalCustomTimer + private val functionalTimer: FunctionalCustomTimer, + private var mediaplayer: MediaPlayer? ): AbstractSessionScreen() { @Composable @@ -18,4 +20,14 @@ class CustomSessionScreen( return resources().getString(AppText.state_focus) } + override fun callMediaPlayer() { + if (functionalTimer.hasEnded()) { + mediaplayer?.setOnCompletionListener { + mediaplayer!!.release() + mediaplayer = null + } + mediaplayer?.start() + } + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt index fc46c9d..be67cff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/EndlessSessionScreen.kt @@ -11,4 +11,6 @@ class EndlessSessionScreen : AbstractSessionScreen() { override fun motivationString(): String { return resources().getString(AppText.state_focus) } + + override fun callMediaPlayer() {} } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt index e378661..98b2d5e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/GetSessionScreen.kt @@ -1,17 +1,18 @@ 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 : FunctionalTimerVisitor { +class GetSessionScreen(private val mediaplayer: MediaPlayer?) : FunctionalTimerVisitor { override fun visitFunctionalCustomTimer(functionalCustomTimer: FunctionalCustomTimer): AbstractSessionScreen = - CustomSessionScreen(functionalCustomTimer) + CustomSessionScreen(functionalCustomTimer, mediaplayer) override fun visitFunctionalEndlessTimer(functionalEndlessTimer: FunctionalEndlessTimer): AbstractSessionScreen = EndlessSessionScreen() override fun visitFunctionalBreakTimer(functionalPomodoroTimer: FunctionalPomodoroTimer): AbstractSessionScreen = - BreakSessionScreen(functionalPomodoroTimer) + BreakSessionScreen(functionalPomodoroTimer, mediaplayer) } \ No newline at end of file diff --git a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt index fe0d1c2..60740d9 100644 --- a/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt +++ b/app/src/test/java/be/ugent/sel/studeez/timer_functional/InvisibleSessionManagerTest.kt @@ -5,7 +5,6 @@ import be.ugent.sel.studeez.data.SelectedTimerState 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.FunctionalTimer import be.ugent.sel.studeez.screens.session.InvisibleSessionManager import be.ugent.sel.studeez.screens.session.SessionViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -20,7 +19,7 @@ import org.mockito.kotlin.mock class InvisibleSessionManagerTest { private var timerState: SelectedTimerState = SelectedTimerState() private lateinit var viewModel: SessionViewModel - private val mediaPlayer = mock() + private var mediaPlayer: MediaPlayer = mock() @Test fun InvisibleEndlessTimerTest() = runTest { @@ -58,25 +57,20 @@ class InvisibleSessionManagerTest { advanceTimeBy(1_000) // start tikker advanceTimeBy(9_000) - Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.FOCUS) // Tijdens het focussen + Assert.assertEquals(viewModel.getTimer().time.time, 1) + // focus, 9 sec, 1 sec nog - advanceTimeBy(1_000) - Assert.assertEquals(viewModel.getTimer().time.time, 0) // Focussen gedaan + advanceTimeBy(2_000) + Assert.assertEquals(viewModel.getTimer().time.time, 4) + // pauze, 11 sec bezig, 4 seconden nog pauze - advanceTimeBy(4_000) - Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.BREAK) // Tijdens pauze + advanceTimeBy(5_000) + Assert.assertEquals(viewModel.getTimer().time.time, 9) + // 2e focus, 16 sec, 9 sec in 2e focus nog - advanceTimeBy(1_000) - Assert.assertEquals(viewModel.getTimer().time.time, 0) // Pauze gedaan - - advanceTimeBy(9_000) - Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.FOCUS_REMAINING) // Tijdens 2e focus - - advanceTimeBy(1_000) - Assert.assertEquals(viewModel.getTimer().time.time, 0) // 2e focus gedaan - - advanceTimeBy(4_000) - Assert.assertEquals(viewModel.getTimer().view, FunctionalTimer.StudyState.DONE) // Done + advanceTimeBy(13_000) + Assert.assertTrue(viewModel.getTimer().hasEnded()) + // Done test.cancel() return@runTest From 8eb199757ce5a857a2d13d56bb971fa0cfba5385 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Fri, 28 Apr 2023 15:30:57 +0200 Subject: [PATCH 13/59] InvisibleSessionManager.kt fixed --- .../screens/session/InvisibleSessionManager.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt index 68fe703..9051fa8 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/InvisibleSessionManager.kt @@ -8,18 +8,21 @@ import kotlin.time.Duration.Companion.seconds @Singleton object InvisibleSessionManager { private var viewModel: SessionViewModel? = null - private var mediaPlayer: MediaPlayer? = null + private lateinit var mediaPlayer: MediaPlayer fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) { this.viewModel = viewModel + this.mediaPlayer = mediaplayer } suspend fun updateTimer() { - if (viewModel != null) { - while (true) { + viewModel?.let { + while (!it.getTimer().hasEnded()) { delay(1.seconds) - viewModel!!.getTimer().tick() - + it.getTimer().tick() + if (it.getTimer().hasCurrentCountdownEnded()) { + mediaPlayer.start() + } } } } From 2ca7d062f30d84ef3ef481f62737f619ce6c5221 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Fri, 28 Apr 2023 19:02:10 +0200 Subject: [PATCH 14/59] mediaplayer null safe listeners --- .../session/sessionScreens/BreakSessionScreen.kt | 10 ++++++---- .../session/sessionScreens/CustomSessionScreen.kt | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt index 34927bc..8fa45ff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/BreakSessionScreen.kt @@ -31,11 +31,13 @@ class BreakSessionScreen( override fun callMediaPlayer() { if (funPomoDoroTimer.hasEnded()) { - mediaplayer?.setOnCompletionListener { - mediaplayer!!.release() - mediaplayer = null + mediaplayer?.let { it: MediaPlayer -> + it.setOnCompletionListener { + it.release() + mediaplayer = null + } + it.start() } - mediaplayer?.start() } else if (funPomoDoroTimer.hasCurrentCountdownEnded()) { mediaplayer?.start() } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt index e998645..7fc60bc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/CustomSessionScreen.kt @@ -22,11 +22,13 @@ class CustomSessionScreen( override fun callMediaPlayer() { if (functionalTimer.hasEnded()) { - mediaplayer?.setOnCompletionListener { - mediaplayer!!.release() - mediaplayer = null + mediaplayer?.let { it: MediaPlayer -> + it.setOnCompletionListener { + it.release() + mediaplayer = null + } + it.start() } - mediaplayer?.start() } } From 024ce85266790605b89c91f9ed12107170a6799a Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Sat, 29 Apr 2023 17:55:20 +0200 Subject: [PATCH 15/59] #26 select time for custom timer --- .../common/composable/ButtonComposable.kt | 23 ++++++++- .../ugent/sel/studeez/common/ext/ShapeExt.kt | 8 +++ .../models/timer_info/CustomTimerInfo.kt | 2 +- .../timer_overview/TimerOverviewScreen.kt | 9 ++++ .../timer_selection/TimerSelectionScreen.kt | 50 ++++++++++++++++++- app/src/main/res/values/strings.xml | 3 ++ 6 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/ext/ShapeExt.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt index 3fa9bd2..9751750 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ButtonComposable.kt @@ -2,7 +2,6 @@ package be.ugent.sel.studeez.common.composable import androidx.annotation.StringRes import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -13,6 +12,7 @@ import androidx.compose.ui.unit.sp import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.common.ext.card +import be.ugent.sel.studeez.common.ext.defaultButtonShape @Composable fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { @@ -30,7 +30,7 @@ fun BasicButton( Button( onClick = onClick, modifier = modifier, - shape = RoundedCornerShape(20.dp), + shape = defaultButtonShape(), colors = colors, border = border, ) { @@ -47,6 +47,25 @@ fun BasicButtonPreview() { BasicButton(text = R.string.add_timer, modifier = Modifier.basicButton()) {} } +@Composable +fun NotInternationalisedButton( + text: String, + modifier: Modifier = Modifier, + colors: ButtonColors = ButtonDefaults.buttonColors(), + border: BorderStroke? = null, + onClick: () -> Unit +) { + Button( + onClick = onClick, + modifier = modifier, + shape = defaultButtonShape(), + colors = colors, + border = border + ) { + Text(text = text) + } +} + @Composable fun StealthButton( @StringRes text: Int, diff --git a/app/src/main/java/be/ugent/sel/studeez/common/ext/ShapeExt.kt b/app/src/main/java/be/ugent/sel/studeez/common/ext/ShapeExt.kt new file mode 100644 index 0000000..2114a74 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/ext/ShapeExt.kt @@ -0,0 +1,8 @@ +package be.ugent.sel.studeez.common.ext + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.unit.dp + +fun defaultButtonShape(): RoundedCornerShape { + return RoundedCornerShape(20.dp) +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt index 5e06536..d33ecc4 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt @@ -6,7 +6,7 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer class CustomTimerInfo( name: String, description: String, - private val studyTime: Int, + var studyTime: Int, id: String = "" ): TimerInfo(id, name, description) { diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt index 9489a30..d6d7b07 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt @@ -61,6 +61,15 @@ fun TimerOverviewScreen( ) { Column { LazyColumn { + // Custom timer, select new duration each time + item { + TimerEntry(timerInfo = CustomTimerInfo( + name = resources().getString(R.string.custom_name), + description = resources().getString(R.string.custom_name), + studyTime = 0 + )) + } + // Default Timers, cannot be edited items(timerOverviewActions.getDefaultTimers()) { TimerEntry(timerInfo = it) {} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index ac46b5c..2f8fcac 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -1,22 +1,29 @@ package be.ugent.sel.studeez.screens.timer_selection +import android.app.TimePickerDialog +import android.content.Context import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.composable.NotInternationalisedButton import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.common.composable.StealthButton import be.ugent.sel.studeez.common.composable.TimerEntry +import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.resources import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import java.util.* data class TimerSelectionActions( val getAllTimers: () -> Flow>, val startSession: (TimerInfo) -> Unit, + val pickDuration: (Context, CustomTimerInfo) -> Unit ) fun getTimerSelectionActions( @@ -26,6 +33,21 @@ fun getTimerSelectionActions( return TimerSelectionActions( getAllTimers = viewModel::getAllTimers, startSession = { viewModel.startSession(open, it) }, + pickDuration = { context, timerInfo -> + val mCalendar = Calendar.getInstance() + val mHour = mCalendar[Calendar.HOUR] + val mMinute = mCalendar[Calendar.MINUTE] + + val mTimePickerDialog = TimePickerDialog( + context, + { _, hour : Int, minute: Int -> timerInfo.studyTime = hour * 60 * 60 + minute * 60 }, + mHour, + mMinute, + true + ) + + mTimePickerDialog.show() + } ) } @@ -52,6 +74,32 @@ fun TimerSelectionScreen( popUp = popUp ) { LazyColumn { + // Custom timer with duration selection button + item { + val timerInfo = CustomTimerInfo( + name = resources().getString(R.string.custom_name), + description = resources().getString(R.string.custom_name), + studyTime = 0 + ) + val context = LocalContext.current + + TimerEntry( + timerInfo = timerInfo, + leftButton = { + StealthButton( + text = R.string.start, + onClick = { timerSelectionActions.startSession(timerInfo) } + ) + }, + rightButton = { + NotInternationalisedButton( + text = resources().getString(R.string.pick_time), + onClick = { timerSelectionActions.pickDuration(context, timerInfo) } + ) + } + ) + } + // All timers items(timers.value) { timerInfo -> TimerEntry( @@ -72,7 +120,7 @@ fun TimerSelectionScreen( @Composable fun TimerSelectionPreview() { TimerSelectionScreen( - timerSelectionActions = TimerSelectionActions({ flowOf() }, {}), + timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _ -> {}}), popUp = {} ) } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb643d3..1876cee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,6 +65,7 @@ Timers Edit Add timer + Select time Focus! Focus one more time! @@ -73,6 +74,8 @@ Done! Take a break! + Custom + Select how long you want to study Settings From 3bf0157adcb5478f4af4b205ed9fd1fb58375a1a Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Sun, 30 Apr 2023 12:26:29 +0200 Subject: [PATCH 16/59] #26 Show selected time --- .../timer_selection/TimerSelectionScreen.kt | 78 ++++++++++--------- .../TimerSelectionViewModel.kt | 6 ++ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index 2f8fcac..780b50a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -18,12 +18,12 @@ import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.resources import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf -import java.util.* data class TimerSelectionActions( val getAllTimers: () -> Flow>, val startSession: (TimerInfo) -> Unit, - val pickDuration: (Context, CustomTimerInfo) -> Unit + val pickDuration: (Context) -> Unit, + val customTimeStudyTime: Int ) fun getTimerSelectionActions( @@ -33,21 +33,20 @@ fun getTimerSelectionActions( return TimerSelectionActions( getAllTimers = viewModel::getAllTimers, startSession = { viewModel.startSession(open, it) }, - pickDuration = { context, timerInfo -> - val mCalendar = Calendar.getInstance() - val mHour = mCalendar[Calendar.HOUR] - val mMinute = mCalendar[Calendar.MINUTE] - - val mTimePickerDialog = TimePickerDialog( + pickDuration = { context -> + val dialog = TimePickerDialog( context, - { _, hour : Int, minute: Int -> timerInfo.studyTime = hour * 60 * 60 + minute * 60 }, - mHour, - mMinute, + { _, hour: Int, minute: Int -> + viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60 + }, + 0, + 0, true ) - mTimePickerDialog.show() - } + dialog.show() + }, + customTimeStudyTime = viewModel.customTimerStudyTime.value ) } @@ -76,28 +75,7 @@ fun TimerSelectionScreen( LazyColumn { // Custom timer with duration selection button item { - val timerInfo = CustomTimerInfo( - name = resources().getString(R.string.custom_name), - description = resources().getString(R.string.custom_name), - studyTime = 0 - ) - val context = LocalContext.current - - TimerEntry( - timerInfo = timerInfo, - leftButton = { - StealthButton( - text = R.string.start, - onClick = { timerSelectionActions.startSession(timerInfo) } - ) - }, - rightButton = { - NotInternationalisedButton( - text = resources().getString(R.string.pick_time), - onClick = { timerSelectionActions.pickDuration(context, timerInfo) } - ) - } - ) + CustomTimerEntry(timerSelectionActions) } // All timers @@ -116,11 +94,39 @@ fun TimerSelectionScreen( } } +@Composable +fun CustomTimerEntry( + timerSelectionActions: TimerSelectionActions +) { + val timerInfo = CustomTimerInfo( + name = resources().getString(R.string.custom_name), + description = resources().getString(R.string.custom_description), + studyTime = timerSelectionActions.customTimeStudyTime + ) + val context = LocalContext.current + + TimerEntry( + timerInfo = timerInfo, + leftButton = { + StealthButton( + text = R.string.start, + onClick = { timerSelectionActions.startSession(timerInfo) } + ) + }, + rightButton = { + NotInternationalisedButton( + text = String.format("%02d:%02d", timerInfo.studyTime / 3600, (timerInfo.studyTime % 3600) / 60), + onClick = { timerSelectionActions.pickDuration(context) } + ) + } + ) +} + @Preview @Composable fun TimerSelectionPreview() { TimerSelectionScreen( - timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _ -> {}}), + timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { {} }, 0), popUp = {} ) } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionViewModel.kt index c555bfa..ab42973 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionViewModel.kt @@ -1,5 +1,9 @@ package be.ugent.sel.studeez.screens.timer_selection +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember 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 @@ -17,6 +21,8 @@ class TimerSelectionViewModel @Inject constructor( logService: LogService ) : StudeezViewModel(logService) { + var customTimerStudyTime: MutableState = mutableStateOf(0) + fun getAllTimers() : Flow> { return timerDAO.getAllTimers() } From 0a409421a85300686021b6670fcdd08aca74bc65 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 10:09:13 +0200 Subject: [PATCH 17/59] Cleanup destinations --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 90 ++++++++++--------- .../composable/drawer/DrawerComposable.kt | 11 ++- .../composable/drawer/DrawerViewModel.kt | 16 +++- .../navbar/NavigationBarComposable.kt | 8 +- .../navbar/NavigationBarViewModel.kt | 6 +- .../studeez/navigation/StudeezDestinations.kt | 26 +++--- .../sel/studeez/screens/home/HomeScreen.kt | 2 +- 7 files changed, 93 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index c8a133b..ae460ff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -91,7 +91,7 @@ fun resources(): Resources { @Composable fun StudeezNavGraph( appState: StudeezAppstate, - modifier: Modifier, + modifier: Modifier = Modifier, ) { val drawerViewModel: DrawerViewModel = hiltViewModel() val navBarViewModel: NavigationBarViewModel = hiltViewModel() @@ -113,8 +113,46 @@ fun StudeezNavGraph( startDestination = StudeezDestinations.SPLASH_SCREEN, modifier = modifier, ) { + // NavBar + composable(StudeezDestinations.HOME_SCREEN) { + HomeRoute( + open, + viewModel = hiltViewModel(), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, + ) + } + composable(StudeezDestinations.TASKS_SCREEN) { + // TODO + } + composable(StudeezDestinations.SESSIONS_SCREEN) { + // TODO + } + + composable(StudeezDestinations.PROFILE_SCREEN) { + ProfileRoute( + open, + viewModel = hiltViewModel(), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, + ) + } + + // Drawer + composable(StudeezDestinations.TIMER_SCREEN) { + TimerOverviewRoute( + viewModel = hiltViewModel(), + drawerActions = drawerActions, + ) + } + + composable(StudeezDestinations.SETTINGS_SCREEN) { + // TODO + } + + // Login flow composable(StudeezDestinations.SPLASH_SCREEN) { SplashRoute( openAndPopUp, @@ -136,31 +174,12 @@ fun StudeezNavGraph( ) } - composable(StudeezDestinations.HOME_SCREEN) { - HomeRoute( + // Studying flow + composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { + TimerSelectionRoute( open, + goBack, viewModel = hiltViewModel(), - drawerActions = drawerActions, - navigationBarActions = navigationBarActions, - ) - } - - // TODO Tasks screen - // TODO Sessions screen - - composable(StudeezDestinations.PROFILE_SCREEN) { - ProfileRoute( - open, - viewModel = hiltViewModel(), - drawerActions = drawerActions, - navigationBarActions = navigationBarActions, - ) - } - - composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) { - TimerOverviewRoute( - viewModel = hiltViewModel(), - drawerActions = drawerActions, ) } @@ -172,8 +191,12 @@ fun StudeezNavGraph( ) } - // TODO Timers screen - // TODO Settings screen + composable(StudeezDestinations.SESSION_RECAP) { + SessionRecapRoute( + openAndPopUp = openAndPopUp, + viewModel = hiltViewModel() + ) + } // Edit screens composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { @@ -183,20 +206,5 @@ fun StudeezNavGraph( viewModel = hiltViewModel(), ) } - - composable(StudeezDestinations.TIMER_SELECTION_SCREEN) { - TimerSelectionRoute( - open, - goBack, - viewModel = hiltViewModel(), - ) - } - - composable(StudeezDestinations.SESSION_RECAP) { - SessionRecapRoute( - openAndPopUp = openAndPopUp, - viewModel = hiltViewModel() - ) - } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt index 47571f5..9510b0d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.common.composable.drawer +import android.content.Context import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -16,6 +17,7 @@ import androidx.compose.material.icons.outlined.Info import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -28,7 +30,7 @@ data class DrawerActions( val onTimersClick: () -> Unit, val onSettingsClick: () -> Unit, val onLogoutClick: () -> Unit, - val onAboutClick: () -> Unit, + val onAboutClick: (Context) -> Unit, ) fun getDrawerActions( @@ -41,7 +43,9 @@ fun getDrawerActions( onTimersClick = { drawerViewModel.onTimersClick(open) }, onSettingsClick = { drawerViewModel.onSettingsClick(open) }, onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, - onAboutClick = { drawerViewModel.onAboutClick(open) }, + onAboutClick = { context -> + drawerViewModel.onAboutClick(open, context = context) + }, ) } @@ -79,10 +83,11 @@ fun Drawer( ) } + val context = LocalContext.current DrawerEntry( icon = Icons.Outlined.Info, text = resources().getString(R.string.about), - onClick = drawerActions.onAboutClick, + onClick = { drawerActions.onAboutClick(context) }, ) } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerViewModel.kt index d16d930..e55c342 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerViewModel.kt @@ -1,5 +1,10 @@ package be.ugent.sel.studeez.common.composable.drawer +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.navigation.StudeezDestinations @@ -9,6 +14,8 @@ import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +const val REPO_URL: String = "https://github.ugent.be/SELab1/project2023-groep14/" + @HiltViewModel class DrawerViewModel @Inject constructor( private val accountDAO: AccountDAO, @@ -20,11 +27,11 @@ class DrawerViewModel @Inject constructor( } fun onTimersClick(openAndPopup: (String) -> Unit) { - openAndPopup(StudeezDestinations.TIMER_OVERVIEW_SCREEN) + openAndPopup(StudeezDestinations.TIMER_SCREEN) } fun onSettingsClick(open: (String) -> Unit) { - // TODO + open(StudeezDestinations.SETTINGS_SCREEN) } fun onLogoutClick(openAndPopUp: (String, String) -> Unit) { @@ -34,7 +41,8 @@ class DrawerViewModel @Inject constructor( } } - fun onAboutClick(open: (String) -> Unit) { - // TODO + fun onAboutClick(open: (String) -> Unit, context: Context) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(REPO_URL)) + context.startActivity(intent) } } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index 79186b5..d84910e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -14,6 +14,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme import be.ugent.sel.studeez.R.string as AppText @@ -71,8 +73,7 @@ fun NavigationBar( ) }, label = { Text(text = resources().getString(AppText.tasks)) }, - // TODO selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), - selected = false, + selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), onClick = navigationBarActions.onTasksClick ) @@ -86,8 +87,7 @@ fun NavigationBar( ) }, label = { Text(text = resources().getString(AppText.sessions)) }, - // TODO selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), - selected = false, + selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), onClick = navigationBarActions.onSessionsClick ) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt index 1e4bd0d..8c68832 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt @@ -4,6 +4,8 @@ import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -19,11 +21,11 @@ class NavigationBarViewModel @Inject constructor( } fun onTasksClick(open: (String) -> Unit) { - // TODO + open(TASKS_SCREEN) } fun onSessionsClick(open: (String) -> Unit) { - // TODO + open(SESSIONS_SCREEN) } fun onProfileClick(open: (String) -> Unit) { diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index ab10c22..bb78b0b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -1,21 +1,25 @@ package be.ugent.sel.studeez.navigation object StudeezDestinations { - const val SPLASH_SCREEN = "splash" - const val SIGN_UP_SCREEN = "signup" - const val LOGIN_SCREEN = "login" - + // NavBar const val HOME_SCREEN = "home" - const val TIMER_OVERVIEW_SCREEN = "timer_overview" + const val TASKS_SCREEN = "tasks" + const val SESSIONS_SCREEN = "sessions" + const val PROFILE_SCREEN = "profile" + + // Drawer + const val TIMER_SCREEN = "timer_overview" + const val SETTINGS_SCREEN = "settings" + + // Login flow + const val SPLASH_SCREEN = "splash" + const val LOGIN_SCREEN = "login" + const val SIGN_UP_SCREEN = "signup" + + // Studying flow 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" - -// const val TIMERS_SCREEN = "timers" -// const val SETTINGS_SCREEN = "settings" // Edit screens const val EDIT_PROFILE_SCREEN = "edit_profile" diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt index 1f760e5..1e9be33 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt @@ -39,7 +39,7 @@ fun HomeScreen( title = resources().getString(R.string.home), drawerActions = drawerActions, navigationBarActions = navigationBarActions, - barAction = { FriendsAction() } + // TODO barAction = { FriendsAction() } ) { BasicButton(R.string.start_session, Modifier.basicButton()) { onStartSessionClick() From da79195e8da8b03513e1a4f30d3edd8e13d82872 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 12:35:08 +0200 Subject: [PATCH 18/59] #67 working popup, not styled --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 33 +++---- .../FloatingActionButtonComposable.kt | 85 ++++++++++++++++--- .../composable/PrimaryScreenComposable.kt | 10 ++- .../navbar/NavigationBarComposable.kt | 21 ++++- .../navbar/NavigationBarViewModel.kt | 15 ++++ .../studeez/navigation/StudeezDestinations.kt | 7 +- .../sel/studeez/screens/home/HomeScreen.kt | 4 +- .../studeez/screens/profile/ProfileScreen.kt | 2 +- 8 files changed, 141 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index ae460ff..584649f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -2,18 +2,8 @@ package be.ugent.sel.studeez import android.content.res.Resources import androidx.compose.foundation.layout.padding -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.ScaffoldState -import androidx.compose.material.Snackbar -import androidx.compose.material.SnackbarHost -import androidx.compose.material.Surface -import androidx.compose.material.rememberScaffoldState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext @@ -119,7 +109,7 @@ fun StudeezNavGraph( open, viewModel = hiltViewModel(), drawerActions = drawerActions, - navigationBarActions = navigationBarActions, + navigationBarActions = navigationBarActions ) } @@ -136,7 +126,7 @@ fun StudeezNavGraph( open, viewModel = hiltViewModel(), drawerActions = drawerActions, - navigationBarActions = navigationBarActions, + navigationBarActions = navigationBarActions ) } @@ -198,7 +188,20 @@ fun StudeezNavGraph( ) } - // Edit screens + // Friends flow + composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) { + // TODO + } + + // Create & edit screens + composable(StudeezDestinations.CREATE_TASK_SCREEN) { + // TODO + } + + composable(StudeezDestinations.CREATE_SESSION_SCREEN) { + // TODO + } + composable(StudeezDestinations.EDIT_PROFILE_SCREEN) { EditProfileRoute( goBack, diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt index 15005fa..078d6fb 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt @@ -1,5 +1,8 @@ package be.ugent.sel.studeez.common.composable +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.updateTransition +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material.FloatingActionButton @@ -11,36 +14,88 @@ import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.Person -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.ui.theme.StudeezTheme +const val TRANSITION = "transition" +enum class MultiFloatingState { + Expanded, + Collapsed +} + +data class AddButtonActions( + val onTaskClick: () -> Unit, + val onFriendClick: () -> Unit, + val onSessionClick: () -> Unit +) + @Composable -fun CollapsedAddButton() { - FloatingActionButton( - onClick = { /* TODO popup add options */ } +fun AddButton( + addButtonActions: AddButtonActions +) { + var multiFloatingState by remember { + mutableStateOf(MultiFloatingState.Collapsed) + } + + // Rotate the button when expanded, normal when collapsed. + val transition = updateTransition(targetState = multiFloatingState, label = TRANSITION) + val rotate by transition.animateFloat(label = TRANSITION) { + when (it) { + MultiFloatingState.Expanded -> 315f + MultiFloatingState.Collapsed -> 0f + } + } + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top ) { - Icon(imageVector = Icons.Default.Add, contentDescription = "fab") + // Show minis when expanded. + if (multiFloatingState == MultiFloatingState.Expanded) { + ExpandedAddButton(addButtonActions = addButtonActions) + } + + // The base add button + FloatingActionButton( + onClick = { + // Toggle expanded/collapsed. + multiFloatingState = when (transition.currentState) { + MultiFloatingState.Collapsed -> MultiFloatingState.Expanded + MultiFloatingState.Expanded -> MultiFloatingState.Collapsed + } + } + ) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = "fab", + modifier = Modifier.rotate(rotate) // The rotation + ) + } } } @Composable -fun ExpandedAddButton() { - Row() { - IconButton(onClick = { /* TODO Go to next step */ }) { +fun ExpandedAddButton( + addButtonActions: AddButtonActions +) { + Row { + IconButton(onClick = addButtonActions.onTaskClick) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.Check, contentDescription = "Task") Text(text = "Task") } } - IconButton(onClick = { /* TODO Go to next step */ }) { + IconButton(onClick = addButtonActions.onFriendClick) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.Person, contentDescription = "Friend") Text(text = "Friend") } } - IconButton(onClick = { /* TODO Go to next step */ }) { + IconButton(onClick = addButtonActions.onSessionClick) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session") Text(text = "Session") @@ -51,12 +106,16 @@ fun ExpandedAddButton() { @Preview @Composable -fun CollapsedAddButtonPreview() { - StudeezTheme { CollapsedAddButton() } +fun AddButtonPreview() { + StudeezTheme { AddButton( + addButtonActions = AddButtonActions({}, {}, {}) + )} } @Preview @Composable fun ExpandedAddButtonPreview() { - StudeezTheme { ExpandedAddButton() } + StudeezTheme { ExpandedAddButton( + addButtonActions = AddButtonActions({}, {}, {}) + ) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt index 79dec41..0cbfb0b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt @@ -56,8 +56,12 @@ fun PrimaryScreenTemplate( bottomBar = { NavigationBar(navigationBarActions) }, floatingActionButtonPosition = FabPosition.Center, - isFloatingActionButtonDocked = true, - floatingActionButton = { CollapsedAddButton() } + isFloatingActionButtonDocked = false, + floatingActionButton = { AddButton(AddButtonActions( + onTaskClick = navigationBarActions.onAddTaskClick, + onFriendClick = navigationBarActions.onAddFriendClick, + onSessionClick = navigationBarActions.onAddSessionClick + )) } ) { content(it) } @@ -70,7 +74,7 @@ fun PrimaryScreenPreview() { PrimaryScreenTemplate( "Preview screen", DrawerActions({}, {}, {}, {}, {}), - NavigationBarActions({ false }, {}, {}, {}, {}), + NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), { IconButton(onClick = { /*TODO*/ }) { Icon( diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index d84910e..b2393d8 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -22,10 +22,16 @@ import be.ugent.sel.studeez.R.string as AppText data class NavigationBarActions( val isSelectedTab: (String) -> Boolean, + val onHomeClick: () -> Unit, val onTasksClick: () -> Unit, val onSessionsClick: () -> Unit, val onProfileClick: () -> Unit, + + // AddButton + val onAddTaskClick: () -> Unit, + val onAddFriendClick: () -> Unit, + val onAddSessionClick: () -> Unit ) fun getNavigationBarActions( @@ -37,6 +43,7 @@ fun getNavigationBarActions( isSelectedTab = { screen -> screen == getCurrentScreen() }, + onHomeClick = { navigationBarViewModel.onHomeClick(open) }, @@ -49,6 +56,18 @@ fun getNavigationBarActions( onProfileClick = { navigationBarViewModel.onProfileClick(open) }, + + onAddTaskClick = { + navigationBarViewModel.onAddTaskClick(open) + }, + + onAddFriendClick = { + navigationBarViewModel.onAddFriendClick(open) + }, + + onAddSessionClick = { + navigationBarViewModel.onAddSessionClick(open) + } ) } @@ -110,7 +129,7 @@ fun NavigationBar( fun NavigationBarPreview() { StudeezTheme { NavigationBar( - navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}), + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), ) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt index 8c68832..ab9256b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt @@ -2,8 +2,11 @@ package be.ugent.sel.studeez.common.composable.navbar import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations.CREATE_SESSION_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.CREATE_TASK_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.SEARCH_FRIENDS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN import be.ugent.sel.studeez.screens.StudeezViewModel @@ -31,4 +34,16 @@ class NavigationBarViewModel @Inject constructor( fun onProfileClick(open: (String) -> Unit) { open(PROFILE_SCREEN) } + + fun onAddTaskClick(open: (String) -> Unit) { + open(CREATE_TASK_SCREEN) + } + + fun onAddFriendClick(open: (String) -> Unit) { + open(SEARCH_FRIENDS_SCREEN) + } + + fun onAddSessionClick(open: (String) -> Unit) { + open(CREATE_SESSION_SCREEN) + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index bb78b0b..0d55dec 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -21,6 +21,11 @@ object StudeezDestinations { const val SESSION_SCREEN = "session" const val SESSION_RECAP = "session_recap" - // Edit screens + // Friends flow + const val SEARCH_FRIENDS_SCREEN = "search_friends" + + // Create & edit screens + const val CREATE_TASK_SCREEN = "create_task" + const val CREATE_SESSION_SCREEN = "create_session" const val EDIT_PROFILE_SCREEN = "edit_profile" } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt index 1e9be33..f02852e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/home/HomeScreen.kt @@ -33,7 +33,7 @@ fun HomeRoute( fun HomeScreen( onStartSessionClick: () -> Unit, drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions, + navigationBarActions: NavigationBarActions ) { PrimaryScreenTemplate( title = resources().getString(R.string.home), @@ -63,6 +63,6 @@ fun HomeScreenPreview() { HomeScreen( onStartSessionClick = {}, drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}) ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt index 0b4a67f..9c76337 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileScreen.kt @@ -88,6 +88,6 @@ fun ProfileScreenPreview() { ProfileScreen( profileActions = ProfileActions({ null }, {}), drawerActions = DrawerActions({}, {}, {}, {}, {}), - navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) + navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}) ) } \ No newline at end of file From 5b0cff23762b9b0f8b8f42dfe1a3f75209860750 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:51:46 +0200 Subject: [PATCH 19/59] timepicker button met popup-klok functionaliteit --- .../composable/TimePickerButtonComposable.kt | 47 +++++++++++++++++++ .../ugent/sel/studeez/data/EditTimerState.kt | 4 ++ .../models/timer_info/TimerInfoVisitor.kt | 4 ++ .../screens/timer_edit/GetTimerEditScreen.kt | 35 ++++++++++++++ .../screens/timer_edit/TimerEditScreen.kt | 2 + .../screens/timer_edit/TimerEditViewModel.kt | 4 ++ .../editScreens/AbstractTimerEditScreen.kt | 4 ++ .../editScreens/BreakTimerEditScreen.kt | 4 ++ .../editScreens/CustomTimerEditScreen.kt | 4 ++ .../editScreens/EndlessTimerEditScreen.kt | 4 ++ 10 files changed, 112 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt new file mode 100644 index 0000000..869d724 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -0,0 +1,47 @@ +package be.ugent.sel.studeez.common.composable + +import android.app.TimePickerDialog +import android.app.TimePickerDialog.OnTimeSetListener +import android.content.Context +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonColors +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import java.util.* + +// TODO codeduplicatie met Tibo, later wegdoen +@Composable +fun TimePickerButton( + hoursMinutesSeconds: HoursMinutesSeconds, + modifier: Modifier = Modifier, + colors: ButtonColors = ButtonDefaults.buttonColors(), + border: BorderStroke? = null, + onTimeSetListener: OnTimeSetListener +) { + val context = LocalContext.current + Button( + onClick = { pickDuration(context, onTimeSetListener) }, + modifier = modifier, + shape = RoundedCornerShape(20.dp), + colors = colors, + border = border + ) { + Text(text = hoursMinutesSeconds.toString()) + } +} + +// TODO idem codedup Tibo +private fun pickDuration(context: Context, listener: OnTimeSetListener) { + val mCalendar = Calendar.getInstance() + val mHour = mCalendar[Calendar.HOUR] + val mMinute = mCalendar[Calendar.MINUTE] + val mTimePickerDialog = TimePickerDialog(context, listener, mHour, mMinute, true) + mTimePickerDialog.show() +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt new file mode 100644 index 0000000..9686e94 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.data + +class EditTimerState { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt new file mode 100644 index 0000000..0dedc94 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.data.local.models.timer_info + +interface TimerInfoVisitor { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt new file mode 100644 index 0000000..c6579e8 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt @@ -0,0 +1,35 @@ +package be.ugent.sel.studeez.screens.timer_edit + +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +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.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor + +class GetTimerEditView: TimerInfoVisitor { + + @SuppressLint("ComposableNaming") + override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) { + + } + + @SuppressLint("ComposableNaming") + override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo) { + + } + + @SuppressLint("ComposableNaming") + override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt new file mode 100644 index 0000000..ac1ff8a --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt @@ -0,0 +1,2 @@ +package be.ugent.sel.studeez.screens.timer_edit + diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt new file mode 100644 index 0000000..20f5952 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +class TimerEditViewModel { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt new file mode 100644 index 0000000..59b04e7 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +abstract class AbstractTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt new file mode 100644 index 0000000..1405682 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +class BreakTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt new file mode 100644 index 0000000..bbe66ec --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +class CustomTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt new file mode 100644 index 0000000..5c6263d --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +class EndlessTimerEditScreen { +} \ No newline at end of file From 1d6de333e4d9a17fc657b93af7adf22a3aba5a4f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:53:35 +0200 Subject: [PATCH 20/59] HMS now takes ints and has totalseconds and tostring functions --- .../timer_functional/HoursMinutesSeconds.kt | 15 +++++++++++++-- .../data/local/models/timer_functional/Time.kt | 6 +----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt index 856aa26..2f630c9 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt @@ -1,4 +1,15 @@ package be.ugent.sel.studeez.data.local.models.timer_functional -data class HoursMinutesSeconds(val hours: String, val minutes: String, val seconds: String -) \ No newline at end of file +data class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) { + + fun getTotalSeconds(): Int { + return hours * 60 * 60 + minutes * 60 + seconds + } + + override fun toString(): String { + val hoursString = hours.toString().padStart(2, '0') + val minutesString = minutes.toString().padStart(2, '0') + val secondsString = seconds.toString().padStart(2, '0') + return "$hoursString : $minutesString : $secondsString" + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index ec7702d..c512d96 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -17,11 +17,7 @@ class Time(initialTime: Int) { val minutes: Int = (time / (60)) % 60 val seconds: Int = time % 60 - return HoursMinutesSeconds( - hours.toString().padStart(2, '0'), - minutes.toString().padStart(2, '0'), - seconds.toString().padStart(2, '0') - ) + return HoursMinutesSeconds(hours, minutes, seconds) } } \ No newline at end of file From f2d45b410e2a288e28025b589f0c70e6a5dd655a Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:54:24 +0200 Subject: [PATCH 21/59] added singleLine parameter (default false) --- .../sel/studeez/common/composable/TextFieldComposable.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt index 2c0b450..47dbb0b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt @@ -41,10 +41,12 @@ fun BasicField( fun LabelledInputField( value: String, onNewValue: (String) -> Unit, - @StringRes label: Int + @StringRes label: Int, + singleLine: Boolean = false ) { OutlinedTextField( value = value, + singleLine = singleLine, onValueChange = onNewValue, label = { Text(text = stringResource(id = label)) }, modifier = Modifier.fieldModifier() From 93a282026eadb334277e6b4b29ec4b00c6c22319 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:56:50 +0200 Subject: [PATCH 22/59] added visitor to TimerInfo --- .../data/local/models/timer_info/CustomTimerInfo.kt | 7 +++++-- .../data/local/models/timer_info/EndlessTimerInfo.kt | 4 ++++ .../data/local/models/timer_info/PomodoroTimerInfo.kt | 11 ++++++++--- .../studeez/data/local/models/timer_info/TimerInfo.kt | 5 +++-- .../data/local/models/timer_info/TimerInfoVisitor.kt | 9 ++++++++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt index 5e06536..b3ecea1 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt @@ -6,11 +6,10 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer class CustomTimerInfo( name: String, description: String, - private val studyTime: Int, + val studyTime: Int, id: String = "" ): TimerInfo(id, name, description) { - override fun getFunctionalTimer(): FunctionalTimer { return FunctionalCustomTimer(studyTime) } @@ -24,4 +23,8 @@ class CustomTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitCustomTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt index d459a4e..45f7fd7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt @@ -22,4 +22,8 @@ class EndlessTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitEndlessTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt index 18bcea6..dbbb0be 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt @@ -2,13 +2,14 @@ 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 +import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor class PomodoroTimerInfo( name: String, description: String, - private val studyTime: Int, - private val breakTime: Int, - private val repeats: Int, + val studyTime: Int, + val breakTime: Int, + val repeats: Int, id: String = "" ): TimerInfo(id, name, description) { @@ -28,4 +29,8 @@ class PomodoroTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitBreakTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt index 343e7e3..e4deded 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt @@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer */ abstract class TimerInfo( val id: String, - val name: String, - val description: String + var name: String, + var description: String ) { /** @@ -21,6 +21,7 @@ abstract class TimerInfo( * TODO implementaties hebben nog hardgecodeerde strings. */ abstract fun asJson(): Map + abstract fun accept(visitor: TimerInfoVisitor): T } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt index 0dedc94..e331c8d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt @@ -1,4 +1,11 @@ package be.ugent.sel.studeez.data.local.models.timer_info -interface TimerInfoVisitor { +interface TimerInfoVisitor { + + fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): T + + fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): T + + fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): T + } \ No newline at end of file From ddbac51c9d44cf363f6a61584090e70a66ca1b58 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:57:31 +0200 Subject: [PATCH 23/59] #30 added edit screen to destinations --- .../java/be/ugent/sel/studeez/data/EditTimerState.kt | 9 ++++++++- .../ugent/sel/studeez/navigation/StudeezDestinations.kt | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt index 9686e94..dceec8c 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt @@ -1,4 +1,11 @@ package be.ugent.sel.studeez.data -class EditTimerState { +import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class EditTimerState @Inject constructor(){ + lateinit var timerInfo: TimerInfo } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index ab10c22..eacf2c1 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -8,6 +8,7 @@ object StudeezDestinations { const val HOME_SCREEN = "home" const val TIMER_OVERVIEW_SCREEN = "timer_overview" const val TIMER_SELECTION_SCREEN = "timer_selection" + const val TIMER_EDIT_SCREEN = "timer_edit" const val SESSION_SCREEN = "session" const val SESSION_RECAP = "session_recap" // const val TASKS_SCREEN = "tasks" From 59c4d8bb5ba4a4dffe574cfd47b8b79870aa8185 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:00:18 +0200 Subject: [PATCH 24/59] hms toString --- .../screens/session/sessionScreens/AbstractSessionScreen.kt | 2 +- .../sel/studeez/screens/session_recap/SessionRecapScreen.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt index 4c0cc3e..06a80b6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session/sessionScreens/AbstractSessionScreen.kt @@ -78,7 +78,7 @@ abstract class AbstractSessionScreen { val hms = sessionActions.getTimer().getHoursMinutesSeconds() Column { Text( - text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}", + text = hms.toString(), modifier = Modifier .fillMaxWidth() .padding(50.dp), diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt index 2ddbc32..53c9a16 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/session_recap/SessionRecapScreen.kt @@ -48,8 +48,7 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi val studyTime: Int = sessionReport.studyTime val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() Column { - Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}") - + Text(text = "You studied: $hms") BasicButton( R.string.save, Modifier.basicButton() ) { From dfbc99ba38b08537c13b5455d4f23eee5fbd2efd Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:01:07 +0200 Subject: [PATCH 25/59] #30 added edit screen to navgraph --- app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index c8a133b..36ecc88 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -40,6 +40,7 @@ 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_edit.TimerEditRoute import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionRoute import be.ugent.sel.studeez.ui.theme.StudeezTheme @@ -161,6 +162,15 @@ fun StudeezNavGraph( TimerOverviewRoute( viewModel = hiltViewModel(), drawerActions = drawerActions, + open = open + ) + } + + composable(StudeezDestinations.TIMER_EDIT_SCREEN) { + TimerEditRoute( + open = open, + popUp = goBack, + viewModel = hiltViewModel() ) } From e592a6acc08bcaad4382c3c58473a7bf53326b83 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:02:29 +0200 Subject: [PATCH 26/59] #30 hierarchical edit screen structure --- .../editScreens/AbstractTimerEditScreen.kt | 58 ++++++++++++++++++- .../editScreens/BreakTimerEditScreen.kt | 27 ++++++++- .../editScreens/CustomTimerEditScreen.kt | 31 +++++++++- .../editScreens/EndlessTimerEditScreen.kt | 4 +- 4 files changed, 114 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt index 59b04e7..eedaa78 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt @@ -1,4 +1,58 @@ -package be.ugent.sel.studeez.screens.timer_edit +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.composable.BasicButton +import be.ugent.sel.studeez.common.composable.LabelledInputField +import be.ugent.sel.studeez.common.ext.basicButton +import be.ugent.sel.studeez.common.ext.fieldModifier +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo + +abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) { + + @Composable + operator fun invoke(onSaveClick: (TimerInfo) -> Unit) { + // TODO klassen hierarchie voor uistate + // TODO klassen extras implementeren + + Column( + modifier = Modifier.fillMaxWidth().fillMaxHeight(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + // Fields that every timer shares (ommited id) + LabelledInputField( + value = timerInfo.name, + onNewValue = {}, + label = R.string.name + ) + LabelledInputField( + value = timerInfo.description, + onNewValue = {}, + label = R.string.description, + singleLine = false + ) + + ExtraFields() + + BasicButton(R.string.save, Modifier.basicButton()) { + onSaveClick(timerInfo) + } + } + } + + @Composable + open fun ExtraFields() { + // By default no extra fields, unless overwritten by subclass. + } -abstract class AbstractTimerEditScreen { } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt index 1405682..f00e9f6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt @@ -1,4 +1,29 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens -class BreakTimerEditScreen { +import androidx.compose.runtime.* +import be.ugent.sel.studeez.common.composable.TimePickerButton +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.data.local.models.timer_functional.Time +import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo + +class BreakTimerEditScreen( + private val breakTimerInfo: PomodoroTimerInfo +): AbstractTimerEditScreen(breakTimerInfo) { + + @Composable + override fun ExtraFields() { + // If the user presses the OK button on the timepicker, the time in the button should change + var studyTime: Int by remember { mutableStateOf(breakTimerInfo.studyTime) } + var breakTime: Int by remember { mutableStateOf(breakTimerInfo.breakTime) } + + val breakHms: HoursMinutesSeconds = Time(breakTime).getAsHMS() + val studyHms: HoursMinutesSeconds = Time(studyTime).getAsHMS() + TimePickerButton(studyHms) { _, hour, minute -> + studyTime = hour * 60 * 60 + minute * 60 + } + TimePickerButton(breakHms) { _, hour, minute -> + breakTime = hour * 60 * 60 + minute * 60 + } + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt index bbe66ec..3e2e234 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt @@ -1,4 +1,31 @@ -package be.ugent.sel.studeez.screens.timer_edit +package be.ugent.sel.studeez.screens.timer_edit.editScreens -class CustomTimerEditScreen { +import androidx.compose.runtime.* +import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.common.composable.TimePickerButton +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.data.local.models.timer_functional.Time +import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo + +class CustomTimerEditScreen(private val customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen(customTimerInfo) { + + @Composable + override fun ExtraFields() { + // If the user presses the OK button on the timepicker, the time in the button should change + var studyTime by remember { mutableStateOf(customTimerInfo.studyTime) } + + val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() + TimePickerButton(hms) { _, hour, minute -> + studyTime = hour * 60 * 60 + minute * 60 + } + } + + +} + +@Preview +@Composable +fun TimePickerPreview() { + val customTimerInfo = CustomTimerInfo("custom", "my description", 25) + CustomTimerEditScreen(customTimerInfo).ExtraFields() } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt index 5c6263d..0f5b30a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt @@ -1,4 +1,6 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens -class EndlessTimerEditScreen { +import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo + +class EndlessTimerEditScreen(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen(endlessTimerInfo) { } \ No newline at end of file From d1c23fce48b716a54b885a61f16c010aaa6d6bd8 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:03:12 +0200 Subject: [PATCH 27/59] #30 Visitor implementatie om Edit scherm te verkrijgen --- .../screens/timer_edit/GetTimerEditScreen.kt | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt index c6579e8..b22b775 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt @@ -1,34 +1,26 @@ package be.ugent.sel.studeez.screens.timer_edit -import android.annotation.SuppressLint -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -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.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor +import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen +import be.ugent.sel.studeez.screens.timer_edit.editScreens.BreakTimerEditScreen +import be.ugent.sel.studeez.screens.timer_edit.editScreens.CustomTimerEditScreen +import be.ugent.sel.studeez.screens.timer_edit.editScreens.EndlessTimerEditScreen -class GetTimerEditView: TimerInfoVisitor { - - @SuppressLint("ComposableNaming") - override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) { +class GetTimerEditScreen: TimerInfoVisitor { + override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen { + return CustomTimerEditScreen(customTimerInfo) } - @SuppressLint("ComposableNaming") - override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo) { - + override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen { + return EndlessTimerEditScreen(endlessTimerInfo) } - @SuppressLint("ComposableNaming") - override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo) { - + override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerEditScreen { + return BreakTimerEditScreen(pomodoroTimerInfo) } From 6d8f9befb31b5a1d4db44db8b83a1bf0b85d7848 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:04:06 +0200 Subject: [PATCH 28/59] #30 timerEdit screen and viewmodel --- .../screens/timer_edit/TimerEditScreen.kt | 80 +++++++++++++++++++ .../screens/timer_edit/TimerEditViewModel.kt | 26 +++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt index ac1ff8a..4540faa 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt @@ -1,2 +1,82 @@ package be.ugent.sel.studeez.screens.timer_edit + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen +import be.ugent.sel.studeez.ui.theme.StudeezTheme + +data class TimerEditActions( + val getTimerInfo: () -> TimerInfo, + val saveTimer: (TimerInfo) -> Unit +) + +fun getTimerEditActions( + viewModel: TimerEditViewModel, + open: (String) -> Unit +): TimerEditActions { + return TimerEditActions( + getTimerInfo = viewModel::getTimerInfo, + saveTimer = viewModel::saveTimer + ) +} + +@Composable +fun TimerEditRoute( + open: (String) -> Unit, + popUp: () -> Unit, + viewModel: TimerEditViewModel, +) { + TimerEditScreen( + timerEditActions = getTimerEditActions(viewModel, open), + popUp = popUp + ) +} + +@Composable +fun TimerEditScreen( + timerEditActions: TimerEditActions, + popUp: () -> Unit +) { + SecondaryScreenTemplate(title = "Edit Timer", popUp = { /*TODO*/ }) { + val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen()) + timerEditScreen { timerInfo -> timerEditActions.saveTimer(timerInfo) } + } +} + +//@Preview +//@Composable +//fun TimerEditScreenPreview() { +// val editEntries: List = listOf( +// EditEntry("Name", "MyTimer") {}, +// EditEntry("Description", "Dit is een leuke timer") {}, +// EditEntry("StudyTime", "25") {} +// ) +// val actions = TimerEditActions { editEntries } +// StudeezTheme { TimerEditScreen(timerEditActions = actions) {} } +//} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt index 20f5952..98d060f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt @@ -1,4 +1,28 @@ package be.ugent.sel.studeez.screens.timer_edit -class TimerEditViewModel { +import be.ugent.sel.studeez.data.EditTimerState +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.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class TimerEditViewModel @Inject constructor( + private val editTimerState: EditTimerState, + private val timerDAO: TimerDAO, + logService: LogService +) : StudeezViewModel(logService) { + + private val timerInfo: TimerInfo = editTimerState.timerInfo + + fun getTimerInfo(): TimerInfo { + return timerInfo + } + + fun saveTimer(timerInfo: TimerInfo) { + timerDAO.updateTimer(timerInfo) + } + } \ No newline at end of file From a218f5fcf59a84f8e178ad071b2ef1dfa06536c3 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:05:45 +0200 Subject: [PATCH 29/59] #30 open wordt nu meegegeven aan de edit functie --- .../studeez/screens/timer_overview/TimerOverviewScreen.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt index 9489a30..1f782e7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewScreen.kt @@ -28,11 +28,12 @@ data class TimerOverviewActions( fun getTimerOverviewActions( viewModel: TimerOverviewViewModel, + open: (String) -> Unit, ): TimerOverviewActions { return TimerOverviewActions( getUserTimers = viewModel::getUserTimers, getDefaultTimers = viewModel::getDefaultTimers, - onEditClick = { viewModel.update(it) }, + onEditClick = { viewModel.update(it, open) }, ) } @@ -40,10 +41,11 @@ fun getTimerOverviewActions( fun TimerOverviewRoute( viewModel: TimerOverviewViewModel, drawerActions: DrawerActions, + open: (String) -> Unit ) { TimerOverviewScreen( - timerOverviewActions = getTimerOverviewActions(viewModel), - drawerActions = drawerActions, + timerOverviewActions = getTimerOverviewActions(viewModel, open), + drawerActions = drawerActions ) } From d9c281330f2333733e971e88ffb590f94d560771 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:06:50 +0200 Subject: [PATCH 30/59] #30 geef timerinfo door naar edit scherm en open editscherm bij onEditClick --- .../screens/timer_overview/TimerOverviewViewModel.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt index c2be1e9..2f9457d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/TimerOverviewViewModel.kt @@ -1,9 +1,11 @@ package be.ugent.sel.studeez.screens.timer_overview +import be.ugent.sel.studeez.data.EditTimerState import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.domain.ConfigurationService 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 @@ -13,6 +15,7 @@ import javax.inject.Inject class TimerOverviewViewModel @Inject constructor( private val configurationService: ConfigurationService, private val timerDAO: TimerDAO, + private val editTimerState: EditTimerState, logService: LogService ) : StudeezViewModel(logService) { @@ -24,7 +27,10 @@ class TimerOverviewViewModel @Inject constructor( return configurationService.getDefaultTimers() } - fun update(timerInfo: TimerInfo) = timerDAO.updateTimer(timerInfo) + fun update(timerInfo: TimerInfo, open: (String) -> Unit) { + editTimerState.timerInfo = timerInfo + open(StudeezDestinations.TIMER_EDIT_SCREEN) + } fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo) From e4fc0a9a0794a25db580333745c774a6b6814388 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 13:09:24 +0200 Subject: [PATCH 31/59] #30 added edit screen specific text --- app/src/main/res/values/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b9f561..d171ff4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,6 +75,14 @@ Done! Take a break! + + Name + Description + Study Time + Break Time + Number of Repeats + + Settings From 2c62e13caad4ea6eb128818c27a86872123d0359 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:51:46 +0200 Subject: [PATCH 32/59] timepicker button met popup-klok functionaliteit --- .../composable/TimePickerButtonComposable.kt | 47 +++++++++++++++++++ .../ugent/sel/studeez/data/EditTimerState.kt | 4 ++ .../models/timer_info/TimerInfoVisitor.kt | 4 ++ .../screens/timer_edit/GetTimerEditScreen.kt | 35 ++++++++++++++ .../screens/timer_edit/TimerEditScreen.kt | 2 + .../screens/timer_edit/TimerEditViewModel.kt | 4 ++ .../editScreens/AbstractTimerEditScreen.kt | 4 ++ .../editScreens/BreakTimerEditScreen.kt | 4 ++ .../editScreens/CustomTimerEditScreen.kt | 4 ++ .../editScreens/EndlessTimerEditScreen.kt | 4 ++ 10 files changed, 112 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt new file mode 100644 index 0000000..869d724 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -0,0 +1,47 @@ +package be.ugent.sel.studeez.common.composable + +import android.app.TimePickerDialog +import android.app.TimePickerDialog.OnTimeSetListener +import android.content.Context +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonColors +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import java.util.* + +// TODO codeduplicatie met Tibo, later wegdoen +@Composable +fun TimePickerButton( + hoursMinutesSeconds: HoursMinutesSeconds, + modifier: Modifier = Modifier, + colors: ButtonColors = ButtonDefaults.buttonColors(), + border: BorderStroke? = null, + onTimeSetListener: OnTimeSetListener +) { + val context = LocalContext.current + Button( + onClick = { pickDuration(context, onTimeSetListener) }, + modifier = modifier, + shape = RoundedCornerShape(20.dp), + colors = colors, + border = border + ) { + Text(text = hoursMinutesSeconds.toString()) + } +} + +// TODO idem codedup Tibo +private fun pickDuration(context: Context, listener: OnTimeSetListener) { + val mCalendar = Calendar.getInstance() + val mHour = mCalendar[Calendar.HOUR] + val mMinute = mCalendar[Calendar.MINUTE] + val mTimePickerDialog = TimePickerDialog(context, listener, mHour, mMinute, true) + mTimePickerDialog.show() +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt new file mode 100644 index 0000000..9686e94 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/EditTimerState.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.data + +class EditTimerState { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt new file mode 100644 index 0000000..0dedc94 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.data.local.models.timer_info + +interface TimerInfoVisitor { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt new file mode 100644 index 0000000..c6579e8 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/GetTimerEditScreen.kt @@ -0,0 +1,35 @@ +package be.ugent.sel.studeez.screens.timer_edit + +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +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.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor + +class GetTimerEditView: TimerInfoVisitor { + + @SuppressLint("ComposableNaming") + override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) { + + } + + @SuppressLint("ComposableNaming") + override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo) { + + } + + @SuppressLint("ComposableNaming") + override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt new file mode 100644 index 0000000..ac1ff8a --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt @@ -0,0 +1,2 @@ +package be.ugent.sel.studeez.screens.timer_edit + diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt new file mode 100644 index 0000000..20f5952 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +class TimerEditViewModel { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt new file mode 100644 index 0000000..59b04e7 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +abstract class AbstractTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt new file mode 100644 index 0000000..1405682 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +class BreakTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt new file mode 100644 index 0000000..bbe66ec --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit + +class CustomTimerEditScreen { +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt new file mode 100644 index 0000000..5c6263d --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +class EndlessTimerEditScreen { +} \ No newline at end of file From 7046a2a98546c9799038079fd866821daddd3301 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:53:35 +0200 Subject: [PATCH 33/59] HMS now takes ints and has totalseconds and tostring functions --- .../timer_functional/HoursMinutesSeconds.kt | 15 +++++++++++++-- .../data/local/models/timer_functional/Time.kt | 6 +----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt index 856aa26..2f630c9 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt @@ -1,4 +1,15 @@ package be.ugent.sel.studeez.data.local.models.timer_functional -data class HoursMinutesSeconds(val hours: String, val minutes: String, val seconds: String -) \ No newline at end of file +data class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) { + + fun getTotalSeconds(): Int { + return hours * 60 * 60 + minutes * 60 + seconds + } + + override fun toString(): String { + val hoursString = hours.toString().padStart(2, '0') + val minutesString = minutes.toString().padStart(2, '0') + val secondsString = seconds.toString().padStart(2, '0') + return "$hoursString : $minutesString : $secondsString" + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index ec7702d..c512d96 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -17,11 +17,7 @@ class Time(initialTime: Int) { val minutes: Int = (time / (60)) % 60 val seconds: Int = time % 60 - return HoursMinutesSeconds( - hours.toString().padStart(2, '0'), - minutes.toString().padStart(2, '0'), - seconds.toString().padStart(2, '0') - ) + return HoursMinutesSeconds(hours, minutes, seconds) } } \ No newline at end of file From 964cd8a6ae816ff08a59b7a32f6cf021f37b212c Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:54:24 +0200 Subject: [PATCH 34/59] added singleLine parameter (default false) --- .../sel/studeez/common/composable/TextFieldComposable.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt index 2c0b450..47dbb0b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextFieldComposable.kt @@ -41,10 +41,12 @@ fun BasicField( fun LabelledInputField( value: String, onNewValue: (String) -> Unit, - @StringRes label: Int + @StringRes label: Int, + singleLine: Boolean = false ) { OutlinedTextField( value = value, + singleLine = singleLine, onValueChange = onNewValue, label = { Text(text = stringResource(id = label)) }, modifier = Modifier.fieldModifier() From 3c73c5a853d412fddb44cf19bf235a7b3156d2e9 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 12:56:50 +0200 Subject: [PATCH 35/59] added visitor to TimerInfo --- .../data/local/models/timer_info/CustomTimerInfo.kt | 5 ++++- .../data/local/models/timer_info/EndlessTimerInfo.kt | 4 ++++ .../data/local/models/timer_info/PomodoroTimerInfo.kt | 11 ++++++++--- .../studeez/data/local/models/timer_info/TimerInfo.kt | 5 +++-- .../data/local/models/timer_info/TimerInfoVisitor.kt | 9 ++++++++- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt index d33ecc4..d88e39f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt @@ -10,7 +10,6 @@ class CustomTimerInfo( id: String = "" ): TimerInfo(id, name, description) { - override fun getFunctionalTimer(): FunctionalTimer { return FunctionalCustomTimer(studyTime) } @@ -24,4 +23,8 @@ class CustomTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitCustomTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt index d459a4e..45f7fd7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/EndlessTimerInfo.kt @@ -22,4 +22,8 @@ class EndlessTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitEndlessTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt index 18bcea6..dbbb0be 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt @@ -2,13 +2,14 @@ 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 +import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor class PomodoroTimerInfo( name: String, description: String, - private val studyTime: Int, - private val breakTime: Int, - private val repeats: Int, + val studyTime: Int, + val breakTime: Int, + val repeats: Int, id: String = "" ): TimerInfo(id, name, description) { @@ -28,4 +29,8 @@ class PomodoroTimerInfo( ) } + override fun accept(visitor: TimerInfoVisitor): T { + return visitor.visitBreakTimerInfo(this) + } + } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt index 343e7e3..e4deded 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfo.kt @@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer */ abstract class TimerInfo( val id: String, - val name: String, - val description: String + var name: String, + var description: String ) { /** @@ -21,6 +21,7 @@ abstract class TimerInfo( * TODO implementaties hebben nog hardgecodeerde strings. */ abstract fun asJson(): Map + abstract fun accept(visitor: TimerInfoVisitor): T } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt index 0dedc94..e331c8d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/TimerInfoVisitor.kt @@ -1,4 +1,11 @@ package be.ugent.sel.studeez.data.local.models.timer_info -interface TimerInfoVisitor { +interface TimerInfoVisitor { + + fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): T + + fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): T + + fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): T + } \ No newline at end of file From 89b9c231237c7135ef7f5195725fc495ff14cdd7 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 13:32:52 +0200 Subject: [PATCH 36/59] Use TimePickerButton --- .../composable/TimePickerButtonComposable.kt | 15 +++++---- .../timer_selection/TimerSelectionScreen.kt | 33 +++++++------------ 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt index 869d724..02bd0d7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -16,7 +16,6 @@ import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import java.util.* -// TODO codeduplicatie met Tibo, later wegdoen @Composable fun TimePickerButton( hoursMinutesSeconds: HoursMinutesSeconds, @@ -37,11 +36,13 @@ fun TimePickerButton( } } -// TODO idem codedup Tibo private fun pickDuration(context: Context, listener: OnTimeSetListener) { - val mCalendar = Calendar.getInstance() - val mHour = mCalendar[Calendar.HOUR] - val mMinute = mCalendar[Calendar.MINUTE] - val mTimePickerDialog = TimePickerDialog(context, listener, mHour, mMinute, true) - mTimePickerDialog.show() + val timePickerDialog = TimePickerDialog( + context, + listener, + 0, + 0, + true + ) + timePickerDialog.show() } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index 780b50a..5ef775e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -1,7 +1,6 @@ package be.ugent.sel.studeez.screens.timer_selection -import android.app.TimePickerDialog -import android.content.Context +import android.widget.TimePicker import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable @@ -9,10 +8,12 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.R -import be.ugent.sel.studeez.common.composable.NotInternationalisedButton import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.common.composable.StealthButton +import be.ugent.sel.studeez.common.composable.TimePickerButton import be.ugent.sel.studeez.common.composable.TimerEntry +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.data.local.models.timer_functional.Time import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.resources @@ -22,7 +23,7 @@ import kotlinx.coroutines.flow.flowOf data class TimerSelectionActions( val getAllTimers: () -> Flow>, val startSession: (TimerInfo) -> Unit, - val pickDuration: (Context) -> Unit, + val pickDuration: (TimePicker?, Int, Int) -> Unit, val customTimeStudyTime: Int ) @@ -33,18 +34,8 @@ fun getTimerSelectionActions( return TimerSelectionActions( getAllTimers = viewModel::getAllTimers, startSession = { viewModel.startSession(open, it) }, - pickDuration = { context -> - val dialog = TimePickerDialog( - context, - { _, hour: Int, minute: Int -> - viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60 - }, - 0, - 0, - true - ) - - dialog.show() + pickDuration = { _, hour: Int, minute: Int -> + viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60 }, customTimeStudyTime = viewModel.customTimerStudyTime.value ) @@ -103,7 +94,7 @@ fun CustomTimerEntry( description = resources().getString(R.string.custom_description), studyTime = timerSelectionActions.customTimeStudyTime ) - val context = LocalContext.current + val hms: HoursMinutesSeconds = Time(timerInfo.studyTime).getAsHMS() TimerEntry( timerInfo = timerInfo, @@ -114,9 +105,9 @@ fun CustomTimerEntry( ) }, rightButton = { - NotInternationalisedButton( - text = String.format("%02d:%02d", timerInfo.studyTime / 3600, (timerInfo.studyTime % 3600) / 60), - onClick = { timerSelectionActions.pickDuration(context) } + TimePickerButton( + hoursMinutesSeconds = hms, + onTimeSetListener = timerSelectionActions.pickDuration ) } ) @@ -126,7 +117,7 @@ fun CustomTimerEntry( @Composable fun TimerSelectionPreview() { TimerSelectionScreen( - timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { {} }, 0), + timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _, _ -> {} }, 0), popUp = {} ) } \ No newline at end of file From 360097cfc5d4c4cb4a3b730b7bd293426b617807 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:50:22 +0200 Subject: [PATCH 37/59] added timepicker card --- .../composable/TimePickerButtonComposable.kt | 86 ++++++++++++++++--- .../editScreens/EditScreenUIState.kt | 4 + 2 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt index 869d724..eab0d35 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -3,45 +3,107 @@ package be.ugent.sel.studeez.common.composable import android.app.TimePickerDialog import android.app.TimePickerDialog.OnTimeSetListener import android.content.Context +import androidx.annotation.StringRes import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Button -import androidx.compose.material.ButtonColors -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.ext.fieldModifier import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.ui.theme.StudeezTheme import java.util.* -// TODO codeduplicatie met Tibo, later wegdoen +@Composable +fun TimePickerCard( + @StringRes text: Int, + initialSeconds: Int, + onTimeChosen: (Int) -> Unit +) { + Card( + modifier = Modifier + .fillMaxWidth() + .fieldModifier(), + elevation = 10.dp + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .fieldModifier(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = stringResource(id = text), + fontWeight = FontWeight.Medium + ) + + TimePickerButton( + initialSeconds = initialSeconds, + onTimeChosen = onTimeChosen + ) + } + } +} + @Composable fun TimePickerButton( - hoursMinutesSeconds: HoursMinutesSeconds, + initialSeconds: Int, modifier: Modifier = Modifier, colors: ButtonColors = ButtonDefaults.buttonColors(), border: BorderStroke? = null, - onTimeSetListener: OnTimeSetListener + onTimeChosen: (Int) -> Unit ) { val context = LocalContext.current + val timeState: MutableState = remember { + mutableStateOf(initialSeconds) + } + Button( - onClick = { pickDuration(context, onTimeSetListener) }, + onClick = { pickDuration(context, onTimeChosen, timeState) }, modifier = modifier, shape = RoundedCornerShape(20.dp), colors = colors, border = border ) { - Text(text = hoursMinutesSeconds.toString()) + Text(text = HoursMinutesSeconds(timeState.value).toString()) } } -// TODO idem codedup Tibo -private fun pickDuration(context: Context, listener: OnTimeSetListener) { +private fun pickDuration(context: Context, nextStep: (Int) -> Unit, timeState: MutableState) { + val listener = OnTimeSetListener { _, hour, minute -> + timeState.value = hour * 60 * 60 + minute * 60 + nextStep(timeState.value) + } val mCalendar = Calendar.getInstance() val mHour = mCalendar[Calendar.HOUR] val mMinute = mCalendar[Calendar.MINUTE] val mTimePickerDialog = TimePickerDialog(context, listener, mHour, mMinute, true) mTimePickerDialog.show() +} + +@Preview +@Composable +fun TimePickerButtonPreview() { + StudeezTheme { + TimePickerButton(initialSeconds = 5 * 60 + 12, onTimeChosen = {}) + } +} + +@Preview +@Composable +fun TimePickerCardPreview() { + StudeezTheme { + TimePickerCard(text = R.string.studyTime, initialSeconds = 5 * 60 + 12, onTimeChosen = {}) + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt new file mode 100644 index 0000000..219c06b --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt @@ -0,0 +1,4 @@ +package be.ugent.sel.studeez.screens.timer_edit.editScreens + +class EditScreenUIState { +} \ No newline at end of file From dafa8cc606d7ae92f72514a037d5da93ae5bf5bb Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:51:51 +0200 Subject: [PATCH 38/59] extra constructor HMS that takes total seconds --- .../local/models/timer_functional/HoursMinutesSeconds.kt | 6 ++++++ .../sel/studeez/data/local/models/timer_functional/Time.kt | 6 +----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt index 2f630c9..d09d8a7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/HoursMinutesSeconds.kt @@ -2,6 +2,12 @@ package be.ugent.sel.studeez.data.local.models.timer_functional data class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) { + constructor(sec: Int): this( + sec / (60 * 60), + (sec / (60)) % 60, + sec % 60 + ) + fun getTotalSeconds(): Int { return hours * 60 * 60 + minutes * 60 + seconds } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index c512d96..ae0d1ef 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -13,11 +13,7 @@ class Time(initialTime: Int) { } fun getAsHMS(): HoursMinutesSeconds { - val hours: Int = time / (60 * 60) - val minutes: Int = (time / (60)) % 60 - val seconds: Int = time % 60 - - return HoursMinutesSeconds(hours, minutes, seconds) + return HoursMinutesSeconds(time) } } \ No newline at end of file From bfde19caaf95d033d32d814eb38c00abdb1e5e3a Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:52:40 +0200 Subject: [PATCH 39/59] making some fields public --- .../studeez/data/local/models/timer_info/CustomTimerInfo.kt | 2 +- .../studeez/data/local/models/timer_info/PomodoroTimerInfo.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt index b3ecea1..d88e39f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/CustomTimerInfo.kt @@ -6,7 +6,7 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer class CustomTimerInfo( name: String, description: String, - val studyTime: Int, + var studyTime: Int, id: String = "" ): TimerInfo(id, name, description) { diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt index dbbb0be..6dd6797 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_info/PomodoroTimerInfo.kt @@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVi class PomodoroTimerInfo( name: String, description: String, - val studyTime: Int, - val breakTime: Int, + var studyTime: Int, + var breakTime: Int, val repeats: Int, id: String = "" ): TimerInfo(id, name, description) { From 48a1a50a5f27176c0077d055ada8cb5eacb9c7a1 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:54:06 +0200 Subject: [PATCH 40/59] #30 added textfieldStates to editScreen --- .../editScreens/AbstractTimerEditScreen.kt | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt index eedaa78..437589b 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/AbstractTimerEditScreen.kt @@ -1,49 +1,57 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.LabelledInputField import be.ugent.sel.studeez.common.ext.basicButton -import be.ugent.sel.studeez.common.ext.fieldModifier import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) { @Composable operator fun invoke(onSaveClick: (TimerInfo) -> Unit) { - // TODO klassen hierarchie voor uistate - // TODO klassen extras implementeren + + var name by remember { mutableStateOf(timerInfo.name) } + var description by remember { mutableStateOf(timerInfo.description) } + + // This shall rerun whenever name and description change + timerInfo.name = name + timerInfo.description = description Column( - modifier = Modifier.fillMaxWidth().fillMaxHeight(), - horizontalAlignment = Alignment.CenterHorizontally + verticalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxHeight().verticalScroll(rememberScrollState()), ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { - // Fields that every timer shares (ommited id) - LabelledInputField( - value = timerInfo.name, - onNewValue = {}, - label = R.string.name - ) - LabelledInputField( - value = timerInfo.description, - onNewValue = {}, - label = R.string.description, - singleLine = false - ) + // Fields that every timer shares (ommited id) + LabelledInputField( + value = name, + onNewValue = { name = it }, + label = R.string.name + ) + LabelledInputField( + value = description, + onNewValue = { description = it }, + label = R.string.description, + singleLine = false + ) - ExtraFields() + ExtraFields() + } BasicButton(R.string.save, Modifier.basicButton()) { onSaveClick(timerInfo) } From ea2c91d59a6d4a501b7bf9c691307ea679c31835 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:55:25 +0200 Subject: [PATCH 41/59] #30 added timepicker card to custom timer edit screen --- .../editScreens/CustomTimerEditScreen.kt | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt index 3e2e234..f3278d5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/CustomTimerEditScreen.kt @@ -2,21 +2,22 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens import androidx.compose.runtime.* import androidx.compose.ui.tooling.preview.Preview -import be.ugent.sel.studeez.common.composable.TimePickerButton -import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds -import be.ugent.sel.studeez.data.local.models.timer_functional.Time +import be.ugent.sel.studeez.common.composable.TimePickerCard import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.ui.theme.StudeezTheme +import be.ugent.sel.studeez.R.string as AppText -class CustomTimerEditScreen(private val customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen(customTimerInfo) { +class CustomTimerEditScreen( + private val customTimerInfo: CustomTimerInfo + ): AbstractTimerEditScreen(customTimerInfo) { @Composable override fun ExtraFields() { - // If the user presses the OK button on the timepicker, the time in the button should change - var studyTime by remember { mutableStateOf(customTimerInfo.studyTime) } - - val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() - TimePickerButton(hms) { _, hour, minute -> - studyTime = hour * 60 * 60 + minute * 60 + TimePickerCard( + text = AppText.studyTime, + initialSeconds = customTimerInfo.studyTime + ) { newTime -> + customTimerInfo.studyTime = newTime } } @@ -25,7 +26,9 @@ class CustomTimerEditScreen(private val customTimerInfo: CustomTimerInfo): Abstr @Preview @Composable -fun TimePickerPreview() { +fun CustomEditScreenPreview() { val customTimerInfo = CustomTimerInfo("custom", "my description", 25) - CustomTimerEditScreen(customTimerInfo).ExtraFields() + StudeezTheme { + CustomTimerEditScreen(customTimerInfo).invoke(onSaveClick = {}) + } } \ No newline at end of file From cfb356cbf183e945e4d8931ddfa7ceb538eac6c9 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:55:48 +0200 Subject: [PATCH 42/59] #30 added two timepicker cards to break timer edit screen --- .../editScreens/BreakTimerEditScreen.kt | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt index f00e9f6..b6104b6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/BreakTimerEditScreen.kt @@ -1,10 +1,16 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens import androidx.compose.runtime.* +import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.TimePickerButton +import be.ugent.sel.studeez.common.composable.TimePickerCard import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import be.ugent.sel.studeez.data.local.models.timer_functional.Time +import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo +import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo +import be.ugent.sel.studeez.ui.theme.StudeezTheme class BreakTimerEditScreen( private val breakTimerInfo: PomodoroTimerInfo @@ -13,17 +19,28 @@ class BreakTimerEditScreen( @Composable override fun ExtraFields() { // If the user presses the OK button on the timepicker, the time in the button should change - var studyTime: Int by remember { mutableStateOf(breakTimerInfo.studyTime) } - var breakTime: Int by remember { mutableStateOf(breakTimerInfo.breakTime) } - val breakHms: HoursMinutesSeconds = Time(breakTime).getAsHMS() - val studyHms: HoursMinutesSeconds = Time(studyTime).getAsHMS() - TimePickerButton(studyHms) { _, hour, minute -> - studyTime = hour * 60 * 60 + minute * 60 + TimePickerCard(R.string.studyTime, breakTimerInfo.studyTime) { newTime -> + breakTimerInfo.studyTime = newTime } - TimePickerButton(breakHms) { _, hour, minute -> - breakTime = hour * 60 * 60 + minute * 60 + TimePickerCard(R.string.breakTime, breakTimerInfo.breakTime) { newTime -> + breakTimerInfo.breakTime = newTime } } +} + +@Preview +@Composable +fun BreakEditScreenPreview() { + val pomodoroTimerInfo = PomodoroTimerInfo( + "Breaky the Breaktimer", + "Breaky is a breakdancer", + 10 * 60, + 60, + 5 + ) + StudeezTheme { + BreakTimerEditScreen(pomodoroTimerInfo).invoke(onSaveClick = {}) + } } \ No newline at end of file From f1d24087b448d159dc0ca37f2cbffde1edcf8575 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:56:32 +0200 Subject: [PATCH 43/59] #30 added preview of endless edit screen --- .../editScreens/EndlessTimerEditScreen.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt index 0f5b30a..0e26209 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EndlessTimerEditScreen.kt @@ -1,6 +1,23 @@ package be.ugent.sel.studeez.screens.timer_edit.editScreens +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo +import be.ugent.sel.studeez.ui.theme.StudeezTheme -class EndlessTimerEditScreen(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen(endlessTimerInfo) { +class EndlessTimerEditScreen( + endlessTimerInfo: EndlessTimerInfo +): AbstractTimerEditScreen(endlessTimerInfo) { +} + +@Preview +@Composable +fun EndlessEditScreenPreview() { + val endlessTimerInfo = EndlessTimerInfo( + "Forever and beyond", + "My endless timer description", + ) + StudeezTheme { + EndlessTimerEditScreen(endlessTimerInfo).invoke(onSaveClick = {}) + } } \ No newline at end of file From bd48a12d52a537dae5db2375add63c36d2bc3482 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:57:42 +0200 Subject: [PATCH 44/59] #30 minor refactor --- .../screens/timer_edit/TimerEditScreen.kt | 35 +++++-------------- .../editScreens/EditScreenUIState.kt | 4 --- 2 files changed, 9 insertions(+), 30 deletions(-) delete mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt index 4540faa..649caf6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditScreen.kt @@ -1,6 +1,7 @@ package be.ugent.sel.studeez.screens.timer_edit import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.tooling.preview.Preview import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo @@ -9,7 +10,7 @@ import be.ugent.sel.studeez.ui.theme.StudeezTheme data class TimerEditActions( val getTimerInfo: () -> TimerInfo, - val saveTimer: (TimerInfo) -> Unit + val saveTimer: (TimerInfo, () -> Unit) -> Unit ) fun getTimerEditActions( @@ -28,36 +29,18 @@ fun TimerEditRoute( popUp: () -> Unit, viewModel: TimerEditViewModel, ) { - TimerEditScreen( - timerEditActions = getTimerEditActions(viewModel, open), - popUp = popUp - ) -} -@Composable -fun TimerEditScreen( - timerEditActions: TimerEditActions, - popUp: () -> Unit -) { - SecondaryScreenTemplate(title = "Edit Timer", popUp = { /*TODO*/ }) { + val timerEditActions = getTimerEditActions(viewModel, open) + + SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { + val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen()) - timerEditScreen { timerInfo -> timerEditActions.saveTimer(timerInfo) } + timerEditScreen { timerInfo -> + timerEditActions.saveTimer(timerInfo, popUp) + } } } -//@Preview -//@Composable -//fun TimerEditScreenPreview() { -// val editEntries: List = listOf( -// EditEntry("Name", "MyTimer") {}, -// EditEntry("Description", "Dit is een leuke timer") {}, -// EditEntry("StudyTime", "25") {} -// ) -// val actions = TimerEditActions { editEntries } -// StudeezTheme { TimerEditScreen(timerEditActions = actions) {} } -//} - - diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt deleted file mode 100644 index 219c06b..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/editScreens/EditScreenUIState.kt +++ /dev/null @@ -1,4 +0,0 @@ -package be.ugent.sel.studeez.screens.timer_edit.editScreens - -class EditScreenUIState { -} \ No newline at end of file From 853a09866a9614ec68c4520f96447f7ae6c7565d Mon Sep 17 00:00:00 2001 From: lbarraga Date: Mon, 1 May 2023 17:58:13 +0200 Subject: [PATCH 45/59] #30 go back when timer is saved --- .../ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt index 98d060f..3258f24 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_edit/TimerEditViewModel.kt @@ -21,8 +21,9 @@ class TimerEditViewModel @Inject constructor( return timerInfo } - fun saveTimer(timerInfo: TimerInfo) { + fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) { timerDAO.updateTimer(timerInfo) + goBack() } } \ No newline at end of file From b2e29417958101368c289e8ea15b112e6ab0a1e9 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 19:04:40 +0200 Subject: [PATCH 46/59] Restructuring strings --- app/src/main/res/values/strings.xml | 69 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b9f561..e6e4ddc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ - + + Studeez Username Email @@ -7,34 +8,22 @@ Repeat password Menu - - Confirm - Save - Discard - Cancel - Go back - Next - Start + + Confirm + Save + Discard + Cancel + Go back + Next + Start - - Success! - Try again - Something wrong happened. Please try again. - Please insert a valid email. + + Success! + Try again + Something wrong happened. Please try again. + Please insert a valid email. - - Create account - Your password should have at least six characters and include one digit, one lower case letter and one upper case letter. - Passwords do not match. - Already have an account? Log in. - - - Don\'t have an account yet? Sign up. - Sign in - Enter your login details - Forgot password? Click to get recovery email. - Check your inbox for the recovery email. - Password cannot be empty. + Home @@ -54,10 +43,8 @@ Editing profile Delete profile - - Friends + - Log out Profile Picture Normal user @@ -81,4 +68,26 @@ About Studeez + + + + Create account + Your password should have at least six characters and include one digit, one lower case letter and one upper case letter. + Passwords do not match. + Already have an account? Log in. + + + Don\'t have an account yet? Sign up. + Sign in + Enter your login details + Forgot password? Click to get recovery email. + Check your inbox for the recovery email. + Password cannot be empty. + + + + + + Friends + From dfd97c8d33508bfc8de74d8b4246130d9b932834 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 19:13:18 +0200 Subject: [PATCH 47/59] Temp sessions screen for feedback --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 6 ++- .../screens/sessions/SessionsScreen.kt | 42 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index 584649f..9dfb136 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -28,6 +28,7 @@ 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.sessions.SessionsRoute 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 @@ -118,7 +119,10 @@ fun StudeezNavGraph( } composable(StudeezDestinations.SESSIONS_SCREEN) { - // TODO + SessionsRoute( + drawerActions = drawerActions, + navigationBarActions = navigationBarActions + ) } composable(StudeezDestinations.PROFILE_SCREEN) { diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt new file mode 100644 index 0000000..fe60ca8 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt @@ -0,0 +1,42 @@ +package be.ugent.sel.studeez.screens.sessions + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun SessionsRoute( + // viewModel: SessionsViewModel, + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions +) { + SessionsScreen( + drawerActions = drawerActions, + navigationBarActions = navigationBarActions + ) +} + +@Composable +fun SessionsScreen( + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions +) { + PrimaryScreenTemplate( + title = resources().getString(AppText.upcoming_sessions), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions + ) { + Text( + text = resources().getString(AppText.sessions_temp_description), + modifier = Modifier.fillMaxSize(), + textAlign = TextAlign.Center + ) + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e6e4ddc..9922860 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,8 +33,10 @@ Tasks + Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own. Sessions End session + Upcoming sessions Profile From e458927c281a15f55724a9991d6e6b696f2cf60e Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 19:19:45 +0200 Subject: [PATCH 48/59] Temp settings screen for feedback --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 5 ++- .../screens/settings/SettingsScreen.kt | 37 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/settings/SettingsScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index 9dfb136..90f20fd 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -29,6 +29,7 @@ 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.sessions.SessionsRoute +import be.ugent.sel.studeez.screens.settings.SettingsRoute 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 @@ -143,7 +144,9 @@ fun StudeezNavGraph( } composable(StudeezDestinations.SETTINGS_SCREEN) { - // TODO + SettingsRoute( + drawerActions = drawerActions + ) } // Login flow diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/settings/SettingsScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/settings/SettingsScreen.kt new file mode 100644 index 0000000..e1098b7 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/settings/SettingsScreen.kt @@ -0,0 +1,37 @@ +package be.ugent.sel.studeez.screens.settings + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import be.ugent.sel.studeez.common.composable.DrawerScreenTemplate +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun SettingsRoute( + // viewModel: SettingsViewModel, + drawerActions: DrawerActions +) { + SettingsScreen( + drawerActions = drawerActions + ) +} + +@Composable +fun SettingsScreen( + drawerActions: DrawerActions +) { + DrawerScreenTemplate( + title = resources().getString(AppText.settings), + drawerActions = drawerActions + ) { + Text( + text = resources().getString(AppText.settings_temp_description), + modifier = Modifier.fillMaxSize(), + textAlign = TextAlign.Center + ) + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9922860..0ed2493 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,6 +65,7 @@ Take a break! + Looks like you found the settings screen! In the future, this will enable you to edit your preferenes such as light/dark mode, end sessions automatically when we detect you are gone etc. Settings From 5a2632c08a96c6f253698d08e5de50c032a2fd3d Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 19:28:50 +0200 Subject: [PATCH 49/59] Add snackbars for missing features --- .../composable/navbar/NavigationBarComposable.kt | 2 -- .../composable/navbar/NavigationBarViewModel.kt | 14 ++++++++------ app/src/main/res/values/strings.xml | 9 +++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index b2393d8..0c4110d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -60,11 +60,9 @@ fun getNavigationBarActions( onAddTaskClick = { navigationBarViewModel.onAddTaskClick(open) }, - onAddFriendClick = { navigationBarViewModel.onAddFriendClick(open) }, - onAddSessionClick = { navigationBarViewModel.onAddSessionClick(open) } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt index ab9256b..e7678e5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt @@ -1,17 +1,16 @@ package be.ugent.sel.studeez.common.composable.navbar +import be.ugent.sel.studeez.common.snackbar.SnackbarManager import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.LogService -import be.ugent.sel.studeez.navigation.StudeezDestinations.CREATE_SESSION_SCREEN -import be.ugent.sel.studeez.navigation.StudeezDestinations.CREATE_TASK_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN -import be.ugent.sel.studeez.navigation.StudeezDestinations.SEARCH_FRIENDS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import be.ugent.sel.studeez.R.string as AppText @HiltViewModel class NavigationBarViewModel @Inject constructor( @@ -36,14 +35,17 @@ class NavigationBarViewModel @Inject constructor( } fun onAddTaskClick(open: (String) -> Unit) { - open(CREATE_TASK_SCREEN) + // TODO open(CREATE_TASK_SCREEN) + SnackbarManager.showMessage(AppText.create_task_not_possible_yet) // TODO Remove } fun onAddFriendClick(open: (String) -> Unit) { - open(SEARCH_FRIENDS_SCREEN) + // TODO open(SEARCH_FRIENDS_SCREEN) + SnackbarManager.showMessage(AppText.add_friend_not_possible_yet) // TODO Remove } fun onAddSessionClick(open: (String) -> Unit) { - open(CREATE_SESSION_SCREEN) + // TODO open(CREATE_SESSION_SCREEN) + SnackbarManager.showMessage(AppText.create_session_not_possible_yet) // TODO Remove } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ed2493..2608612 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -92,5 +92,14 @@ Friends + Adding friends still needs to be implemented. Hang on tight! + + + + + Creating tasks still needs to be implemented. Hang on tight! + + + Creating sessions still needs to be implemented. Hang on tight! From f74da5abc37e2caaffd6a620bce666c76b9705cf Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 19:45:35 +0200 Subject: [PATCH 50/59] #67 fab styling --- .../FloatingActionButtonComposable.kt | 20 +++++++++++++------ .../composable/drawer/DrawerComposable.kt | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt index 078d6fb..7ef6c2a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt @@ -2,9 +2,7 @@ package be.ugent.sel.studeez.common.composable import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.updateTransition -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.* import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -19,9 +17,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.ui.theme.StudeezTheme const val TRANSITION = "transition" +val HEIGHT_DIFFERENCE = 30.dp enum class MultiFloatingState { Expanded, Collapsed @@ -83,20 +83,28 @@ fun ExpandedAddButton( addButtonActions: AddButtonActions ) { Row { - IconButton(onClick = addButtonActions.onTaskClick) { + IconButton( + onClick = addButtonActions.onTaskClick, + modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) + ) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.Check, contentDescription = "Task") Text(text = "Task") } } + IconButton(onClick = addButtonActions.onFriendClick) { Column (horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.Person, contentDescription = "Friend") Text(text = "Friend") } } - IconButton(onClick = addButtonActions.onSessionClick) { - Column (horizontalAlignment = Alignment.CenterHorizontally) { + + IconButton( + onClick = addButtonActions.onSessionClick, + modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session") Text(text = "Session") } diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt index 9510b0d..7b2d3f8 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt @@ -101,7 +101,7 @@ fun DrawerEntry( Row( horizontalArrangement = Arrangement.Center, modifier = Modifier - .clickable(onClick = { onClick() }) + .clickable(onClick = onClick) .fillMaxWidth() ) { Box( From e65c2fe0029a4f0a33f811503ee14237be8ea81c Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 21:33:51 +0200 Subject: [PATCH 51/59] #67 fab unfixed pos --- .../FloatingActionButtonComposable.kt | 76 +++++++++++++------ .../composable/PrimaryScreenComposable.kt | 2 +- .../navbar/NavigationBarComposable.kt | 2 +- .../be/ugent/sel/studeez/ui/theme/Theme.kt | 4 +- 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt index 7ef6c2a..10ed586 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt @@ -2,7 +2,10 @@ package be.ugent.sel.studeez.common.composable import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.updateTransition -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -16,9 +19,12 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme +import be.ugent.sel.studeez.R.string as AppText const val TRANSITION = "transition" val HEIGHT_DIFFERENCE = 30.dp @@ -56,7 +62,9 @@ fun AddButton( ) { // Show minis when expanded. if (multiFloatingState == MultiFloatingState.Expanded) { - ExpandedAddButton(addButtonActions = addButtonActions) + ExpandedAddButton( + addButtonActions = addButtonActions + ) } // The base add button @@ -83,35 +91,57 @@ fun ExpandedAddButton( addButtonActions: AddButtonActions ) { Row { - IconButton( + ExpandedEntry( + name = AppText.task, + imageVector = Icons.Default.Check, onClick = addButtonActions.onTaskClick, modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) - ) { - Column (horizontalAlignment = Alignment.CenterHorizontally) { - Icon(imageVector = Icons.Default.Check, contentDescription = "Task") - Text(text = "Task") - } - } + ) - IconButton(onClick = addButtonActions.onFriendClick) { - Column (horizontalAlignment = Alignment.CenterHorizontally) { - Icon(imageVector = Icons.Default.Person, contentDescription = "Friend") - Text(text = "Friend") - } - } + ExpandedEntry( + name = AppText.friend, + imageVector = Icons.Default.Person, + onClick = addButtonActions.onFriendClick + ) - IconButton( + ExpandedEntry( + name = AppText.session, + imageVector = Icons.Default.DateRange, onClick = addButtonActions.onSessionClick, modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp) - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session") - Text(text = "Session") - } - } + ) } } +@Composable +fun ExpandedEntry( + name: Int, + imageVector: ImageVector, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + IconButton( + onClick = onClick, + modifier = modifier + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + imageVector = imageVector, + contentDescription = resources().getString(name), + // TODO Dark overlay + // tint = colors.surface + ) + Text( + text = resources().getString(name), + // TODO Dark overlay + // color = colors.surface + ) + } + + } + +} + @Preview @Composable fun AddButtonPreview() { @@ -123,7 +153,7 @@ fun AddButtonPreview() { @Preview @Composable fun ExpandedAddButtonPreview() { - StudeezTheme { ExpandedAddButton( + StudeezTheme { ExpandedAddButton ( addButtonActions = AddButtonActions({}, {}, {}) ) } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt index 0cbfb0b..0b3ee6e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/PrimaryScreenComposable.kt @@ -56,7 +56,7 @@ fun PrimaryScreenTemplate( bottomBar = { NavigationBar(navigationBarActions) }, floatingActionButtonPosition = FabPosition.Center, - isFloatingActionButtonDocked = false, + isFloatingActionButtonDocked = true, floatingActionButton = { AddButton(AddButtonActions( onTaskClick = navigationBarActions.onAddTaskClick, onFriendClick = navigationBarActions.onAddFriendClick, diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index 0c4110d..56b81eb 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -95,7 +95,7 @@ fun NavigationBar( ) // Hack to space the entries in the navigation bar, make space for fab - BottomNavigationItem(icon = {}, onClick = {}, selected = false) + BottomNavigationItem(icon = {}, onClick = {}, selected = false, enabled = false) BottomNavigationItem( icon = { diff --git a/app/src/main/java/be/ugent/sel/studeez/ui/theme/Theme.kt b/app/src/main/java/be/ugent/sel/studeez/ui/theme/Theme.kt index bc2c315..9a29e85 100644 --- a/app/src/main/java/be/ugent/sel/studeez/ui/theme/Theme.kt +++ b/app/src/main/java/be/ugent/sel/studeez/ui/theme/Theme.kt @@ -12,7 +12,9 @@ import androidx.compose.ui.graphics.Color private val DarkColorPalette = darkColors( primary = Blue100, primaryVariant = Blue120, - secondary = Yellow100 + secondary = Yellow100, + + onPrimary = Color.White ) private val LightColorPalette = lightColors( From 5788053c7544905711b8383708a4fb1813f33675 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Mon, 1 May 2023 21:43:58 +0200 Subject: [PATCH 52/59] #67 fix fab position --- .../FloatingActionButtonComposable.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt index 10ed586..e62165f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt @@ -2,10 +2,8 @@ package be.ugent.sel.studeez.common.composable import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.updateTransition -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -60,11 +58,13 @@ fun AddButton( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top ) { - // Show minis when expanded. - if (multiFloatingState == MultiFloatingState.Expanded) { - ExpandedAddButton( - addButtonActions = addButtonActions - ) + Box { + // Show minis when expanded. + if (multiFloatingState == MultiFloatingState.Expanded) { + ExpandedAddButton( + addButtonActions = addButtonActions + ) + } } // The base add button @@ -75,7 +75,8 @@ fun AddButton( MultiFloatingState.Collapsed -> MultiFloatingState.Expanded MultiFloatingState.Expanded -> MultiFloatingState.Collapsed } - } + }, + modifier = Modifier.padding(bottom = if (multiFloatingState == MultiFloatingState.Expanded) 78.dp else 0.dp) ) { Icon( imageVector = Icons.Default.Add, From 4b4c9539f83f5ac92fd959f35a715847d7655222 Mon Sep 17 00:00:00 2001 From: Rune Dyselinck Date: Tue, 2 May 2023 13:57:03 +0200 Subject: [PATCH 53/59] addTimer finished --- .../java/be/ugent/sel/studeez/StudeezApp.kt | 1 - .../composable/navbar/TimePickerComposable.kt | 24 +++ .../add_timer/AddTimerUiState.kt | 13 +- .../add_timer/AddTimerViewModel.kt | 34 +-- .../add_timer/addTimerScreen.kt | 201 +++++++++++------- .../timer_selection/TimerSelectionScreen.kt | 4 +- app/src/main/res/values/strings.xml | 15 ++ 7 files changed, 193 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index be8ad00..d7465b0 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -172,7 +172,6 @@ fun StudeezNavGraph( composable(StudeezDestinations.ADD_TIMER_SCREEN) { AddTimerRoute( open = open, - openAndPopUp = openAndPopUp, goBack = goBack, viewModel = hiltViewModel() ) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt new file mode 100644 index 0000000..3a59519 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/TimePickerComposable.kt @@ -0,0 +1,24 @@ +package be.ugent.sel.studeez.common.composable.navbar + +import android.app.TimePickerDialog +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +fun BasicTimePicker( + onHoursChange: (Int) -> Unit, + onMinutesChange: (Int) -> Unit, + Hours: Int, + Minutes: Int, +): TimePickerDialog { + return TimePickerDialog( + LocalContext.current, + { _, mHour: Int, mMinute: Int -> + onHoursChange(mHour) + onMinutesChange(mMinute) + }, + Hours, + Minutes, + true + ) +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt index 9b17121..fcfa79a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerUiState.kt @@ -1,11 +1,12 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer data class AddTimerUiState( - val studyTimeHours: Float = 1f, - val studyTimeMinutes: Float = 0f, + val studyTimeHours: Int = 1, + val studyTimeMinutes: Int = 0, val withBreaks: Boolean = false, - val breakTime: Float = 5f, - val repeats: Float = 1f, - val name: String = "", - val description: String = "", + val breakTimeMinutes: Int = 5, + val breakTimeHours: Int = 0, + val repeats: Int = 1, + val name: String = "Timer", + val description: String = "Long study session", ) \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt index 7e79e1e..d507974 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/AddTimerViewModel.kt @@ -3,7 +3,6 @@ package be.ugent.sel.studeez.screens.timer_overview.add_timer import androidx.compose.runtime.mutableStateOf import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo -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.screens.StudeezViewModel @@ -24,8 +23,11 @@ class AddTimerViewModel @Inject constructor( private val studyTimeMinutes get() = uiState.value.studyTimeMinutes - private val breakTime - get() = uiState.value.breakTime + private val breakTimeHours + get() = uiState.value.breakTimeHours + + private val breakTimeMinutes + get() = uiState.value.breakTimeMinutes private val repeats get() = uiState.value.repeats @@ -36,24 +38,28 @@ class AddTimerViewModel @Inject constructor( private val description get() = uiState.value.description - fun onStudyTimeHoursChange(newValue: Float) { + fun onStudyTimeHoursChange(newValue: Int) { uiState.value = uiState.value.copy(studyTimeHours = newValue) } - fun onStudyTimeMinutesChange(newValue: Float) { + fun onStudyTimeMinutesChange(newValue: Int) { uiState.value = uiState.value.copy(studyTimeMinutes = newValue) } - fun onWithBreaksChange(newValue: Boolean) { - uiState.value = uiState.value.copy(withBreaks = newValue) + fun onWithBreaksChange() { + uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks) } - fun onBreakTimeChange(newValue: Float) { - uiState.value = uiState.value.copy(breakTime = newValue) + fun onBreakTimeHourChange(newValue: Int) { + uiState.value = uiState.value.copy(breakTimeHours = newValue) } - fun onRepeatsChange(newValue: Float) { + fun onBreakTimeMinutesChange(newValue: Int) { + uiState.value = uiState.value.copy(breakTimeMinutes = newValue) + } + + fun onRepeatsChange(newValue: Int) { uiState.value = uiState.value.copy(repeats = newValue) } @@ -62,15 +68,15 @@ class AddTimerViewModel @Inject constructor( timerDAO.saveTimer(PomodoroTimerInfo( name = uiState.value.name, description = uiState.value.description, - studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60, - breakTime = breakTime.toInt() * 60, - repeats = repeats.toInt() + studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60, + breakTime = breakTimeHours * 60 * 60 + breakTimeMinutes * 60, + repeats = repeats )) } else { timerDAO.saveTimer(CustomTimerInfo( name = uiState.value.name, description = uiState.value.description, - studyTime = studyTimeHours.toInt() * 60 * 60 + studyTimeMinutes.toInt() * 60 + studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60 )) } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt index 772917d..77bdeda 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_overview/add_timer/addTimerScreen.kt @@ -6,45 +6,54 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Button import androidx.compose.material.Checkbox -import androidx.compose.material.Slider import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.BasicButton import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.common.composable.navbar.BasicTimePicker +import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme data class AddTimerActions( + val open: (String) -> Unit, val goBack: () -> Unit, - val onStudyTimeHoursChange: (Float) -> Unit, - val onStudyTimeMinutesChange: (Float) -> Unit, - val onBreakTimeChange: (Float) -> Unit, - val onRepeatsChange: (Float) -> Unit, - val onWithBreaksChange: (Boolean) -> Unit, + val onStudyTimeHoursChange: (Int) -> Unit, + val onStudyTimeMinutesChange: (Int) -> Unit, + val onBreakTimeHourChange: (Int) -> Unit, + val onBreakTimeMinutesChange: (Int) -> Unit, + val onRepeatsChange: (Int) -> Unit, + val onWithBreaksChange: () -> Unit, val addTimer: () -> Unit, val onNameChange: (String) -> Unit, val onDescriptionChange: (String) -> Unit, ) fun getAddTimerActions( + open: (String) -> Unit, goBack: () -> Unit, viewModel: AddTimerViewModel, ): AddTimerActions { return AddTimerActions( + open = open, goBack = goBack, onWithBreaksChange = viewModel::onWithBreaksChange, onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange, onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange, - onBreakTimeChange = viewModel::onBreakTimeChange, + onBreakTimeHourChange = viewModel::onBreakTimeHourChange, + onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange, onRepeatsChange = viewModel::onRepeatsChange, addTimer = viewModel::addTimer, onNameChange = viewModel::onNameChange, @@ -55,7 +64,6 @@ fun getAddTimerActions( @Composable fun AddTimerRoute( open: (String) -> Unit, - openAndPopUp: (String, String) -> Unit, goBack: () -> Unit, viewModel: AddTimerViewModel, ) { @@ -63,6 +71,7 @@ fun AddTimerRoute( AddTimerScreen( addTimerActions = getAddTimerActions( + open = open, goBack = goBack, viewModel = viewModel, ), @@ -75,6 +84,20 @@ fun AddTimerScreen( addTimerActions: AddTimerActions, uiState: AddTimerUiState, ) { + val mStudyTimePicker = BasicTimePicker( + onHoursChange = addTimerActions.onStudyTimeHoursChange, + onMinutesChange = addTimerActions.onStudyTimeMinutesChange, + Hours = uiState.studyTimeHours, + Minutes = uiState.studyTimeMinutes + ) + + val mBreakTimePicker = BasicTimePicker( + onHoursChange = addTimerActions.onBreakTimeHourChange, + onMinutesChange = addTimerActions.onBreakTimeMinutesChange, + Hours = uiState.breakTimeHours, + Minutes = uiState.breakTimeMinutes + ) + SecondaryScreenTemplate( title = resources().getString(R.string.add_timer), popUp = addTimerActions.goBack @@ -82,52 +105,40 @@ fun AddTimerScreen( LazyColumn( modifier = Modifier .fillMaxWidth() - .padding(16.dp) + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally ) { item { Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center + modifier = Modifier + .padding(16.dp) ) { Text( - text = "How long do you want to study?", + text = stringResource(R.string.addTimer_question), textAlign = TextAlign.Center ) } } + item { Text( - text = "${uiState.studyTimeHours.toInt()} hour${ if (uiState.studyTimeHours == 1f) "" else "s"}" + text = uiState.studyTimeHours.toString() + stringResource(R.string.addTimer_studytime_1) + uiState.studyTimeMinutes + stringResource( + R.string.addTimer_studytime_2) ) } + item { - Slider( - value = uiState.studyTimeHours, - onValueChange = { - addTimerActions.onStudyTimeHoursChange(it) + Button( + onClick = { + mStudyTimePicker.show() }, - steps = 8, - valueRange = 1f..10f, - enabled = true - ) - } - item { - Text( - text = "${uiState.studyTimeMinutes.toInt()} minutes" - ) - } - item { - Slider( - value = uiState.studyTimeMinutes, - onValueChange = { - addTimerActions.onStudyTimeMinutesChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = true - ) + ) { + Text( + text = stringResource(R.string.addTimer_timepicker), + ) + } } + item { Row( modifier = Modifier.fillMaxWidth(), @@ -135,68 +146,99 @@ fun AddTimerScreen( horizontalArrangement = Arrangement.Center ) { Text( - text = "With breaks?", + text = stringResource(R.string.addTimer_break_question), ) Checkbox( checked = uiState.withBreaks, - onCheckedChange = { addTimerActions.onWithBreaksChange(it) } + onCheckedChange = { addTimerActions.onWithBreaksChange() } ) } } + + if (uiState.withBreaks) { + item { + Text( + text = if (uiState.repeats == 1) uiState.repeats.toString() + stringResource( + R.string.addTimer_break_1) + else uiState.repeats.toString() + stringResource( + R.string.addTimer_break_s) + ) + TextField( + value = uiState.repeats.toString(), + onValueChange = { it: String -> + it.toIntOrNull()?.let { it1 -> + addTimerActions.onRepeatsChange( + kotlin.math.abs(it1) + ) + } + } + ) + } + + item { + Text( + text = uiState.breakTimeHours.toString() + stringResource(R.string.breakTime_1) + uiState.breakTimeMinutes + stringResource( + R.string.breakTime_2) + ) + } + + item { + Button( + onClick = { + mBreakTimePicker.show() + }, + ) { + Text( + text = stringResource(R.string.addTimer_timepicker), + ) + } + } + } + item { Text( - text = if (uiState.withBreaks) "breaks of ${uiState.breakTime.toInt()} minutes" else "", - ) - } - item { - Slider( - value = uiState.breakTime, - onValueChange = { - addTimerActions.onBreakTimeChange(it) - }, - steps = 11, - valueRange = 0f..60f, - enabled = uiState.withBreaks - ) - } - item { - Text( - text = if (uiState.withBreaks) "${uiState.repeats.toInt()} breaks" else "" - ) - } - item { - Slider( - value = uiState.repeats, - onValueChange = { - addTimerActions.onRepeatsChange(it) - }, - steps = 8, - valueRange = 1f..10f, - enabled = uiState.withBreaks - ) - } - item { - Text( - text = "Timer name" + text = stringResource(R.string.addTimer_name) ) } + item { TextField( value = uiState.name, onValueChange = { addTimerActions.onNameChange(it) } ) } + + item { + if (uiState.name == "") { + Text( + text = stringResource(R.string.addTimer_name_error), + color = Color.Red + ) + } + } + item { Text( - text = "Timer description" + text = stringResource(R.string.addTimer_description) ) } + item { TextField( value = uiState.description, onValueChange = { addTimerActions.onDescriptionChange(it) } ) } + + item { + if (uiState.description == "") { + Text( + text = stringResource(R.string.addTimer_description_error), + color = Color.Red + ) + } + } + item { Row( modifier = Modifier @@ -208,7 +250,12 @@ fun AddTimerScreen( BasicButton( text = R.string.add_timer, modifier = Modifier, - onClick = addTimerActions.addTimer + onClick = { + if (uiState.description != "" && uiState.name != "") { + addTimerActions.addTimer() + addTimerActions.open(StudeezDestinations.TIMER_OVERVIEW_SCREEN) + } + } ) } } @@ -220,8 +267,8 @@ fun AddTimerScreen( @Composable fun AddTimerScreenPreview() { StudeezTheme { AddTimerScreen( - addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}), + addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}), uiState = AddTimerUiState() ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt index 47e7f91..a3318bc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_selection/TimerSelectionScreen.kt @@ -64,7 +64,9 @@ fun TimerSelectionScreen( drawerActions = drawerActions, navigationBarActions = navigationBarActions, ) { - LazyColumn(verticalArrangement = Arrangement.spacedBy(7.dp)) { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(7.dp), + ) { // All timers items(timers.value) { timerInfo -> TimerEntry( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 39abda6..50df45b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,4 +79,19 @@ About Studeez + + Timer description cannot be empty! + Timer description + Timer name cannot be empty! + Timer name + Open Time Picker + " hours and " + " minutes of breaktime" + " break" + " breaks" + With breaks? + " hours and " + " minutes of studytime" + How long do you want to study? + From 1bf96c2200932f72b2492e16b9e04aefb9ee58b7 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Tue, 2 May 2023 22:22:23 +0200 Subject: [PATCH 54/59] Add missing resources #94 --- app/src/main/res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2608612..935dc7d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,10 +31,12 @@ Tasks + Task Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own. Sessions + Session End session Upcoming sessions @@ -92,6 +94,7 @@ Friends + Friend Adding friends still needs to be implemented. Hang on tight! From aea49295a0bb54cbfc7c6b31014d8c51f68603a4 Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Tue, 2 May 2023 22:41:04 +0200 Subject: [PATCH 55/59] Exit profile edit screen on save #94 --- .../ugent/sel/studeez/screens/profile/ProfileEditScreen.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt index 3dbe270..c6fcbaf 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/profile/ProfileEditScreen.kt @@ -63,7 +63,10 @@ fun EditProfileScreen( BasicTextButton( text = R.string.save, Modifier.textButton(), - action = editProfileActions.onSaveClick + action = { + editProfileActions.onSaveClick() + goBack() + } ) BasicTextButton( text = R.string.delete_profile, From 3ff2ed225ba83d80a17b87a440707ba8535fde4f Mon Sep 17 00:00:00 2001 From: tdpeuter Date: Tue, 2 May 2023 22:44:53 +0200 Subject: [PATCH 56/59] Codestyle #94 --- .../FloatingActionButtonComposable.kt | 26 +++++-------------- .../composable/drawer/DrawerComposable.kt | 4 +-- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt index e62165f..bc40ead 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/FloatingActionButtonComposable.kt @@ -26,10 +26,6 @@ import be.ugent.sel.studeez.R.string as AppText const val TRANSITION = "transition" val HEIGHT_DIFFERENCE = 30.dp -enum class MultiFloatingState { - Expanded, - Collapsed -} data class AddButtonActions( val onTaskClick: () -> Unit, @@ -41,18 +37,11 @@ data class AddButtonActions( fun AddButton( addButtonActions: AddButtonActions ) { - var multiFloatingState by remember { - mutableStateOf(MultiFloatingState.Collapsed) - } + var isExpanded by remember { mutableStateOf(false) } // Rotate the button when expanded, normal when collapsed. - val transition = updateTransition(targetState = multiFloatingState, label = TRANSITION) - val rotate by transition.animateFloat(label = TRANSITION) { - when (it) { - MultiFloatingState.Expanded -> 315f - MultiFloatingState.Collapsed -> 0f - } - } + val transition = updateTransition(targetState = isExpanded, label = TRANSITION) + val rotate by transition.animateFloat(label = TRANSITION) { expanded -> if (expanded) 315f else 0f } Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -60,7 +49,7 @@ fun AddButton( ) { Box { // Show minis when expanded. - if (multiFloatingState == MultiFloatingState.Expanded) { + if (isExpanded) { ExpandedAddButton( addButtonActions = addButtonActions ) @@ -71,12 +60,9 @@ fun AddButton( FloatingActionButton( onClick = { // Toggle expanded/collapsed. - multiFloatingState = when (transition.currentState) { - MultiFloatingState.Collapsed -> MultiFloatingState.Expanded - MultiFloatingState.Expanded -> MultiFloatingState.Collapsed - } + isExpanded = !isExpanded }, - modifier = Modifier.padding(bottom = if (multiFloatingState == MultiFloatingState.Expanded) 78.dp else 0.dp) + modifier = Modifier.padding(bottom = if (isExpanded) 78.dp else 0.dp) ) { Icon( imageVector = Icons.Default.Add, diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt index 7b2d3f8..2d4eab3 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/drawer/DrawerComposable.kt @@ -43,9 +43,7 @@ fun getDrawerActions( onTimersClick = { drawerViewModel.onTimersClick(open) }, onSettingsClick = { drawerViewModel.onSettingsClick(open) }, onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, - onAboutClick = { context -> - drawerViewModel.onAboutClick(open, context = context) - }, + onAboutClick = { context -> drawerViewModel.onAboutClick(open, context = context) }, ) } From e0f46d676b69a7b7c4b4239f521c9a317a2bc542 Mon Sep 17 00:00:00 2001 From: Lukas Barragan Torres Date: Wed, 3 May 2023 13:53:35 +0200 Subject: [PATCH 57/59] changed Time increase and decrease functions --- .../timer_functional/FunctionalCustomTimer.kt | 2 +- .../timer_functional/FunctionalEndlessTimer.kt | 2 +- .../timer_functional/FunctionalPomodoroTimer.kt | 2 +- .../models/timer_functional/FunctionalTimer.kt | 2 +- .../data/local/models/timer_functional/Time.kt | 16 +++++----------- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt index 7038c7d..e049054 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalCustomTimer.kt @@ -4,7 +4,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) { override fun tick() { if (!hasEnded()) { - time.minOne() + time++ totalStudyTime++ } } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt index 41be874..51ee182 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalEndlessTimer.kt @@ -11,7 +11,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) { } override fun tick() { - time.plusOne() + time++ totalStudyTime++ } diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt index 8eeb1c6..6d4f868 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalPomodoroTimer.kt @@ -22,7 +22,7 @@ class FunctionalPomodoroTimer( } isInBreak = !isInBreak } - time.minOne() + time-- if (!isInBreak) { totalStudyTime++ diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt index e95bbfb..1f4231a 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/FunctionalTimer.kt @@ -4,7 +4,7 @@ import be.ugent.sel.studeez.data.local.models.SessionReport import com.google.firebase.Timestamp abstract class FunctionalTimer(initialValue: Int) { - val time: Time = Time(initialValue) + var time: Time = Time(initialValue) var totalStudyTime: Int = 0 fun getHoursMinutesSeconds(): HoursMinutesSeconds { diff --git a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt index ae0d1ef..7260faa 100644 --- a/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt +++ b/app/src/main/java/be/ugent/sel/studeez/data/local/models/timer_functional/Time.kt @@ -1,19 +1,13 @@ package be.ugent.sel.studeez.data.local.models.timer_functional -class Time(initialTime: Int) { +class Time(var time: Int) { + operator fun invoke() = time - var time = initialTime + operator fun inc(): Time = Time(time + 1) - fun minOne() { - time-- - } - - fun plusOne() { - time++ - } + operator fun dec(): Time = Time(time - 1) fun getAsHMS(): HoursMinutesSeconds { return HoursMinutesSeconds(time) } - -} \ No newline at end of file +} From 8e3cca531a1099c7954e6d8f12c45f0f26588c83 Mon Sep 17 00:00:00 2001 From: Lukas Barragan Torres Date: Wed, 3 May 2023 16:19:27 +0200 Subject: [PATCH 58/59] time picker composable shows picked hour and not current hour --- .../composable/TimePickerButtonComposable.kt | 19 +++++--- .../screens/timer_add/TimerAddScreen.kt | 44 +++++++++++++++++++ .../screens/timer_add/TimerAddViewModel.kt | 29 ++++++++++++ .../timer_add/TimerTypeSelectScreen.kt | 43 ++++++++++++++++++ .../timer_add/TimerTypeSelectViewModel.kt | 25 +++++++++++ 5 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt index eab0d35..e2b5216 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -22,6 +22,7 @@ import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.ext.fieldModifier import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import be.ugent.sel.studeez.ui.theme.StudeezTheme +import com.commandiron.wheel_picker_compose.WheelTimePicker import java.util.* @Composable @@ -80,15 +81,19 @@ fun TimePickerButton( } } -private fun pickDuration(context: Context, nextStep: (Int) -> Unit, timeState: MutableState) { +private fun pickDuration(context: Context, onTimeChosen: (Int) -> Unit, timeState: MutableState) { val listener = OnTimeSetListener { _, hour, minute -> - timeState.value = hour * 60 * 60 + minute * 60 - nextStep(timeState.value) + timeState.value = HoursMinutesSeconds(hour, minute, 0).getTotalSeconds() + onTimeChosen(timeState.value) } - val mCalendar = Calendar.getInstance() - val mHour = mCalendar[Calendar.HOUR] - val mMinute = mCalendar[Calendar.MINUTE] - val mTimePickerDialog = TimePickerDialog(context, listener, mHour, mMinute, true) + val hms = HoursMinutesSeconds(timeState.value) + val mTimePickerDialog = TimePickerDialog( + context, + listener, + hms.hours, + hms.minutes, + true + ) mTimePickerDialog.show() } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt new file mode 100644 index 0000000..7cb6a8f --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddScreen.kt @@ -0,0 +1,44 @@ +package be.ugent.sel.studeez.screens.timer_add + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.tooling.preview.Preview +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo +import be.ugent.sel.studeez.screens.timer_edit.GetTimerEditScreen +import be.ugent.sel.studeez.screens.timer_edit.TimerEditViewModel +import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen +import be.ugent.sel.studeez.ui.theme.StudeezTheme + +data class TimerEditActions( + val getTimerInfo: () -> TimerInfo, + val saveTimer: (TimerInfo, () -> Unit) -> Unit +) + +fun getTimerEditActions( + viewModel: TimerEditViewModel, + open: (String) -> Unit +): TimerEditActions { + return TimerEditActions( + getTimerInfo = viewModel::getTimerInfo, + saveTimer = viewModel::saveTimer + ) +} + +@Composable +fun TimerEditRoute( + open: (String) -> Unit, + popUp: () -> Unit, + viewModel: TimerEditViewModel, +) { + + val timerEditActions = getTimerEditActions(viewModel, open) + + SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { + + val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen()) + timerEditScreen { timerInfo -> + timerEditActions.saveTimer(timerInfo, popUp) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt new file mode 100644 index 0000000..9ab766c --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerAddViewModel.kt @@ -0,0 +1,29 @@ +package be.ugent.sel.studeez.screens.timer_add + +import be.ugent.sel.studeez.data.EditTimerState +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.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class TimerAddViewModel @Inject constructor( + private val editTimerState: EditTimerState, + private val timerDAO: TimerDAO, + logService: LogService +) : StudeezViewModel(logService) { + + private val timerInfo: TimerInfo = editTimerState.timerInfo + + fun getTimerInfo(): TimerInfo { + return timerInfo + } + + fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) { + timerDAO.updateTimer(timerInfo) + goBack() + } + +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt new file mode 100644 index 0000000..d14bb86 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectScreen.kt @@ -0,0 +1,43 @@ +package be.ugent.sel.studeez.screens.timer_add + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate +import be.ugent.sel.studeez.data.local.models.timer_info.* +import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.CUSTOM +import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.BREAK +import be.ugent.sel.studeez.data.local.models.timer_info.TimerType.ENDLESS + +val defaultTimerInfo: Map = mapOf( + CUSTOM to CustomTimerInfo("", "", 0), + BREAK to PomodoroTimerInfo("", "", 0, 0, 0), + ENDLESS to EndlessTimerInfo("", ""), +) + + +@Composable +fun TimerTypeSelectScreen( + open: (String) -> Unit, + popUp: () -> Unit, + viewModel: TimerTypeSelectViewModel = hiltViewModel() +) { + + SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxWidth() + ) { + TimerType.values().forEach { timerType -> + Button(onClick = { viewModel.onTimerTypeChosen(defaultTimerInfo[timerType]!!, open) }) { + Text(text = timerType.name) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt new file mode 100644 index 0000000..1892833 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/timer_add/TimerTypeSelectViewModel.kt @@ -0,0 +1,25 @@ +package be.ugent.sel.studeez.screens.timer_add + +import be.ugent.sel.studeez.data.EditTimerState +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 TimerTypeSelectViewModel @Inject constructor( + private val editTimerState: EditTimerState, + private val timerDAO: TimerDAO, + logService: LogService +) : StudeezViewModel(logService) { + + + fun onTimerTypeChosen(timerInfo: TimerInfo, open: (String) -> Unit) { + editTimerState.timerInfo = timerInfo + open(StudeezDestinations.TIMER_EDIT_SCREEN) + } +} \ No newline at end of file From ff77227ea87e1891ad10e4e44f9627abce236fac Mon Sep 17 00:00:00 2001 From: Lukas Barragan Torres Date: Wed, 3 May 2023 19:59:33 +0200 Subject: [PATCH 59/59] removed Wheelpicker from imports --- .../common/composable/TimePickerButtonComposable.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt index e2b5216..c5e75cc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TimePickerButtonComposable.kt @@ -10,7 +10,10 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -22,8 +25,6 @@ import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.ext.fieldModifier import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import be.ugent.sel.studeez.ui.theme.StudeezTheme -import com.commandiron.wheel_picker_compose.WheelTimePicker -import java.util.* @Composable fun TimePickerCard(