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.annotation.StringRes
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
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.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
@ -48,6 +50,7 @@ fun BasicButton(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||||
border: BorderStroke? = null,
|
border: BorderStroke? = null,
|
||||||
|
enabled: Boolean = true,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Button(
|
Button(
|
||||||
|
@ -56,6 +59,7 @@ fun BasicButton(
|
||||||
shape = defaultButtonShape(),
|
shape = defaultButtonShape(),
|
||||||
colors = colors,
|
colors = colors,
|
||||||
border = border,
|
border = border,
|
||||||
|
enabled = enabled,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(text),
|
text = stringResource(text),
|
||||||
|
@ -74,17 +78,22 @@ fun BasicButtonPreview() {
|
||||||
fun StealthButton(
|
fun StealthButton(
|
||||||
@StringRes text: Int,
|
@StringRes text: Int,
|
||||||
modifier: Modifier = Modifier.card(),
|
modifier: Modifier = Modifier.card(),
|
||||||
|
enabled: Boolean = true,
|
||||||
onClick: () -> Unit,
|
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(
|
BasicButton(
|
||||||
text = text,
|
text = text,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
backgroundColor = MaterialTheme.colors.surface,
|
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,21 +9,47 @@ import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
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
|
||||||
import androidx.compose.ui.unit.sp
|
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.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.FeedEntry
|
||||||
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
|
||||||
|
import be.ugent.sel.studeez.R.string as AppText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Feed(
|
fun Feed(
|
||||||
uiState: FeedUiState,
|
uiState: FeedUiState,
|
||||||
continueTask: (String, String) -> Unit,
|
continueTask: (String, String) -> Unit,
|
||||||
|
onEmptyFeedHelp: () -> Unit
|
||||||
) {
|
) {
|
||||||
when (uiState) {
|
when (uiState) {
|
||||||
FeedUiState.Loading -> {
|
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(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -33,8 +59,13 @@ fun Feed(
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
|
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FeedUiState.Succes -> {
|
|
||||||
|
@Composable
|
||||||
|
fun FeedWithElements(
|
||||||
|
uiState: FeedUiState.Succes,
|
||||||
|
continueTask: (String, String) -> Unit,
|
||||||
|
) {
|
||||||
val feedEntries = uiState.feedEntries
|
val feedEntries = uiState.feedEntries
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
items(feedEntries.toList()) { (date, feedEntries) ->
|
items(feedEntries.toList()) { (date, feedEntries) ->
|
||||||
|
@ -61,6 +92,22 @@ fun Feed(
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
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() {
|
fun FeedLoadingPreview() {
|
||||||
Feed(
|
Feed(
|
||||||
uiState = FeedUiState.Loading,
|
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.common.composable.StealthButton
|
||||||
import be.ugent.sel.studeez.data.local.models.FeedEntry
|
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.data.local.models.timer_functional.HoursMinutesSeconds
|
||||||
|
import be.ugent.sel.studeez.R.string as AppText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FeedEntry(
|
fun FeedEntry(
|
||||||
|
@ -69,15 +70,20 @@ fun FeedEntry(
|
||||||
Text(text = HoursMinutesSeconds(feedEntry.totalStudyTime).toString())
|
Text(text = HoursMinutesSeconds(feedEntry.totalStudyTime).toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val buttonText: Int = if (feedEntry.isArchived) AppText.deleted else AppText.continue_task
|
||||||
StealthButton(
|
StealthButton(
|
||||||
text = R.string.continue_task,
|
text = buttonText,
|
||||||
|
enabled = !feedEntry.isArchived,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 10.dp, end = 5.dp)
|
.padding(start = 10.dp, end = 5.dp)
|
||||||
.weight(6f)
|
.weight(6f)
|
||||||
) {
|
) {
|
||||||
|
if (!feedEntry.isArchived) {
|
||||||
continueWithTask()
|
continueWithTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,4 +38,8 @@ class FeedViewModel @Inject constructor(
|
||||||
open(StudeezDestinations.TIMER_SELECTION_SCREEN)
|
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
|
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.foundation.layout.*
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.composed
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
fun Modifier.textButton(): Modifier {
|
fun Modifier.textButton(): Modifier {
|
||||||
return this.fillMaxWidth().padding(16.dp, 8.dp, 16.dp, 0.dp)
|
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 {
|
fun Modifier.basicButton(): Modifier {
|
||||||
return this.fillMaxWidth().padding(16.dp, 8.dp)
|
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 taskId: String = "", // Name of task is not unique
|
||||||
val subjectId: String = "",
|
val subjectId: String = "",
|
||||||
val totalStudyTime: Int = 0,
|
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,
|
taskId = task.id,
|
||||||
subjectId = subject.id,
|
subjectId = subject.id,
|
||||||
totalStudyTime = sessionReport.studyTime,
|
totalStudyTime = sessionReport.studyTime,
|
||||||
endTime = sessionReport.endTime
|
endTime = sessionReport.endTime,
|
||||||
|
isArchived = task.archived || subject.archived
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,6 +32,7 @@ fun HomeRoute(
|
||||||
navigationBarActions = navigationBarActions,
|
navigationBarActions = navigationBarActions,
|
||||||
feedUiState = feedUiState,
|
feedUiState = feedUiState,
|
||||||
continueTask = { subjectId, taskId -> feedViewModel.continueTask(open, subjectId, taskId) },
|
continueTask = { subjectId, taskId -> feedViewModel.continueTask(open, subjectId, taskId) },
|
||||||
|
onEmptyFeedHelp = { feedViewModel.onEmptyFeedHelp(open) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ fun HomeScreen(
|
||||||
navigationBarActions: NavigationBarActions,
|
navigationBarActions: NavigationBarActions,
|
||||||
feedUiState: FeedUiState,
|
feedUiState: FeedUiState,
|
||||||
continueTask: (String, String) -> Unit,
|
continueTask: (String, String) -> Unit,
|
||||||
|
onEmptyFeedHelp: () -> Unit,
|
||||||
) {
|
) {
|
||||||
PrimaryScreenTemplate(
|
PrimaryScreenTemplate(
|
||||||
title = resources().getString(R.string.home),
|
title = resources().getString(R.string.home),
|
||||||
|
@ -49,7 +51,7 @@ fun HomeScreen(
|
||||||
navigationBarActions = navigationBarActions,
|
navigationBarActions = navigationBarActions,
|
||||||
// TODO barAction = { FriendsAction() }
|
// TODO barAction = { FriendsAction() }
|
||||||
) {
|
) {
|
||||||
Feed(feedUiState, continueTask)
|
Feed(feedUiState, continueTask, onEmptyFeedHelp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,5 +103,6 @@ fun HomeScreenPreview() {
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
continueTask = { _, _ -> run {} },
|
continueTask = { _, _ -> run {} },
|
||||||
|
onEmptyFeedHelp = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,12 +82,13 @@ fun TimerOverviewScreen(
|
||||||
items(timers.value) { timerInfo ->
|
items(timers.value) { timerInfo ->
|
||||||
TimerEntry(
|
TimerEntry(
|
||||||
timerInfo = timerInfo,
|
timerInfo = timerInfo,
|
||||||
) {
|
rightButton = {
|
||||||
StealthButton(
|
StealthButton(
|
||||||
text = R.string.edit,
|
text = R.string.edit,
|
||||||
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
onClick = { timerOverviewActions.onEditClick(timerInfo) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package be.ugent.sel.studeez.screens.timer_selection
|
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.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.Modifier
|
||||||
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.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
|
||||||
|
@ -99,7 +102,10 @@ fun CustomTimerEntry(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
rightButton = {
|
rightButton = {
|
||||||
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
|
TimePickerButton(
|
||||||
|
initialSeconds = hms.getTotalSeconds(),
|
||||||
|
modifier = Modifier.padding(horizontal = 5.dp)
|
||||||
|
) { chosenTime ->
|
||||||
timerInfo.studyTime = chosenTime
|
timerInfo.studyTime = chosenTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
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_functional.HoursMinutesSeconds
|
||||||
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
|
||||||
import be.ugent.sel.studeez.domain.TimerDAO
|
import be.ugent.sel.studeez.domain.TimerDAO
|
||||||
|
@ -21,7 +22,9 @@ class TimerSelectionViewModel @Inject constructor(
|
||||||
logService: LogService
|
logService: LogService
|
||||||
) : StudeezViewModel(logService) {
|
) : StudeezViewModel(logService) {
|
||||||
|
|
||||||
var customTimerStudyTime: MutableState<Int> = mutableStateOf(0)
|
var customTimerStudyTime: MutableState<Int> = mutableStateOf(
|
||||||
|
HoursMinutesSeconds(1, 0, 0).getTotalSeconds()
|
||||||
|
)
|
||||||
|
|
||||||
fun getAllTimers() : Flow<List<TimerInfo>> {
|
fun getAllTimers() : Flow<List<TimerInfo>> {
|
||||||
return timerDAO.getAllTimers()
|
return timerDAO.getAllTimers()
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
<!-- Feed-->
|
<!-- Feed-->
|
||||||
<string name="continue_task">Continue</string>
|
<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 -->
|
<!-- Tasks -->
|
||||||
<string name="tasks">Tasks</string>
|
<string name="tasks">Tasks</string>
|
||||||
|
|
Reference in a new issue