fix mergeconflict when merging tasksoverview

This commit is contained in:
brreynie 2023-05-04 22:12:08 +02:00
commit e2ada0b9d4
67 changed files with 1833 additions and 281 deletions

View file

@ -33,13 +33,13 @@ fun HomeRoute(
fun HomeScreen(
onStartSessionClick: () -> Unit,
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
navigationBarActions: NavigationBarActions
) {
PrimaryScreenTemplate(
title = resources().getString(R.string.home),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
barAction = { FriendsAction() }
// TODO barAction = { FriendsAction() }
) {
BasicButton(R.string.start_session, Modifier.basicButton()) {
onStartSessionClick()
@ -63,6 +63,6 @@ fun HomeScreenPreview() {
HomeScreen(
onStartSessionClick = {},
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {})
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
)
}

View file

@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicTextButton
import be.ugent.sel.studeez.common.composable.LabelledInputField
@ -64,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,

View file

@ -88,6 +88,6 @@ fun ProfileScreenPreview() {
ProfileScreen(
profileActions = ProfileActions({ null }, {}),
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {})
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
)
}

View file

@ -0,0 +1,29 @@
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 lateinit var mediaPlayer: MediaPlayer
fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) {
this.viewModel = viewModel
this.mediaPlayer = mediaplayer
}
suspend fun updateTimer() {
viewModel?.let {
while (!it.getTimer().hasEnded()) {
delay(1.seconds)
it.getTimer().tick()
if (it.getTimer().hasCurrentCountdownEnded()) {
mediaPlayer.start()
}
}
}
}
}

View file

@ -12,7 +12,7 @@ import be.ugent.sel.studeez.screens.session.sessionScreens.GetSessionScreen
data class SessionActions(
val getTimer: () -> FunctionalTimer,
val getTask: () -> String,
val prepareMediaPlayer: () -> Unit,
val startMediaPlayer: () -> Unit,
val releaseMediaPlayer: () -> Unit,
val endSession: () -> Unit
)
@ -26,8 +26,8 @@ private fun getSessionActions(
getTimer = viewModel::getTimer,
getTask = viewModel::getTask,
endSession = { viewModel.endSession(openAndPopUp) },
prepareMediaPlayer = mediaplayer::prepareAsync,
releaseMediaPlayer = mediaplayer::release
startMediaPlayer = mediaplayer::start,
releaseMediaPlayer = mediaplayer::release,
)
}
@ -39,26 +39,15 @@ fun SessionRoute(
) {
val context = LocalContext.current
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val mediaplayer = MediaPlayer()
mediaplayer.setDataSource(context, uri)
mediaplayer.setOnCompletionListener {
mediaplayer.stop()
//if (timerEnd) {
// mediaplayer.release()
//}
}
mediaplayer.setOnPreparedListener {
// mediaplayer.start()
}
val mediaplayer = MediaPlayer.create(context, uri)
mediaplayer.isLooping = false
val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen())
InvisibleSessionManager.setParameters(
viewModel = viewModel,
mediaplayer = mediaplayer
)
//val sessionScreen = when (val timer = viewModel.getTimer()) {
// is FunctionalCustomTimer -> CustomSessionScreen(timer)
// is FunctionalPomodoroTimer -> BreakSessionScreen(timer)
// is FunctionalEndlessTimer -> EndlessSessionScreen()
// else -> throw java.lang.IllegalArgumentException("Unknown Timer")
//}
val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen(mediaplayer))
sessionScreen(
open = open,

View file

@ -9,7 +9,12 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -19,16 +24,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.session.SessionActions
import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.seconds
abstract class AbstractSessionScreen {
var timerEnd = false
@Composable
operator fun invoke(
open: (String) -> Unit,
@ -75,22 +76,10 @@ abstract class AbstractSessionScreen {
LaunchedEffect(tikker) {
delay(1.seconds)
sessionActions.getTimer().tick()
callMediaPlayer()
tikker = !tikker
}
if (
sessionActions.getTimer().hasCurrentCountdownEnded() && !sessionActions.getTimer()
.hasEnded()
) {
// sessionActions.prepareMediaPlayer()
}
if (!timerEnd && sessionActions.getTimer().hasEnded()) {
// sessionActions.prepareMediaPlayer()
timerEnd =
true // Placeholder, vanaf hier moet het report opgestart worden en de sessie afgesloten
}
val hms = sessionActions.getTimer().getHoursMinutesSeconds()
Column {
Text(
@ -137,6 +126,8 @@ abstract class AbstractSessionScreen {
@Composable
abstract fun motivationString(): String
abstract fun callMediaPlayer()
}
@Preview
@ -145,6 +136,7 @@ fun TimerPreview() {
val sessionScreen = object : AbstractSessionScreen() {
@Composable
override fun motivationString(): String = "Test"
override fun callMediaPlayer() {}
}
sessionScreen.Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {}, {}))

View file

@ -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,17 @@ class BreakSessionScreen(
)
}
override fun callMediaPlayer() {
if (funPomoDoroTimer.hasEnded()) {
mediaplayer?.let { it: MediaPlayer ->
it.setOnCompletionListener {
it.release()
mediaplayer = null
}
it.start()
}
} else if (funPomoDoroTimer.hasCurrentCountdownEnded()) {
mediaplayer?.start()
}
}
}

View file

@ -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,16 @@ class CustomSessionScreen(
return resources().getString(AppText.state_focus)
}
override fun callMediaPlayer() {
if (functionalTimer.hasEnded()) {
mediaplayer?.let { it: MediaPlayer ->
it.setOnCompletionListener {
it.release()
mediaplayer = null
}
it.start()
}
}
}
}

View file

@ -11,4 +11,6 @@ class EndlessSessionScreen : AbstractSessionScreen() {
override fun motivationString(): String {
return resources().getString(AppText.state_focus)
}
override fun callMediaPlayer() {}
}

View file

@ -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<AbstractSessionScreen> {
class GetSessionScreen(private val mediaplayer: MediaPlayer?) : FunctionalTimerVisitor<AbstractSessionScreen> {
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)
}

View file

@ -26,7 +26,7 @@ fun getSessionRecapActions(
return SessionRecapActions(
viewModel::getSessionReport,
{viewModel.saveSession(openAndPopUp)},
{viewModel.saveSession(openAndPopUp)}
{viewModel.discardSession(openAndPopUp)}
)
}
@ -47,8 +47,10 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi
val sessionReport: SessionReport = sessionRecapActions.getSessionReport()
val studyTime: Int = sessionReport.studyTime
val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS()
Column {
Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}")
Column(
modifier = modifier
) {
Text(text = "You studied: $hms")
BasicButton(
R.string.save, Modifier.basicButton()

View file

@ -11,7 +11,7 @@ import javax.inject.Inject
@HiltViewModel
class SessionRecapViewModel @Inject constructor(
private val sessionReportState: SessionReportState,
sessionReportState: SessionReportState,
private val sessionDAO: SessionDAO,
logService: LogService
) : StudeezViewModel(logService) {

View file

@ -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
)
}
}

View file

@ -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
)
}
}

View file

@ -72,7 +72,7 @@ fun SubjectScreen(
fun SubjectScreenPreview() {
SubjectScreen(
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
addSubject = {},
getSubjects = { flowOf() },
onViewSubject = {},

View file

@ -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)
}
}
}

View file

@ -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()
}
}

View file

@ -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<TimerType, TimerInfo> = 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)
}
}
}
}
}

View file

@ -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)
}
}

View file

@ -0,0 +1,27 @@
package be.ugent.sel.studeez.screens.timer_edit
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 GetTimerEditScreen: TimerInfoVisitor<AbstractTimerEditScreen> {
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen {
return CustomTimerEditScreen(customTimerInfo)
}
override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen {
return EndlessTimerEditScreen(endlessTimerInfo)
}
override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerEditScreen {
return BreakTimerEditScreen(pomodoroTimerInfo)
}
}

View file

@ -0,0 +1,65 @@
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
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)
}
}
}

View file

@ -0,0 +1,29 @@
package be.ugent.sel.studeez.screens.timer_edit
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, goBack: () -> Unit) {
timerDAO.updateTimer(timerInfo)
goBack()
}
}

View file

@ -0,0 +1,71 @@
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.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import 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.data.local.models.timer_info.TimerInfo
abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) {
@Composable
operator fun invoke(onSaveClick: (TimerInfo) -> Unit) {
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(
verticalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxHeight().verticalScroll(rememberScrollState()),
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
// 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()
}
BasicButton(R.string.save, Modifier.basicButton()) {
onSaveClick(timerInfo)
}
}
}
@Composable
open fun ExtraFields() {
// By default no extra fields, unless overwritten by subclass.
}
}

View file

@ -0,0 +1,46 @@
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
): AbstractTimerEditScreen(breakTimerInfo) {
@Composable
override fun ExtraFields() {
// If the user presses the OK button on the timepicker, the time in the button should change
TimePickerCard(R.string.studyTime, breakTimerInfo.studyTime) { newTime ->
breakTimerInfo.studyTime = newTime
}
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 = {})
}
}

View file

@ -0,0 +1,34 @@
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.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) {
@Composable
override fun ExtraFields() {
TimePickerCard(
text = AppText.studyTime,
initialSeconds = customTimerInfo.studyTime
) { newTime ->
customTimerInfo.studyTime = newTime
}
}
}
@Preview
@Composable
fun CustomEditScreenPreview() {
val customTimerInfo = CustomTimerInfo("custom", "my description", 25)
StudeezTheme {
CustomTimerEditScreen(customTimerInfo).invoke(onSaveClick = {})
}
}

View file

@ -0,0 +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) {
}
@Preview
@Composable
fun EndlessEditScreenPreview() {
val endlessTimerInfo = EndlessTimerInfo(
"Forever and beyond",
"My endless timer description",
)
StudeezTheme {
EndlessTimerEditScreen(endlessTimerInfo).invoke(onSaveClick = {})
}
}

View file

@ -16,6 +16,7 @@ import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
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
@ -24,15 +25,18 @@ data class TimerOverviewActions(
val getUserTimers: () -> Flow<List<TimerInfo>>,
val getDefaultTimers: () -> List<TimerInfo>,
val onEditClick: (TimerInfo) -> Unit,
val onAddClick: () -> Unit,
)
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) },
onAddClick = { viewModel.create(open) }
)
}
@ -40,10 +44,11 @@ fun getTimerOverviewActions(
fun TimerOverviewRoute(
viewModel: TimerOverviewViewModel,
drawerActions: DrawerActions,
open: (String) -> Unit
) {
TimerOverviewScreen(
timerOverviewActions = getTimerOverviewActions(viewModel),
drawerActions = drawerActions,
timerOverviewActions = getTimerOverviewActions(viewModel, open),
drawerActions = drawerActions
)
}
@ -59,8 +64,16 @@ fun TimerOverviewScreen(
title = resources().getString(R.string.timers),
drawerActions = drawerActions
) {
Column {
Column { // TODO knop beneden
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) {}
@ -77,9 +90,13 @@ fun TimerOverviewScreen(
}
}
}
BasicButton(R.string.add_timer, Modifier.basicButton()) {
// TODO
// TODO uit lazy column
item {
BasicButton(R.string.add_timer, Modifier.basicButton()) {
timerOverviewActions.onAddClick()
}
}
}
}
}
@ -95,7 +112,9 @@ fun TimerOverviewPreview() {
timerOverviewActions = TimerOverviewActions(
{ flowOf() },
{ listOf(customTimer, customTimer) },
{}),
{},
{}
),
drawerActions = DrawerActions({}, {}, {}, {}, {})
)
}

View file

@ -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,14 @@ 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 create(open: (String) -> Unit) {
open(StudeezDestinations.ADD_TIMER_SCREEN)
}
fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo)

View file

@ -0,0 +1,12 @@
package be.ugent.sel.studeez.screens.timer_overview.add_timer
data class AddTimerUiState(
val studyTimeHours: Int = 1,
val studyTimeMinutes: Int = 0,
val withBreaks: Boolean = false,
val breakTimeMinutes: Int = 5,
val breakTimeHours: Int = 0,
val repeats: Int = 1,
val name: String = "Timer",
val description: String = "Long study session",
)

View file

@ -0,0 +1,91 @@
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.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,
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 breakTimeHours
get() = uiState.value.breakTimeHours
private val breakTimeMinutes
get() = uiState.value.breakTimeMinutes
private val repeats
get() = uiState.value.repeats
private val name
get() = uiState.value.name
private val description
get() = uiState.value.description
fun onStudyTimeHoursChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeHours = newValue)
}
fun onStudyTimeMinutesChange(newValue: Int) {
uiState.value = uiState.value.copy(studyTimeMinutes = newValue)
}
fun onWithBreaksChange() {
uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks)
}
fun onBreakTimeHourChange(newValue: Int) {
uiState.value = uiState.value.copy(breakTimeHours = newValue)
}
fun onBreakTimeMinutesChange(newValue: Int) {
uiState.value = uiState.value.copy(breakTimeMinutes = newValue)
}
fun onRepeatsChange(newValue: Int) {
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 * 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 * 60 * 60 + studyTimeMinutes * 60
))
}
}
fun onNameChange(newValue: String) {
uiState.value = uiState.value.copy(name = newValue)
}
fun onDescriptionChange(newValue: String) {
uiState.value = uiState.value.copy(description = newValue)
}
}

View file

@ -0,0 +1,274 @@
package be.ugent.sel.studeez.screens.timer_overview.add_timer
import androidx.compose.foundation.layout.Arrangement
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.Button
import androidx.compose.material.Checkbox
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: (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,
onBreakTimeHourChange = viewModel::onBreakTimeHourChange,
onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange,
onRepeatsChange = viewModel::onRepeatsChange,
addTimer = viewModel::addTimer,
onNameChange = viewModel::onNameChange,
onDescriptionChange = viewModel::onDescriptionChange
)
}
@Composable
fun AddTimerRoute(
open: (String) -> Unit,
goBack: () -> Unit,
viewModel: AddTimerViewModel,
) {
val uiState by viewModel.uiState
AddTimerScreen(
addTimerActions = getAddTimerActions(
open = open,
goBack = goBack,
viewModel = viewModel,
),
uiState = uiState
)
}
@Composable
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
) {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
item {
Row(
modifier = Modifier
.padding(16.dp)
) {
Text(
text = stringResource(R.string.addTimer_question),
textAlign = TextAlign.Center
)
}
}
item {
Text(
text = uiState.studyTimeHours.toString() + stringResource(R.string.addTimer_studytime_1) + uiState.studyTimeMinutes + stringResource(
R.string.addTimer_studytime_2)
)
}
item {
Button(
onClick = {
mStudyTimePicker.show()
},
) {
Text(
text = stringResource(R.string.addTimer_timepicker),
)
}
}
item {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(
text = stringResource(R.string.addTimer_break_question),
)
Checkbox(
checked = uiState.withBreaks,
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 = 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 = 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
.fillMaxWidth()
.fillMaxHeight(),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.Center
) {
BasicButton(
text = R.string.add_timer,
modifier = Modifier,
onClick = {
if (uiState.description != "" && uiState.name != "") {
addTimerActions.addTimer()
addTimerActions.open(StudeezDestinations.TIMER_SCREEN)
}
}
)
}
}
}
}
}
@Preview
@Composable
fun AddTimerScreenPreview() { StudeezTheme {
AddTimerScreen(
addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}),
uiState = AddTimerUiState()
)
}
}

View file

@ -8,7 +8,11 @@ import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R
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
import kotlinx.coroutines.flow.Flow
@ -17,6 +21,7 @@ import kotlinx.coroutines.flow.flowOf
data class TimerSelectionActions(
val getAllTimers: () -> Flow<List<TimerInfo>>,
val startSession: (TimerInfo) -> Unit,
val customTimeStudyTime: Int
)
fun getTimerSelectionActions(
@ -26,6 +31,7 @@ fun getTimerSelectionActions(
return TimerSelectionActions(
getAllTimers = viewModel::getAllTimers,
startSession = { viewModel.startSession(open, it) },
customTimeStudyTime = viewModel.customTimerStudyTime.value
)
}
@ -52,6 +58,11 @@ fun TimerSelectionScreen(
popUp = popUp
) {
LazyColumn {
// Custom timer with duration selection button
item {
CustomTimerEntry(timerSelectionActions)
}
// All timers
items(timers.value) { timerInfo ->
TimerEntry(
@ -68,11 +79,38 @@ 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 hms: HoursMinutesSeconds = Time(timerInfo.studyTime).getAsHMS()
TimerEntry(
timerInfo = timerInfo,
leftButton = {
StealthButton(
text = R.string.start,
onClick = { timerSelectionActions.startSession(timerInfo) }
)
},
rightButton = {
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
timerInfo.studyTime = chosenTime
}
}
)
}
@Preview
@Composable
fun TimerSelectionPreview() {
TimerSelectionScreen(
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}),
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, 0),
popUp = {}
)
}

View file

@ -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<Int> = mutableStateOf(0)
fun getAllTimers() : Flow<List<TimerInfo>> {
return timerDAO.getAllTimers()
}