fix mergeconflict when merging tasksoverview
This commit is contained in:
commit
e2ada0b9d4
67 changed files with 1833 additions and 281 deletions
|
@ -38,6 +38,8 @@ import be.ugent.sel.studeez.screens.profile.EditProfileRoute
|
|||
import be.ugent.sel.studeez.screens.profile.ProfileRoute
|
||||
import be.ugent.sel.studeez.screens.session.SessionRoute
|
||||
import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute
|
||||
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.tasks.SubjectRoute
|
||||
|
@ -46,7 +48,9 @@ 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_overview.TimerOverviewRoute
|
||||
import be.ugent.sel.studeez.screens.timer_overview.add_timer.AddTimerRoute
|
||||
import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionRoute
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -97,7 +101,7 @@ fun resources(): Resources {
|
|||
@Composable
|
||||
fun StudeezNavGraph(
|
||||
appState: StudeezAppstate,
|
||||
modifier: Modifier,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val drawerViewModel: DrawerViewModel = hiltViewModel()
|
||||
val navBarViewModel: NavigationBarViewModel = hiltViewModel()
|
||||
|
@ -119,35 +123,13 @@ fun StudeezNavGraph(
|
|||
startDestination = StudeezDestinations.SPLASH_SCREEN,
|
||||
modifier = modifier,
|
||||
) {
|
||||
|
||||
|
||||
composable(StudeezDestinations.SPLASH_SCREEN) {
|
||||
SplashRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.LOGIN_SCREEN) {
|
||||
LoginRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.SIGN_UP_SCREEN) {
|
||||
SignUpRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
// NavBar
|
||||
composable(StudeezDestinations.HOME_SCREEN) {
|
||||
HomeRoute(
|
||||
open,
|
||||
viewModel = hiltViewModel(),
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions,
|
||||
navigationBarActions = navigationBarActions
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -176,6 +158,14 @@ fun StudeezNavGraph(
|
|||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.TASKS_SCREEN) {
|
||||
TaskRoute(
|
||||
goBack = goBack,
|
||||
open = open,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.ADD_TASK_FORM) {
|
||||
TaskAddRoute(
|
||||
goBack = goBack,
|
||||
|
@ -192,16 +182,14 @@ fun StudeezNavGraph(
|
|||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.TASKS_SCREEN) {
|
||||
TaskRoute(
|
||||
goBack = goBack,
|
||||
open = open,
|
||||
viewModel = hiltViewModel(),
|
||||
|
||||
composable(StudeezDestinations.SESSIONS_SCREEN) {
|
||||
SessionsRoute(
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions
|
||||
)
|
||||
}
|
||||
|
||||
// TODO Sessions screen
|
||||
|
||||
composable(StudeezDestinations.PROFILE_SCREEN) {
|
||||
ProfileRoute(
|
||||
open,
|
||||
|
@ -211,10 +199,49 @@ fun StudeezNavGraph(
|
|||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) {
|
||||
// Drawer
|
||||
composable(StudeezDestinations.TIMER_SCREEN) {
|
||||
TimerOverviewRoute(
|
||||
viewModel = hiltViewModel(),
|
||||
drawerActions = drawerActions,
|
||||
open = open
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.SETTINGS_SCREEN) {
|
||||
SettingsRoute(
|
||||
drawerActions = drawerActions
|
||||
)
|
||||
}
|
||||
|
||||
// Login flow
|
||||
composable(StudeezDestinations.SPLASH_SCREEN) {
|
||||
SplashRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.LOGIN_SCREEN) {
|
||||
LoginRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.SIGN_UP_SCREEN) {
|
||||
SignUpRoute(
|
||||
openAndPopUp,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
// Studying flow
|
||||
composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
|
||||
TimerSelectionRoute(
|
||||
open,
|
||||
goBack,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -226,10 +253,43 @@ fun StudeezNavGraph(
|
|||
)
|
||||
}
|
||||
|
||||
// TODO Timers screen
|
||||
// TODO Settings screen
|
||||
composable(StudeezDestinations.SESSION_RECAP) {
|
||||
SessionRecapRoute(
|
||||
openAndPopUp = openAndPopUp,
|
||||
viewModel = hiltViewModel()
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.ADD_TIMER_SCREEN) {
|
||||
AddTimerRoute(
|
||||
open = open,
|
||||
goBack = goBack,
|
||||
viewModel = hiltViewModel()
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.TIMER_EDIT_SCREEN) {
|
||||
TimerEditRoute(
|
||||
open = open,
|
||||
popUp = goBack,
|
||||
viewModel = hiltViewModel()
|
||||
)
|
||||
}
|
||||
|
||||
// Friends flow
|
||||
composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Create & edit screens
|
||||
composable(StudeezDestinations.CREATE_TASK_SCREEN) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.CREATE_SESSION_SCREEN) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Edit screens
|
||||
composable(StudeezDestinations.EDIT_PROFILE_SCREEN) {
|
||||
EditProfileRoute(
|
||||
goBack,
|
||||
|
@ -237,20 +297,5 @@ fun StudeezNavGraph(
|
|||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
|
||||
TimerSelectionRoute(
|
||||
open,
|
||||
goBack,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.SESSION_RECAP) {
|
||||
SessionRecapRoute(
|
||||
openAndPopUp = openAndPopUp,
|
||||
viewModel = hiltViewModel()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,15 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import be.ugent.sel.studeez.StudeezApp
|
||||
import be.ugent.sel.studeez.screens.session.InvisibleSessionManager
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
var onTimerInvisible: Job? = null
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
@ -30,6 +36,18 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
onTimerInvisible = lifecycleScope.launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
}
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
onTimerInvisible?.cancel()
|
||||
super.onStart()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -27,11 +27,19 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.common.ext.card
|
||||
import be.ugent.sel.studeez.common.ext.defaultButtonShape
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) {
|
||||
TextButton(onClick = action, modifier = modifier) { Text(text = stringResource(text)) }
|
||||
TextButton(
|
||||
onClick = action,
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(text)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -45,7 +53,7 @@ fun BasicButton(
|
|||
Button(
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
shape = defaultButtonShape(),
|
||||
colors = colors,
|
||||
border = border,
|
||||
) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package be.ugent.sel.studeez.common.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.FloatingActionButton
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
|
@ -11,52 +13,134 @@ import androidx.compose.material.icons.filled.Add
|
|||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
const val TRANSITION = "transition"
|
||||
val HEIGHT_DIFFERENCE = 30.dp
|
||||
|
||||
data class AddButtonActions(
|
||||
val onTaskClick: () -> Unit,
|
||||
val onFriendClick: () -> Unit,
|
||||
val onSessionClick: () -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CollapsedAddButton() {
|
||||
FloatingActionButton(
|
||||
onClick = { /* TODO popup add options */ }
|
||||
fun AddButton(
|
||||
addButtonActions: AddButtonActions
|
||||
) {
|
||||
var isExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
// Rotate the button when expanded, normal when collapsed.
|
||||
val transition = updateTransition(targetState = isExpanded, label = TRANSITION)
|
||||
val rotate by transition.animateFloat(label = TRANSITION) { expanded -> if (expanded) 315f else 0f }
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Top
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Add, contentDescription = "fab")
|
||||
Box {
|
||||
// Show minis when expanded.
|
||||
if (isExpanded) {
|
||||
ExpandedAddButton(
|
||||
addButtonActions = addButtonActions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The base add button
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
// Toggle expanded/collapsed.
|
||||
isExpanded = !isExpanded
|
||||
},
|
||||
modifier = Modifier.padding(bottom = if (isExpanded) 78.dp else 0.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = "fab",
|
||||
modifier = Modifier.rotate(rotate) // The rotation
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ExpandedAddButton() {
|
||||
Row() {
|
||||
IconButton(onClick = { /* TODO Go to next step */ }) {
|
||||
Column (horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(imageVector = Icons.Default.Check, contentDescription = "Task")
|
||||
Text(text = "Task")
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { /* TODO Go to next step */ }) {
|
||||
Column (horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(imageVector = Icons.Default.Person, contentDescription = "Friend")
|
||||
Text(text = "Friend")
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { /* TODO Go to next step */ }) {
|
||||
Column (horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session")
|
||||
Text(text = "Session")
|
||||
}
|
||||
}
|
||||
fun ExpandedAddButton(
|
||||
addButtonActions: AddButtonActions
|
||||
) {
|
||||
Row {
|
||||
ExpandedEntry(
|
||||
name = AppText.task,
|
||||
imageVector = Icons.Default.Check,
|
||||
onClick = addButtonActions.onTaskClick,
|
||||
modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp)
|
||||
)
|
||||
|
||||
ExpandedEntry(
|
||||
name = AppText.friend,
|
||||
imageVector = Icons.Default.Person,
|
||||
onClick = addButtonActions.onFriendClick
|
||||
)
|
||||
|
||||
ExpandedEntry(
|
||||
name = AppText.session,
|
||||
imageVector = Icons.Default.DateRange,
|
||||
onClick = addButtonActions.onSessionClick,
|
||||
modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ExpandedEntry(
|
||||
name: Int,
|
||||
imageVector: ImageVector,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = resources().getString(name),
|
||||
// TODO Dark overlay
|
||||
// tint = colors.surface
|
||||
)
|
||||
Text(
|
||||
text = resources().getString(name),
|
||||
// TODO Dark overlay
|
||||
// color = colors.surface
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CollapsedAddButtonPreview() {
|
||||
StudeezTheme { CollapsedAddButton() }
|
||||
fun AddButtonPreview() {
|
||||
StudeezTheme { AddButton(
|
||||
addButtonActions = AddButtonActions({}, {}, {})
|
||||
)}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ExpandedAddButtonPreview() {
|
||||
StudeezTheme { ExpandedAddButton() }
|
||||
StudeezTheme { ExpandedAddButton (
|
||||
addButtonActions = AddButtonActions({}, {}, {})
|
||||
) }
|
||||
}
|
|
@ -57,7 +57,11 @@ fun PrimaryScreenTemplate(
|
|||
bottomBar = { NavigationBar(navigationBarActions) },
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
isFloatingActionButtonDocked = true,
|
||||
floatingActionButton = { CollapsedAddButton() }
|
||||
floatingActionButton = { AddButton(AddButtonActions(
|
||||
onTaskClick = navigationBarActions.onAddTaskClick,
|
||||
onFriendClick = navigationBarActions.onAddFriendClick,
|
||||
onSessionClick = navigationBarActions.onAddSessionClick
|
||||
)) }
|
||||
) {
|
||||
content(it)
|
||||
}
|
||||
|
@ -70,7 +74,7 @@ fun PrimaryScreenPreview() {
|
|||
PrimaryScreenTemplate(
|
||||
"Preview screen",
|
||||
DrawerActions({}, {}, {}, {}, {}),
|
||||
NavigationBarActions({ false }, {}, {}, {}, {}),
|
||||
NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
|
||||
{
|
||||
IconButton(onClick = { /*TODO*/ }) {
|
||||
Icon(
|
||||
|
|
|
@ -41,10 +41,12 @@ fun BasicField(
|
|||
fun LabelledInputField(
|
||||
value: String,
|
||||
onNewValue: (String) -> Unit,
|
||||
@StringRes label: Int
|
||||
@StringRes label: Int,
|
||||
singleLine: Boolean = false
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = value,
|
||||
singleLine = singleLine,
|
||||
onValueChange = onNewValue,
|
||||
label = { Text(text = stringResource(id = label)) },
|
||||
modifier = Modifier.fieldModifier()
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
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.*
|
||||
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 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(
|
||||
initialSeconds: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
border: BorderStroke? = null,
|
||||
onTimeChosen: (Int) -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val timeState: MutableState<Int> = remember {
|
||||
mutableStateOf(initialSeconds)
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { pickDuration(context, onTimeChosen, timeState) },
|
||||
modifier = modifier,
|
||||
shape = RoundedCornerShape(20.dp),
|
||||
colors = colors,
|
||||
border = border
|
||||
) {
|
||||
Text(text = HoursMinutesSeconds(timeState.value).toString())
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
hms.hours,
|
||||
hms.minutes,
|
||||
true
|
||||
)
|
||||
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,5 +1,6 @@
|
|||
package be.ugent.sel.studeez.common.composable.drawer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
@ -16,6 +17,7 @@ import androidx.compose.material.icons.outlined.Info
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -28,7 +30,7 @@ data class DrawerActions(
|
|||
val onTimersClick: () -> Unit,
|
||||
val onSettingsClick: () -> Unit,
|
||||
val onLogoutClick: () -> Unit,
|
||||
val onAboutClick: () -> Unit,
|
||||
val onAboutClick: (Context) -> Unit,
|
||||
)
|
||||
|
||||
fun getDrawerActions(
|
||||
|
@ -41,7 +43,7 @@ fun getDrawerActions(
|
|||
onTimersClick = { drawerViewModel.onTimersClick(open) },
|
||||
onSettingsClick = { drawerViewModel.onSettingsClick(open) },
|
||||
onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) },
|
||||
onAboutClick = { drawerViewModel.onAboutClick(open) },
|
||||
onAboutClick = { context -> drawerViewModel.onAboutClick(open, context = context) },
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -79,10 +81,11 @@ fun Drawer(
|
|||
)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
DrawerEntry(
|
||||
icon = Icons.Outlined.Info,
|
||||
text = resources().getString(R.string.about),
|
||||
onClick = drawerActions.onAboutClick,
|
||||
onClick = { drawerActions.onAboutClick(context) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ fun DrawerEntry(
|
|||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.clickable(onClick = { onClick() })
|
||||
.clickable(onClick = onClick)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Box(
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package be.ugent.sel.studeez.common.composable.drawer
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import be.ugent.sel.studeez.domain.AccountDAO
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
|
@ -9,6 +14,8 @@ import be.ugent.sel.studeez.screens.StudeezViewModel
|
|||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
const val REPO_URL: String = "https://github.ugent.be/SELab1/project2023-groep14/"
|
||||
|
||||
@HiltViewModel
|
||||
class DrawerViewModel @Inject constructor(
|
||||
private val accountDAO: AccountDAO,
|
||||
|
@ -20,11 +27,11 @@ class DrawerViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onTimersClick(openAndPopup: (String) -> Unit) {
|
||||
openAndPopup(StudeezDestinations.TIMER_OVERVIEW_SCREEN)
|
||||
openAndPopup(StudeezDestinations.TIMER_SCREEN)
|
||||
}
|
||||
|
||||
fun onSettingsClick(open: (String) -> Unit) {
|
||||
// TODO
|
||||
open(StudeezDestinations.SETTINGS_SCREEN)
|
||||
}
|
||||
|
||||
fun onLogoutClick(openAndPopUp: (String, String) -> Unit) {
|
||||
|
@ -34,7 +41,8 @@ class DrawerViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onAboutClick(open: (String) -> Unit) {
|
||||
// TODO
|
||||
fun onAboutClick(open: (String) -> Unit, context: Context) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(REPO_URL))
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package be.ugent.sel.studeez.common.composable.navbar
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.material.BottomNavigation
|
||||
import androidx.compose.material.BottomNavigationItem
|
||||
import androidx.compose.material.Icon
|
||||
|
@ -15,6 +14,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SUBJECT_SCREEN
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
|
@ -22,10 +22,16 @@ import be.ugent.sel.studeez.R.string as AppText
|
|||
|
||||
data class NavigationBarActions(
|
||||
val isSelectedTab: (String) -> Boolean,
|
||||
|
||||
val onHomeClick: () -> Unit,
|
||||
val onTasksClick: () -> Unit,
|
||||
val onSessionsClick: () -> Unit,
|
||||
val onProfileClick: () -> Unit,
|
||||
|
||||
// AddButton
|
||||
val onAddTaskClick: () -> Unit,
|
||||
val onAddFriendClick: () -> Unit,
|
||||
val onAddSessionClick: () -> Unit
|
||||
)
|
||||
|
||||
fun getNavigationBarActions(
|
||||
|
@ -49,6 +55,16 @@ fun getNavigationBarActions(
|
|||
onProfileClick = {
|
||||
navigationBarViewModel.onProfileClick(open)
|
||||
},
|
||||
|
||||
onAddTaskClick = {
|
||||
navigationBarViewModel.onAddTaskClick(open)
|
||||
},
|
||||
onAddFriendClick = {
|
||||
navigationBarViewModel.onAddFriendClick(open)
|
||||
},
|
||||
onAddSessionClick = {
|
||||
navigationBarViewModel.onAddSessionClick(open)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -78,7 +94,7 @@ fun NavigationBar(
|
|||
)
|
||||
|
||||
// Hack to space the entries in the navigation bar, make space for fab
|
||||
BottomNavigationItem(icon = {}, onClick = {}, selected = false)
|
||||
BottomNavigationItem(icon = {}, onClick = {}, selected = false, enabled = false)
|
||||
|
||||
BottomNavigationItem(
|
||||
icon = {
|
||||
|
@ -87,8 +103,7 @@ fun NavigationBar(
|
|||
)
|
||||
},
|
||||
label = { Text(text = resources().getString(AppText.sessions)) },
|
||||
// TODO selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN),
|
||||
selected = false,
|
||||
selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN),
|
||||
onClick = navigationBarActions.onSessionsClick
|
||||
)
|
||||
|
||||
|
@ -111,7 +126,7 @@ fun NavigationBar(
|
|||
fun NavigationBarPreview() {
|
||||
StudeezTheme {
|
||||
NavigationBar(
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
package be.ugent.sel.studeez.common.composable.navbar
|
||||
|
||||
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SUBJECT_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@HiltViewModel
|
||||
class NavigationBarViewModel @Inject constructor(
|
||||
|
@ -23,10 +25,25 @@ class NavigationBarViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onSessionsClick(open: (String) -> Unit) {
|
||||
// TODO
|
||||
open(SESSIONS_SCREEN)
|
||||
}
|
||||
|
||||
fun onProfileClick(open: (String) -> Unit) {
|
||||
open(PROFILE_SCREEN)
|
||||
}
|
||||
|
||||
fun onAddTaskClick(open: (String) -> Unit) {
|
||||
// TODO open(CREATE_TASK_SCREEN)
|
||||
SnackbarManager.showMessage(AppText.create_task_not_possible_yet) // TODO Remove
|
||||
}
|
||||
|
||||
fun onAddFriendClick(open: (String) -> Unit) {
|
||||
// TODO open(SEARCH_FRIENDS_SCREEN)
|
||||
SnackbarManager.showMessage(AppText.add_friend_not_possible_yet) // TODO Remove
|
||||
}
|
||||
|
||||
fun onAddSessionClick(open: (String) -> Unit) {
|
||||
// TODO open(CREATE_SESSION_SCREEN)
|
||||
SnackbarManager.showMessage(AppText.create_session_not_possible_yet) // TODO Remove
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package be.ugent.sel.studeez.common.composable.navbar
|
||||
|
||||
import android.app.TimePickerDialog
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
@Composable
|
||||
fun BasicTimePicker(
|
||||
onHoursChange: (Int) -> Unit,
|
||||
onMinutesChange: (Int) -> Unit,
|
||||
Hours: Int,
|
||||
Minutes: Int,
|
||||
): TimePickerDialog {
|
||||
return TimePickerDialog(
|
||||
LocalContext.current,
|
||||
{ _, mHour: Int, mMinute: Int ->
|
||||
onHoursChange(mHour)
|
||||
onMinutesChange(mMinute)
|
||||
},
|
||||
Hours,
|
||||
Minutes,
|
||||
true
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package be.ugent.sel.studeez.common.ext
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
fun defaultButtonShape(): RoundedCornerShape {
|
||||
return RoundedCornerShape(20.dp)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package be.ugent.sel.studeez.data
|
||||
|
||||
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
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.SessionReport
|
||||
import be.ugent.sel.studeez.screens.session.sessionScreens.CustomSessionScreen
|
||||
import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
|
||||
|
||||
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++
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.screens.session.sessionScreens.BreakSessionScreen
|
||||
import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
|
||||
|
||||
class FunctionalPomodoroTimer(
|
||||
private var studyTime: Int,
|
||||
private var breakTime: Int, repeats: Int
|
||||
|
@ -25,7 +22,7 @@ class FunctionalPomodoroTimer(
|
|||
}
|
||||
isInBreak = !isInBreak
|
||||
}
|
||||
time.minOne()
|
||||
time--
|
||||
|
||||
if (!isInBreak) {
|
||||
totalStudyTime++
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.SessionReport
|
||||
import be.ugent.sel.studeez.screens.session.sessionScreens.AbstractSessionScreen
|
||||
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 {
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
package be.ugent.sel.studeez.data.local.models.timer_functional
|
||||
|
||||
class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) {
|
||||
constructor(seconds: Int) : this(
|
||||
hours = seconds / (60 * 60),
|
||||
minutes = (seconds / 60) % 60,
|
||||
seconds = seconds % 60,
|
||||
data class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) {
|
||||
|
||||
constructor(sec: Int): this(
|
||||
hours = sec / (60 * 60),
|
||||
minutes = (sec / (60)) % 60,
|
||||
seconds = sec % 60,
|
||||
)
|
||||
|
||||
fun getTotalSeconds(): Int {
|
||||
return (hours * 60 * 60) + (minutes * 60) + seconds
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return hours.toString().padStart(2, '0') +
|
||||
":" +
|
||||
minutes.toString().padStart(2, '0') +
|
||||
":" +
|
||||
seconds.toString().padStart(2, '0')
|
||||
val hoursString = hours.toString().padStart(2, '0')
|
||||
val minutesString = minutes.toString().padStart(2, '0')
|
||||
val secondsString = seconds.toString().padStart(2, '0')
|
||||
return "$hoursString:$minutesString:$secondsString"
|
||||
}
|
||||
}
|
|
@ -1,16 +1,11 @@
|
|||
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 {
|
||||
return HoursMinutesSeconds(time)
|
||||
|
|
|
@ -6,11 +6,10 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
|||
class CustomTimerInfo(
|
||||
name: String,
|
||||
description: String,
|
||||
private val studyTime: Int,
|
||||
var studyTime: Int,
|
||||
id: String = ""
|
||||
): TimerInfo(id, name, description) {
|
||||
|
||||
|
||||
override fun getFunctionalTimer(): FunctionalTimer {
|
||||
return FunctionalCustomTimer(studyTime)
|
||||
}
|
||||
|
@ -24,4 +23,8 @@ class CustomTimerInfo(
|
|||
)
|
||||
}
|
||||
|
||||
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
|
||||
return visitor.visitCustomTimerInfo(this)
|
||||
}
|
||||
|
||||
}
|
|
@ -22,4 +22,8 @@ class EndlessTimerInfo(
|
|||
)
|
||||
}
|
||||
|
||||
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
|
||||
return visitor.visitEndlessTimerInfo(this)
|
||||
}
|
||||
|
||||
}
|
|
@ -2,13 +2,14 @@ package be.ugent.sel.studeez.data.local.models.timer_info
|
|||
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor
|
||||
|
||||
class PomodoroTimerInfo(
|
||||
name: String,
|
||||
description: String,
|
||||
private val studyTime: Int,
|
||||
private val breakTime: Int,
|
||||
private val repeats: Int,
|
||||
var studyTime: Int,
|
||||
var breakTime: Int,
|
||||
val repeats: Int,
|
||||
id: String = ""
|
||||
): TimerInfo(id, name, description) {
|
||||
|
||||
|
@ -28,4 +29,8 @@ class PomodoroTimerInfo(
|
|||
)
|
||||
}
|
||||
|
||||
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
|
||||
return visitor.visitBreakTimerInfo(this)
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
|||
*/
|
||||
abstract class TimerInfo(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val description: String
|
||||
var name: String,
|
||||
var description: String
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@ abstract class TimerInfo(
|
|||
* TODO implementaties hebben nog hardgecodeerde strings.
|
||||
*/
|
||||
abstract fun asJson(): Map<String, Any>
|
||||
abstract fun <T> accept(visitor: TimerInfoVisitor<T>): T
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package be.ugent.sel.studeez.data.local.models.timer_info
|
||||
|
||||
interface TimerInfoVisitor<T> {
|
||||
|
||||
fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): T
|
||||
|
||||
fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): T
|
||||
|
||||
fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): T
|
||||
|
||||
}
|
|
@ -1,29 +1,40 @@
|
|||
package be.ugent.sel.studeez.navigation
|
||||
|
||||
object StudeezDestinations {
|
||||
const val SPLASH_SCREEN = "splash"
|
||||
const val SIGN_UP_SCREEN = "signup"
|
||||
const val LOGIN_SCREEN = "login"
|
||||
|
||||
// NavBar
|
||||
const val HOME_SCREEN = "home"
|
||||
const val TIMER_OVERVIEW_SCREEN = "timer_overview"
|
||||
const val SUBJECT_SCREEN = "subjects"
|
||||
const val SESSIONS_SCREEN = "sessions"
|
||||
const val PROFILE_SCREEN = "profile"
|
||||
|
||||
// Drawer
|
||||
const val TIMER_SCREEN = "timer_overview"
|
||||
const val SETTINGS_SCREEN = "settings"
|
||||
|
||||
// Login flow
|
||||
const val SPLASH_SCREEN = "splash"
|
||||
const val LOGIN_SCREEN = "login"
|
||||
const val SIGN_UP_SCREEN = "signup"
|
||||
|
||||
// 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"
|
||||
|
||||
const val SUBJECT_SCREEN = "subjects"
|
||||
const val ADD_SUBJECT_FORM = "add_subject"
|
||||
const val EDIT_SUBJECT_FORM = "edit_subject"
|
||||
const val TASKS_SCREEN = "tasks"
|
||||
const val ADD_TASK_FORM = "add_task"
|
||||
const val EDIT_TASK_FORM = "edit_task"
|
||||
|
||||
// const val SESSIONS_SCREEN = "sessions"
|
||||
const val PROFILE_SCREEN = "profile"
|
||||
// Friends flow
|
||||
const val SEARCH_FRIENDS_SCREEN = "search_friends"
|
||||
|
||||
// const val TIMERS_SCREEN = "timers"
|
||||
// const val SETTINGS_SCREEN = "settings"
|
||||
|
||||
// Edit screens
|
||||
// Create & edit screens
|
||||
const val CREATE_TASK_SCREEN = "create_task"
|
||||
const val CREATE_SESSION_SCREEN = "create_session"
|
||||
const val EDIT_PROFILE_SCREEN = "edit_profile"
|
||||
|
||||
const val ADD_TIMER_SCREEN = "add_timer"
|
||||
}
|
|
@ -33,13 +33,13 @@ fun HomeRoute(
|
|||
fun HomeScreen(
|
||||
onStartSessionClick: () -> Unit,
|
||||
drawerActions: DrawerActions,
|
||||
navigationBarActions: NavigationBarActions,
|
||||
navigationBarActions: NavigationBarActions
|
||||
) {
|
||||
PrimaryScreenTemplate(
|
||||
title = resources().getString(R.string.home),
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions,
|
||||
barAction = { FriendsAction() }
|
||||
// TODO barAction = { FriendsAction() }
|
||||
) {
|
||||
BasicButton(R.string.start_session, Modifier.basicButton()) {
|
||||
onStartSessionClick()
|
||||
|
@ -63,6 +63,6 @@ fun HomeScreenPreview() {
|
|||
HomeScreen(
|
||||
onStartSessionClick = {},
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {})
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.BasicTextButton
|
||||
import be.ugent.sel.studeez.common.composable.LabelledInputField
|
||||
|
@ -64,7 +63,10 @@ fun EditProfileScreen(
|
|||
BasicTextButton(
|
||||
text = R.string.save,
|
||||
Modifier.textButton(),
|
||||
action = editProfileActions.onSaveClick
|
||||
action = {
|
||||
editProfileActions.onSaveClick()
|
||||
goBack()
|
||||
}
|
||||
)
|
||||
BasicTextButton(
|
||||
text = R.string.delete_profile,
|
||||
|
|
|
@ -88,6 +88,6 @@ fun ProfileScreenPreview() {
|
|||
ProfileScreen(
|
||||
profileActions = ProfileActions({ null }, {}),
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {})
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
|
||||
)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package be.ugent.sel.studeez.screens.session
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import kotlinx.coroutines.delay
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Singleton
|
||||
object InvisibleSessionManager {
|
||||
private var viewModel: SessionViewModel? = null
|
||||
private lateinit var mediaPlayer: MediaPlayer
|
||||
|
||||
fun setParameters(viewModel: SessionViewModel, mediaplayer: MediaPlayer) {
|
||||
this.viewModel = viewModel
|
||||
this.mediaPlayer = mediaplayer
|
||||
}
|
||||
|
||||
suspend fun updateTimer() {
|
||||
viewModel?.let {
|
||||
while (!it.getTimer().hasEnded()) {
|
||||
delay(1.seconds)
|
||||
it.getTimer().tick()
|
||||
if (it.getTimer().hasCurrentCountdownEnded()) {
|
||||
mediaPlayer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import be.ugent.sel.studeez.screens.session.sessionScreens.GetSessionScreen
|
|||
data class SessionActions(
|
||||
val getTimer: () -> FunctionalTimer,
|
||||
val getTask: () -> String,
|
||||
val prepareMediaPlayer: () -> Unit,
|
||||
val startMediaPlayer: () -> Unit,
|
||||
val releaseMediaPlayer: () -> Unit,
|
||||
val endSession: () -> Unit
|
||||
)
|
||||
|
@ -26,8 +26,8 @@ private fun getSessionActions(
|
|||
getTimer = viewModel::getTimer,
|
||||
getTask = viewModel::getTask,
|
||||
endSession = { viewModel.endSession(openAndPopUp) },
|
||||
prepareMediaPlayer = mediaplayer::prepareAsync,
|
||||
releaseMediaPlayer = mediaplayer::release
|
||||
startMediaPlayer = mediaplayer::start,
|
||||
releaseMediaPlayer = mediaplayer::release,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -39,26 +39,15 @@ fun SessionRoute(
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val mediaplayer = MediaPlayer()
|
||||
mediaplayer.setDataSource(context, uri)
|
||||
mediaplayer.setOnCompletionListener {
|
||||
mediaplayer.stop()
|
||||
//if (timerEnd) {
|
||||
// mediaplayer.release()
|
||||
//}
|
||||
}
|
||||
mediaplayer.setOnPreparedListener {
|
||||
// mediaplayer.start()
|
||||
}
|
||||
val mediaplayer = MediaPlayer.create(context, uri)
|
||||
mediaplayer.isLooping = false
|
||||
|
||||
val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen())
|
||||
InvisibleSessionManager.setParameters(
|
||||
viewModel = viewModel,
|
||||
mediaplayer = mediaplayer
|
||||
)
|
||||
|
||||
//val sessionScreen = when (val timer = viewModel.getTimer()) {
|
||||
// is FunctionalCustomTimer -> CustomSessionScreen(timer)
|
||||
// is FunctionalPomodoroTimer -> BreakSessionScreen(timer)
|
||||
// is FunctionalEndlessTimer -> EndlessSessionScreen()
|
||||
// else -> throw java.lang.IllegalArgumentException("Unknown Timer")
|
||||
//}
|
||||
val sessionScreen: AbstractSessionScreen = viewModel.getTimer().accept(GetSessionScreen(mediaplayer))
|
||||
|
||||
sessionScreen(
|
||||
open = open,
|
||||
|
|
|
@ -9,7 +9,12 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
@ -19,16 +24,12 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.screens.session.SessionActions
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
abstract class AbstractSessionScreen {
|
||||
|
||||
var timerEnd = false
|
||||
|
||||
@Composable
|
||||
operator fun invoke(
|
||||
open: (String) -> Unit,
|
||||
|
@ -75,22 +76,10 @@ abstract class AbstractSessionScreen {
|
|||
LaunchedEffect(tikker) {
|
||||
delay(1.seconds)
|
||||
sessionActions.getTimer().tick()
|
||||
callMediaPlayer()
|
||||
tikker = !tikker
|
||||
}
|
||||
|
||||
if (
|
||||
sessionActions.getTimer().hasCurrentCountdownEnded() && !sessionActions.getTimer()
|
||||
.hasEnded()
|
||||
) {
|
||||
// sessionActions.prepareMediaPlayer()
|
||||
}
|
||||
|
||||
if (!timerEnd && sessionActions.getTimer().hasEnded()) {
|
||||
// sessionActions.prepareMediaPlayer()
|
||||
timerEnd =
|
||||
true // Placeholder, vanaf hier moet het report opgestart worden en de sessie afgesloten
|
||||
}
|
||||
|
||||
val hms = sessionActions.getTimer().getHoursMinutesSeconds()
|
||||
Column {
|
||||
Text(
|
||||
|
@ -137,6 +126,8 @@ abstract class AbstractSessionScreen {
|
|||
@Composable
|
||||
abstract fun motivationString(): String
|
||||
|
||||
abstract fun callMediaPlayer()
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
@ -145,6 +136,7 @@ fun TimerPreview() {
|
|||
val sessionScreen = object : AbstractSessionScreen() {
|
||||
@Composable
|
||||
override fun motivationString(): String = "Test"
|
||||
override fun callMediaPlayer() {}
|
||||
|
||||
}
|
||||
sessionScreen.Timer(sessionActions = SessionActions({ FunctionalEndlessTimer() }, { "Preview" }, {}, {}, {}))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package be.ugent.sel.studeez.screens.session.sessionScreens
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import androidx.compose.runtime.Composable
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
|
@ -7,7 +8,8 @@ import be.ugent.sel.studeez.resources
|
|||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
class BreakSessionScreen(
|
||||
private val funPomoDoroTimer: FunctionalPomodoroTimer
|
||||
private val funPomoDoroTimer: FunctionalPomodoroTimer,
|
||||
private var mediaplayer: MediaPlayer?
|
||||
): AbstractSessionScreen() {
|
||||
|
||||
@Composable
|
||||
|
@ -27,4 +29,17 @@ class BreakSessionScreen(
|
|||
)
|
||||
}
|
||||
|
||||
override fun callMediaPlayer() {
|
||||
if (funPomoDoroTimer.hasEnded()) {
|
||||
mediaplayer?.let { it: MediaPlayer ->
|
||||
it.setOnCompletionListener {
|
||||
it.release()
|
||||
mediaplayer = null
|
||||
}
|
||||
it.start()
|
||||
}
|
||||
} else if (funPomoDoroTimer.hasCurrentCountdownEnded()) {
|
||||
mediaplayer?.start()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package be.ugent.sel.studeez.screens.session.sessionScreens
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import androidx.compose.runtime.Composable
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
|
||||
import be.ugent.sel.studeez.resources
|
||||
|
@ -7,7 +8,8 @@ import be.ugent.sel.studeez.R.string as AppText
|
|||
|
||||
|
||||
class CustomSessionScreen(
|
||||
private val functionalTimer: FunctionalCustomTimer
|
||||
private val functionalTimer: FunctionalCustomTimer,
|
||||
private var mediaplayer: MediaPlayer?
|
||||
): AbstractSessionScreen() {
|
||||
|
||||
@Composable
|
||||
|
@ -18,4 +20,16 @@ class CustomSessionScreen(
|
|||
return resources().getString(AppText.state_focus)
|
||||
}
|
||||
|
||||
override fun callMediaPlayer() {
|
||||
if (functionalTimer.hasEnded()) {
|
||||
mediaplayer?.let { it: MediaPlayer ->
|
||||
it.setOnCompletionListener {
|
||||
it.release()
|
||||
mediaplayer = null
|
||||
}
|
||||
it.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,4 +11,6 @@ class EndlessSessionScreen : AbstractSessionScreen() {
|
|||
override fun motivationString(): String {
|
||||
return resources().getString(AppText.state_focus)
|
||||
}
|
||||
|
||||
override fun callMediaPlayer() {}
|
||||
}
|
|
@ -1,17 +1,18 @@
|
|||
package be.ugent.sel.studeez.screens.session.sessionScreens
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor
|
||||
|
||||
class GetSessionScreen : FunctionalTimerVisitor<AbstractSessionScreen> {
|
||||
class GetSessionScreen(private val mediaplayer: MediaPlayer?) : FunctionalTimerVisitor<AbstractSessionScreen> {
|
||||
override fun visitFunctionalCustomTimer(functionalCustomTimer: FunctionalCustomTimer): AbstractSessionScreen =
|
||||
CustomSessionScreen(functionalCustomTimer)
|
||||
CustomSessionScreen(functionalCustomTimer, mediaplayer)
|
||||
|
||||
override fun visitFunctionalEndlessTimer(functionalEndlessTimer: FunctionalEndlessTimer): AbstractSessionScreen =
|
||||
EndlessSessionScreen()
|
||||
|
||||
override fun visitFunctionalBreakTimer(functionalPomodoroTimer: FunctionalPomodoroTimer): AbstractSessionScreen =
|
||||
BreakSessionScreen(functionalPomodoroTimer)
|
||||
BreakSessionScreen(functionalPomodoroTimer, mediaplayer)
|
||||
}
|
|
@ -26,7 +26,7 @@ fun getSessionRecapActions(
|
|||
return SessionRecapActions(
|
||||
viewModel::getSessionReport,
|
||||
{viewModel.saveSession(openAndPopUp)},
|
||||
{viewModel.saveSession(openAndPopUp)}
|
||||
{viewModel.discardSession(openAndPopUp)}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,10 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi
|
|||
val sessionReport: SessionReport = sessionRecapActions.getSessionReport()
|
||||
val studyTime: Int = sessionReport.studyTime
|
||||
val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS()
|
||||
Column {
|
||||
Text(text = "You studied: ${hms.hours} : ${hms.minutes} : ${hms.seconds}")
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(text = "You studied: $hms")
|
||||
|
||||
BasicButton(
|
||||
R.string.save, Modifier.basicButton()
|
||||
|
|
|
@ -11,7 +11,7 @@ import javax.inject.Inject
|
|||
|
||||
@HiltViewModel
|
||||
class SessionRecapViewModel @Inject constructor(
|
||||
private val sessionReportState: SessionReportState,
|
||||
sessionReportState: SessionReportState,
|
||||
private val sessionDAO: SessionDAO,
|
||||
logService: LogService
|
||||
) : StudeezViewModel(logService) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package be.ugent.sel.studeez.screens.sessions
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
fun SessionsRoute(
|
||||
// viewModel: SessionsViewModel,
|
||||
drawerActions: DrawerActions,
|
||||
navigationBarActions: NavigationBarActions
|
||||
) {
|
||||
SessionsScreen(
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SessionsScreen(
|
||||
drawerActions: DrawerActions,
|
||||
navigationBarActions: NavigationBarActions
|
||||
) {
|
||||
PrimaryScreenTemplate(
|
||||
title = resources().getString(AppText.upcoming_sessions),
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions
|
||||
) {
|
||||
Text(
|
||||
text = resources().getString(AppText.sessions_temp_description),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package be.ugent.sel.studeez.screens.settings
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import be.ugent.sel.studeez.common.composable.DrawerScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
fun SettingsRoute(
|
||||
// viewModel: SettingsViewModel,
|
||||
drawerActions: DrawerActions
|
||||
) {
|
||||
SettingsScreen(
|
||||
drawerActions = drawerActions
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
drawerActions: DrawerActions
|
||||
) {
|
||||
DrawerScreenTemplate(
|
||||
title = resources().getString(AppText.settings),
|
||||
drawerActions = drawerActions
|
||||
) {
|
||||
Text(
|
||||
text = resources().getString(AppText.settings_temp_description),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
|
@ -72,7 +72,7 @@ fun SubjectScreen(
|
|||
fun SubjectScreenPreview() {
|
||||
SubjectScreen(
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
|
||||
addSubject = {},
|
||||
getSubjects = { flowOf() },
|
||||
onViewSubject = {},
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor
|
||||
import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen
|
||||
import be.ugent.sel.studeez.screens.timer_edit.editScreens.BreakTimerEditScreen
|
||||
import be.ugent.sel.studeez.screens.timer_edit.editScreens.CustomTimerEditScreen
|
||||
import be.ugent.sel.studeez.screens.timer_edit.editScreens.EndlessTimerEditScreen
|
||||
|
||||
class GetTimerEditScreen: TimerInfoVisitor<AbstractTimerEditScreen> {
|
||||
|
||||
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo): AbstractTimerEditScreen {
|
||||
return CustomTimerEditScreen(customTimerInfo)
|
||||
}
|
||||
|
||||
override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo): AbstractTimerEditScreen {
|
||||
return EndlessTimerEditScreen(endlessTimerInfo)
|
||||
}
|
||||
|
||||
override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo): AbstractTimerEditScreen {
|
||||
return BreakTimerEditScreen(pomodoroTimerInfo)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.screens.timer_edit.editScreens.AbstractTimerEditScreen
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
|
||||
data class TimerEditActions(
|
||||
val getTimerInfo: () -> TimerInfo,
|
||||
val saveTimer: (TimerInfo, () -> Unit) -> Unit
|
||||
)
|
||||
|
||||
fun getTimerEditActions(
|
||||
viewModel: TimerEditViewModel,
|
||||
open: (String) -> Unit
|
||||
): TimerEditActions {
|
||||
return TimerEditActions(
|
||||
getTimerInfo = viewModel::getTimerInfo,
|
||||
saveTimer = viewModel::saveTimer
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TimerEditRoute(
|
||||
open: (String) -> Unit,
|
||||
popUp: () -> Unit,
|
||||
viewModel: TimerEditViewModel,
|
||||
) {
|
||||
|
||||
val timerEditActions = getTimerEditActions(viewModel, open)
|
||||
|
||||
SecondaryScreenTemplate(title = "Edit Timer", popUp = popUp) {
|
||||
|
||||
val timerEditScreen = timerEditActions.getTimerInfo().accept(GetTimerEditScreen())
|
||||
timerEditScreen { timerInfo ->
|
||||
timerEditActions.saveTimer(timerInfo, popUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit
|
||||
|
||||
import be.ugent.sel.studeez.data.EditTimerState
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.domain.TimerDAO
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TimerEditViewModel @Inject constructor(
|
||||
private val editTimerState: EditTimerState,
|
||||
private val timerDAO: TimerDAO,
|
||||
logService: LogService
|
||||
) : StudeezViewModel(logService) {
|
||||
|
||||
private val timerInfo: TimerInfo = editTimerState.timerInfo
|
||||
|
||||
fun getTimerInfo(): TimerInfo {
|
||||
return timerInfo
|
||||
}
|
||||
|
||||
fun saveTimer(timerInfo: TimerInfo, goBack: () -> Unit) {
|
||||
timerDAO.updateTimer(timerInfo)
|
||||
goBack()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit.editScreens
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||
import be.ugent.sel.studeez.common.composable.LabelledInputField
|
||||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
|
||||
abstract class AbstractTimerEditScreen(private val timerInfo: TimerInfo) {
|
||||
|
||||
@Composable
|
||||
operator fun invoke(onSaveClick: (TimerInfo) -> Unit) {
|
||||
|
||||
var name by remember { mutableStateOf(timerInfo.name) }
|
||||
var description by remember { mutableStateOf(timerInfo.description) }
|
||||
|
||||
// This shall rerun whenever name and description change
|
||||
timerInfo.name = name
|
||||
timerInfo.description = description
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxHeight().verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
// Fields that every timer shares (ommited id)
|
||||
LabelledInputField(
|
||||
value = name,
|
||||
onNewValue = { name = it },
|
||||
label = R.string.name
|
||||
)
|
||||
|
||||
LabelledInputField(
|
||||
value = description,
|
||||
onNewValue = { description = it },
|
||||
label = R.string.description,
|
||||
singleLine = false
|
||||
)
|
||||
|
||||
ExtraFields()
|
||||
|
||||
}
|
||||
BasicButton(R.string.save, Modifier.basicButton()) {
|
||||
onSaveClick(timerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
open fun ExtraFields() {
|
||||
// By default no extra fields, unless overwritten by subclass.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit.editScreens
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.TimePickerButton
|
||||
import be.ugent.sel.studeez.common.composable.TimePickerCard
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.Time
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
|
||||
class BreakTimerEditScreen(
|
||||
private val breakTimerInfo: PomodoroTimerInfo
|
||||
): AbstractTimerEditScreen(breakTimerInfo) {
|
||||
|
||||
@Composable
|
||||
override fun ExtraFields() {
|
||||
// If the user presses the OK button on the timepicker, the time in the button should change
|
||||
|
||||
TimePickerCard(R.string.studyTime, breakTimerInfo.studyTime) { newTime ->
|
||||
breakTimerInfo.studyTime = newTime
|
||||
}
|
||||
TimePickerCard(R.string.breakTime, breakTimerInfo.breakTime) { newTime ->
|
||||
breakTimerInfo.breakTime = newTime
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun BreakEditScreenPreview() {
|
||||
val pomodoroTimerInfo = PomodoroTimerInfo(
|
||||
"Breaky the Breaktimer",
|
||||
"Breaky is a breakdancer",
|
||||
10 * 60,
|
||||
60,
|
||||
5
|
||||
)
|
||||
StudeezTheme {
|
||||
BreakTimerEditScreen(pomodoroTimerInfo).invoke(onSaveClick = {})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit.editScreens
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import be.ugent.sel.studeez.common.composable.TimePickerCard
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
class CustomTimerEditScreen(
|
||||
private val customTimerInfo: CustomTimerInfo
|
||||
): AbstractTimerEditScreen(customTimerInfo) {
|
||||
|
||||
@Composable
|
||||
override fun ExtraFields() {
|
||||
TimePickerCard(
|
||||
text = AppText.studyTime,
|
||||
initialSeconds = customTimerInfo.studyTime
|
||||
) { newTime ->
|
||||
customTimerInfo.studyTime = newTime
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CustomEditScreenPreview() {
|
||||
val customTimerInfo = CustomTimerInfo("custom", "my description", 25)
|
||||
StudeezTheme {
|
||||
CustomTimerEditScreen(customTimerInfo).invoke(onSaveClick = {})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package be.ugent.sel.studeez.screens.timer_edit.editScreens
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
|
||||
class EndlessTimerEditScreen(
|
||||
endlessTimerInfo: EndlessTimerInfo
|
||||
): AbstractTimerEditScreen(endlessTimerInfo) {
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun EndlessEditScreenPreview() {
|
||||
val endlessTimerInfo = EndlessTimerInfo(
|
||||
"Forever and beyond",
|
||||
"My endless timer description",
|
||||
)
|
||||
StudeezTheme {
|
||||
EndlessTimerEditScreen(endlessTimerInfo).invoke(onSaveClick = {})
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
|||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.resources
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
@ -24,15 +25,18 @@ data class TimerOverviewActions(
|
|||
val getUserTimers: () -> Flow<List<TimerInfo>>,
|
||||
val getDefaultTimers: () -> List<TimerInfo>,
|
||||
val onEditClick: (TimerInfo) -> Unit,
|
||||
val onAddClick: () -> Unit,
|
||||
)
|
||||
|
||||
fun getTimerOverviewActions(
|
||||
viewModel: TimerOverviewViewModel,
|
||||
open: (String) -> Unit,
|
||||
): TimerOverviewActions {
|
||||
return TimerOverviewActions(
|
||||
getUserTimers = viewModel::getUserTimers,
|
||||
getDefaultTimers = viewModel::getDefaultTimers,
|
||||
onEditClick = { viewModel.update(it) },
|
||||
onEditClick = { viewModel.update(it, open) },
|
||||
onAddClick = { viewModel.create(open) }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -40,10 +44,11 @@ fun getTimerOverviewActions(
|
|||
fun TimerOverviewRoute(
|
||||
viewModel: TimerOverviewViewModel,
|
||||
drawerActions: DrawerActions,
|
||||
open: (String) -> Unit
|
||||
) {
|
||||
TimerOverviewScreen(
|
||||
timerOverviewActions = getTimerOverviewActions(viewModel),
|
||||
drawerActions = drawerActions,
|
||||
timerOverviewActions = getTimerOverviewActions(viewModel, open),
|
||||
drawerActions = drawerActions
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -59,8 +64,16 @@ fun TimerOverviewScreen(
|
|||
title = resources().getString(R.string.timers),
|
||||
drawerActions = drawerActions
|
||||
) {
|
||||
Column {
|
||||
Column { // TODO knop beneden
|
||||
LazyColumn {
|
||||
// Custom timer, select new duration each time
|
||||
item {
|
||||
TimerEntry(timerInfo = CustomTimerInfo(
|
||||
name = resources().getString(R.string.custom_name),
|
||||
description = resources().getString(R.string.custom_name),
|
||||
studyTime = 0
|
||||
))
|
||||
}
|
||||
// Default Timers, cannot be edited
|
||||
items(timerOverviewActions.getDefaultTimers()) {
|
||||
TimerEntry(timerInfo = it) {}
|
||||
|
@ -77,9 +90,13 @@ fun TimerOverviewScreen(
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
BasicButton(R.string.add_timer, Modifier.basicButton()) {
|
||||
// TODO
|
||||
|
||||
// TODO uit lazy column
|
||||
item {
|
||||
BasicButton(R.string.add_timer, Modifier.basicButton()) {
|
||||
timerOverviewActions.onAddClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +112,9 @@ fun TimerOverviewPreview() {
|
|||
timerOverviewActions = TimerOverviewActions(
|
||||
{ flowOf() },
|
||||
{ listOf(customTimer, customTimer) },
|
||||
{}),
|
||||
{},
|
||||
{}
|
||||
),
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package be.ugent.sel.studeez.screens.timer_overview.add_timer
|
||||
|
||||
data class AddTimerUiState(
|
||||
val studyTimeHours: Int = 1,
|
||||
val studyTimeMinutes: Int = 0,
|
||||
val withBreaks: Boolean = false,
|
||||
val breakTimeMinutes: Int = 5,
|
||||
val breakTimeHours: Int = 0,
|
||||
val repeats: Int = 1,
|
||||
val name: String = "Timer",
|
||||
val description: String = "Long study session",
|
||||
)
|
|
@ -0,0 +1,91 @@
|
|||
package be.ugent.sel.studeez.screens.timer_overview.add_timer
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.domain.TimerDAO
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AddTimerViewModel @Inject constructor(
|
||||
logService: LogService,
|
||||
private val timerDAO: TimerDAO,
|
||||
): StudeezViewModel(logService) {
|
||||
var uiState = mutableStateOf(AddTimerUiState())
|
||||
private set
|
||||
|
||||
private val studyTimeHours
|
||||
get() = uiState.value.studyTimeHours
|
||||
|
||||
private val studyTimeMinutes
|
||||
get() = uiState.value.studyTimeMinutes
|
||||
|
||||
private val breakTimeHours
|
||||
get() = uiState.value.breakTimeHours
|
||||
|
||||
private val breakTimeMinutes
|
||||
get() = uiState.value.breakTimeMinutes
|
||||
|
||||
private val repeats
|
||||
get() = uiState.value.repeats
|
||||
|
||||
private val name
|
||||
get() = uiState.value.name
|
||||
|
||||
private val description
|
||||
get() = uiState.value.description
|
||||
|
||||
fun onStudyTimeHoursChange(newValue: Int) {
|
||||
uiState.value = uiState.value.copy(studyTimeHours = newValue)
|
||||
|
||||
}
|
||||
|
||||
fun onStudyTimeMinutesChange(newValue: Int) {
|
||||
uiState.value = uiState.value.copy(studyTimeMinutes = newValue)
|
||||
}
|
||||
|
||||
fun onWithBreaksChange() {
|
||||
uiState.value = uiState.value.copy(withBreaks = !uiState.value.withBreaks)
|
||||
}
|
||||
|
||||
fun onBreakTimeHourChange(newValue: Int) {
|
||||
uiState.value = uiState.value.copy(breakTimeHours = newValue)
|
||||
}
|
||||
|
||||
fun onBreakTimeMinutesChange(newValue: Int) {
|
||||
uiState.value = uiState.value.copy(breakTimeMinutes = newValue)
|
||||
}
|
||||
|
||||
fun onRepeatsChange(newValue: Int) {
|
||||
uiState.value = uiState.value.copy(repeats = newValue)
|
||||
}
|
||||
|
||||
fun addTimer() {
|
||||
if (uiState.value.withBreaks) {
|
||||
timerDAO.saveTimer(PomodoroTimerInfo(
|
||||
name = uiState.value.name,
|
||||
description = uiState.value.description,
|
||||
studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60,
|
||||
breakTime = breakTimeHours * 60 * 60 + breakTimeMinutes * 60,
|
||||
repeats = repeats
|
||||
))
|
||||
} else {
|
||||
timerDAO.saveTimer(CustomTimerInfo(
|
||||
name = uiState.value.name,
|
||||
description = uiState.value.description,
|
||||
studyTime = studyTimeHours * 60 * 60 + studyTimeMinutes * 60
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun onNameChange(newValue: String) {
|
||||
uiState.value = uiState.value.copy(name = newValue)
|
||||
}
|
||||
|
||||
fun onDescriptionChange(newValue: String) {
|
||||
uiState.value = uiState.value.copy(description = newValue)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
package be.ugent.sel.studeez.screens.timer_overview.add_timer
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.navbar.BasicTimePicker
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||
|
||||
data class AddTimerActions(
|
||||
val open: (String) -> Unit,
|
||||
val goBack: () -> Unit,
|
||||
val onStudyTimeHoursChange: (Int) -> Unit,
|
||||
val onStudyTimeMinutesChange: (Int) -> Unit,
|
||||
val onBreakTimeHourChange: (Int) -> Unit,
|
||||
val onBreakTimeMinutesChange: (Int) -> Unit,
|
||||
val onRepeatsChange: (Int) -> Unit,
|
||||
val onWithBreaksChange: () -> Unit,
|
||||
val addTimer: () -> Unit,
|
||||
val onNameChange: (String) -> Unit,
|
||||
val onDescriptionChange: (String) -> Unit,
|
||||
)
|
||||
|
||||
fun getAddTimerActions(
|
||||
open: (String) -> Unit,
|
||||
goBack: () -> Unit,
|
||||
viewModel: AddTimerViewModel,
|
||||
): AddTimerActions {
|
||||
return AddTimerActions(
|
||||
open = open,
|
||||
goBack = goBack,
|
||||
onWithBreaksChange = viewModel::onWithBreaksChange,
|
||||
onStudyTimeHoursChange = viewModel::onStudyTimeHoursChange,
|
||||
onStudyTimeMinutesChange = viewModel::onStudyTimeMinutesChange,
|
||||
onBreakTimeHourChange = viewModel::onBreakTimeHourChange,
|
||||
onBreakTimeMinutesChange = viewModel::onBreakTimeMinutesChange,
|
||||
onRepeatsChange = viewModel::onRepeatsChange,
|
||||
addTimer = viewModel::addTimer,
|
||||
onNameChange = viewModel::onNameChange,
|
||||
onDescriptionChange = viewModel::onDescriptionChange
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddTimerRoute(
|
||||
open: (String) -> Unit,
|
||||
goBack: () -> Unit,
|
||||
viewModel: AddTimerViewModel,
|
||||
) {
|
||||
val uiState by viewModel.uiState
|
||||
|
||||
AddTimerScreen(
|
||||
addTimerActions = getAddTimerActions(
|
||||
open = open,
|
||||
goBack = goBack,
|
||||
viewModel = viewModel,
|
||||
),
|
||||
uiState = uiState
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddTimerScreen(
|
||||
addTimerActions: AddTimerActions,
|
||||
uiState: AddTimerUiState,
|
||||
) {
|
||||
val mStudyTimePicker = BasicTimePicker(
|
||||
onHoursChange = addTimerActions.onStudyTimeHoursChange,
|
||||
onMinutesChange = addTimerActions.onStudyTimeMinutesChange,
|
||||
Hours = uiState.studyTimeHours,
|
||||
Minutes = uiState.studyTimeMinutes
|
||||
)
|
||||
|
||||
val mBreakTimePicker = BasicTimePicker(
|
||||
onHoursChange = addTimerActions.onBreakTimeHourChange,
|
||||
onMinutesChange = addTimerActions.onBreakTimeMinutesChange,
|
||||
Hours = uiState.breakTimeHours,
|
||||
Minutes = uiState.breakTimeMinutes
|
||||
)
|
||||
|
||||
SecondaryScreenTemplate(
|
||||
title = resources().getString(R.string.add_timer),
|
||||
popUp = addTimerActions.goBack
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_question),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = uiState.studyTimeHours.toString() + stringResource(R.string.addTimer_studytime_1) + uiState.studyTimeMinutes + stringResource(
|
||||
R.string.addTimer_studytime_2)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Button(
|
||||
onClick = {
|
||||
mStudyTimePicker.show()
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_timepicker),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_break_question),
|
||||
)
|
||||
Checkbox(
|
||||
checked = uiState.withBreaks,
|
||||
onCheckedChange = { addTimerActions.onWithBreaksChange() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.withBreaks) {
|
||||
item {
|
||||
Text(
|
||||
text = if (uiState.repeats == 1) uiState.repeats.toString() + stringResource(
|
||||
R.string.addTimer_break_1)
|
||||
else uiState.repeats.toString() + stringResource(
|
||||
R.string.addTimer_break_s)
|
||||
)
|
||||
TextField(
|
||||
value = uiState.repeats.toString(),
|
||||
onValueChange = { it: String ->
|
||||
it.toIntOrNull()?.let { it1 ->
|
||||
addTimerActions.onRepeatsChange(
|
||||
kotlin.math.abs(it1)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = uiState.breakTimeHours.toString() + stringResource(R.string.breakTime_1) + uiState.breakTimeMinutes + stringResource(
|
||||
R.string.breakTime_2)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Button(
|
||||
onClick = {
|
||||
mBreakTimePicker.show()
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_timepicker),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_name)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextField(
|
||||
value = uiState.name,
|
||||
onValueChange = { addTimerActions.onNameChange(it) }
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
if (uiState.name == "") {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_name_error),
|
||||
color = Color.Red
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_description)
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
TextField(
|
||||
value = uiState.description,
|
||||
onValueChange = { addTimerActions.onDescriptionChange(it) }
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
if (uiState.description == "") {
|
||||
Text(
|
||||
text = stringResource(R.string.addTimer_description_error),
|
||||
color = Color.Red
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
BasicButton(
|
||||
text = R.string.add_timer,
|
||||
modifier = Modifier,
|
||||
onClick = {
|
||||
if (uiState.description != "" && uiState.name != "") {
|
||||
addTimerActions.addTimer()
|
||||
addTimerActions.open(StudeezDestinations.TIMER_SCREEN)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AddTimerScreenPreview() { StudeezTheme {
|
||||
AddTimerScreen(
|
||||
addTimerActions = AddTimerActions({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}),
|
||||
uiState = AddTimerUiState()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,11 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.StealthButton
|
||||
import be.ugent.sel.studeez.common.composable.TimePickerButton
|
||||
import be.ugent.sel.studeez.common.composable.TimerEntry
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.Time
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.resources
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -17,6 +21,7 @@ import kotlinx.coroutines.flow.flowOf
|
|||
data class TimerSelectionActions(
|
||||
val getAllTimers: () -> Flow<List<TimerInfo>>,
|
||||
val startSession: (TimerInfo) -> Unit,
|
||||
val customTimeStudyTime: Int
|
||||
)
|
||||
|
||||
fun getTimerSelectionActions(
|
||||
|
@ -26,6 +31,7 @@ fun getTimerSelectionActions(
|
|||
return TimerSelectionActions(
|
||||
getAllTimers = viewModel::getAllTimers,
|
||||
startSession = { viewModel.startSession(open, it) },
|
||||
customTimeStudyTime = viewModel.customTimerStudyTime.value
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -52,6 +58,11 @@ fun TimerSelectionScreen(
|
|||
popUp = popUp
|
||||
) {
|
||||
LazyColumn {
|
||||
// Custom timer with duration selection button
|
||||
item {
|
||||
CustomTimerEntry(timerSelectionActions)
|
||||
}
|
||||
|
||||
// All timers
|
||||
items(timers.value) { timerInfo ->
|
||||
TimerEntry(
|
||||
|
@ -68,11 +79,38 @@ fun TimerSelectionScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomTimerEntry(
|
||||
timerSelectionActions: TimerSelectionActions
|
||||
) {
|
||||
val timerInfo = CustomTimerInfo(
|
||||
name = resources().getString(R.string.custom_name),
|
||||
description = resources().getString(R.string.custom_description),
|
||||
studyTime = timerSelectionActions.customTimeStudyTime
|
||||
)
|
||||
val hms: HoursMinutesSeconds = Time(timerInfo.studyTime).getAsHMS()
|
||||
|
||||
TimerEntry(
|
||||
timerInfo = timerInfo,
|
||||
leftButton = {
|
||||
StealthButton(
|
||||
text = R.string.start,
|
||||
onClick = { timerSelectionActions.startSession(timerInfo) }
|
||||
)
|
||||
},
|
||||
rightButton = {
|
||||
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
|
||||
timerInfo.studyTime = chosenTime
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TimerSelectionPreview() {
|
||||
TimerSelectionScreen(
|
||||
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}),
|
||||
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, 0),
|
||||
popUp = {}
|
||||
)
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
package be.ugent.sel.studeez.screens.timer_selection
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import be.ugent.sel.studeez.data.SelectedTimerState
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
|
@ -17,6 +21,8 @@ class TimerSelectionViewModel @Inject constructor(
|
|||
logService: LogService
|
||||
) : StudeezViewModel(logService) {
|
||||
|
||||
var customTimerStudyTime: MutableState<Int> = mutableStateOf(0)
|
||||
|
||||
fun getAllTimers() : Flow<List<TimerInfo>> {
|
||||
return timerDAO.getAllTimers()
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@ import androidx.compose.ui.graphics.Color
|
|||
private val DarkColorPalette = darkColors(
|
||||
primary = Blue100,
|
||||
primaryVariant = Blue120,
|
||||
secondary = Yellow100
|
||||
secondary = Yellow100,
|
||||
|
||||
onPrimary = Color.White
|
||||
)
|
||||
|
||||
private val LightColorPalette = lightColors(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<resources>
|
||||
<!-- Common -->
|
||||
<!-- ========== Common ========== -->
|
||||
|
||||
<string name="app_name">Studeez</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="email">Email</string>
|
||||
|
@ -7,20 +8,83 @@
|
|||
<string name="repeat_password">Repeat password</string>
|
||||
<string name="menu">Menu</string>
|
||||
|
||||
<!-- Actions -->
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="discard">Discard</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="go_back">Go back</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="start">Start</string>
|
||||
<!-- Actions -->
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="discard">Discard</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="go_back">Go back</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="start">Start</string>
|
||||
|
||||
<!-- Messages -->
|
||||
<string name="success">Success!</string>
|
||||
<string name="try_again">Try again</string>
|
||||
<string name="generic_error">Something wrong happened. Please try again.</string>
|
||||
<string name="email_error">Please insert a valid email.</string>
|
||||
<!-- Messages -->
|
||||
<string name="success">Success!</string>
|
||||
<string name="try_again">Try again</string>
|
||||
<string name="generic_error">Something wrong happened. Please try again.</string>
|
||||
<string name="email_error">Please insert a valid email.</string>
|
||||
|
||||
<!-- ========== NavBar ========== -->
|
||||
|
||||
<!-- HomeScreen -->
|
||||
<string name="home">Home</string>
|
||||
<string name="start_session">Start session</string>
|
||||
|
||||
<!-- Tasks -->
|
||||
<string name="tasks">Tasks</string>
|
||||
<string name="task">Task</string>
|
||||
<string name="my_subjects">My Subjects</string>
|
||||
<string name="new_subject">New Subject</string>
|
||||
<string name="new_task">New Task</string>
|
||||
<string name="edit_subject">Edit Subject</string>
|
||||
<string name="edit_task">Edit Task</string>
|
||||
<string name="delete_subject">Delete Subject</string>
|
||||
<string name="delete_task">Delete Task</string>
|
||||
<string name="view_tasks">View</string>
|
||||
|
||||
<!-- Sessions -->
|
||||
<string name="sessions_temp_description">Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own.</string> <!-- TODO Remove this description line once implemented. -->
|
||||
<string name="sessions">Sessions</string>
|
||||
<string name="session">Session</string>
|
||||
<string name="end_session">End session</string>
|
||||
<string name="upcoming_sessions">Upcoming sessions</string>
|
||||
|
||||
<!-- Profile -->
|
||||
<string name="profile">Profile</string>
|
||||
<string name="no_username">Unknown username</string>
|
||||
<string name="edit_profile">Edit profile</string>
|
||||
<string name="editing_profile">Editing profile</string>
|
||||
<string name="delete_profile">Delete profile</string>
|
||||
|
||||
<!-- ========== Drawer ========== -->
|
||||
|
||||
<string name="log_out">Log out</string>
|
||||
<string name="profile_picture_description">Profile Picture</string>
|
||||
<string name="user_description">Normal user</string>
|
||||
|
||||
<!-- Timers -->
|
||||
<string name="timers">Timers</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="add_timer">Add timer</string>
|
||||
<string name="pick_time">Select time</string>
|
||||
<string name="state_focus">Focus!</string>
|
||||
<plurals name="state_focus_remaining">
|
||||
<item quantity="zero">Focus one more time!</item>
|
||||
<item quantity="one">Focus! (%d break remaining)</item>
|
||||
<item quantity="other">Focus! (%d breaks remaining)</item>
|
||||
</plurals>
|
||||
<string name="state_done">Done!</string>
|
||||
<string name="state_take_a_break">Take a break!</string>
|
||||
<string name="custom_name">Custom</string>
|
||||
<string name="custom_description">Select how long you want to study</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="settings_temp_description">Looks like you found the settings screen! In the future, this will enable you to edit your preferenes such as light/dark mode, end sessions automatically when we detect you are gone etc.</string> <!-- TODO Remove this description line once implemented. -->
|
||||
<string name="settings">Settings</string>
|
||||
|
||||
<!-- About -->
|
||||
<string name="about">About Studeez</string>
|
||||
|
||||
<!-- ========== Login flow ========== -->
|
||||
|
||||
<!-- SignUpScreen -->
|
||||
<string name="create_account">Create account</string>
|
||||
|
@ -36,58 +100,42 @@
|
|||
<string name="recovery_email_sent">Check your inbox for the recovery email.</string>
|
||||
<string name="empty_password_error">Password cannot be empty.</string>
|
||||
|
||||
<!-- HomeScreen -->
|
||||
<string name="home">Home</string>
|
||||
<string name="start_session">Start session</string>
|
||||
<!-- ========== Studying flow ========== -->
|
||||
|
||||
<!-- Tasks -->
|
||||
<string name="tasks">Tasks</string>
|
||||
<string name="my_subjects">My Subjects</string>
|
||||
<string name="new_subject">New Subject</string>
|
||||
<string name="new_task">New Task</string>
|
||||
<string name="edit_subject">Edit Subject</string>
|
||||
<string name="edit_task">Edit Task</string>
|
||||
<string name="delete_subject">Delete Subject</string>
|
||||
<string name="delete_task">Delete Task</string>
|
||||
<string name="view_tasks">View</string>
|
||||
<!-- ========== Friends flow ========== -->
|
||||
|
||||
<!-- Form -->
|
||||
<string name="name">Name</string>
|
||||
|
||||
<!-- Sessions -->
|
||||
<string name="sessions">Sessions</string>
|
||||
|
||||
<!-- Profile -->
|
||||
<string name="profile">Profile</string>
|
||||
<string name="no_username">Unknown username</string>
|
||||
<string name="edit_profile">Edit profile</string>
|
||||
<string name="editing_profile">Editing profile</string>
|
||||
<string name="delete_profile">Delete profile</string>
|
||||
|
||||
<!-- Friends -->
|
||||
<string name="friends">Friends</string>
|
||||
<string name="friend">Friend</string>
|
||||
<string name="add_friend_not_possible_yet">Adding friends still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. -->
|
||||
|
||||
<!-- Drawer / SideMenu -->
|
||||
<string name="log_out">Log out</string>
|
||||
<string name="profile_picture_description">Profile Picture</string>
|
||||
<string name="user_description">Normal user</string>
|
||||
<!-- ========== Create & edit screens ========== -->
|
||||
|
||||
<!-- Timers -->
|
||||
<string name="timers">Timers</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="add_timer">Add timer</string>
|
||||
<string name="state_focus">Focus!</string>
|
||||
<plurals name="state_focus_remaining">
|
||||
<item quantity="zero">Focus one more time!</item>
|
||||
<item quantity="one">Focus! (%d break remaining)</item>
|
||||
<item quantity="other">Focus! (%d breaks remaining)</item>
|
||||
</plurals>
|
||||
<string name="state_done">Done!</string>
|
||||
<string name="state_take_a_break">Take a break!</string>
|
||||
<!-- Task -->
|
||||
<string name="create_task_not_possible_yet">Creating tasks still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. -->
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="settings">Settings</string>
|
||||
<!-- 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>
|
||||
<string name="addTimer_name_error">Timer name cannot be empty!</string>
|
||||
<string name="addTimer_name">Timer name</string>
|
||||
<string name="addTimer_timepicker">Open Time Picker</string>
|
||||
<string name="breakTime_1">" hours and "</string>
|
||||
<string name="breakTime_2">" minutes of breaktime"</string>
|
||||
<string name="addTimer_break_1">" break"</string>
|
||||
<string name="addTimer_break_s">" breaks"</string>
|
||||
<string name="addTimer_break_question">With breaks?</string>
|
||||
<string name="addTimer_studytime_1">" hours and "</string>
|
||||
<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>
|
||||
|
||||
<!-- About -->
|
||||
<string name="about">About Studeez</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package be.ugent.sel.studeez.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package be.ugent.sel.studeez.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package be.ugent.sel.studeez.timer_functional
|
||||
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package be.ugent.sel.studeez.timer_functional
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import be.ugent.sel.studeez.data.SelectedTimerState
|
||||
import be.ugent.sel.studeez.data.SessionReportState
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.screens.session.InvisibleSessionManager
|
||||
import be.ugent.sel.studeez.screens.session.SessionViewModel
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class InvisibleSessionManagerTest {
|
||||
private var timerState: SelectedTimerState = SelectedTimerState()
|
||||
private lateinit var viewModel: SessionViewModel
|
||||
private var mediaPlayer: MediaPlayer = mock()
|
||||
|
||||
@Test
|
||||
fun InvisibleEndlessTimerTest() = runTest {
|
||||
timerState.selectedTimer = FunctionalEndlessTimer()
|
||||
viewModel = SessionViewModel(timerState, SessionReportState(), mock())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
}
|
||||
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 0)
|
||||
advanceTimeBy(1_000) // Start tikker
|
||||
advanceTimeBy(10_000_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 10000)
|
||||
|
||||
test.cancel()
|
||||
return@runTest
|
||||
}
|
||||
|
||||
@Test
|
||||
fun InvisiblePomodoroTimerTest() = runTest {
|
||||
val studyTime = 10
|
||||
val breakTime = 5
|
||||
val repeats = 1
|
||||
timerState.selectedTimer = FunctionalPomodoroTimer(studyTime, breakTime, repeats)
|
||||
viewModel = SessionViewModel(timerState, SessionReportState(), mock())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
}
|
||||
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 10)
|
||||
advanceTimeBy(1_000) // start tikker
|
||||
|
||||
advanceTimeBy(9_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 1)
|
||||
// focus, 9 sec, 1 sec nog
|
||||
|
||||
advanceTimeBy(2_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 4)
|
||||
// pauze, 11 sec bezig, 4 seconden nog pauze
|
||||
|
||||
advanceTimeBy(5_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 9)
|
||||
// 2e focus, 16 sec, 9 sec in 2e focus nog
|
||||
|
||||
advanceTimeBy(13_000)
|
||||
Assert.assertTrue(viewModel.getTimer().hasEnded())
|
||||
// Done
|
||||
|
||||
test.cancel()
|
||||
return@runTest
|
||||
}
|
||||
|
||||
@Test
|
||||
fun InvisibleCustomTimerTest() = runTest {
|
||||
timerState.selectedTimer = FunctionalCustomTimer(5)
|
||||
viewModel = SessionViewModel(timerState, SessionReportState(), mock())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
}
|
||||
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 5)
|
||||
advanceTimeBy(1_000) // Start tikker
|
||||
advanceTimeBy(4_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 1)
|
||||
advanceTimeBy(1_000)
|
||||
Assert.assertEquals(viewModel.getTimer().time.time, 0)
|
||||
|
||||
test.cancel()
|
||||
return@runTest
|
||||
}
|
||||
}
|
Reference in a new issue