resolve merge conflicts when merging to development
This commit is contained in:
		
						commit
						5b8d59cb75
					
				
					 23 changed files with 231 additions and 592 deletions
				
			
		| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = {})
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = {})
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = {})
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in a new issue