Merge pull request #95 from SELab1/timer_edit

Timer edit
This commit is contained in:
lbarraga 2023-05-04 00:13:25 +02:00 committed by GitHub Enterprise
commit d3159e0b2a
29 changed files with 583 additions and 110 deletions

View file

@ -32,6 +32,7 @@ import be.ugent.sel.studeez.screens.sessions.SessionsRoute
import be.ugent.sel.studeez.screens.settings.SettingsRoute import be.ugent.sel.studeez.screens.settings.SettingsRoute
import be.ugent.sel.studeez.screens.sign_up.SignUpRoute import be.ugent.sel.studeez.screens.sign_up.SignUpRoute
import be.ugent.sel.studeez.screens.splash.SplashRoute 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_overview.TimerOverviewRoute
import be.ugent.sel.studeez.screens.timer_overview.add_timer.AddTimerRoute 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.screens.timer_selection.TimerSelectionRoute
@ -205,6 +206,14 @@ fun StudeezNavGraph(
) )
} }
composable(StudeezDestinations.TIMER_EDIT_SCREEN) {
TimerEditRoute(
open = open,
popUp = goBack,
viewModel = hiltViewModel()
)
}
// Friends flow // Friends flow
composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) { composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) {
// TODO // TODO

View file

@ -3,46 +3,113 @@ package be.ugent.sel.studeez.common.composable
import android.app.TimePickerDialog import android.app.TimePickerDialog
import android.app.TimePickerDialog.OnTimeSetListener import android.app.TimePickerDialog.OnTimeSetListener
import android.content.Context import android.content.Context
import androidx.annotation.StringRes
import androidx.compose.foundation.BorderStroke 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.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button import androidx.compose.material.*
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable 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.Modifier
import androidx.compose.ui.platform.LocalContext 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 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.data.local.models.timer_functional.HoursMinutesSeconds
import java.util.* import be.ugent.sel.studeez.ui.theme.StudeezTheme
@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 @Composable
fun TimePickerButton( fun TimePickerButton(
hoursMinutesSeconds: HoursMinutesSeconds, initialSeconds: Int,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
colors: ButtonColors = ButtonDefaults.buttonColors(), colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null, border: BorderStroke? = null,
onTimeSetListener: OnTimeSetListener onTimeChosen: (Int) -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
val timeState: MutableState<Int> = remember {
mutableStateOf(initialSeconds)
}
Button( Button(
onClick = { pickDuration(context, onTimeSetListener) }, onClick = { pickDuration(context, onTimeChosen, timeState) },
modifier = modifier, modifier = modifier,
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
colors = colors, colors = colors,
border = border border = border
) { ) {
Text(text = hoursMinutesSeconds.toString()) Text(text = HoursMinutesSeconds(timeState.value).toString())
} }
} }
private fun pickDuration(context: Context, listener: OnTimeSetListener) { private fun pickDuration(context: Context, onTimeChosen: (Int) -> Unit, timeState: MutableState<Int>) {
val timePickerDialog = TimePickerDialog( val listener = OnTimeSetListener { _, hour, minute ->
timeState.value = HoursMinutesSeconds(hour, minute, 0).getTotalSeconds()
onTimeChosen(timeState.value)
}
val hms = HoursMinutesSeconds(timeState.value)
val mTimePickerDialog = TimePickerDialog(
context, context,
listener, listener,
0, hms.hours,
0, hms.minutes,
true true
) )
timePickerDialog.show() 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 = {})
}
} }

View file

@ -1,4 +1,11 @@
package be.ugent.sel.studeez.data 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
} }

View file

@ -4,7 +4,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) {
override fun tick() { override fun tick() {
if (!hasEnded()) { if (!hasEnded()) {
time.minOne() time--
totalStudyTime++ totalStudyTime++
} }
} }

View file

@ -11,7 +11,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) {
} }
override fun tick() { override fun tick() {
time.plusOne() time++
totalStudyTime++ totalStudyTime++
} }

View file

@ -22,7 +22,7 @@ class FunctionalPomodoroTimer(
} }
isInBreak = !isInBreak isInBreak = !isInBreak
} }
time.minOne() time--
if (!isInBreak) { if (!isInBreak) {
totalStudyTime++ totalStudyTime++

View file

@ -4,7 +4,7 @@ import be.ugent.sel.studeez.data.local.models.SessionReport
import com.google.firebase.Timestamp import com.google.firebase.Timestamp
abstract class FunctionalTimer(initialValue: Int) { abstract class FunctionalTimer(initialValue: Int) {
val time: Time = Time(initialValue) var time: Time = Time(initialValue)
var totalStudyTime: Int = 0 var totalStudyTime: Int = 0
fun getHoursMinutesSeconds(): HoursMinutesSeconds { fun getHoursMinutesSeconds(): HoursMinutesSeconds {

View file

@ -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) { 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 { fun getTotalSeconds(): Int {
return hours * 60 * 60 + minutes * 60 + seconds return hours * 60 * 60 + minutes * 60 + seconds
} }

View file

@ -1,23 +1,13 @@
package be.ugent.sel.studeez.data.local.models.timer_functional 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() { operator fun dec(): Time = Time(time - 1)
time--
}
fun plusOne() {
time++
}
fun getAsHMS(): HoursMinutesSeconds { fun getAsHMS(): HoursMinutesSeconds {
val hours: Int = time / (60 * 60) return HoursMinutesSeconds(time)
val minutes: Int = (time / (60)) % 60
val seconds: Int = time % 60
return HoursMinutesSeconds(hours, minutes, seconds)
} }
}
}

View file

@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVi
class PomodoroTimerInfo( class PomodoroTimerInfo(
name: String, name: String,
description: String, description: String,
val studyTime: Int, var studyTime: Int,
val breakTime: Int, var breakTime: Int,
val repeats: Int, val repeats: Int,
id: String = "" id: String = ""
): TimerInfo(id, name, description) { ): TimerInfo(id, name, description) {

View file

@ -18,6 +18,7 @@ object StudeezDestinations {
// Studying flow // Studying flow
const val TIMER_SELECTION_SCREEN = "timer_selection" const val TIMER_SELECTION_SCREEN = "timer_selection"
const val TIMER_EDIT_SCREEN = "timer_edit"
const val SESSION_SCREEN = "session" const val SESSION_SCREEN = "session"
const val SESSION_RECAP = "session_recap" const val SESSION_RECAP = "session_recap"

View file

@ -78,7 +78,7 @@ abstract class AbstractSessionScreen {
val hms = sessionActions.getTimer().getHoursMinutesSeconds() val hms = sessionActions.getTimer().getHoursMinutesSeconds()
Column { Column {
Text( Text(
text = "${hms.hours} : ${hms.minutes} : ${hms.seconds}", text = hms.toString(),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(50.dp), .padding(50.dp),

View file

@ -50,7 +50,7 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi
Column( Column(
modifier = modifier modifier = modifier
) { ) {
Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}") Text(text = "You studied: $hms")
BasicButton( BasicButton(
R.string.save, Modifier.basicButton() R.string.save, Modifier.basicButton()

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

@ -1,34 +1,26 @@
package be.ugent.sel.studeez.screens.timer_edit 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.CustomTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo 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.PomodoroTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor 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<Unit> { class GetTimerEditScreen: TimerInfoVisitor<AbstractTimerEditScreen> {
@SuppressLint("ComposableNaming")
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) {
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen {
return CustomTimerEditScreen(customTimerInfo)
} }
@SuppressLint("ComposableNaming") override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen {
override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo) { return EndlessTimerEditScreen(endlessTimerInfo)
} }
@SuppressLint("ComposableNaming") override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerEditScreen {
override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo) { return BreakTimerEditScreen(pomodoroTimerInfo)
} }

View file

@ -1,2 +1,65 @@
package be.ugent.sel.studeez.screens.timer_edit 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

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

View file

@ -1,4 +1,70 @@
package be.ugent.sel.studeez.screens.timer_edit 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.*
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
)
repeat(20) {
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.
}
abstract class AbstractTimerEditScreen {
} }

View file

@ -1,4 +1,46 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens package be.ugent.sel.studeez.screens.timer_edit.editScreens
class BreakTimerEditScreen { 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

@ -1,4 +1,34 @@
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.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

@ -1,4 +1,23 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens package be.ugent.sel.studeez.screens.timer_edit.editScreens
class EndlessTimerEditScreen { 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

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.screens.timer_overview package be.ugent.sel.studeez.screens.timer_overview
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -24,7 +25,7 @@ data class TimerOverviewActions(
val getUserTimers: () -> Flow<List<TimerInfo>>, val getUserTimers: () -> Flow<List<TimerInfo>>,
val getDefaultTimers: () -> List<TimerInfo>, val getDefaultTimers: () -> List<TimerInfo>,
val onEditClick: (TimerInfo) -> Unit, val onEditClick: (TimerInfo) -> Unit,
val open: (String) -> Unit, val onAddClick: () -> Unit,
) )
fun getTimerOverviewActions( fun getTimerOverviewActions(
@ -34,20 +35,20 @@ fun getTimerOverviewActions(
return TimerOverviewActions( return TimerOverviewActions(
getUserTimers = viewModel::getUserTimers, getUserTimers = viewModel::getUserTimers,
getDefaultTimers = viewModel::getDefaultTimers, getDefaultTimers = viewModel::getDefaultTimers,
onEditClick = { viewModel.update(it) }, onEditClick = { viewModel.update(it, open) },
open = open onAddClick = { viewModel.create(open) }
) )
} }
@Composable @Composable
fun TimerOverviewRoute( fun TimerOverviewRoute(
open: (String) -> Unit,
viewModel: TimerOverviewViewModel, viewModel: TimerOverviewViewModel,
drawerActions: DrawerActions, drawerActions: DrawerActions,
open: (String) -> Unit
) { ) {
TimerOverviewScreen( TimerOverviewScreen(
timerOverviewActions = getTimerOverviewActions(viewModel, open), timerOverviewActions = getTimerOverviewActions(viewModel, open),
drawerActions = drawerActions, drawerActions = drawerActions
) )
} }
@ -63,34 +64,38 @@ fun TimerOverviewScreen(
title = resources().getString(R.string.timers), title = resources().getString(R.string.timers),
drawerActions = drawerActions drawerActions = drawerActions
) { ) {
LazyColumn { Column { // TODO knop beneden
// Custom timer, select new duration each time LazyColumn {
item { // Custom timer, select new duration each time
TimerEntry(timerInfo = CustomTimerInfo( item {
name = resources().getString(R.string.custom_name), TimerEntry(timerInfo = CustomTimerInfo(
description = resources().getString(R.string.custom_name), name = resources().getString(R.string.custom_name),
studyTime = 0 description = resources().getString(R.string.custom_name),
)) studyTime = 0
} ))
// Default Timers, cannot be edited }
items(timerOverviewActions.getDefaultTimers()) { // Default Timers, cannot be edited
TimerEntry(timerInfo = it) {} items(timerOverviewActions.getDefaultTimers()) {
} TimerEntry(timerInfo = it) {}
// User timers, can be edited }
items(timers.value) { timerInfo -> // User timers, can be edited
TimerEntry( items(timers.value) { timerInfo ->
timerInfo = timerInfo, TimerEntry(
) { timerInfo = timerInfo,
StealthButton( ) {
text = R.string.edit, StealthButton(
onClick = { timerOverviewActions.onEditClick(timerInfo) } text = R.string.edit,
) onClick = { timerOverviewActions.onEditClick(timerInfo) }
)
}
} }
} // TODO uit lazy column
item { item {
BasicButton(R.string.add_timer, Modifier.basicButton()) { BasicButton(R.string.add_timer, Modifier.basicButton()) {
timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN) timerOverviewActions.onAddClick()
}
} }
} }
} }

View file

@ -1,9 +1,11 @@
package be.ugent.sel.studeez.screens.timer_overview 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.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.domain.ConfigurationService import be.ugent.sel.studeez.domain.ConfigurationService
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TimerDAO import be.ugent.sel.studeez.domain.TimerDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -13,6 +15,7 @@ import javax.inject.Inject
class TimerOverviewViewModel @Inject constructor( class TimerOverviewViewModel @Inject constructor(
private val configurationService: ConfigurationService, private val configurationService: ConfigurationService,
private val timerDAO: TimerDAO, private val timerDAO: TimerDAO,
private val editTimerState: EditTimerState,
logService: LogService logService: LogService
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
@ -24,7 +27,14 @@ class TimerOverviewViewModel @Inject constructor(
return configurationService.getDefaultTimers() 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) fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo)

View file

@ -253,7 +253,7 @@ fun AddTimerScreen(
onClick = { onClick = {
if (uiState.description != "" && uiState.name != "") { if (uiState.description != "" && uiState.name != "") {
addTimerActions.addTimer() addTimerActions.addTimer()
addTimerActions.open(StudeezDestinations.TIMER_OVERVIEW_SCREEN) addTimerActions.open(StudeezDestinations.TIMER_SCREEN)
} }
} }
) )

View file

@ -1,11 +1,9 @@
package be.ugent.sel.studeez.screens.timer_selection package be.ugent.sel.studeez.screens.timer_selection
import android.widget.TimePicker
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
@ -23,7 +21,6 @@ import kotlinx.coroutines.flow.flowOf
data class TimerSelectionActions( data class TimerSelectionActions(
val getAllTimers: () -> Flow<List<TimerInfo>>, val getAllTimers: () -> Flow<List<TimerInfo>>,
val startSession: (TimerInfo) -> Unit, val startSession: (TimerInfo) -> Unit,
val pickDuration: (TimePicker?, Int, Int) -> Unit,
val customTimeStudyTime: Int val customTimeStudyTime: Int
) )
@ -34,9 +31,6 @@ fun getTimerSelectionActions(
return TimerSelectionActions( return TimerSelectionActions(
getAllTimers = viewModel::getAllTimers, getAllTimers = viewModel::getAllTimers,
startSession = { viewModel.startSession(open, it) }, startSession = { viewModel.startSession(open, it) },
pickDuration = { _, hour: Int, minute: Int ->
viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60
},
customTimeStudyTime = viewModel.customTimerStudyTime.value customTimeStudyTime = viewModel.customTimerStudyTime.value
) )
} }
@ -105,10 +99,9 @@ fun CustomTimerEntry(
) )
}, },
rightButton = { rightButton = {
TimePickerButton( TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
hoursMinutesSeconds = hms, timerInfo.studyTime = chosenTime
onTimeSetListener = timerSelectionActions.pickDuration }
)
} }
) )
} }
@ -117,7 +110,7 @@ fun CustomTimerEntry(
@Composable @Composable
fun TimerSelectionPreview() { fun TimerSelectionPreview() {
TimerSelectionScreen( TimerSelectionScreen(
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _, _ -> {} }, 0), timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, 0),
popUp = {} popUp = {}
) )
} }

View file

@ -107,7 +107,7 @@
<!-- Session --> <!-- Session -->
<string name="create_session_not_possible_yet">Creating sessions still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. --> <string name="create_session_not_possible_yet">Creating sessions still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. -->
<!-- Add Timer --> <!-- Add Timer -->
<string name="addTimer_description_error">Timer description cannot be empty!</string> <string name="addTimer_description_error">Timer description cannot be empty!</string>
<string name="addTimer_description">Timer description</string> <string name="addTimer_description">Timer description</string>
@ -123,4 +123,11 @@
<string name="addTimer_studytime_2">" minutes of studytime"</string> <string name="addTimer_studytime_2">" minutes of studytime"</string>
<string name="addTimer_question">How long do you want to study?</string> <string name="addTimer_question">How long do you want to study?</string>
<!-- Edit Timer-->
<string name="name">Name</string>
<string name="description">Description</string>
<string name="studyTime">Study Time</string>
<string name="breakTime">Break Time</string>
<string name="repeats">Number of Repeats</string>
</resources> </resources>