commit
e8c073039e
12 changed files with 143 additions and 49 deletions
|
@ -2,6 +2,7 @@ package be.ugent.sel.studeez.common.composable
|
|||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -20,6 +21,7 @@ import androidx.compose.material.icons.filled.Add
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
@ -48,6 +50,7 @@ fun BasicButton(
|
|||
modifier: Modifier = Modifier,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
border: BorderStroke? = null,
|
||||
enabled: Boolean = true,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Button(
|
||||
|
@ -56,6 +59,7 @@ fun BasicButton(
|
|||
shape = defaultButtonShape(),
|
||||
colors = colors,
|
||||
border = border,
|
||||
enabled = enabled,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(text),
|
||||
|
@ -74,17 +78,22 @@ fun BasicButtonPreview() {
|
|||
fun StealthButton(
|
||||
@StringRes text: Int,
|
||||
modifier: Modifier = Modifier.card(),
|
||||
enabled: Boolean = true,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
//val clickablemodifier = if (disabled) Modifier.clickable(indication = null) else modifier
|
||||
val borderColor = if (enabled) MaterialTheme.colors.primary
|
||||
else MaterialTheme.colors.onSurface.copy(alpha = 0.3f)
|
||||
BasicButton(
|
||||
text = text,
|
||||
onClick = onClick,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = MaterialTheme.colors.surface,
|
||||
contentColor = MaterialTheme.colors.onSurface.copy(alpha = 0.4f)
|
||||
contentColor = borderColor
|
||||
),
|
||||
border = BorderStroke(3.dp, MaterialTheme.colors.onSurface.copy(alpha = 0.4f))
|
||||
border = BorderStroke(2.dp, borderColor)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,58 +9,105 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import be.ugent.sel.studeez.common.composable.BasicTextButton
|
||||
import be.ugent.sel.studeez.common.composable.DateText
|
||||
import be.ugent.sel.studeez.common.composable.Headline
|
||||
import be.ugent.sel.studeez.common.ext.textButton
|
||||
import be.ugent.sel.studeez.data.local.models.FeedEntry
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
fun Feed(
|
||||
uiState: FeedUiState,
|
||||
continueTask: (String, String) -> Unit,
|
||||
onEmptyFeedHelp: () -> Unit
|
||||
) {
|
||||
when (uiState) {
|
||||
FeedUiState.Loading -> {
|
||||
Column(
|
||||
FeedUiState.Loading -> LoadingFeed()
|
||||
is FeedUiState.Succes -> LoadedFeed(
|
||||
uiState = uiState,
|
||||
continueTask = continueTask,
|
||||
onEmptyFeedHelp = onEmptyFeedHelp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadedFeed(
|
||||
uiState: FeedUiState.Succes,
|
||||
continueTask: (String, String) -> Unit,
|
||||
onEmptyFeedHelp: () -> Unit,
|
||||
) {
|
||||
if (uiState.feedEntries.isEmpty()) EmptyFeed(onEmptyFeedHelp)
|
||||
else FeedWithElements(uiState = uiState, continueTask = continueTask)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingFeed() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FeedWithElements(
|
||||
uiState: FeedUiState.Succes,
|
||||
continueTask: (String, String) -> Unit,
|
||||
) {
|
||||
val feedEntries = uiState.feedEntries
|
||||
LazyColumn {
|
||||
items(feedEntries.toList()) { (date, feedEntries) ->
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
|
||||
val totalDayStudyTime: Int = feedEntries.sumOf { it.totalStudyTime }
|
||||
DateText(date = date)
|
||||
Text(
|
||||
text = "${HoursMinutesSeconds(totalDayStudyTime)}",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
is FeedUiState.Succes -> {
|
||||
val feedEntries = uiState.feedEntries
|
||||
LazyColumn {
|
||||
items(feedEntries.toList()) { (date, feedEntries) ->
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val totalDayStudyTime: Int = feedEntries.sumOf { it.totalStudyTime }
|
||||
DateText(date = date)
|
||||
Text(
|
||||
text = "${HoursMinutesSeconds(totalDayStudyTime)}",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
feedEntries.forEach { feedEntry ->
|
||||
FeedEntry(feedEntry = feedEntry) {
|
||||
continueTask(feedEntry.subjectId, feedEntry.taskId)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
feedEntries.forEach { feedEntry ->
|
||||
FeedEntry(feedEntry = feedEntry) {
|
||||
continueTask(feedEntry.subjectId, feedEntry.taskId)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmptyFeed(onEmptyFeedHelp: () -> Unit) {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Headline(text = stringResource(id = AppText.your_feed))
|
||||
|
||||
BasicTextButton(
|
||||
AppText.empty_feed_help_text,
|
||||
Modifier.textButton(),
|
||||
action = onEmptyFeedHelp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +117,7 @@ fun Feed(
|
|||
fun FeedLoadingPreview() {
|
||||
Feed(
|
||||
uiState = FeedUiState.Loading,
|
||||
continueTask = { _, _ -> run {} },
|
||||
continueTask = { _, _ -> run {} }, {}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -108,6 +155,6 @@ fun FeedPreview() {
|
|||
)
|
||||
)
|
||||
),
|
||||
continueTask = { _, _ -> run {} },
|
||||
continueTask = { _, _ -> run {} }, {}
|
||||
)
|
||||
}
|
|
@ -18,6 +18,7 @@ import be.ugent.sel.studeez.R
|
|||
import be.ugent.sel.studeez.common.composable.StealthButton
|
||||
import be.ugent.sel.studeez.data.local.models.FeedEntry
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@Composable
|
||||
fun FeedEntry(
|
||||
|
@ -69,14 +70,19 @@ fun FeedEntry(
|
|||
Text(text = HoursMinutesSeconds(feedEntry.totalStudyTime).toString())
|
||||
}
|
||||
}
|
||||
val buttonText: Int = if (feedEntry.isArchived) AppText.deleted else AppText.continue_task
|
||||
StealthButton(
|
||||
text = R.string.continue_task,
|
||||
text = buttonText,
|
||||
enabled = !feedEntry.isArchived,
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp, end = 5.dp)
|
||||
.weight(6f)
|
||||
) {
|
||||
continueWithTask()
|
||||
if (!feedEntry.isArchived) {
|
||||
continueWithTask()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,4 +38,8 @@ class FeedViewModel @Inject constructor(
|
|||
open(StudeezDestinations.TIMER_SELECTION_SCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
fun onEmptyFeedHelp(open: (String) -> Unit) {
|
||||
open(StudeezDestinations.ADD_SUBJECT_FORM)
|
||||
}
|
||||
}
|
|
@ -1,14 +1,25 @@
|
|||
package be.ugent.sel.studeez.common.ext
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
fun Modifier.textButton(): Modifier {
|
||||
return this.fillMaxWidth().padding(16.dp, 8.dp, 16.dp, 0.dp)
|
||||
}
|
||||
|
||||
fun Modifier.noRippleClickable(onClick: () -> Unit): Modifier = composed {
|
||||
clickable(indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }) {
|
||||
onClick()
|
||||
}
|
||||
}
|
||||
|
||||
fun Modifier.basicButton(): Modifier {
|
||||
return this.fillMaxWidth().padding(16.dp, 8.dp)
|
||||
}
|
||||
|
|
|
@ -9,5 +9,6 @@ data class FeedEntry(
|
|||
val taskId: String = "", // Name of task is not unique
|
||||
val subjectId: String = "",
|
||||
val totalStudyTime: Int = 0,
|
||||
val endTime: Timestamp = Timestamp(0, 0)
|
||||
val endTime: Timestamp = Timestamp(0, 0),
|
||||
val isArchived: Boolean = false
|
||||
)
|
||||
|
|
|
@ -74,7 +74,8 @@ class FirebaseFeedDAO @Inject constructor(
|
|||
taskId = task.id,
|
||||
subjectId = subject.id,
|
||||
totalStudyTime = sessionReport.studyTime,
|
||||
endTime = sessionReport.endTime
|
||||
endTime = sessionReport.endTime,
|
||||
isArchived = task.archived || subject.archived
|
||||
)
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ fun HomeRoute(
|
|||
navigationBarActions = navigationBarActions,
|
||||
feedUiState = feedUiState,
|
||||
continueTask = { subjectId, taskId -> feedViewModel.continueTask(open, subjectId, taskId) },
|
||||
onEmptyFeedHelp = { feedViewModel.onEmptyFeedHelp(open) }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ fun HomeScreen(
|
|||
navigationBarActions: NavigationBarActions,
|
||||
feedUiState: FeedUiState,
|
||||
continueTask: (String, String) -> Unit,
|
||||
onEmptyFeedHelp: () -> Unit,
|
||||
) {
|
||||
PrimaryScreenTemplate(
|
||||
title = resources().getString(R.string.home),
|
||||
|
@ -49,7 +51,7 @@ fun HomeScreen(
|
|||
navigationBarActions = navigationBarActions,
|
||||
// TODO barAction = { FriendsAction() }
|
||||
) {
|
||||
Feed(feedUiState, continueTask)
|
||||
Feed(feedUiState, continueTask, onEmptyFeedHelp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,5 +103,6 @@ fun HomeScreenPreview() {
|
|||
)
|
||||
),
|
||||
continueTask = { _, _ -> run {} },
|
||||
onEmptyFeedHelp = {}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -82,12 +82,13 @@ fun TimerOverviewScreen(
|
|||
items(timers.value) { timerInfo ->
|
||||
TimerEntry(
|
||||
timerInfo = timerInfo,
|
||||
) {
|
||||
StealthButton(
|
||||
text = R.string.edit,
|
||||
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
||||
)
|
||||
}
|
||||
rightButton = {
|
||||
StealthButton(
|
||||
text = R.string.edit,
|
||||
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package be.ugent.sel.studeez.screens.timer_selection
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
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.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.StealthButton
|
||||
|
@ -99,7 +102,10 @@ fun CustomTimerEntry(
|
|||
)
|
||||
},
|
||||
rightButton = {
|
||||
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
|
||||
TimePickerButton(
|
||||
initialSeconds = hms.getTotalSeconds(),
|
||||
modifier = Modifier.padding(horizontal = 5.dp)
|
||||
) { chosenTime ->
|
||||
timerInfo.studyTime = chosenTime
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ 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_functional.HoursMinutesSeconds
|
||||
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
|
||||
|
@ -21,7 +22,9 @@ class TimerSelectionViewModel @Inject constructor(
|
|||
logService: LogService
|
||||
) : StudeezViewModel(logService) {
|
||||
|
||||
var customTimerStudyTime: MutableState<Int> = mutableStateOf(0)
|
||||
var customTimerStudyTime: MutableState<Int> = mutableStateOf(
|
||||
HoursMinutesSeconds(1, 0, 0).getTotalSeconds()
|
||||
)
|
||||
|
||||
fun getAllTimers() : Flow<List<TimerInfo>> {
|
||||
return timerDAO.getAllTimers()
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
<!-- Feed-->
|
||||
<string name="continue_task">Continue</string>
|
||||
<string name="your_feed">This is your feed</string>
|
||||
<string name="empty_feed_help_text">Create you first subject and tasks to get started</string>
|
||||
|
||||
<!-- Tasks -->
|
||||
<string name="tasks">Tasks</string>
|
||||
|
|
Reference in a new issue