refactor feed to use UiState.Loading
This commit is contained in:
		
							parent
							
								
									d31276ef81
								
							
						
					
					
						commit
						6ba0018765
					
				
					 8 changed files with 131 additions and 101 deletions
				
			
		|  | @ -0,0 +1,99 @@ | ||||||
|  | package be.ugent.sel.studeez.common.composable.feed | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.layout.* | ||||||
|  | import androidx.compose.foundation.lazy.LazyColumn | ||||||
|  | import androidx.compose.foundation.lazy.items | ||||||
|  | import androidx.compose.material.CircularProgressIndicator | ||||||
|  | import androidx.compose.material.MaterialTheme | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | 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.DateText | ||||||
|  | import be.ugent.sel.studeez.data.local.models.FeedEntry | ||||||
|  | import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.flowOf | ||||||
|  | 
 | ||||||
|  | data class FeedActions( | ||||||
|  |     val getFeedEntries: () -> Flow<Map<String, List<FeedEntry>>>, | ||||||
|  |     val continueTask: (String, String) -> Unit, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | fun getFeedActions( | ||||||
|  |     viewmodel: FeedViewModel, | ||||||
|  |     open: (String) -> Unit, | ||||||
|  | ): FeedActions { | ||||||
|  |     return FeedActions( | ||||||
|  |         getFeedEntries = viewmodel::getFeedEntries, | ||||||
|  |         continueTask = { subjectId, taskId -> | ||||||
|  |             viewmodel.continueTask( | ||||||
|  |                 open, | ||||||
|  |                 subjectId, | ||||||
|  |                 taskId, | ||||||
|  |             ) | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun Feed( | ||||||
|  |     feedActions: FeedActions, | ||||||
|  |     uiState: FeedUiState, | ||||||
|  | ) { | ||||||
|  |     when (uiState) { | ||||||
|  |         FeedUiState.Loading -> { | ||||||
|  |             Column( | ||||||
|  |                 modifier = Modifier | ||||||
|  |                     .fillMaxWidth() | ||||||
|  |                     .fillMaxHeight(), | ||||||
|  |                 verticalArrangement = Arrangement.Center, | ||||||
|  |                 horizontalAlignment = Alignment.CenterHorizontally | ||||||
|  |             ) { | ||||||
|  |                 CircularProgressIndicator(color = MaterialTheme.colors.onBackground) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         is FeedUiState.Succes -> { | ||||||
|  | //            val feedEntries = feedActions.getFeedEntries().collectAsState(initial = emptyMap()) | ||||||
|  |             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) { | ||||||
|  |                             feedActions.continueTask(feedEntry.subjectId, feedEntry.taskId) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     Spacer(modifier = Modifier.height(20.dp)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun FeedPreview() { | ||||||
|  |     Feed( | ||||||
|  |         feedActions = FeedActions({ flowOf() }, { _, _ -> run {} }), | ||||||
|  |         uiState = FeedUiState.Loading, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package be.ugent.sel.studeez.screens.home | package be.ugent.sel.studeez.common.composable.feed | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.background | import androidx.compose.foundation.background | ||||||
| import androidx.compose.foundation.layout.* | import androidx.compose.foundation.layout.* | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | package be.ugent.sel.studeez.common.composable.feed | ||||||
|  | 
 | ||||||
|  | import be.ugent.sel.studeez.data.local.models.FeedEntry | ||||||
|  | 
 | ||||||
|  | sealed interface FeedUiState { | ||||||
|  |     object Loading : FeedUiState | ||||||
|  |     data class Succes(val feedEntries: Map<String, List<FeedEntry>>) : FeedUiState | ||||||
|  | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| package be.ugent.sel.studeez.screens.home | package be.ugent.sel.studeez.common.composable.feed | ||||||
| 
 | 
 | ||||||
| import androidx.lifecycle.viewModelScope | import androidx.lifecycle.viewModelScope | ||||||
| import be.ugent.sel.studeez.data.SelectedTask | import be.ugent.sel.studeez.data.SelectedTask | ||||||
|  | @ -9,13 +9,13 @@ import be.ugent.sel.studeez.domain.TaskDAO | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||||
| 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 kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.* | ||||||
| import kotlinx.coroutines.launch | import kotlinx.coroutines.launch | ||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
| 
 | 
 | ||||||
| @HiltViewModel | @HiltViewModel | ||||||
| class FeedViewModel @Inject constructor( | class FeedViewModel @Inject constructor( | ||||||
|     private val feedDAO: FeedDAO, |     feedDAO: FeedDAO, | ||||||
|     private val taskDAO: TaskDAO, |     private val taskDAO: TaskDAO, | ||||||
|     private val selectedTask: SelectedTask, |     private val selectedTask: SelectedTask, | ||||||
|     logService: LogService |     logService: LogService | ||||||
|  | @ -23,6 +23,14 @@ class FeedViewModel @Inject constructor( | ||||||
| 
 | 
 | ||||||
|     private val entries: Flow<Map<String, List<FeedEntry>>> = feedDAO.getFeedEntries() |     private val entries: Flow<Map<String, List<FeedEntry>>> = feedDAO.getFeedEntries() | ||||||
| 
 | 
 | ||||||
|  |     val uiState: StateFlow<FeedUiState> = feedDAO.getFeedEntries() | ||||||
|  |         .map { FeedUiState.Succes(it) } | ||||||
|  |         .stateIn( | ||||||
|  |             scope = viewModelScope, | ||||||
|  |             initialValue = FeedUiState.Loading, | ||||||
|  |             started = SharingStarted.Eagerly, | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|     fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>> { |     fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>> { | ||||||
|         return entries |         return entries | ||||||
|     } |     } | ||||||
|  | @ -15,7 +15,6 @@ import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
| import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel | ||||||
| import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions | ||||||
| import be.ugent.sel.studeez.screens.home.HomeRoute | import be.ugent.sel.studeez.screens.home.HomeRoute | ||||||
| import be.ugent.sel.studeez.screens.home.getFeedActions |  | ||||||
| import be.ugent.sel.studeez.screens.log_in.LoginRoute | import be.ugent.sel.studeez.screens.log_in.LoginRoute | ||||||
| import be.ugent.sel.studeez.screens.profile.EditProfileRoute | import be.ugent.sel.studeez.screens.profile.EditProfileRoute | ||||||
| import be.ugent.sel.studeez.screens.profile.ProfileRoute | import be.ugent.sel.studeez.screens.profile.ProfileRoute | ||||||
|  | @ -66,10 +65,9 @@ fun StudeezNavGraph( | ||||||
|         composable(StudeezDestinations.HOME_SCREEN) { |         composable(StudeezDestinations.HOME_SCREEN) { | ||||||
|             HomeRoute( |             HomeRoute( | ||||||
|                 open, |                 open, | ||||||
|                 viewModel = hiltViewModel(), |  | ||||||
|                 drawerActions = drawerActions, |                 drawerActions = drawerActions, | ||||||
|                 navigationBarActions = navigationBarActions, |                 navigationBarActions = navigationBarActions, | ||||||
|                 feedActions = getFeedActions(hiltViewModel(), open), |                 feedViewModel = hiltViewModel(), | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,70 +0,0 @@ | ||||||
| package be.ugent.sel.studeez.screens.home |  | ||||||
| 
 |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.foundation.lazy.LazyColumn |  | ||||||
| import androidx.compose.foundation.lazy.items |  | ||||||
| import androidx.compose.material.Text |  | ||||||
| import androidx.compose.runtime.Composable |  | ||||||
| import androidx.compose.runtime.collectAsState |  | ||||||
| import androidx.compose.ui.Alignment |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.text.font.FontWeight |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import androidx.compose.ui.unit.sp |  | ||||||
| import be.ugent.sel.studeez.common.composable.DateText |  | ||||||
| import be.ugent.sel.studeez.data.local.models.FeedEntry |  | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds |  | ||||||
| import kotlinx.coroutines.flow.Flow |  | ||||||
| 
 |  | ||||||
| data class FeedActions( |  | ||||||
|     val getFeedEntries: () -> Flow<Map<String, List<FeedEntry>>>, |  | ||||||
|     val continueTask: (String, String) -> Unit, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| fun getFeedActions( |  | ||||||
|     viewmodel: FeedViewModel, |  | ||||||
|     open: (String) -> Unit, |  | ||||||
| ): FeedActions { |  | ||||||
|     return FeedActions( |  | ||||||
|         getFeedEntries = viewmodel::getFeedEntries, |  | ||||||
|         continueTask = { subjectId, taskId -> |  | ||||||
|             viewmodel.continueTask( |  | ||||||
|                 open, |  | ||||||
|                 subjectId, |  | ||||||
|                 taskId, |  | ||||||
|             ) |  | ||||||
|         }, |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @Composable |  | ||||||
| fun Feed( |  | ||||||
|     feedActions: FeedActions, |  | ||||||
| ) { |  | ||||||
|     val feedEntries = feedActions.getFeedEntries().collectAsState(initial = emptyMap()) |  | ||||||
|     LazyColumn { |  | ||||||
|         items(feedEntries.value.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) { |  | ||||||
|                     feedActions.continueTask(feedEntry.subjectId, feedEntry.taskId) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Spacer(modifier = Modifier.height(20.dp)) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -5,10 +5,13 @@ import androidx.compose.material.IconButton | ||||||
| import androidx.compose.material.icons.Icons | import androidx.compose.material.icons.Icons | ||||||
| import androidx.compose.material.icons.filled.Person | import androidx.compose.material.icons.filled.Person | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.collectAsState | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
| 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.PrimaryScreenTemplate | import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate | ||||||
| import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | import be.ugent.sel.studeez.common.composable.drawer.DrawerActions | ||||||
|  | import be.ugent.sel.studeez.common.composable.feed.* | ||||||
| import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import kotlinx.coroutines.flow.flowOf | import kotlinx.coroutines.flow.flowOf | ||||||
|  | @ -16,16 +19,17 @@ import kotlinx.coroutines.flow.flowOf | ||||||
| @Composable | @Composable | ||||||
| fun HomeRoute( | fun HomeRoute( | ||||||
|     open: (String) -> Unit, |     open: (String) -> Unit, | ||||||
|     viewModel: HomeViewModel, |  | ||||||
|     drawerActions: DrawerActions, |     drawerActions: DrawerActions, | ||||||
|     navigationBarActions: NavigationBarActions, |     navigationBarActions: NavigationBarActions, | ||||||
|     feedActions: FeedActions, |     feedViewModel: FeedViewModel, | ||||||
| ) { | ) { | ||||||
|  |     val feedUiState by feedViewModel.uiState.collectAsState() | ||||||
|     HomeScreen( |     HomeScreen( | ||||||
|         drawerActions = drawerActions, |         drawerActions = drawerActions, | ||||||
|         open = open, |         open = open, | ||||||
|         navigationBarActions = navigationBarActions, |         navigationBarActions = navigationBarActions, | ||||||
|         feedActions = feedActions, |         feedActions = getFeedActions(feedViewModel, open), | ||||||
|  |         feedUiState = feedUiState, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -35,6 +39,7 @@ fun HomeScreen( | ||||||
|     drawerActions: DrawerActions, |     drawerActions: DrawerActions, | ||||||
|     navigationBarActions: NavigationBarActions, |     navigationBarActions: NavigationBarActions, | ||||||
|     feedActions: FeedActions, |     feedActions: FeedActions, | ||||||
|  |     feedUiState: FeedUiState, | ||||||
| ) { | ) { | ||||||
|     PrimaryScreenTemplate( |     PrimaryScreenTemplate( | ||||||
|         title = resources().getString(R.string.home), |         title = resources().getString(R.string.home), | ||||||
|  | @ -42,7 +47,7 @@ fun HomeScreen( | ||||||
|         navigationBarActions = navigationBarActions, |         navigationBarActions = navigationBarActions, | ||||||
|         // TODO barAction = { FriendsAction() } |         // TODO barAction = { FriendsAction() } | ||||||
|     ) { |     ) { | ||||||
|         Feed(feedActions) |         Feed(feedActions, feedUiState) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -63,6 +68,7 @@ fun HomeScreenPreview() { | ||||||
|         drawerActions = DrawerActions({}, {}, {}, {}, {}), |         drawerActions = DrawerActions({}, {}, {}, {}, {}), | ||||||
|         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), |         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), | ||||||
|         open = {}, |         open = {}, | ||||||
|         feedActions = FeedActions({ flowOf() }, { _, _ -> run {} }) |         feedActions = FeedActions({ flowOf() }, { _, _ -> run {} }), | ||||||
|  |         feedUiState = FeedUiState.Loading, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,19 +0,0 @@ | ||||||
| package be.ugent.sel.studeez.screens.home |  | ||||||
| 
 |  | ||||||
| import be.ugent.sel.studeez.domain.AccountDAO |  | ||||||
| import be.ugent.sel.studeez.domain.LogService |  | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations |  | ||||||
| import be.ugent.sel.studeez.screens.StudeezViewModel |  | ||||||
| import dagger.hilt.android.lifecycle.HiltViewModel |  | ||||||
| import javax.inject.Inject |  | ||||||
| 
 |  | ||||||
| @HiltViewModel |  | ||||||
| class HomeViewModel @Inject constructor( |  | ||||||
|     private val accountDAO: AccountDAO, |  | ||||||
|     logService: LogService |  | ||||||
| ) : StudeezViewModel(logService) { |  | ||||||
| 
 |  | ||||||
|     fun onStartSessionClick(open: (String) -> Unit) { |  | ||||||
|         open(StudeezDestinations.TIMER_SELECTION_SCREEN) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Reference in a new issue
	
	 brreynie
						brreynie