Why my lazyColumn is only loading when I go to a different fragment and back in Android? - android

I have this list I am getting from Firebase and displaying in a LazyColumn but it only works when I navigate to a different fragment and press back. My lazyColumn is being composed inside de ScreenController for the bottomNavigation.
What do I have to do to display it directly?
below is my Fragment
#AndroidEntryPoint
class OpenTicketFragment : Fragment() {
private val viewModel: OpenTicketsViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
val ticketsList = viewModel.tickets.value.data
val currentUserId = viewModel.currentUserId.value
TheProjectTheme {
val navController = rememberNavController()
val title = remember { mutableStateOf("Open Tickets") }
val isDialogOpen = remember { mutableStateOf(false) }
Scaffold(
topBar = {
TopAppBar(
navigationIcon = {
IconButton(onClick = {
isDialogOpen.value = true
}) {
Icon(Icons.Default.ExitToApp, contentDescription = null)
}
},
title = {
Text(text = title.value)
},
actions = {
IconButton(onClick = {
findNavController().navigate(R.id.action_openTicketFragment_to_profileFragment)
}) {
Icon(Icons.Default.Person, contentDescription = null)
}
}
)
},
bottomBar = {
val items = listOf(
Screen.Open,
Screen.Available,
Screen.Closed
)
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute =
navBackStackEntry?.arguments?.getString(KEY_ROUTE)
items.forEach {
BottomNavigationItem(
icon = { Icon(it.icon, contentDescription = null) },
selected = currentRoute == it.route,
label = { Text(text = it.label) },
onClick = {
navController.popBackStack(
navController.graph.startDestination, false
)
if (currentRoute != it.route) {
navController.navigate(it.route)
}
})
}
}
}
)
{
ScreenController(
navHostController = navController,
title,
ticketsList!!,
findNavController(),
currentUserId
)
AlertDialogComponent(isDialogOpen, findNavController(), viewModel)
}
}
}
}
}
}
#Composable
fun OpenTicketLazyColumn(
ticket: Ticket,
// onClick: () -> Unit,
navController: NavController,
) {
Card(
modifier = Modifier
.padding(8.dp)
.clickable {
val action =
OpenTicketFragmentDirections.actionOpenTicketFragmentToTicketDetailFragment(
ticket.ticketId,
ticket.problem,
ticket.address,
ticket.dateOpened,
ticket.description,
ticket.name,
ticket.status
)
Log.d("SSS8", ticket.ticketId)
navController.navigate(action)
},
elevation = 4.dp
) {
Row(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier
.padding(8.dp)
.weight(1f)
) {
Text(
text = "Ticket Opened Date: ${ticket.dateOpened}",
fontSize = 16.sp,
)
Text(
text = "Service required: ${ticket.problem}",
fontSize = 14.sp,
)
}
Column(
modifier = Modifier
.padding(8.dp)
.weight(1f)
) {
Text(
text = "Status: ${ticket.status}",
fontSize = 16.sp,
)
Text(
text = "Address: ${ticket.address}",
fontSize = 16.sp,
)
}
}
}
}
and my composables
#Composable
fun ScreenController(
navHostController: NavHostController,
topBarTitle: MutableState<String>,
ticketList: List<Ticket>,
navController: NavController,
currentUserId: String
) {
NavHost(
navController = navHostController, startDestination = "open"
) {
composable("open") {
Log.d("SACO", currentUserId)
LazyColumn(
modifier = Modifier
.padding(8.dp)
) {
items(items = ticketList) { item ->
val status = remember { mutableStateOf(item.status)}
if (status.value == ASSIGNED && item.assignedToId == currentUserId) {
OpenTickets(
item,
navController
)
}
}
}
topBarTitle.value = "Open Tickets"
}
composable("available") {
LazyColumn(
modifier = Modifier
.padding(8.dp)
) {
items(items = ticketList) { item ->
val status = remember { mutableStateOf(item.status)}
if (status.value == OPEN) {
ClosedTickets(
item,
navController
)
}
}
}
topBarTitle.value = "Available Tickets"
}
composable("closed") {
LazyColumn(
modifier = Modifier
.padding(8.dp)
) {
items(items = ticketList) { item ->
val status = remember { mutableStateOf(item.status)}
if (status.value == CLOSED && item.assignedToId == currentUserId) {
AvailableTickets(
item,
navController
)
}
}
}
topBarTitle.value = "Closed Tickets"
}
}
}
#Composable
fun OpenTickets(
ticket: Ticket,
navController: NavController
) {
OpenTicketLazyColumn(
ticket,
navController
)
}
the viewModel
#HiltViewModel
class OpenTicketsViewModel #Inject constructor(
private val repository: WorkerRepositoryImpl,
private val firesource: FireBaseSource
) : ViewModel() {
val currentUserId = mutableStateOf("")
val tickets: MutableState<DataOrException<List<Ticket>, Exception>> = mutableStateOf(
DataOrException(
listOf(),
Exception("")
)
)
init {
getAllTickets(listOfServices)
}
private fun getAllTickets() {
viewModelScope.launch {
val ticketsList = repository.getAllTickets().data
tickets.value.data = ticketsList
}
}
the firebaseSource
class FireBaseSource #Inject constructor(
private val firebaseAuth: FirebaseAuth,
private val firestore: FirebaseFirestore
) {
suspend fun getAllTickets(
listOfServices: List<String>
): DataOrException<List<Ticket>, Exception> {
val dataOrException = DataOrException<List<Ticket>, Exception>()
try {
dataOrException.data = firestore.collection(TICKETS)
.whereEqualTo(PROBLEM, ELECTRICIAN)
.get()
.await().map { document ->
document.toObject(Ticket::class.java)
}
} catch (e: FirebaseFirestoreException) {
dataOrException.e = e
}
return dataOrException
}
}
1. List item

Related

How do I cancel an event after another one has started?

I am having an issue, where after a Snackbar appears the FAB won't perform navigation for the period of the Snackbar message. If I click it multiple times when the Snackbar is displayed it will stack and open multiple instances of one screen (only after the Snackbar is gone). How do I cancel showing the Snackbar on click of the FAB and preserve the functionality of the FAB at all times?
TasksList.kt:
#OptIn(ExperimentalMaterial3Api::class)
#Composable
fun TasksListScreen(
modifier: Modifier = Modifier,
onNavigate: (UiEvent.Navigate) -> Unit,
viewModel: TaskListViewModel = hiltViewModel()
) {
val tasks = viewModel.tasks.collectAsState(initial = emptyList())
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collect { event ->
when (event) {
is UiEvent.ShowSnackbar -> {
val result = snackbarHostState.showSnackbar(
message = event.message,
actionLabel = event.action,
duration = SnackbarDuration.Long,
)
if (result == SnackbarResult.ActionPerformed) {
viewModel.onEvent(TaskListEvent.OnUndoDeleteTask)
}
}
is UiEvent.Navigate -> onNavigate(event)
else -> Unit
}
}
}
Scaffold(
snackbarHost = {
SnackbarHost(snackbarHostState) { data ->
Snackbar(
shape = RoundedShapes.medium,
actionColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background,
snackbarData = data
)
}
},
floatingActionButton = {
FloatingActionButton(
shape = RoundedShapes.medium,
onClick = { viewModel.onEvent(TaskListEvent.OnAddTask) },
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.background
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(R.string.fab_cd)
)
}
},
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.background
)
)
},
) { padding ->
LazyColumn(
state = rememberLazyListState(),
verticalArrangement = spacedBy(12.dp),
contentPadding = PaddingValues(vertical = 16.dp),
modifier = modifier
.fillMaxSize()
.padding(padding)
.padding(horizontal = 16.dp),
) {
items(items = tasks.value, key = { task -> task.hashCode() }) { task ->
val currentTask by rememberUpdatedState(newValue = task)
val dismissState = rememberDismissState(confirmValueChange = {
if (it == DismissValue.DismissedToStart) {
viewModel.onEvent(TaskListEvent.OnDeleteTask(currentTask))
}
true
})
SwipeToDismiss(state = dismissState,
directions = setOf(DismissDirection.EndToStart),
background = { },
dismissContent = {
TaskItem(
task = task, modifier = modifier
)
})
}
}
}
}
TaskListViewModel:
#HiltViewModel
class TaskListViewModel #Inject constructor(private val repository: TaskRepositoryImplementation) :
ViewModel() {
val tasks = repository.getTasks()
private val _uiEvent = Channel<UiEvent>()
val uiEvent = _uiEvent.receiveAsFlow()
private var deletedTask: Task? = null
fun onEvent(event: TaskListEvent) {
when (event) {
is TaskListEvent.OnAddTask -> {
sendUiEvent(UiEvent.Navigate(Routes.ADD_EDIT_TASK))
}
is TaskListEvent.OnEditClick -> {
sendUiEvent(UiEvent.Navigate(Routes.ADD_EDIT_TASK + "?taskId=${event.task.id}"))
}
is TaskListEvent.OnDeleteTask -> {
val context = TaskApp.instance?.context
viewModelScope.launch(Dispatchers.IO) {
deletedTask = event.task
repository.deleteTask(event.task)
if (context != null) {
sendUiEvent(
UiEvent.ShowSnackbar(
message = context.getString(R.string.snackbar_deleted),
action = context.getString(R.string.snackbar_action)
)
)
}
}
}
is TaskListEvent.OnUndoDeleteTask -> {
deletedTask?.let { task ->
viewModelScope.launch {
repository.addTask(task)
}
}
}
}
}
private fun sendUiEvent(event: UiEvent) {
viewModelScope.launch(Dispatchers.IO) {
_uiEvent.send(event)
}
}
}

how to Update my UI using android jetpack compose and retrofit with a new request data from retrofit

I have created an app using kotlin and android jetpack compose and dependency injection for creating my
retrofit and room datebase the problem is that I'm getting some data using retrofit from internet and showing them in my ui but when I want to send a request for the second time I get the information but
I don't know how to put them insted of existing list that I have .
It's like a movie app that I want to go to next page or load more data when the list ends
interface AppGameApi {
#GET("farsroid")
suspend fun getAppGameFromPage(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String,
#Query("page") page: String
): AppGame
#GET("farsroid")
suspend fun getAppGameFromSearch(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "search",
#Query("q") q: String = ""
): AppGame
#GET("farsroid")
suspend fun getAppGameFromDownload(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "download",
#Query("link") link: String = ""
): AppGameDownload
}
class AppGameRetrofitRepository #Inject constructor(private val api: AppGameApi) {
private val appGames = DataOrException<AppGame,Boolean,Exception>()
private val appGamesSearch = DataOrException<AppGame,Boolean,Exception>()
private val appGamesDownload = DataOrException<AppGameDownload,Boolean,Exception>()
suspend fun getAllAppGames(page:String,action:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGames.isLoading = true
appGames.data = api.getAppGameFromPage(page = page, action = action)
if (appGames.data!!.status == 200) appGames.isLoading = false
Log.d("Mr", "getAllAppGames: ${appGames.data!!.result[0]}")
}catch (exception:Exception){
appGames.e = exception
}
return appGames
}
suspend fun getAllAppGamesSearch(q:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGamesSearch.isLoading = true
appGamesSearch.data = api.getAppGameFromSearch(q = q)
if (appGamesSearch.data!!.status == 200) appGamesSearch.isLoading = false
}catch (exception:Exception){
appGamesSearch.e = exception
Log.d("Error", "getAllAppGames: ${appGamesSearch.e!!.localizedMessage} ")
}
return appGamesSearch
}
suspend fun getAllAppGamesDownload(link:String):DataOrException<AppGameDownload,Boolean,java.lang.Exception>{
try {
appGamesDownload.isLoading = true
appGamesDownload.data = api.getAppGameFromDownload(link = link)
if (appGamesDownload.data!!.status == 200) appGamesDownload.isLoading = false
}catch (exception:Exception){
appGamesDownload.e = exception
Log.d("Error", "getAllAppGames: ${appGamesDownload.e!!.localizedMessage} ")
}
return appGamesDownload
}
}
#HiltViewModel
class AppGameRetrofitViewModel #Inject constructor(private val repository: AppGameRetrofitRepository) :
ViewModel() {
var appGame: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameSearch: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameDownload: MutableState<DataOrException<AppGameDownload, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
init {
getAllAppGames("1","app")
}
fun getAllAppGames(
page: String,
action: String
): DataOrException<AppGame, Boolean, Exception> {
viewModelScope.launch {
appGame.value.isLoading = true
appGame.value = repository.getAllAppGames(page = page, action = action)
if (appGame.value.data!!.status == 200) appGame.value.isLoading = false
}
return appGame.value
}
private fun getAllAppGamesSearch(q: String = "") {
viewModelScope.launch {
appGameSearch.value.isLoading = true
appGameSearch.value = repository.getAllAppGamesSearch(q = q)
if (appGameSearch.value.data!!.status == 200) appGameSearch.value.isLoading = false
}
}
private fun getAllAppGamesDownload(link: String = "") {
viewModelScope.launch {
appGameDownload.value.isLoading = true
appGameDownload.value = repository.getAllAppGamesDownload(link = link)
if (appGameDownload.value.data!!.status == 200) appGameDownload.value.isLoading = false
}
}
}
I have tried these and my mainActivity looks like this
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Android_Complete_TemplateTheme {
val appGameViewModelRoomDatabase by viewModels<RoomDatabaseViewModel>()
val appGameViewModelRetrofit by viewModels<AppGameRetrofitViewModel>()
val navController = rememberNavController()
val pageCounter = remember {
mutableStateOf("1")
}
val pageAction = remember {
mutableStateOf("game")
}
FarsroidNavigationSystem(
roomDatabaseViewModel = appGameViewModelRoomDatabase,
appGameRetrofitViewModel = appGameViewModelRetrofit,
navController = navController,
) {
if (appGameViewModelRetrofit.appGame.value.isLoading == true) {
AppGame(
status = 200,
result = listOf()
)
} else {
appGameViewModelRetrofit.getAllAppGames(
pageCounter.value,
pageAction.value
).data!!
}
}
pageCounter.value= pageCounter.value+1
}
}
}
}
#Composable
fun FarsroidNavigationSystem(
roomDatabaseViewModel: RoomDatabaseViewModel,
appGameRetrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
NavHost(
navController = navController,
startDestination = Screens.HomeScreen.name
) {
composable(route = Screens.HomeScreen.name) {
HomeScreen(
retrofitViewModel = appGameRetrofitViewModel,
navController = navController
){
onClicked()
}
}
composable(route = Screens.DetailScreen.name) {
DetailScreen(
roomDatabaseViewModel = roomDatabaseViewModel,
navController = navController
)
}
}
}
#Composable
fun HomeScreen(
retrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
Scaffold(
modifier = Modifier
.fillMaxSize(),
backgroundColor = Color.White,
contentColor = Color.DarkGray
) { paddingValues ->
Spacer(modifier = Modifier.padding(paddingValues))
if (onClicked().status != 200)
CircularProgressIndicator(modifier = Modifier.fillMaxSize(), color = Color.Red)
else
LazyColumn {
items(onClicked().result) {
ItemCard(resultAppGame = it)
}
}
Button(onClick = {
onClicked()
}) {
Text("LoadMore")
}
}
}
#Composable
fun ItemCard(
resultAppGame: ResultAppGame,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
shape = CutCornerShape(10.dp),
backgroundColor = Color.White,
contentColor = Color.DarkGray,
elevation = 10.dp
) {
Column(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier
.size(150.dp)
.padding(20.dp),
elevation = 10.dp,
shape = CircleShape,
backgroundColor = Color.White,
border = BorderStroke(width = 0.5.dp, Color.LightGray)
) {
Image(
painter = rememberAsyncImagePainter(
model = resultAppGame.pic),
contentDescription = resultAppGame.pic,
contentScale = ContentScale.Fit
)
}
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.title, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.description, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.link)
}
}
}

Code is not executed below a collect() method call in ViewModel

Depending on the status of PagingData<ShoppingListItem>, I'm updating the loading status in the ViewModel with a sealed class. As I don't know how to check if PagingData<ShoppingListItem> is emtpy in the ViewModel, I'm just collecting the PagingData and calling the .map function on it to add it to a mutableList. I then update the loading state as Emtpy if the list is empty and display an empty message in the UI. The problem is all the code below the collect() method call does not execute, and the circular progress bar does not go away. Even a Log statement below it does not execute. How can I make this work?
Sealed Class
sealed class ListItemsState {
object Loading : ListItemsState()
object Empty : ListItemsState()
object Error : ListItemsState()
data class Success(val allItems: Flow<PagingData<ShoppingListItem>>?) : ListItemsState()
}
ViewModel
#HiltViewModel
class ShoppingListScreenViewModel #Inject constructor(
private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase
) {
private val _shoppingListItemsState = mutableStateOf<Flow<PagingData<ShoppingListItem>>?>(null)
private val _listItemsLoadingState = MutableStateFlow<ListItemsState>(ListItemsState.Loading)
val listItemsLoadingState = _listItemsLoadingState.asStateFlow()
private val tempList = mutableListOf<ShoppingListItem>()
init {
viewModelScope.launch {
getAllShoppingListItemsFromDb()
}
}
private suspend fun getAllShoppingListItemsFromDb() {
_shoppingListItemsState.value = getAllShoppingListItemsUseCase().distinctUntilChanged()
_shoppingListItemsState.value?.collect {
it.map { shoppingListItem ->
tempList.add(shoppingListItem)
}
} //everything below this line does not execute
Log.i("##sealed", tempList.isEmpty().toString())
when {
tempList.isEmpty() -> _listItemsLoadingState.value = ListItemsState.Empty
else -> _listItemsLoadingState.value =
ListItemsState.Success(_shoppingListItemsState.value)
}
}
}
ShoppingListScreen Composable
#Composable
fun ShoppingListScreen(
navController: NavHostController,
shoppingListScreenViewModel: ShoppingListScreenViewModel,
sharedViewModel: SharedViewModel
) {
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val allItemsState = shoppingListScreenViewModel.listItemsLoadingState.collectAsState().value
Scaffold(
topBar = {
CustomAppBar(
title = "Shopping List",
titleFontSize = 20.sp,
appBarElevation = 4.dp,
navController = navController
)
},
floatingActionButton = {
FloatingActionButton(
onClick = {
shoppingListScreenViewModel.setStateValue(SHOW_ADD_ITEM_DIALOG_STR, true)
},
backgroundColor = Color.Blue,
contentColor = Color.White
) {
Icon(Icons.Filled.Add, "")
}
},
backgroundColor = Color.White,
// Defaults to false
isFloatingActionButtonDocked = false,
bottomBar = { BottomNavigationBar(navController = navController) }
) {
Box {
when (allItemsState) {
is ListItemsState.Loading -> ConditionalCircularProgressBar(isDisplayed = true)
is ListItemState.Empty -> Text("Empty!")
is ListItemsState.Error -> Text("Error!")
is ListItemsState.Success -> {
ConditionalCircularProgressBar(isDisplayed = false)
val successItems = allItemsState.allItems?.collectAsLazyPagingItems()
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(screenHeight)
) {
items(
items = successItems!!,
key = { item ->
item.id
}
) { item ->
ShoppingListScreenItem(
navController = navController,
item = item,
sharedViewModel = sharedViewModel
) { isChecked ->
scope.launch {
shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
}
}
}
item { Spacer(modifier = Modifier.padding(screenHeight - (screenHeight - 70.dp))) }
}
}
else -> {}
}
}
}
}

PagingData<T> is empty briefly in Compose UI

I have a LazyColumn that collects a Flow<PagingData<ShoppingListItem>>? from the ViewModel, but the itemCount property of the collected state reports an empty list with 0 items at first briefly before it reports the actual number of items in the database. How can I fix this?
Logcat Output
2022-11-17 06:41:06.187 I/##successItemsCount: 0
2022-11-17 06:41:06.447 I/##successItemsCount: 0
2022-11-17 06:41:06.501 I/##successItemsCount: 11
Sealed Class
sealed class ListItemsState {
object Loading : ListItemsState()
object Error : ListItemsState()
data class Success(val allItems: Flow<PagingData<ShoppingListItem>>?) : ListItemsState()
}
ViewModel
#HiltViewModel
class ShoppingListScreenViewModel #Inject constructor(
private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase
) {
private val _shoppingListItemsState = mutableStateOf<Flow<PagingData<ShoppingListItem>>?>(null)
private val _listItemsLoadingState = MutableStateFlow<ListItemsState>(ListItemsState.Loading)
val listItemsLoadingState = _listItemsLoadingState.asStateFlow()
init {
getAllShoppingListItemsFromDb()
}
private fun getAllShoppingListItemsFromDb() {
viewModelScope.launch {
_shoppingListItemsState.value = getAllShoppingListItemsUseCase().distinctUntilChanged()
_listItemsLoadingState.value = ListItemsState.Success(_shoppingListItemsState.value)
}
}
}
ShoppingListScreen Composable
#Composable
fun ShoppingListScreen(
navController: NavHostController,
shoppingListScreenViewModel: ShoppingListScreenViewModel,
sharedViewModel: SharedViewModel
) {
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val allItemsState = shoppingListScreenViewModel.listItemsLoadingState.collectAsState().value
Scaffold(
topBar = {
CustomAppBar(
title = "Shopping List",
titleFontSize = 20.sp,
appBarElevation = 4.dp,
navController = navController
)
},
floatingActionButton = {
FloatingActionButton(
onClick = {
shoppingListScreenViewModel.setStateValue(SHOW_ADD_ITEM_DIALOG_STR, true)
},
backgroundColor = Color.Blue,
contentColor = Color.White
) {
Icon(Icons.Filled.Add, "")
}
},
backgroundColor = Color.White,
// Defaults to false
isFloatingActionButtonDocked = false,
bottomBar = { BottomNavigationBar(navController = navController) }
) {
Box {
when (allItemsState) {
is ListItemsState.Loading -> ConditionalCircularProgressBar(isDisplayed = true)
is ListItemsState.Error -> Text("Error!")
is ListItemsState.Success -> {
ConditionalCircularProgressBar(isDisplayed = false)
val successItems = allItemsState.allItems?.collectAsLazyPagingItems()
Log.i("##successItemsCount", successItems.itemCount.toString())
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(screenHeight)
) {
items(
items = successItems!!,
key = { item ->
item.id
}
) { item ->
ShoppingListScreenItem(
navController = navController,
item = item,
sharedViewModel = sharedViewModel
) { isChecked ->
scope.launch {
shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
}
}
}
item { Spacer(modifier = Modifier.padding(screenHeight - (screenHeight - 70.dp))) }
}
}
else -> {}
}
}
}
}

How to skip loginScreen and passwordScreen after launch the app

Hello i would like to know How to skip the loginScreen and the passwordScreen and move to homeScreen after launching the app because i have Stored the username and password in Datastore, So how can i do that?
Here is my code:
MainActivity.kt
setContent {
EEETheme {
// A surface container using the 'background'
// color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Nav()
}
}
}
Screen Class
sealed class Screen(val route: String) {
object LoginScreen: Screen(route = "LoginPage_route")
object PasswordScreen: Screen(route = "PasswordPage_route")
}
Navigation.kt
#Composable
fun Nav() {
val context = LocalContext.current
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screen.LoginScreen.route
) {
composable(route = Screen.LoginScreen.route) {
LoginScreen(navController)
}
composable(route = Screen.PasswordScreen.route) {
PasswordScreen(navController)
}
composable(route = Screen.Home.route) {
Screen_A_with_WithTopBar(navController)
}
}
LoginScreen.kt
#Composable
fun LoginScreen(navController: NavController) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
) {
val context = LocalContext.current
var username by remember { mutableStateOf("") }
Text(text = "Login", fontSize = 33.sp)
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
textStyle = TextStyle(fontSize = 24.sp),
value = username,
onValueChange = { username = it },
label = { Text("Enter Your username") },
maxLines = 1
)
Button(onClick = {
}) {
Text(text = "Submit", fontSize = 33.sp)
}
}
}
PasswordScreen.kt
#Composable
fun PasswordLogin(navController: NavController) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
) {
val context = LocalContext.current
var username by remember { mutableStateOf("") }
Text(text = "Login", fontSize = 33.sp)
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
textStyle = TextStyle(fontSize = 24.sp),
value = username,
onValueChange = { username = it },
label = { Text("Enter Your username") },
maxLines = 1
)
Button(onClick = {
}) {
Text(text = "Submit", fontSize = 33.sp)
}
}
}
HomeScreen.kt
#Composable
fun HomeScreen(navController: NavController) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
) {
Text(text = "Home Screen", fontSize = 33.sp)
}
}
DataStore Class
class StoreUserName(private val context: Context) {
// to make sure there's only one instance
companion object {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("authentication")
val USERNAME_KEY = stringPreferencesKey("username")
val PASSWORD_KEY = stringPreferencesKey("password")
}
//get the saved CompanyID
val getUsername: Flow<String?> = context.dataStore.data
.map { preferences ->
preferences[USERNAME_KEY] ?: ""
}
//get the saved LoginID
val getPassword: Flow<String?> = context.dataStore.data
.map { preferences ->
preferences[PASSWORD_KEY] ?: ""
}
//save username into datastore
suspend fun saveUsername(username: String) {
context.dataStore.edit { preferences ->
preferences[USERNAME_KEY] = username
}
}
//save Password into datastore
suspend fun savePassword(password: String) {
context.dataStore.edit { preferences ->
preferences[PASSWORD_KEY] = password
}
}
}
In your fun Nav() you should check if you have credentials stored and then based on that you should set startDestination
for example:
#Composable
fun Nav() {
val context = LocalContext.current
val navController = rememberNavController()
val isLoginRequired = //you condition
NavHost(
navController = navController,
startDestination = if(isLoginRequired)
Screen.LoginScreen.route
else
Screen.Home.route
) {
composable(route = Screen.LoginScreen.route) {
LoginScreen(navController)
}
composable(route = Screen.PasswordScreen.route) {
PasswordScreen(navController)
}
composable(route = Screen.Home.route) {
Screen_A_with_WithTopBar(navController)
}
}

Categories

Resources