Scaffold(bottomBar = {
if (currentRoute(navController) != Screen.SplashScreen.route)
// AnimatedVisibility(visible= bottomBarState.value ) {
BottomAppBar(modifier = modifier
.height(80.dp)
.padding(5.dp)
.clip(shape = RoundedCornerShape(60.dp)), containerColor = Color.Gray, tonalElevation = 5.dp) {
items.forEach { items ->
val selected = items.route == backStackEntry.value?.destination?.route
NavigationBarItem(
selected = items.route == navController.currentDestination?.route,
onClick = { onItemClick(items) },
icon = {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
if (items.badgeCount > 0) {
BadgedBox(badge = {
Text(text = items.badgeCount.toString())
}) {
Icon(imageVector = items.icon, contentDescription = items.name)
}
} else {
Icon(imageVector = items.icon, contentDescription = items.name)
}
if (selected) {
Text(text = items.name, textAlign = TextAlign.Center, fontSize = 10.sp)
}
}
},
colors = NavigationBarItemDefaults.colors(
selectedIconColor = Color.Green,
unselectedIconColor = Color.Red
,
selectedTextColor = Color.Green,
indicatorColor = Color.DarkGray
)
)
}
}
//}
}){
}
You can use something like this:
Your extension function:
#Stable
#Composable
private fun NavController.shouldShowBottomNavigationAsState(shouldHideRoutes: List<String>): State<Boolean> {
val shouldShowBottomNavigation = remember { mutableStateOf(false) }
DisposableEffect(this) {
val listener = NavController.OnDestinationChangedListener { _, destination, _ ->
if (shouldHideRoutes.any { it == destination.route }) {
shouldShowBottomNavigation.value = true
} else {
shouldShowBottomNavigation.value = false
}
}
addOnDestinationChangedListener(listener)
onDispose {
removeOnDestinationChangedListener(listener)
}
}
return shouldShowBottomNavigation
}
Usage:
val useBottomNavigation by navController.shouldShowBottomNavigationAsState(
listOf(
"route1","route2" // put your routes that you want to hide bottom navigation view
),
)
if (useBottomNavigation) {
// your bottom navigation composable
}
Related
I am currently observing some strange behavior when using an OutlinedTextField inside of an ExposedDropdownMenuBox. If I have already clicked into the OutlinedTextField once, the focus always jumps back to it when I click into another field or sometimes when I'm simply scrolling through my view - preferably after the keyboard is closed manually, if the keyboard keeps visible I can click into the other input fields without any problem.
Has anyone experienced a similar behaviour and knows how to fix this?
I'm using version 1.3.1 of androidx.compose.material:material
My Composable looks like this:
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun ContributorComposable(contributor: Contributor, logbookEntryState: LogbookEntryState, enabled: Boolean) {
Spacer(modifier = Modifier.height(8.dp))
val addContributor: #Composable () -> Unit = {
IconButton(onClick = { logbookEntryState.contributors.add(Contributor()) }) {
Icon(imageVector = Icons.Filled.Add, contentDescription = "")
}
}
var expanded by remember { mutableStateOf(false) }
val options = logbookEntryState.contributorsDropDownList
Column(modifier = Modifier.fillMaxWidth()) {
Row(verticalAlignment = CenterVertically, horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
Spacer(modifier = Modifier.width(40.dp))
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded && enabled },
modifier = Modifier.focusable(false)
) {
Row(verticalAlignment = CenterVertically, horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
OutlinedTextField(
colors = if (
contributor.company.value.isNotBlank() ||
contributor.registrationNumber.value.isNotBlank() ||
contributor.userCertificationNumber.value.isNotBlank() ||
contributor.companyCertificationNumber.value.isNotBlank() ||
contributor.userFullname.value.isNotBlank()
) TextFieldDefaults.outlinedTextFieldColors(unfocusedBorderColor = db_primary_red) else TextFieldDefaults.outlinedTextFieldColors(),
modifier = Modifier
.weight(1f),
value = contributor.userFullname.value,
onValueChange = { newText ->
contributor.userFullname.value = newText
viewModel.findContributorByName(logbookEntryState, newText)
expanded = true
},
label = { Text(stringResource(id = R.string.logbook_entry_create_contributors)) },
trailingIcon = if (enabled) addContributor else null,
enabled = enabled,
)
if (enabled && logbookEntryState.contributors.size > 1) {
IconButton(onClick = { logbookEntryState.contributors.remove(contributor) }, modifier = Modifier.width(40.dp)) {
Icon(imageVector = Icons.Filled.Delete, contentDescription = "")
}
} else {
Spacer(modifier = Modifier.width(40.dp))
}
}
if (options.isNotEmpty())
ExposedDropdownMenu(
expanded = expanded,
modifier = Modifier.background(db_secondary_white),
onDismissRequest = { expanded = false },
) {
options.forEach { selectionOption ->
DropdownMenuItem(
modifier = Modifier
.background(db_secondary_white)
.exposedDropdownSize(true),
onClick = {
contributor.internalId = selectionOption.internalId
contributor.userFullname.value = selectionOption.userFullname.value
contributor.userFullnameErrorMessage.value = ""
contributor.company.value = selectionOption.company.value
contributor.companyErrorMessage.value = ""
contributor.registrationNumber.value = selectionOption.registrationNumber.value
contributor.registrationNumberErrorMessage.value = ""
contributor.userCertificationNumber.value = selectionOption.userCertificationNumber.value
contributor.userCertificationNumberErrorMessage.value = ""
contributor.companyCertificationNumber.value = selectionOption.companyCertificationNumber.value
contributor.companyCertificationNumberErrorMessage.value = ""
contributor.id = selectionOption.id
contributor.entryId = selectionOption.entryId
contributor.createdBy = selectionOption.createdBy
contributor.creationDate = selectionOption.creationDate
expanded = false
}
) {
Column(modifier = Modifier.fillMaxWidth()) {
Row(verticalAlignment = CenterVertically) {
Text(text = selectionOption.userFullname.value ?: "")
}
// if there are users with the same name, we show additional information
if (options.groupBy { it.userFullname }.size > 1) {
Row(verticalAlignment = CenterVertically) {
Text(text = selectionOption.company.value ?: "")
}
Row(verticalAlignment = CenterVertically) {
Text(text = selectionOption.registrationNumber.value ?: "")
}
if (viewModel.shouldShowCertificatenummber()) {
Row(verticalAlignment = CenterVertically) {
Text(text = selectionOption.userCertificationNumber.value ?: "")
}
}
if (viewModel.shouldShowCertificatenummber()) {
Row(verticalAlignment = CenterVertically) {
Text(text = selectionOption.companyCertificationNumber.value ?: "")
}
}
DefaultDivider()
Spacer(modifier = Modifier.height(8.dp))
}
}
}
}
}
}
}
ErrorComposable(contributor.userFullnameErrorMessage.value)
}
CustomTextField(
label = R.string.logbook_entry_create_company_contributors,
input = contributor.company,
errorMessage = contributor.companyErrorMessage,
enabled = enabled,
shouldShow = true,
mandatoryField = contributor.userFullname.value.isNotBlank(),
)
CustomTextField(
label = R.string.logbook_entry_create_registrationnr_contributors,
input = contributor.registrationNumber,
errorMessage = contributor.registrationNumberErrorMessage,
enabled = enabled,
shouldShow = viewModel.logbook?.classEntity?.hasRegistrationNumber == true,
mandatoryField = contributor.userFullname.value.isNotBlank(),
)
CustomTextField(
label = R.string.logbook_entry_create_certification_numbers_contributors,
input = contributor.userCertificationNumber,
errorMessage = contributor.userCertificationNumberErrorMessage,
enabled = enabled,
shouldShow = viewModel.shouldShowCertificatenummber(),
mandatoryField = contributor.userFullname.value.isNotBlank(),
)
CustomTextField(
label = R.string.logbook_entry_create_company_certification_numbers_contributors,
input = contributor.companyCertificationNumber,
errorMessage = contributor.companyCertificationNumberErrorMessage,
enabled = enabled,
shouldShow = viewModel.shouldShowCertificatenummber(),
mandatoryField = contributor.userFullname.value.isNotBlank(),
)
}
I'm using room database with jetpack compose,upon deleting all items the ui is not recomposing unless i move to another screen and come back again , any help would be appreciated , Thank you
This is my code
fun CheckOutScreen(shopViewModel: ShopViewModel,
navHostController: NavHostController,
list : SnapshotStateList<PurchaseModel> ) {
val firebaseAuth = FirebaseAuth.getInstance()
val databaseReference = FirebaseDatabase.getInstance().reference
val context = LocalContext.current
val totalAmount = remember { mutableStateOf(0.0) }
val count = remember { mutableStateOf(0) }
val isDialogShowing = remember { mutableStateOf(false) }
val isProgressShowing = remember { mutableStateOf(false) }
val isDataSaving = remember { mutableStateOf(false) }
val isMovingToAnotherScreen = remember { mutableStateOf(false)}
list.forEach {
if(count.value < list.size){
totalAmount.value += it.totalPrice
count.value++
}
}
Scaffold{
Column {
Row(modifier = Modifier.fillMaxWidth()) {
Text(text = "Cart", modifier = Modifier
.weight(1f)
.padding(10.dp), color = Color.DarkGray,
style = MaterialTheme.typography.h1, fontSize = 17.sp)
IconButton(onClick = {
isDialogShowing.value = true
}) {
Icon(Icons.Filled.Delete,"")
}
}
if(list.size == 0){
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
Text("No Items In The Cart", style = MaterialTheme.typography.h1,
color = Color.DarkGray , fontSize = 17.sp)
}
}
else {
Box(contentAlignment = Alignment.Center){
Column() {
Text(text = "Purchase To : " + list[0].fullName, modifier = Modifier.padding(start = 10.dp,
end = 10.dp, top = 5.dp), fontSize = 17.sp,style = MaterialTheme.typography.body1)
LazyColumn(modifier = Modifier
.weight(1f)
.padding(top = 10.dp)){
items(list.size, key = { item -> item.hashCode()}){ pos ->
val dismissState = rememberDismissState(confirmStateChange = {
if(it == DismissValue.DismissedToStart || it == DismissValue.DismissedToEnd){
shopViewModel.deletePurchase(list[pos].purchaseId!!)
Toast.makeText(context,"Item Successfully Dismissed",Toast.LENGTH_SHORT).show()
}
true
})
if(!isMovingToAnotherScreen.value){
SwipeToDismiss(
state = dismissState,
background = {},
dismissContent = {
Card(elevation = 10.dp, modifier = Modifier
.clip(shape = RoundedCornerShape(6.dp))
.padding(5.dp)) {
Row(modifier = Modifier.fillMaxWidth()) {
Box(contentAlignment = Alignment.Center) {
AsyncImage(model = ImageRequest.Builder(context).data(list[pos].productImage).build(),
contentScale = ContentScale.Crop,
modifier = Modifier
.width(80.dp)
.height(80.dp)
.padding(10.dp),
contentDescription = "")
}
Column(modifier = Modifier.weight(1f)) {
Text(list[pos].title, modifier = Modifier.padding(5.dp), fontWeight = FontWeight.Bold)
Text("Quantity : " + list[pos].totalQuantity)
Text("Due To : " + list[pos].totalPrice)
}
}
}
},
directions = setOf(DismissDirection.StartToEnd,DismissDirection.EndToStart))
}
}
}
Card(modifier = Modifier
.fillMaxWidth()
.clip(shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp))) {
Button(modifier = Modifier.padding(start = 20.dp, end = 20.dp),onClick = {
isProgressShowing.value = true
}) {
Text("Pay ${totalAmount.value}")
}
}
}
}
AnimatedVisibility(visible = isProgressShowing.value) {
CircularProgressIndicator(color = Color.DarkGray)
}
}
}
if(isProgressShowing.value){
val map = hashMapOf<String,Any>()
map["list"] = list
map["uid"] = firebaseAuth.currentUser!!.uid
map["totalPrice"] = totalAmount.value.toString()
val db = databaseReference.child("Purchases")
db.child(firebaseAuth.currentUser!!.uid)
.child(Calendar.getInstance().timeInMillis.toString())
.setValue(map)
.addOnSuccessListener {
isDataSaving.value = true
}
.addOnFailureListener {
}
}
if(isDialogShowing.value){
AlertDialog(
onDismissRequest = { isDialogShowing.value = false },
confirmButton = {
TextButton(onClick = {
shopViewModel.deletePurchases()
isDialogShowing.value = false
Toast.makeText(context,"All items are successfully removed",Toast.LENGTH_SHORT).show()
}) {
Text("Proceed")
}
},
dismissButton = {
TextButton(onClick = { isDialogShowing.value = false }) {
Text("Cancel")
}
},
title = { Text("Removing Items ") },
text = { Text("Do you want to remove items from cart ! ") }
)
}
if(isDataSaving.value){
LaunchedEffect(Unit){
delay(3000)
isMovingToAnotherScreen.value = true
shopViewModel.deletePurchases()
isProgressShowing.value = false
isDataSaving.value = false
navHostController.navigate(AppRouting.Payment.route)
}
}
}
BackHandler {
isMovingToAnotherScreen.value = true
navHostController.popBackStack()
}
}
It's most likely because of not updating value of your State. In you example it's always the same list. You either need to set value with new instance of list or use SnapshotStateList. You can check this answer also.
I have a list of products. On the ProductsScreen I have some filter options, search box, also filter chips :
I'm using paging 3 library for the pagination. I want to scroll to the top when the search query or selected filter chip has changed. Here is my code :
ProductScreen
#Composable
fun ProductsScreen(
modifier: Modifier = Modifier,
navController: NavController,
viewModel: ProductsScreenViewModel = hiltViewModel(),
onProductItemClick: (String) -> Unit = {},
onProductFilterButtonClick: (ProductsFilterPreferences) -> Unit = {},
) {
//products
val products = viewModel.products.collectAsLazyPagingItems()
//load state
val isLoading = products.loadState.refresh is LoadState.Loading
val scrollToTop = viewModel.scrollToTop.observeAsState()
val scaffoldState = rememberScaffoldState()
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
val query by viewModel.query.collectAsState()
val context = LocalContext.current
//not working
LaunchedEffect(key1 = Unit) {
scrollToTop.value?.getContentIfNotHandled()?.let { scroll ->
if (scroll) {
listState.scrollToItem(0)
}
}
}
RubiBrandsScaffold(
modifier = modifier,
scaffoldState = scaffoldState,
topBar = {
ProductsScreenToolbar(
showFilterBadge = viewModel.showFilterBadge,
onFilterButtonClick = { onProductFilterButtonClick(viewModel.productsFilterPreferences.value) },
searchQuery = query,
onTrailingIconClick = {
viewModel.setQuery("")
},
onQueryChange = { query ->
viewModel.setQuery(query)
},
onSearchButtonClick = { query ->
viewModel.onSearch(query)
},
onChipClick = { chip ->
viewModel.onChipSelected(chip)
},
selectedChip = viewModel.selectedChip,
)
},
floatingActionButton = {
AnimatedVisibility(
visible = showFab,
enter = scaleIn(),
exit = scaleOut()
) {
FloatingActionButton(
backgroundColor = MaterialTheme.colors.primary,
onClick = {
scope.launch {
//working
listState.scrollToItem(0)
}
},
modifier = Modifier
.padding(
dimensionResource(id = R.dimen.dimen_16)
)
) {
Icon(
painter = painterResource(id = R.drawable.ic_up),
contentDescription = null,
tint = MaterialTheme.colors.onPrimary
)
}
}
}
) { paddingValues ->
SwipeRefresh(
indicator = { state, trigger ->
RubiBrandsSwipeRefreshIndicator(state = state, trigger = trigger)
}, state = swipeRefreshState, onRefresh = products::refresh
) {
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize()
) {
items(products) { product ->
product?.let {
ProductItem(
modifier = Modifier.clickable {
if (!isLoading) onProductItemClick(
product.id
)
},
childModifier = Modifier.shimmerModifier(isLoading),
productImage = product.productImage?.get(0),
productTitle = product.productTitle,
productCount = product.productCount,
productStatus = product.productStatus?.asString(context)
)
}
}
products.apply {
when {
loadState.source.refresh is LoadState.Loading -> {
items(10) {
ProductItem(
childModifier = Modifier.shimmerModifier(true),
productImage = null,
productTitle = "",
productCount = "",
productStatus = ""
)
}
}
loadState.source.append is LoadState.Loading -> {
item {
CircularProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.wrapContentWidth(Alignment.CenterHorizontally)
)
}
}
loadState.source.refresh is LoadState.Error -> {
val e = products.loadState.refresh as LoadState.Error
item {
ErrorItem(
modifier = Modifier.fillParentMaxSize(),
message = e.error.localizedMessage
?: stringResource(id = R.string.something_went_wrong),
onRetryClick = products::retry
)
}
}
loadState.source.append is LoadState.Error -> {
val e = products.loadState.append as LoadState.Error
item {
ErrorItem(
modifier = Modifier
.fillParentMaxWidth()
.wrapContentHeight(),
message = e.error.localizedMessage
?: stringResource(id = R.string.something_went_wrong),
onRetryClick = products::retry
)
}
}
loadState.source.refresh is LoadState.NotLoading && loadState.source.refresh !is LoadState.Error && products.itemCount < 1 -> {
item {
RubiBrandsEmptyListView(modifier = Modifier.fillParentMaxSize())
}
}
}
}
}
}
}
}
Here is also my ProductsScreenViewModel :
#HiltViewModel
class ProductsScreenViewModel #Inject constructor(
private val productsScreenUseCase: ProductsScreenUseCase
) : ViewModel() {
var showFilterBadge by mutableStateOf(false)
private set
private val _query = MutableStateFlow<String>("")
val query: StateFlow<String> = _query
var selectedChip by mutableStateOf<ProductsChips>(ProductsChips.ALL)
private val _productsFilterPreferences = MutableStateFlow(ProductsFilterPreferences())
val productsFilterPreferences: StateFlow<ProductsFilterPreferences> = _productsFilterPreferences
private val _scrollToTop = MutableLiveData<Event<Boolean>>()
val scrollToTop: LiveData<Event<Boolean>> get() = _scrollToTop
val products =
_productsFilterPreferences.flatMapLatest { filterPreferences ->
showFilterBadge = filterPreferences.sort.value != null
|| filterPreferences.saleStatus.value != null
|| filterPreferences.stockStatus.value != null
|| filterPreferences.sku != null
|| filterPreferences.priceOptions.value != R.string.all
productsScreenUseCase.fetchProducts(params = filterPreferences)
}.cachedIn(viewModelScope)
fun setFilters(
filters: ProductsFilterPreferences
) {
_scrollToTop.value = Event(true)
_productsFilterPreferences.update {
it.copy(
sort = filters.sort,
state = filters.state,
saleStatus = filters.saleStatus,
stockStatus = filters.stockStatus,
sku = filters.sku,
priceOptions = filters.priceOptions
)
}
}
fun setQuery(query: String) {
if (query.isEmpty()) {
onSearch(query)
}
_query.value = query
}
fun onSearch(query: String) {
//if I press the search button I'm setting scroll to top to true
_scrollToTop.value = Event(true)
_productsFilterPreferences.update {
it.copy(query = query.trim().ifEmpty { null })
}
}
fun onChipSelected(chip: ProductsChips) {
selectedChip = chip
//if I change the chip I'm setting scroll to top to true
_scrollToTop.value = Event(true)
_productsFilterPreferences.update {
it.copy(state = chip.value)
}
}
}
There is a related question about that but it is valid for XML.
So whenever the search query or selected chip has changed I'm setting the scrollToTop value to true and then observing it from my ProductsScreen composable. But it is not working.
You can try using the LaunchedEffect and the scrollState of Lazycolumn to scroll it to top.
val scrollState = rememberLazyListState()
LazyColumn( state = scrollState){}
LaunchedEffect(true) {
scrollState.animateScrollToItem(0)
}
I've just put the LaunchEffect within the if block and the issue have been resolved. Here is the code:
scrollToTop?.getContentIfNotHandled()?.let { scroll ->
if (scroll) {
LaunchedEffect(key1 = Unit) {
listState.scrollToItem(0)
}
}
}
How can I add more elements to the static list in the jetpack compose
#OptIn(ExperimentalFoundationApi::class)
#Composable
fun AddNotesToList(notesList: List<String>) {
val listState = rememberScrollState()
Log.d("TAG", notesList.toString())
LazyColumn() {
items(notesList.size) {
Box(contentAlignment = Alignment.Center,
modifier = Modifier
.padding(start = 15.dp, top = 15.dp, bottom = 1.dp, end = 15.dp)
.fillMaxSize() .horizontalScroll(listState)
.background(Color.White)
.clip(RoundedCornerShape(10.dp)) .padding(15.dp)
.animateItemPlacement(animationSpec = tween(1000))) {
Text(text = notesList[it],
color = Color.Black,
modifier = Modifier.align( Alignment.BottomCenter)
.animateItemPlacement(animationSpec = tween(10000)))
}
}
}
}
this is my addition to the Ui function, this is now I add elements
AddNotesToList(notesList = listOf(
"Drink water",
"Read Books",
"Eat fruits",
"Go for a Walk",
"Drink water",
"Read Books",
"Eat fruits",
"Go for## Heading ## a Walk",
"Go for a Walk",
"Drink water",
"Read Books",
"Eat fruits",
"Go for a Walk"))
now I want to add one more element and I am trying this
function
#Composable
fun AddNewNote(noteDescription: String) {
Log.d("noteDescription", noteDescription)
AddNotesToList(notesList = listOf(noteDescription))
}
Solution:
val _noteList = remember { MutableStateFlow(listOf<String>()) }
val noteList by remember { _noteList }.collectAsState()
// Add note
fun addItem(item: String) {
val newList = ArrayList(noteList)
newList.add(yourItem)
_noteList.value = newList
}
And then you can pass noteList to your LazyColumn
This is how i call my function
AddNewNote { item -> //updating state with added item noteListState = noteListState + listOf(item) }
This is my function
#OptIn(ExperimentalAnimationApi::class)
#Composable
fun AddNewNote(onNewNoteAdded: (String) -> Unit) {
val openDialog = remember { mutableStateOf(true) }
val (visible) = remember { mutableStateOf(true) }
var text by remember { mutableStateOf("") }
AnimatedVisibility(
visible = visible,
enter = slideInVertically(initialOffsetY = { 9000 * it }),
exit = fadeOut()
) {
if (openDialog.value) {
AlertDialog(
onDismissRequest = {
openDialog.value = false
},
title = {
Text(
modifier = Modifier.animateEnterExit(
enter = slideInVertically(
initialOffsetY = { 9000 * it },
),
exit = slideOutVertically()
),
text = "Add Note Description"
)
},
text = {
Column() {
TextField(
value = text,
onValueChange = { text = it }
)
Text("Note description")
}
},
buttons = {
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
val addNoteButtonState by remember { mutableStateOf(false) }
if (addNoteButtonState) {
onNewNoteAdded(text)
} else {
Box(contentAlignment = Alignment.Center) {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
if (text != "") {
onNewNoteAdded(text)
}
// addNoteButtonState = true
openDialog.value = false
}
) {
Text(
"Add Note To The List",
)
}
}
}
}
},
)
}
}
}
My problem is, that i can't manage to navigate to another Screen inside a foreach-loop altough it's possible in another Screen to route to the wanted Screen, but not in a foreach loop.
When i click on the button, it says, that he can't find the article with the id, but i checked and the id, which he says he can't find does exist
This is my Code (which produces the error):
Surface(
modifier = Modifier
.fillMaxSize()
)
{
Box()
{
shopping.forEach {
Button(
modifier = Modifier
.offset(it.coordinates.x.dp, it.coordinates.y.dp)
.size(10.dp),
onClick = { navController.navigate(
Screen.ArtikelDetailScreen.route
+ "/${it.id}" })
)
{
Text(
modifier = Modifier
.padding(
top = ProjectTheme.paddings.tiny,
bottom = ProjectTheme.paddings.tiny
),
style = ProjectTheme.typography.h6,
text = it.name
)
}
}
}
}
This is the code to which it should route:
#Composable
fun ArtikelDetailScreen(
id: Long,
navController: NavController,
viewModel: ArtikelViewModel = hiltViewModel()
) {
val artikel = viewModel.shoppingState.value.find { p -> p.id == id }
if(artikel == null) {
Log.e(tag, "Artikel mit der id = $id wurde nicht gefunden")
return
}
viewModel.artikel = artikel
viewModel.setState()
val scrollState = rememberScrollState()
ProjectTheme {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(
text = stringResource(R.string.ArtDetailScreenName))
}
)
}
) {
Column(
modifier = Modifier
.wrapContentWidth()
.padding(all = ProjectTheme.paddings.small)
.verticalScroll(
state = scrollState,
enabled = true,
reverseScrolling = true
)
) {
ArtikelInfos(viewModel)
Button(
modifier = Modifier
.fillMaxWidth()
.padding(top = ProjectTheme.paddings.default),
onClick = {
viewModel.remove(id)
viewModel.add()
navController.navigate(
route = Screen.ShoppingListScreen.route)
{
popUpTo(
route = Screen.ShoppingListScreen.route
)
{
inclusive = true
}
}
}
) {
Text(
modifier = Modifier
.padding(
top = ProjectTheme.paddings.tiny,
bottom = ProjectTheme.paddings.tiny
),
style = ProjectTheme.typography.h6,
text = stringResource(R.string.back)
)
}
}
}
}
}
And this is where it works:
LazyColumn {
items(
viewModel.shoppingState.value
)
{
artikel ->
var artikelRemoved: Artikel?
val dismissState = rememberDismissState(
confirmStateChange =
{
if (it == DismissValue.DismissedToEnd) {
logThread("==>SwipeToDismiss().", "-> Edit")
navController.navigate(
Screen.ArtikelDetailScreen.route
+ "/${artikel.id}"
)
return#rememberDismissState true
}
else if (it == DismissValue.DismissedToStart)
{
logThread("==>SwipeToDismiss().", "-> Delete")
artikelRemoved = artikel
viewModel.remove(artikel.id)
navController.navigate(
Screen.ShoppingListScreen.route
)
return#rememberDismissState true
}
return#rememberDismissState false
}
)
SwipeToDismiss(
state = dismissState,
modifier = Modifier.padding(vertical = 4.dp),
directions = setOf(
DismissDirection.StartToEnd,
DismissDirection.EndToStart
),
dismissThresholds =
{
direction ->
FractionalThreshold(
if (direction == DismissDirection.StartToEnd)
{
0.25f
}
else
{
0.25f
}
)
},
background =
{
val direction =
dismissState.dismissDirection ?: return#SwipeToDismiss
val colorBox by animateColorAsState(
when (dismissState.targetValue)
{
DismissValue.Default -> ProjectTheme.colors.secondary
DismissValue.DismissedToEnd -> Color.Green
DismissValue.DismissedToStart -> Color.Red
}
)
val colorIcon by animateColorAsState(
when (dismissState.targetValue)
{
DismissValue.Default -> Color.Black
DismissValue.DismissedToEnd -> Color.DarkGray
DismissValue.DismissedToStart -> Color.White
}
)
val alignment = when (direction)
{
DismissDirection.StartToEnd -> Alignment.CenterStart
DismissDirection.EndToStart -> Alignment.CenterEnd
}
val icon = when (direction)
{
DismissDirection.StartToEnd -> Icons.Default.Edit
DismissDirection.EndToStart -> Icons.Default.Delete
}
val scale by animateFloatAsState(
if (dismissState.targetValue == DismissValue.Default)
{
1.25f
}
else
{
2.0f
}
)
Box(
Modifier
.fillMaxSize()
.background(colorBox)
.padding(horizontal = 20.dp),
contentAlignment = alignment
) {
Icon(
icon,
contentDescription = "Localized description",
modifier = Modifier
.scale(scale),
tint = colorIcon
)
}
},
dismissContent = {
Column {
ArtikelCard(
artikel = artikel,
elevation = animateDpAsState(
if (dismissState.dismissDirection != null)
{
8.dp
}
else
{
0.dp
}
).value,
) {
// onClick
// THIS WORKS navController.navigate(
Screen.ArtikelDetailScreen.route
+ "/${artikel.id}"
)
}
Divider()
}
}
)
}
}