Merge branch 'development' into addTimer

This commit is contained in:
Tibo De Peuter 2023-05-03 22:46:39 +02:00 committed by GitHub Enterprise
commit 3e721be32c
37 changed files with 694 additions and 193 deletions

View file

@ -2,18 +2,8 @@ package be.ugent.sel.studeez
import android.content.res.Resources import android.content.res.Resources
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme import androidx.compose.material.*
import androidx.compose.material.Scaffold import androidx.compose.runtime.*
import androidx.compose.material.ScaffoldState
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHost
import androidx.compose.material.Surface
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -38,6 +28,8 @@ import be.ugent.sel.studeez.screens.profile.EditProfileRoute
import be.ugent.sel.studeez.screens.profile.ProfileRoute import be.ugent.sel.studeez.screens.profile.ProfileRoute
import be.ugent.sel.studeez.screens.session.SessionRoute import be.ugent.sel.studeez.screens.session.SessionRoute
import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute 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.sign_up.SignUpRoute
import be.ugent.sel.studeez.screens.splash.SplashRoute import be.ugent.sel.studeez.screens.splash.SplashRoute
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewRoute
@ -92,7 +84,7 @@ fun resources(): Resources {
@Composable @Composable
fun StudeezNavGraph( fun StudeezNavGraph(
appState: StudeezAppstate, appState: StudeezAppstate,
modifier: Modifier, modifier: Modifier = Modifier,
) { ) {
val drawerViewModel: DrawerViewModel = hiltViewModel() val drawerViewModel: DrawerViewModel = hiltViewModel()
val navBarViewModel: NavigationBarViewModel = hiltViewModel() val navBarViewModel: NavigationBarViewModel = hiltViewModel()
@ -114,8 +106,52 @@ fun StudeezNavGraph(
startDestination = StudeezDestinations.SPLASH_SCREEN, startDestination = StudeezDestinations.SPLASH_SCREEN,
modifier = modifier, modifier = modifier,
) { ) {
// NavBar
composable(StudeezDestinations.HOME_SCREEN) {
HomeRoute(
open,
viewModel = hiltViewModel(),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions
)
}
composable(StudeezDestinations.TASKS_SCREEN) {
// TODO
}
composable(StudeezDestinations.SESSIONS_SCREEN) {
SessionsRoute(
drawerActions = drawerActions,
navigationBarActions = navigationBarActions
)
}
composable(StudeezDestinations.PROFILE_SCREEN) {
ProfileRoute(
open,
viewModel = hiltViewModel(),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions
)
}
// 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) { composable(StudeezDestinations.SPLASH_SCREEN) {
SplashRoute( SplashRoute(
openAndPopUp, openAndPopUp,
@ -137,32 +173,12 @@ fun StudeezNavGraph(
) )
} }
composable(StudeezDestinations.HOME_SCREEN) { // Studying flow
HomeRoute( composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
TimerSelectionRoute(
open, open,
goBack,
viewModel = hiltViewModel(), viewModel = hiltViewModel(),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
)
}
// TODO Tasks screen
// TODO Sessions screen
composable(StudeezDestinations.PROFILE_SCREEN) {
ProfileRoute(
open,
viewModel = hiltViewModel(),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions,
)
}
composable(StudeezDestinations.TIMER_OVERVIEW_SCREEN) {
TimerOverviewRoute(
viewModel = hiltViewModel(),
drawerActions = drawerActions,
open = open
) )
} }
@ -174,26 +190,6 @@ fun StudeezNavGraph(
) )
} }
// TODO Timers screen
// TODO Settings screen
// Edit screens
composable(StudeezDestinations.EDIT_PROFILE_SCREEN) {
EditProfileRoute(
goBack,
openAndPopUp,
viewModel = hiltViewModel(),
)
}
composable(StudeezDestinations.TIMER_SELECTION_SCREEN) {
TimerSelectionRoute(
open,
goBack,
viewModel = hiltViewModel(),
)
}
composable(StudeezDestinations.SESSION_RECAP) { composable(StudeezDestinations.SESSION_RECAP) {
SessionRecapRoute( SessionRecapRoute(
openAndPopUp = openAndPopUp, openAndPopUp = openAndPopUp,
@ -208,5 +204,27 @@ fun StudeezNavGraph(
viewModel = hiltViewModel() 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
}
composable(StudeezDestinations.EDIT_PROFILE_SCREEN) {
EditProfileRoute(
goBack,
openAndPopUp,
viewModel = hiltViewModel(),
)
}
} }
} }

View file

@ -2,7 +2,6 @@ package be.ugent.sel.studeez.common.composable
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -13,6 +12,7 @@ import androidx.compose.ui.unit.sp
import be.ugent.sel.studeez.R import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.ext.basicButton import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.common.ext.card import be.ugent.sel.studeez.common.ext.card
import be.ugent.sel.studeez.common.ext.defaultButtonShape
@Composable @Composable
fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) {
@ -37,7 +37,7 @@ fun BasicButton(
Button( Button(
onClick = onClick, onClick = onClick,
modifier = modifier, modifier = modifier,
shape = RoundedCornerShape(20.dp), shape = defaultButtonShape(),
colors = colors, colors = colors,
border = border, border = border,
) { ) {
@ -54,6 +54,25 @@ fun BasicButtonPreview() {
BasicButton(text = R.string.add_timer, modifier = Modifier.basicButton()) {} BasicButton(text = R.string.add_timer, modifier = Modifier.basicButton()) {}
} }
@Composable
fun NotInternationalisedButton(
text: String,
modifier: Modifier = Modifier,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
onClick: () -> Unit
) {
Button(
onClick = onClick,
modifier = modifier,
shape = defaultButtonShape(),
colors = colors,
border = border
) {
Text(text = text)
}
}
@Composable @Composable
fun StealthButton( fun StealthButton(
@StringRes text: Int, @StringRes text: Int,

View file

@ -1,7 +1,9 @@
package be.ugent.sel.studeez.common.composable package be.ugent.sel.studeez.common.composable
import androidx.compose.foundation.layout.Column import androidx.compose.animation.core.animateFloat
import androidx.compose.foundation.layout.Row 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.FloatingActionButton
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.IconButton 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.Check
import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.DateRange
import androidx.compose.material.icons.filled.Person 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.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.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.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 @Composable
fun CollapsedAddButton() { fun AddButton(
FloatingActionButton( addButtonActions: AddButtonActions
onClick = { /* TODO popup add options */ } ) {
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 @Composable
fun ExpandedAddButton() { fun ExpandedAddButton(
Row() { addButtonActions: AddButtonActions
IconButton(onClick = { /* TODO Go to next step */ }) { ) {
Column (horizontalAlignment = Alignment.CenterHorizontally) { Row {
Icon(imageVector = Icons.Default.Check, contentDescription = "Task") ExpandedEntry(
Text(text = "Task") name = AppText.task,
} imageVector = Icons.Default.Check,
} onClick = addButtonActions.onTaskClick,
IconButton(onClick = { /* TODO Go to next step */ }) { modifier = Modifier.padding(36.dp, HEIGHT_DIFFERENCE, 36.dp, 0.dp)
Column (horizontalAlignment = Alignment.CenterHorizontally) { )
Icon(imageVector = Icons.Default.Person, contentDescription = "Friend")
Text(text = "Friend") ExpandedEntry(
} name = AppText.friend,
} imageVector = Icons.Default.Person,
IconButton(onClick = { /* TODO Go to next step */ }) { onClick = addButtonActions.onFriendClick
Column (horizontalAlignment = Alignment.CenterHorizontally) { )
Icon(imageVector = Icons.Default.DateRange, contentDescription = "Session")
Text(text = "Session") 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 @Preview
@Composable @Composable
fun CollapsedAddButtonPreview() { fun AddButtonPreview() {
StudeezTheme { CollapsedAddButton() } StudeezTheme { AddButton(
addButtonActions = AddButtonActions({}, {}, {})
)}
} }
@Preview @Preview
@Composable @Composable
fun ExpandedAddButtonPreview() { fun ExpandedAddButtonPreview() {
StudeezTheme { ExpandedAddButton() } StudeezTheme { ExpandedAddButton (
addButtonActions = AddButtonActions({}, {}, {})
) }
} }

View file

@ -57,7 +57,11 @@ fun PrimaryScreenTemplate(
bottomBar = { NavigationBar(navigationBarActions) }, bottomBar = { NavigationBar(navigationBarActions) },
floatingActionButtonPosition = FabPosition.Center, floatingActionButtonPosition = FabPosition.Center,
isFloatingActionButtonDocked = true, isFloatingActionButtonDocked = true,
floatingActionButton = { CollapsedAddButton() } floatingActionButton = { AddButton(AddButtonActions(
onTaskClick = navigationBarActions.onAddTaskClick,
onFriendClick = navigationBarActions.onAddFriendClick,
onSessionClick = navigationBarActions.onAddSessionClick
)) }
) { ) {
content(it) content(it)
} }
@ -70,7 +74,7 @@ fun PrimaryScreenPreview() {
PrimaryScreenTemplate( PrimaryScreenTemplate(
"Preview screen", "Preview screen",
DrawerActions({}, {}, {}, {}, {}), DrawerActions({}, {}, {}, {}, {}),
NavigationBarActions({ false }, {}, {}, {}, {}), NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
{ {
IconButton(onClick = { /*TODO*/ }) { IconButton(onClick = { /*TODO*/ }) {
Icon( Icon(

View file

@ -41,10 +41,12 @@ fun BasicField(
fun LabelledInputField( fun LabelledInputField(
value: String, value: String,
onNewValue: (String) -> Unit, onNewValue: (String) -> Unit,
@StringRes label: Int @StringRes label: Int,
singleLine: Boolean = false
) { ) {
OutlinedTextField( OutlinedTextField(
value = value, value = value,
singleLine = singleLine,
onValueChange = onNewValue, onValueChange = onNewValue,
label = { Text(text = stringResource(id = label)) }, label = { Text(text = stringResource(id = label)) },
modifier = Modifier.fieldModifier() modifier = Modifier.fieldModifier()

View file

@ -0,0 +1,48 @@
package be.ugent.sel.studeez.common.composable
import android.app.TimePickerDialog
import android.app.TimePickerDialog.OnTimeSetListener
import android.content.Context
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
import java.util.*
@Composable
fun TimePickerButton(
hoursMinutesSeconds: HoursMinutesSeconds,
modifier: Modifier = Modifier,
colors: ButtonColors = ButtonDefaults.buttonColors(),
border: BorderStroke? = null,
onTimeSetListener: OnTimeSetListener
) {
val context = LocalContext.current
Button(
onClick = { pickDuration(context, onTimeSetListener) },
modifier = modifier,
shape = RoundedCornerShape(20.dp),
colors = colors,
border = border
) {
Text(text = hoursMinutesSeconds.toString())
}
}
private fun pickDuration(context: Context, listener: OnTimeSetListener) {
val timePickerDialog = TimePickerDialog(
context,
listener,
0,
0,
true
)
timePickerDialog.show()
}

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.common.composable.drawer package be.ugent.sel.studeez.common.composable.drawer
import android.content.Context
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box 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.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -28,7 +30,7 @@ data class DrawerActions(
val onTimersClick: () -> Unit, val onTimersClick: () -> Unit,
val onSettingsClick: () -> Unit, val onSettingsClick: () -> Unit,
val onLogoutClick: () -> Unit, val onLogoutClick: () -> Unit,
val onAboutClick: () -> Unit, val onAboutClick: (Context) -> Unit,
) )
fun getDrawerActions( fun getDrawerActions(
@ -41,7 +43,7 @@ fun getDrawerActions(
onTimersClick = { drawerViewModel.onTimersClick(open) }, onTimersClick = { drawerViewModel.onTimersClick(open) },
onSettingsClick = { drawerViewModel.onSettingsClick(open) }, onSettingsClick = { drawerViewModel.onSettingsClick(open) },
onLogoutClick = { drawerViewModel.onLogoutClick(openAndPopUp) }, 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( DrawerEntry(
icon = Icons.Outlined.Info, icon = Icons.Outlined.Info,
text = resources().getString(R.string.about), text = resources().getString(R.string.about),
onClick = drawerActions.onAboutClick, onClick = { drawerActions.onAboutClick(context) },
) )
} }
} }
@ -96,7 +99,7 @@ fun DrawerEntry(
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.clickable(onClick = { onClick() }) .clickable(onClick = onClick)
.fillMaxWidth() .fillMaxWidth()
) { ) {
Box( Box(

View file

@ -1,5 +1,10 @@
package be.ugent.sel.studeez.common.composable.drawer 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.AccountDAO
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.navigation.StudeezDestinations 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 dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
const val REPO_URL: String = "https://github.ugent.be/SELab1/project2023-groep14/"
@HiltViewModel @HiltViewModel
class DrawerViewModel @Inject constructor( class DrawerViewModel @Inject constructor(
private val accountDAO: AccountDAO, private val accountDAO: AccountDAO,
@ -20,11 +27,11 @@ class DrawerViewModel @Inject constructor(
} }
fun onTimersClick(openAndPopup: (String) -> Unit) { fun onTimersClick(openAndPopup: (String) -> Unit) {
openAndPopup(StudeezDestinations.TIMER_OVERVIEW_SCREEN) openAndPopup(StudeezDestinations.TIMER_SCREEN)
} }
fun onSettingsClick(open: (String) -> Unit) { fun onSettingsClick(open: (String) -> Unit) {
// TODO open(StudeezDestinations.SETTINGS_SCREEN)
} }
fun onLogoutClick(openAndPopUp: (String, String) -> Unit) { fun onLogoutClick(openAndPopUp: (String, String) -> Unit) {
@ -34,7 +41,8 @@ class DrawerViewModel @Inject constructor(
} }
} }
fun onAboutClick(open: (String) -> Unit) { fun onAboutClick(open: (String) -> Unit, context: Context) {
// TODO val intent = Intent(Intent.ACTION_VIEW, Uri.parse(REPO_URL))
context.startActivity(intent)
} }
} }

View file

@ -14,16 +14,24 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN 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.PROFILE_SCREEN
import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN
import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN
import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme import be.ugent.sel.studeez.ui.theme.StudeezTheme
import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.R.string as AppText
data class NavigationBarActions( data class NavigationBarActions(
val isSelectedTab: (String) -> Boolean, val isSelectedTab: (String) -> Boolean,
val onHomeClick: () -> Unit, val onHomeClick: () -> Unit,
val onTasksClick: () -> Unit, val onTasksClick: () -> Unit,
val onSessionsClick: () -> Unit, val onSessionsClick: () -> Unit,
val onProfileClick: () -> Unit, val onProfileClick: () -> Unit,
// AddButton
val onAddTaskClick: () -> Unit,
val onAddFriendClick: () -> Unit,
val onAddSessionClick: () -> Unit
) )
fun getNavigationBarActions( fun getNavigationBarActions(
@ -35,6 +43,7 @@ fun getNavigationBarActions(
isSelectedTab = { screen -> isSelectedTab = { screen ->
screen == getCurrentScreen() screen == getCurrentScreen()
}, },
onHomeClick = { onHomeClick = {
navigationBarViewModel.onHomeClick(open) navigationBarViewModel.onHomeClick(open)
}, },
@ -47,6 +56,16 @@ fun getNavigationBarActions(
onProfileClick = { onProfileClick = {
navigationBarViewModel.onProfileClick(open) navigationBarViewModel.onProfileClick(open)
}, },
onAddTaskClick = {
navigationBarViewModel.onAddTaskClick(open)
},
onAddFriendClick = {
navigationBarViewModel.onAddFriendClick(open)
},
onAddSessionClick = {
navigationBarViewModel.onAddSessionClick(open)
}
) )
} }
@ -71,13 +90,12 @@ fun NavigationBar(
) )
}, },
label = { Text(text = resources().getString(AppText.tasks)) }, label = { Text(text = resources().getString(AppText.tasks)) },
// TODO selected = navigationBarActions.isSelectedTab(TASKS_SCREEN), selected = navigationBarActions.isSelectedTab(TASKS_SCREEN),
selected = false,
onClick = navigationBarActions.onTasksClick onClick = navigationBarActions.onTasksClick
) )
// Hack to space the entries in the navigation bar, make space for fab // 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( BottomNavigationItem(
icon = { icon = {
@ -86,8 +104,7 @@ fun NavigationBar(
) )
}, },
label = { Text(text = resources().getString(AppText.sessions)) }, label = { Text(text = resources().getString(AppText.sessions)) },
// TODO selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN),
selected = false,
onClick = navigationBarActions.onSessionsClick onClick = navigationBarActions.onSessionsClick
) )
@ -110,7 +127,7 @@ fun NavigationBar(
fun NavigationBarPreview() { fun NavigationBarPreview() {
StudeezTheme { StudeezTheme {
NavigationBar( NavigationBar(
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}), navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
) )
} }
} }

View file

@ -1,12 +1,16 @@
package be.ugent.sel.studeez.common.composable.navbar package be.ugent.sel.studeez.common.composable.navbar
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN 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.PROFILE_SCREEN
import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN
import be.ugent.sel.studeez.navigation.StudeezDestinations.TASKS_SCREEN
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
import be.ugent.sel.studeez.R.string as AppText
@HiltViewModel @HiltViewModel
class NavigationBarViewModel @Inject constructor( class NavigationBarViewModel @Inject constructor(
@ -19,14 +23,29 @@ class NavigationBarViewModel @Inject constructor(
} }
fun onTasksClick(open: (String) -> Unit) { fun onTasksClick(open: (String) -> Unit) {
// TODO open(TASKS_SCREEN)
} }
fun onSessionsClick(open: (String) -> Unit) { fun onSessionsClick(open: (String) -> Unit) {
// TODO open(SESSIONS_SCREEN)
} }
fun onProfileClick(open: (String) -> Unit) { fun onProfileClick(open: (String) -> Unit) {
open(PROFILE_SCREEN) 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
}
} }

View file

@ -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)
}

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.data
class EditTimerState {
}

View file

@ -1,4 +1,15 @@
package be.ugent.sel.studeez.data.local.models.timer_functional package be.ugent.sel.studeez.data.local.models.timer_functional
data class HoursMinutesSeconds(val hours: String, val minutes: String, val seconds: String data class HoursMinutesSeconds(val hours: Int, val minutes: Int, val seconds: Int) {
)
fun getTotalSeconds(): Int {
return hours * 60 * 60 + minutes * 60 + seconds
}
override fun toString(): String {
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"
}
}

View file

@ -17,11 +17,7 @@ class Time(initialTime: Int) {
val minutes: Int = (time / (60)) % 60 val minutes: Int = (time / (60)) % 60
val seconds: Int = time % 60 val seconds: Int = time % 60
return HoursMinutesSeconds( return HoursMinutesSeconds(hours, minutes, seconds)
hours.toString().padStart(2, '0'),
minutes.toString().padStart(2, '0'),
seconds.toString().padStart(2, '0')
)
} }
} }

View file

@ -6,11 +6,10 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
class CustomTimerInfo( class CustomTimerInfo(
name: String, name: String,
description: String, description: String,
private val studyTime: Int, var studyTime: Int,
id: String = "" id: String = ""
): TimerInfo(id, name, description) { ): TimerInfo(id, name, description) {
override fun getFunctionalTimer(): FunctionalTimer { override fun getFunctionalTimer(): FunctionalTimer {
return FunctionalCustomTimer(studyTime) return FunctionalCustomTimer(studyTime)
} }
@ -24,4 +23,8 @@ class CustomTimerInfo(
) )
} }
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
return visitor.visitCustomTimerInfo(this)
}
} }

View file

@ -22,4 +22,8 @@ class EndlessTimerInfo(
) )
} }
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
return visitor.visitEndlessTimerInfo(this)
}
} }

View file

@ -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.FunctionalPomodoroTimer
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimerVisitor
class PomodoroTimerInfo( class PomodoroTimerInfo(
name: String, name: String,
description: String, description: String,
private val studyTime: Int, val studyTime: Int,
private val breakTime: Int, val breakTime: Int,
private val repeats: Int, val repeats: Int,
id: String = "" id: String = ""
): TimerInfo(id, name, description) { ): TimerInfo(id, name, description) {
@ -28,4 +29,8 @@ class PomodoroTimerInfo(
) )
} }
override fun <T> accept(visitor: TimerInfoVisitor<T>): T {
return visitor.visitBreakTimerInfo(this)
}
} }

View file

@ -7,8 +7,8 @@ import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
*/ */
abstract class TimerInfo( abstract class TimerInfo(
val id: String, val id: String,
val name: String, var name: String,
val description: String var description: String
) { ) {
/** /**
@ -21,6 +21,7 @@ abstract class TimerInfo(
* TODO implementaties hebben nog hardgecodeerde strings. * TODO implementaties hebben nog hardgecodeerde strings.
*/ */
abstract fun asJson(): Map<String, Any> abstract fun asJson(): Map<String, Any>
abstract fun <T> accept(visitor: TimerInfoVisitor<T>): T
} }

View file

@ -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
}

View file

@ -1,23 +1,32 @@
package be.ugent.sel.studeez.navigation package be.ugent.sel.studeez.navigation
object StudeezDestinations { object StudeezDestinations {
const val SPLASH_SCREEN = "splash" // NavBar
const val SIGN_UP_SCREEN = "signup"
const val LOGIN_SCREEN = "login"
const val HOME_SCREEN = "home" const val HOME_SCREEN = "home"
const val TIMER_OVERVIEW_SCREEN = "timer_overview" const val TASKS_SCREEN = "tasks"
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_SELECTION_SCREEN = "timer_selection"
const val SESSION_SCREEN = "session" const val SESSION_SCREEN = "session"
const val SESSION_RECAP = "session_recap" const val SESSION_RECAP = "session_recap"
// const val TASKS_SCREEN = "tasks"
// const val SESSIONS_SCREEN = "sessions"
const val PROFILE_SCREEN = "profile"
// const val TIMERS_SCREEN = "timers" // Friends flow
// const val SETTINGS_SCREEN = "settings" const val SEARCH_FRIENDS_SCREEN = "search_friends"
// 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 EDIT_PROFILE_SCREEN = "edit_profile"
const val ADD_TIMER_SCREEN = "add_timer" const val ADD_TIMER_SCREEN = "add_timer"

View file

@ -33,13 +33,13 @@ fun HomeRoute(
fun HomeScreen( fun HomeScreen(
onStartSessionClick: () -> Unit, onStartSessionClick: () -> Unit,
drawerActions: DrawerActions, drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions, navigationBarActions: NavigationBarActions
) { ) {
PrimaryScreenTemplate( PrimaryScreenTemplate(
title = resources().getString(R.string.home), title = resources().getString(R.string.home),
drawerActions = drawerActions, drawerActions = drawerActions,
navigationBarActions = navigationBarActions, navigationBarActions = navigationBarActions,
barAction = { FriendsAction() } // TODO barAction = { FriendsAction() }
) { ) {
BasicButton(R.string.start_session, Modifier.basicButton()) { BasicButton(R.string.start_session, Modifier.basicButton()) {
onStartSessionClick() onStartSessionClick()
@ -63,6 +63,6 @@ fun HomeScreenPreview() {
HomeScreen( HomeScreen(
onStartSessionClick = {}, onStartSessionClick = {},
drawerActions = DrawerActions({}, {}, {}, {}, {}), drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
) )
} }

View file

@ -63,7 +63,10 @@ fun EditProfileScreen(
BasicTextButton( BasicTextButton(
text = R.string.save, text = R.string.save,
Modifier.textButton(), Modifier.textButton(),
action = editProfileActions.onSaveClick action = {
editProfileActions.onSaveClick()
goBack()
}
) )
BasicTextButton( BasicTextButton(
text = R.string.delete_profile, text = R.string.delete_profile,

View file

@ -88,6 +88,6 @@ fun ProfileScreenPreview() {
ProfileScreen( ProfileScreen(
profileActions = ProfileActions({ null }, {}), profileActions = ProfileActions({ null }, {}),
drawerActions = DrawerActions({}, {}, {}, {}, {}), drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}) navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
) )
} }

View file

@ -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
)
}
}

View file

@ -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
)
}
}

View file

@ -0,0 +1,35 @@
package be.ugent.sel.studeez.screens.timer_edit
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.data.local.models.timer_info.CustomTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.PomodoroTimerInfo
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfoVisitor
class GetTimerEditView: TimerInfoVisitor<Unit> {
@SuppressLint("ComposableNaming")
override fun visitCustomTimerInfo(customTimerInfo: CustomTimerInfo) {
}
@SuppressLint("ComposableNaming")
override fun visitEndlessTimerInfo(endlessTimerInfo: EndlessTimerInfo) {
}
@SuppressLint("ComposableNaming")
override fun visitBreakTimerInfo(pomodoroTimerInfo: PomodoroTimerInfo) {
}
}

View file

@ -0,0 +1,2 @@
package be.ugent.sel.studeez.screens.timer_edit

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit
class TimerEditViewModel {
}

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit
abstract class AbstractTimerEditScreen {
}

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
class BreakTimerEditScreen {
}

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit
class CustomTimerEditScreen {
}

View file

@ -0,0 +1,4 @@
package be.ugent.sel.studeez.screens.timer_edit.editScreens
class EndlessTimerEditScreen {
}

View file

@ -64,6 +64,14 @@ fun TimerOverviewScreen(
drawerActions = drawerActions drawerActions = drawerActions
) { ) {
LazyColumn { 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 // Default Timers, cannot be edited
items(timerOverviewActions.getDefaultTimers()) { items(timerOverviewActions.getDefaultTimers()) {
TimerEntry(timerInfo = it) {} TimerEntry(timerInfo = it) {}

View file

@ -1,14 +1,20 @@
package be.ugent.sel.studeez.screens.timer_selection package be.ugent.sel.studeez.screens.timer_selection
import android.widget.TimePicker
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.composable.StealthButton 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.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.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.resources
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -17,6 +23,8 @@ import kotlinx.coroutines.flow.flowOf
data class TimerSelectionActions( data class TimerSelectionActions(
val getAllTimers: () -> Flow<List<TimerInfo>>, val getAllTimers: () -> Flow<List<TimerInfo>>,
val startSession: (TimerInfo) -> Unit, val startSession: (TimerInfo) -> Unit,
val pickDuration: (TimePicker?, Int, Int) -> Unit,
val customTimeStudyTime: Int
) )
fun getTimerSelectionActions( fun getTimerSelectionActions(
@ -26,6 +34,10 @@ fun getTimerSelectionActions(
return TimerSelectionActions( return TimerSelectionActions(
getAllTimers = viewModel::getAllTimers, getAllTimers = viewModel::getAllTimers,
startSession = { viewModel.startSession(open, it) }, startSession = { viewModel.startSession(open, it) },
pickDuration = { _, hour: Int, minute: Int ->
viewModel.customTimerStudyTime.value = hour * 60 * 60 + minute * 60
},
customTimeStudyTime = viewModel.customTimerStudyTime.value
) )
} }
@ -52,6 +64,11 @@ fun TimerSelectionScreen(
popUp = popUp popUp = popUp
) { ) {
LazyColumn { LazyColumn {
// Custom timer with duration selection button
item {
CustomTimerEntry(timerSelectionActions)
}
// All timers // All timers
items(timers.value) { timerInfo -> items(timers.value) { timerInfo ->
TimerEntry( TimerEntry(
@ -68,11 +85,39 @@ 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(
hoursMinutesSeconds = hms,
onTimeSetListener = timerSelectionActions.pickDuration
)
}
)
}
@Preview @Preview
@Composable @Composable
fun TimerSelectionPreview() { fun TimerSelectionPreview() {
TimerSelectionScreen( TimerSelectionScreen(
timerSelectionActions = TimerSelectionActions({ flowOf() }, {}), timerSelectionActions = TimerSelectionActions({ flowOf() }, {}, { _, _, _ -> {} }, 0),
popUp = {} popUp = {}
) )
} }

View file

@ -1,5 +1,9 @@
package be.ugent.sel.studeez.screens.timer_selection 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.SelectedTimerState
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
@ -17,6 +21,8 @@ class TimerSelectionViewModel @Inject constructor(
logService: LogService logService: LogService
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
var customTimerStudyTime: MutableState<Int> = mutableStateOf(0)
fun getAllTimers() : Flow<List<TimerInfo>> { fun getAllTimers() : Flow<List<TimerInfo>> {
return timerDAO.getAllTimers() return timerDAO.getAllTimers()
} }

View file

@ -12,7 +12,9 @@ import androidx.compose.ui.graphics.Color
private val DarkColorPalette = darkColors( private val DarkColorPalette = darkColors(
primary = Blue100, primary = Blue100,
primaryVariant = Blue120, primaryVariant = Blue120,
secondary = Yellow100 secondary = Yellow100,
onPrimary = Color.White
) )
private val LightColorPalette = lightColors( private val LightColorPalette = lightColors(

View file

@ -1,5 +1,6 @@
<resources> <resources>
<!-- Common --> <!-- ========== Common ========== -->
<string name="app_name">Studeez</string> <string name="app_name">Studeez</string>
<string name="username">Username</string> <string name="username">Username</string>
<string name="email">Email</string> <string name="email">Email</string>
@ -22,6 +23,61 @@
<string name="generic_error">Something wrong happened. Please try again.</string> <string name="generic_error">Something wrong happened. Please try again.</string>
<string name="email_error">Please insert a valid email.</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>
<!-- 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 --> <!-- SignUpScreen -->
<string name="create_account">Create account</string> <string name="create_account">Create account</string>
<string name="password_error">Your password should have at least six characters and include one digit, one lower case letter and one upper case letter.</string> <string name="password_error">Your password should have at least six characters and include one digit, one lower case letter and one upper case letter.</string>
@ -36,50 +92,21 @@
<string name="recovery_email_sent">Check your inbox for the recovery email.</string> <string name="recovery_email_sent">Check your inbox for the recovery email.</string>
<string name="empty_password_error">Password cannot be empty.</string> <string name="empty_password_error">Password cannot be empty.</string>
<!-- HomeScreen --> <!-- ========== Studying flow ========== -->
<string name="home">Home</string>
<string name="start_session">Start session</string>
<!-- Tasks --> <!-- ========== Friends flow ========== -->
<string name="tasks">Tasks</string>
<!-- Sessions -->
<string name="sessions">Sessions</string>
<string name="end_session">End session</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="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 --> <!-- ========== Create & edit screens ========== -->
<string name="log_out">Log out</string>
<string name="profile_picture_description">Profile Picture</string>
<string name="user_description">Normal user</string>
<!-- Timers --> <!-- Task -->
<string name="timers">Timers</string> <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. -->
<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>
<!-- Settings --> <!-- Session -->
<string name="settings">Settings</string> <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. -->
<!-- About -->
<string name="about">About Studeez</string>
<!-- Add Timer --> <!-- Add Timer -->
<string name="addTimer_description_error">Timer description cannot be empty!</string> <string name="addTimer_description_error">Timer description cannot be empty!</string>