resolve merge conflicts when merging to development

This commit is contained in:
brreynie 2023-05-05 11:25:18 +02:00
commit 5b8d59cb75
23 changed files with 231 additions and 592 deletions

View file

@ -1,11 +1,11 @@
package be.ugent.sel.studeez.common.composable
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Lock
@ -14,10 +14,15 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.common.ext.fieldModifier
import be.ugent.sel.studeez.resources
import kotlin.math.sin
import be.ugent.sel.studeez.R.drawable as AppIcon
import be.ugent.sel.studeez.R.string as AppText
@ -85,6 +90,86 @@ fun EmailField(
)
}
@Composable
fun LabeledNumberInputField(
value: Int,
onNewValue: (Int) -> Unit,
@StringRes label: Int,
singleLine: Boolean = false
) {
var number by remember { mutableStateOf(value) }
OutlinedTextField(
value = number.toString(),
singleLine = singleLine,
label = { Text(resources().getString(label)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
onValueChange = {typedInt ->
val isNumber = typedInt.matches(Regex("[1-9]+\\d*]"))
if (isNumber) {
number = typedInt.toInt()
onNewValue(typedInt.toInt())
}
}
)
}
@Composable
fun LabeledErrorTextField(
modifier: Modifier = Modifier,
initialValue: String,
@StringRes label: Int,
singleLine: Boolean = false,
errorText: Int,
keyboardType: KeyboardType,
predicate: (String) -> Boolean,
onNewCorrectValue: (String) -> Unit
) {
var value by remember {
mutableStateOf(initialValue)
}
var isValid by remember {
mutableStateOf(predicate(value))
}
Column {
OutlinedTextField(
modifier = modifier.fieldModifier(),
value = value,
onValueChange = { newText ->
value = newText
isValid = predicate(value)
if (isValid) {
onNewCorrectValue(newText)
}
},
singleLine = singleLine,
label = { Text(text = stringResource(id = label)) },
isError = !isValid,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
imeAction = ImeAction.Done
)
)
if (!isValid) {
Text(
modifier = Modifier.padding(start = 16.dp),
text = stringResource(id = errorText),
color = MaterialTheme.colors.error
)
}
}
}
@Preview(showBackground = true)
@Composable
fun IntInputPreview() {
LabeledNumberInputField(value = 1, onNewValue = {}, label = AppText.email)
}
@Composable
fun PasswordField(
value: String,

View file

@ -9,7 +9,7 @@ class PomodoroTimerInfo(
description: String,
var studyTime: Int,
var breakTime: Int,
val repeats: Int,
var repeats: Int,
id: String = ""
): TimerInfo(id, name, description) {

View file

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

View file

@ -30,9 +30,10 @@ import be.ugent.sel.studeez.screens.tasks.forms.SubjectAddRoute
import be.ugent.sel.studeez.screens.tasks.forms.SubjectEditRoute
import be.ugent.sel.studeez.screens.tasks.forms.TaskAddRoute
import be.ugent.sel.studeez.screens.tasks.forms.TaskEditRoute
import be.ugent.sel.studeez.screens.timer_edit.TimerEditRoute
import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute
import be.ugent.sel.studeez.screens.timer_form.TimerEditRoute
import be.ugent.sel.studeez.screens.timer_form.timer_type_select.TimerTypeSelectScreen
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
@Composable
@ -182,6 +183,13 @@ fun StudeezNavGraph(
)
}
composable(StudeezDestinations.TIMER_TYPE_CHOOSING_SCREEN) {
TimerTypeSelectScreen(
open = open,
popUp = goBack
)
}
composable(StudeezDestinations.SESSION_SCREEN) {
SessionRoute(
open,
@ -198,16 +206,14 @@ fun StudeezNavGraph(
}
composable(StudeezDestinations.ADD_TIMER_SCREEN) {
AddTimerRoute(
open = open,
goBack = goBack,
TimerAddRoute(
popUp = goBack,
viewModel = hiltViewModel()
)
}
composable(StudeezDestinations.TIMER_EDIT_SCREEN) {
TimerEditRoute(
open = open,
popUp = goBack,
viewModel = hiltViewModel()
)
@ -236,3 +242,4 @@ fun StudeezNavGraph(
}
}
}

View file

@ -1,44 +0,0 @@
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

@ -1,29 +0,0 @@
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

@ -1,27 +0,0 @@
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

@ -1,65 +0,0 @@
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,27 @@
package be.ugent.sel.studeez.screens.timer_form
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_form.form_screens.AbstractTimerFormScreen
import be.ugent.sel.studeez.screens.timer_form.form_screens.BreakTimerFormScreen
import be.ugent.sel.studeez.screens.timer_form.form_screens.CustomTimerFormScreen
import be.ugent.sel.studeez.screens.timer_form.form_screens.EndlessTimerFormScreen
class GetTimerFormScreen: TimerInfoVisitor<AbstractTimerFormScreen> {
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerFormScreen {
return CustomTimerFormScreen(customTimerInfo)
}
override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerFormScreen {
return EndlessTimerFormScreen(endlessTimerInfo)
}
override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerFormScreen {
return BreakTimerFormScreen(pomodoroTimerInfo)
}
}

View file

@ -0,0 +1,42 @@
package be.ugent.sel.studeez.screens.timer_form
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun TimerAddRoute(
popUp: () -> Unit,
viewModel: TimerFormViewModel
) {
TimerFormScreen(popUp = popUp, getTimerInfo = viewModel::getTimerInfo, AppText.add_timer) {
viewModel.saveTimer(it, goBack = popUp)
}
}
@Composable
fun TimerEditRoute(
popUp: () -> Unit,
viewModel: TimerFormViewModel
) {
TimerFormScreen(popUp = popUp, getTimerInfo = viewModel::getTimerInfo, AppText.edit_timer) {
viewModel.editTimer(it, goBack = popUp)
}
}
@Composable
fun TimerFormScreen(
popUp: () -> Unit,
getTimerInfo: () -> TimerInfo,
@StringRes label: Int,
onConfirmClick: (TimerInfo) -> Unit
) {
val timerFormScreen = getTimerInfo().accept(GetTimerFormScreen())
SecondaryScreenTemplate(title = stringResource(id = label), popUp = popUp) {
timerFormScreen(onConfirmClick)
}
}

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit
package be.ugent.sel.studeez.screens.timer_form
import be.ugent.sel.studeez.data.EditTimerState
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
@ -9,7 +9,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class TimerEditViewModel @Inject constructor(
class TimerFormViewModel @Inject constructor(
private val editTimerState: EditTimerState,
private val timerDAO: TimerDAO,
logService: LogService
@ -21,9 +21,13 @@ class TimerEditViewModel @Inject constructor(
return timerInfo
}
fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) {
fun editTimer(timerInfo: TimerInfo, goBack: () -> Unit) {
timerDAO.updateTimer(timerInfo)
goBack()
}
fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) {
timerDAO.saveTimer(timerInfo)
goBack()
}
}

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
package be.ugent.sel.studeez.screens.timer_form.form_screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -18,8 +18,9 @@ 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
import be.ugent.sel.studeez.R.string as AppText
abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) {
abstract class AbstractTimerFormScreen(private val timerInfo: TimerInfo) {
@Composable
operator fun invoke(onSaveClick: (TimerInfo) -> Unit) {
@ -50,7 +51,7 @@ abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) {
LabelledInputField(
value = description,
onNewValue = { description = it },
label = R.string.description,
label = AppText.description,
singleLine = false
)

View file

@ -1,20 +1,19 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
package be.ugent.sel.studeez.screens.timer_form.form_screens
import androidx.compose.runtime.*
import androidx.compose.ui.text.input.KeyboardType
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.LabeledErrorTextField
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
import be.ugent.sel.studeez.R.string as AppText
class BreakTimerEditScreen(
class BreakTimerFormScreen(
private val breakTimerInfo: PomodoroTimerInfo
): AbstractTimerEditScreen(breakTimerInfo) {
): AbstractTimerFormScreen(breakTimerInfo) {
@Composable
override fun ExtraFields() {
@ -26,8 +25,18 @@ class BreakTimerEditScreen(
TimePickerCard(R.string.breakTime, breakTimerInfo.breakTime) { newTime ->
breakTimerInfo.breakTime = newTime
}
}
LabeledErrorTextField(
initialValue = breakTimerInfo.repeats.toString(),
label = R.string.repeats,
errorText = AppText.repeats_error,
keyboardType = KeyboardType.Decimal,
predicate = { it.matches(Regex("[1-9]+\\d*")) }
) { correctlyTypedInt ->
breakTimerInfo.repeats = correctlyTypedInt.toInt()
}
}
}
@Preview
@ -41,6 +50,6 @@ fun BreakEditScreenPreview() {
5
)
StudeezTheme {
BreakTimerEditScreen(pomodoroTimerInfo).invoke(onSaveClick = {})
BreakTimerFormScreen(pomodoroTimerInfo).invoke(onSaveClick = {})
}
}

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
package be.ugent.sel.studeez.screens.timer_form.form_screens
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
@ -7,9 +7,9 @@ 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(
class CustomTimerFormScreen(
private val customTimerInfo: CustomTimerInfo
): AbstractTimerEditScreen(customTimerInfo) {
): AbstractTimerFormScreen(customTimerInfo) {
@Composable
override fun ExtraFields() {
@ -29,6 +29,6 @@ class CustomTimerEditScreen(
fun CustomEditScreenPreview() {
val customTimerInfo = CustomTimerInfo("custom", "my description", 25)
StudeezTheme {
CustomTimerEditScreen(customTimerInfo).invoke(onSaveClick = {})
CustomTimerFormScreen(customTimerInfo).invoke(onSaveClick = {})
}
}

View file

@ -1,13 +1,13 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
package be.ugent.sel.studeez.screens.timer_form.form_screens
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(
class EndlessTimerFormScreen(
endlessTimerInfo: EndlessTimerInfo
): AbstractTimerEditScreen(endlessTimerInfo) {
): AbstractTimerFormScreen(endlessTimerInfo) {
}
@Preview
@ -18,6 +18,6 @@ fun EndlessEditScreenPreview() {
"My endless timer description",
)
StudeezTheme {
EndlessTimerEditScreen(endlessTimerInfo).invoke(onSaveClick = {})
EndlessTimerFormScreen(endlessTimerInfo).invoke(onSaveClick = {})
}
}

View file

@ -1,4 +1,4 @@
package be.ugent.sel.studeez.screens.timer_add
package be.ugent.sel.studeez.screens.timer_form.timer_type_select
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@ -7,16 +7,18 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.R.string as AppText
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),
BREAK to PomodoroTimerInfo("", "", 0, 0, 1),
ENDLESS to EndlessTimerInfo("", ""),
)
@ -28,13 +30,14 @@ fun TimerTypeSelectScreen(
viewModel: TimerTypeSelectViewModel = hiltViewModel()
) {
SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) {
SecondaryScreenTemplate(title = stringResource(id = AppText.timer_type_select), popUp = popUp) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
TimerType.values().forEach { timerType ->
Button(onClick = { viewModel.onTimerTypeChosen(defaultTimerInfo[timerType]!!, open) }) {
val default: TimerInfo = defaultTimerInfo.getValue(timerType)
Button(onClick = { viewModel.onTimerTypeChosen(default, open) }) {
Text(text = timerType.name)
}
}

View file

@ -1,25 +1,22 @@
package be.ugent.sel.studeez.screens.timer_add
package be.ugent.sel.studeez.screens.timer_form.timer_type_select
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)
open(StudeezDestinations.ADD_TIMER_SCREEN)
}
}

View file

@ -25,7 +25,7 @@ data class TimerOverviewActions(
val getUserTimers: () -> Flow<List<TimerInfo>>,
val getDefaultTimers: () -> List<TimerInfo>,
val onEditClick: (TimerInfo) -> Unit,
val onAddClick: () -> Unit,
val onAddClick: () -> Unit
)
fun getTimerOverviewActions(
@ -36,7 +36,7 @@ fun getTimerOverviewActions(
getUserTimers = viewModel::getUserTimers,
getDefaultTimers = viewModel::getDefaultTimers,
onEditClick = { viewModel.update(it, open) },
onAddClick = { viewModel.create(open) }
onAddClick = { viewModel.onAddClick(open) }
)
}
@ -48,14 +48,14 @@ fun TimerOverviewRoute(
) {
TimerOverviewScreen(
timerOverviewActions = getTimerOverviewActions(viewModel, open),
drawerActions = drawerActions
drawerActions = drawerActions,
)
}
@Composable
fun TimerOverviewScreen(
timerOverviewActions: TimerOverviewActions,
drawerActions: DrawerActions
drawerActions: DrawerActions,
) {
val timers = timerOverviewActions.getUserTimers().collectAsState(initial = emptyList())

View file

@ -32,8 +32,8 @@ class TimerOverviewViewModel @Inject constructor(
open(StudeezDestinations.TIMER_EDIT_SCREEN)
}
fun create(open: (String) -> Unit) {
open(StudeezDestinations.ADD_TIMER_SCREEN)
fun onAddClick(open: (String) -> Unit) {
open(StudeezDestinations.TIMER_TYPE_CHOOSING_SCREEN)
}
fun delete(timerInfo: TimerInfo) =timerDAO.deleteTimer(timerInfo)

View file

@ -1,12 +0,0 @@
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

@ -1,91 +0,0 @@
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

@ -1,274 +0,0 @@
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

@ -131,8 +131,13 @@
<string name="addTimer_studytime_2">" minutes of studytime"</string>
<string name="addTimer_question">How long do you want to study?</string>
<!-- Timer Type Select -->
<string name="timer_type_select">Select Timer Type</string>
<!-- Edit Timer-->
<string name="name">Name</string>
<string name="edit_timer">Edit Timer</string>
<string name="repeats_error">Repeats must be a positive non-zero number</string>
<string name="description">Description</string>
<string name="studyTime">Study Time</string>
<string name="breakTime">Break Time</string>