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.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 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.screens.StudeezViewModel
 | 
			
		||||
import dagger.hilt.android.lifecycle.HiltViewModel
 | 
			
		||||
import kotlinx.coroutines.flow.Flow
 | 
			
		||||
import kotlinx.coroutines.flow.*
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
@HiltViewModel
 | 
			
		||||
class FeedViewModel @Inject constructor(
 | 
			
		||||
    private val feedDAO: FeedDAO,
 | 
			
		||||
    feedDAO: FeedDAO,
 | 
			
		||||
    private val taskDAO: TaskDAO,
 | 
			
		||||
    private val selectedTask: SelectedTask,
 | 
			
		||||
    logService: LogService
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,14 @@ class FeedViewModel @Inject constructor(
 | 
			
		|||
 | 
			
		||||
    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>>> {
 | 
			
		||||
        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.getNavigationBarActions
 | 
			
		||||
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.profile.EditProfileRoute
 | 
			
		||||
import be.ugent.sel.studeez.screens.profile.ProfileRoute
 | 
			
		||||
| 
						 | 
				
			
			@ -66,10 +65,9 @@ fun StudeezNavGraph(
 | 
			
		|||
        composable(StudeezDestinations.HOME_SCREEN) {
 | 
			
		||||
            HomeRoute(
 | 
			
		||||
                open,
 | 
			
		||||
                viewModel = hiltViewModel(),
 | 
			
		||||
                drawerActions = drawerActions,
 | 
			
		||||
                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.filled.Person
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.tooling.preview.Preview
 | 
			
		||||
import be.ugent.sel.studeez.R
 | 
			
		||||
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
 | 
			
		||||
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.resources
 | 
			
		||||
import kotlinx.coroutines.flow.flowOf
 | 
			
		||||
| 
						 | 
				
			
			@ -16,16 +19,17 @@ import kotlinx.coroutines.flow.flowOf
 | 
			
		|||
@Composable
 | 
			
		||||
fun HomeRoute(
 | 
			
		||||
    open: (String) -> Unit,
 | 
			
		||||
    viewModel: HomeViewModel,
 | 
			
		||||
    drawerActions: DrawerActions,
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
    feedActions: FeedActions,
 | 
			
		||||
    feedViewModel: FeedViewModel,
 | 
			
		||||
) {
 | 
			
		||||
    val feedUiState by feedViewModel.uiState.collectAsState()
 | 
			
		||||
    HomeScreen(
 | 
			
		||||
        drawerActions = drawerActions,
 | 
			
		||||
        open = open,
 | 
			
		||||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
        feedActions = feedActions,
 | 
			
		||||
        feedActions = getFeedActions(feedViewModel, open),
 | 
			
		||||
        feedUiState = feedUiState,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +39,7 @@ fun HomeScreen(
 | 
			
		|||
    drawerActions: DrawerActions,
 | 
			
		||||
    navigationBarActions: NavigationBarActions,
 | 
			
		||||
    feedActions: FeedActions,
 | 
			
		||||
    feedUiState: FeedUiState,
 | 
			
		||||
) {
 | 
			
		||||
    PrimaryScreenTemplate(
 | 
			
		||||
        title = resources().getString(R.string.home),
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +47,7 @@ fun HomeScreen(
 | 
			
		|||
        navigationBarActions = navigationBarActions,
 | 
			
		||||
        // TODO barAction = { FriendsAction() }
 | 
			
		||||
    ) {
 | 
			
		||||
        Feed(feedActions)
 | 
			
		||||
        Feed(feedActions, feedUiState)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +68,7 @@ fun HomeScreenPreview() {
 | 
			
		|||
        drawerActions = DrawerActions({}, {}, {}, {}, {}),
 | 
			
		||||
        navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
 | 
			
		||||
        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