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
	
	 brreynie
						brreynie