commit
d3159e0b2a
29 changed files with 583 additions and 110 deletions
|
@ -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.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_overview.add_timer.AddTimerRoute
|
||||
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
|
||||
composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) {
|
||||
// TODO
|
||||
|
|
|
@ -3,46 +3,113 @@ 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.material.*
|
||||
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
|
||||
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 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
|
||||
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<Int> = 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())
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickDuration(context: Context, listener: OnTimeSetListener) {
|
||||
val timePickerDialog = TimePickerDialog(
|
||||
private fun pickDuration(context: Context, onTimeChosen: (Int) -> Unit, timeState: MutableState<Int>) {
|
||||
val listener = OnTimeSetListener { _, hour, minute ->
|
||||
timeState.value = HoursMinutesSeconds(hour, minute, 0).getTotalSeconds()
|
||||
onTimeChosen(timeState.value)
|
||||
}
|
||||
val hms = HoursMinutesSeconds(timeState.value)
|
||||
val mTimePickerDialog = TimePickerDialog(
|
||||
context,
|
||||
listener,
|
||||
0,
|
||||
0,
|
||||
hms.hours,
|
||||
hms.minutes,
|
||||
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 = {})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -4,7 +4,7 @@ class FunctionalCustomTimer(studyTime: Int) : FunctionalTimer(studyTime) {
|
|||
|
||||
override fun tick() {
|
||||
if (!hasEnded()) {
|
||||
time.minOne()
|
||||
time--
|
||||
totalStudyTime++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class FunctionalEndlessTimer : FunctionalTimer(0) {
|
|||
}
|
||||
|
||||
override fun tick() {
|
||||
time.plusOne()
|
||||
time++
|
||||
totalStudyTime++
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class FunctionalPomodoroTimer(
|
|||
}
|
||||
isInBreak = !isInBreak
|
||||
}
|
||||
time.minOne()
|
||||
time--
|
||||
|
||||
if (!isInBreak) {
|
||||
totalStudyTime++
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,23 +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 {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -18,6 +18,7 @@ object StudeezDestinations {
|
|||
|
||||
// Studying flow
|
||||
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"
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -50,7 +50,7 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi
|
|||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}")
|
||||
Text(text = "You studied: $hms")
|
||||
|
||||
BasicButton(
|
||||
R.string.save, Modifier.basicButton()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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<Unit> {
|
||||
|
||||
@SuppressLint("ComposableNaming")
|
||||
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) {
|
||||
class GetTimerEditScreen: TimerInfoVisitor<AbstractTimerEditScreen> {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,29 @@
|
|||
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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -1,4 +1,46 @@
|
|||
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 = {})
|
||||
}
|
||||
}
|
|
@ -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 = {})
|
||||
}
|
||||
}
|
|
@ -1,4 +1,23 @@
|
|||
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 = {})
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
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.items
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -24,7 +25,7 @@ data class TimerOverviewActions(
|
|||
val getUserTimers: () -> Flow<List<TimerInfo>>,
|
||||
val getDefaultTimers: () -> List<TimerInfo>,
|
||||
val onEditClick: (TimerInfo) -> Unit,
|
||||
val open: (String) -> Unit,
|
||||
val onAddClick: () -> Unit,
|
||||
)
|
||||
|
||||
fun getTimerOverviewActions(
|
||||
|
@ -34,20 +35,20 @@ fun getTimerOverviewActions(
|
|||
return TimerOverviewActions(
|
||||
getUserTimers = viewModel::getUserTimers,
|
||||
getDefaultTimers = viewModel::getDefaultTimers,
|
||||
onEditClick = { viewModel.update(it) },
|
||||
open = open
|
||||
onEditClick = { viewModel.update(it, open) },
|
||||
onAddClick = { viewModel.create(open) }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TimerOverviewRoute(
|
||||
open: (String) -> Unit,
|
||||
viewModel: TimerOverviewViewModel,
|
||||
drawerActions: DrawerActions,
|
||||
open: (String) -> Unit
|
||||
) {
|
||||
TimerOverviewScreen(
|
||||
timerOverviewActions = getTimerOverviewActions(viewModel, open),
|
||||
drawerActions = drawerActions,
|
||||
drawerActions = drawerActions
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -63,34 +64,38 @@ fun TimerOverviewScreen(
|
|||
title = resources().getString(R.string.timers),
|
||||
drawerActions = drawerActions
|
||||
) {
|
||||
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) {}
|
||||
}
|
||||
// User timers, can be edited
|
||||
items(timers.value) { timerInfo ->
|
||||
TimerEntry(
|
||||
timerInfo = timerInfo,
|
||||
) {
|
||||
StealthButton(
|
||||
text = R.string.edit,
|
||||
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
||||
)
|
||||
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) {}
|
||||
}
|
||||
// User timers, can be edited
|
||||
items(timers.value) { timerInfo ->
|
||||
TimerEntry(
|
||||
timerInfo = timerInfo,
|
||||
) {
|
||||
StealthButton(
|
||||
text = R.string.edit,
|
||||
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
item {
|
||||
BasicButton(R.string.add_timer, Modifier.basicButton()) {
|
||||
timerOverviewActions.open(StudeezDestinations.ADD_TIMER_SCREEN)
|
||||
// TODO uit lazy column
|
||||
item {
|
||||
BasicButton(R.string.add_timer, Modifier.basicButton()) {
|
||||
timerOverviewActions.onAddClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ fun AddTimerScreen(
|
|||
onClick = {
|
||||
if (uiState.description != "" && uiState.name != "") {
|
||||
addTimerActions.addTimer()
|
||||
addTimerActions.open(StudeezDestinations.TIMER_OVERVIEW_SCREEN)
|
||||
addTimerActions.open(StudeezDestinations.TIMER_SCREEN)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package be.ugent.sel.studeez.screens.timer_selection
|
||||
|
||||
import android.widget.TimePicker
|
||||
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.SecondaryScreenTemplate
|
||||
|
@ -23,7 +21,6 @@ import kotlinx.coroutines.flow.flowOf
|
|||
data class TimerSelectionActions(
|
||||
val getAllTimers: () -> Flow<List<TimerInfo>>,
|
||||
val startSession: (TimerInfo) -> Unit,
|
||||
val pickDuration: (TimePicker?, Int, Int) -> Unit,
|
||||
val customTimeStudyTime: Int
|
||||
)
|
||||
|
||||
|
@ -34,9 +31,6 @@ fun getTimerSelectionActions(
|
|||
return TimerSelectionActions(
|
||||
getAllTimers = viewModel::getAllTimers,
|
||||
startSession = { viewModel.startSession(open, it) },
|
||||
pickDuration = { _, hour: Int, minute: Int ->
|
||||
viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60
|
||||
},
|
||||
customTimeStudyTime = viewModel.customTimerStudyTime.value
|
||||
)
|
||||
}
|
||||
|
@ -105,10 +99,9 @@ fun CustomTimerEntry(
|
|||
)
|
||||
},
|
||||
rightButton = {
|
||||
TimePickerButton(
|
||||
hoursMinutesSeconds = hms,
|
||||
onTimeSetListener = timerSelectionActions.pickDuration
|
||||
)
|
||||
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
|
||||
timerInfo.studyTime = chosenTime
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -117,7 +110,7 @@ fun CustomTimerEntry(
|
|||
@Composable
|
||||
fun TimerSelectionPreview() {
|
||||
TimerSelectionScreen(
|
||||
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _, _ -> {} }, 0),
|
||||
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, 0),
|
||||
popUp = {}
|
||||
)
|
||||
}
|
|
@ -107,7 +107,7 @@
|
|||
|
||||
<!-- 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. -->
|
||||
|
||||
|
||||
<!-- Add Timer -->
|
||||
<string name="addTimer_description_error">Timer description cannot be empty!</string>
|
||||
<string name="addTimer_description">Timer description</string>
|
||||
|
@ -123,4 +123,11 @@
|
|||
<string name="addTimer_studytime_2">" minutes of studytime"</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>
|
||||
|
|
Reference in a new issue