Improve weird bottom sheet scrolling behavior
This commit is contained in:
parent
aa69fb5f42
commit
7d078c69d0
@ -80,6 +80,7 @@ fun RestoreBackupSheet(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(it)
|
||||||
) {
|
) {
|
||||||
when (state) {
|
when (state) {
|
||||||
RestoreBackupState.Parsing -> {
|
RestoreBackupState.Parsing -> {
|
||||||
|
|||||||
@ -51,7 +51,7 @@ fun WeatherLocationSearchDialog(
|
|||||||
) {
|
) {
|
||||||
var query by remember { mutableStateOf("") }
|
var query by remember { mutableStateOf("") }
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth().padding(it)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.padding(bottom = 16.dp)
|
Modifier.padding(bottom = 16.dp)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@ -58,7 +59,7 @@ fun BottomSheetDialog(
|
|||||||
dismissButton: @Composable (() -> Unit)? = null,
|
dismissButton: @Composable (() -> Unit)? = null,
|
||||||
swipeToDismiss: () -> Boolean = { true },
|
swipeToDismiss: () -> Boolean = { true },
|
||||||
dismissOnBackPress: () -> Boolean = { true },
|
dismissOnBackPress: () -> Boolean = { true },
|
||||||
content: @Composable () -> Unit,
|
content: @Composable (paddingValues: PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
val swipeState = remember {
|
val swipeState = remember {
|
||||||
SwipeableState(
|
SwipeableState(
|
||||||
@ -200,12 +201,11 @@ fun BottomSheetDialog(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight(),
|
||||||
.padding(horizontal = 24.dp, vertical = 8.dp),
|
|
||||||
propagateMinConstraints = true,
|
propagateMinConstraints = true,
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
content()
|
content(PaddingValues(horizontal = 24.dp, vertical = 8.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,8 @@ fun CustomizeSearchableSheet(
|
|||||||
if (!pickIcon) {
|
if (!pickIcon) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 8.dp),
|
.padding(top = 8.dp)
|
||||||
|
.padding(it),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -162,7 +163,8 @@ fun CustomizeSearchableSheet(
|
|||||||
|
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
columns = GridCells.Fixed(columns)
|
columns = GridCells.Fixed(columns),
|
||||||
|
contentPadding = it,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
item(span = { GridItemSpan(columns) }) {
|
item(span = { GridItemSpan(columns) }) {
|
||||||
|
|||||||
@ -151,6 +151,7 @@ fun EditFavoritesSheet(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
|
.padding(it)
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -159,15 +160,15 @@ fun EditFavoritesSheet(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (createShortcutTarget != null) {
|
} else if (createShortcutTarget != null) {
|
||||||
ShortcutPicker(viewModel)
|
ShortcutPicker(viewModel, it)
|
||||||
} else {
|
} else {
|
||||||
ReorderFavoritesGrid(viewModel)
|
ReorderFavoritesGrid(viewModel, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
|
fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: PaddingValues) {
|
||||||
val items by viewModel.gridItems.observeAsState(emptyList())
|
val items by viewModel.gridItems.observeAsState(emptyList())
|
||||||
val columns = LocalGridSettings.current.columnCount
|
val columns = LocalGridSettings.current.columnCount
|
||||||
|
|
||||||
@ -238,6 +239,7 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM) {
|
|||||||
LazyVerticalDragAndDropGrid(
|
LazyVerticalDragAndDropGrid(
|
||||||
state = state,
|
state = state,
|
||||||
columns = GridCells.Fixed(columns),
|
columns = GridCells.Fixed(columns),
|
||||||
|
contentPadding = paddingValues,
|
||||||
|
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
@ -670,7 +672,7 @@ fun GridItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ShortcutPicker(viewModel: EditFavoritesSheetVM) {
|
fun ShortcutPicker(viewModel: EditFavoritesSheetVM, paddingValues: PaddingValues) {
|
||||||
|
|
||||||
val hasShortcutPermission by remember { viewModel.hasShortcutPermission }.collectAsState(null)
|
val hasShortcutPermission by remember { viewModel.hasShortcutPermission }.collectAsState(null)
|
||||||
|
|
||||||
@ -690,7 +692,9 @@ fun ShortcutPicker(viewModel: EditFavoritesSheetVM) {
|
|||||||
|
|
||||||
val iconSize = 48.dp.toPixels().roundToInt()
|
val iconSize = 48.dp.toPixels().roundToInt()
|
||||||
val activity = LocalLifecycleOwner.current as AppCompatActivity
|
val activity = LocalLifecycleOwner.current as AppCompatActivity
|
||||||
LazyColumn {
|
LazyColumn(
|
||||||
|
contentPadding = paddingValues
|
||||||
|
) {
|
||||||
if (hasShortcutPermission == false) {
|
if (hasShortcutPermission == false) {
|
||||||
item {
|
item {
|
||||||
MissingPermissionBanner(
|
MissingPermissionBanner(
|
||||||
|
|||||||
@ -56,6 +56,7 @@ fun HiddenItemsSheet(
|
|||||||
items,
|
items,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(it)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,6 +93,7 @@ fun CreateBackupSheet(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(it)
|
||||||
) {
|
) {
|
||||||
when (state) {
|
when (state) {
|
||||||
CreateBackupState.Ready -> {
|
CreateBackupState.Ready -> {
|
||||||
@ -143,7 +144,9 @@ fun CreateBackupSheet(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
SmallMessage(
|
SmallMessage(
|
||||||
modifier = Modifier.padding(top = 8.dp),
|
modifier = Modifier
|
||||||
|
.padding(top = 8.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
icon = Icons.Rounded.Warning,
|
icon = Icons.Rounded.Warning,
|
||||||
text = stringResource(R.string.backup_not_included)
|
text = stringResource(R.string.backup_not_included)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -205,20 +205,25 @@ fun EditSearchActionSheet(
|
|||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
when (page) {
|
when (page) {
|
||||||
EditSearchActionPage.SelectType -> SelectTypePage(viewModel)
|
EditSearchActionPage.SelectType -> SelectTypePage(viewModel, it)
|
||||||
EditSearchActionPage.InitWebSearch -> InitWebSearchPage(viewModel)
|
EditSearchActionPage.InitWebSearch -> InitWebSearchPage(viewModel, it)
|
||||||
EditSearchActionPage.InitAppSearch -> InitAppSearchPage(viewModel)
|
EditSearchActionPage.InitAppSearch -> InitAppSearchPage(viewModel, it)
|
||||||
EditSearchActionPage.CustomizeWebSearch -> CustomizeWebSearch(viewModel)
|
EditSearchActionPage.CustomizeWebSearch -> CustomizeWebSearch(viewModel, it)
|
||||||
EditSearchActionPage.CustomizeCustomIntent -> CustomizeCustomIntent(viewModel)
|
EditSearchActionPage.CustomizeCustomIntent -> CustomizeCustomIntent(viewModel, it)
|
||||||
EditSearchActionPage.CustomizeAppSearch -> CustomizeAppSearch(viewModel)
|
EditSearchActionPage.CustomizeAppSearch -> CustomizeAppSearch(viewModel, it)
|
||||||
EditSearchActionPage.PickIcon -> PickIcon(viewModel)
|
EditSearchActionPage.PickIcon -> PickIcon(viewModel, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SelectTypePage(viewModel: EditSearchActionSheetVM) {
|
private fun SelectTypePage(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
Column {
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(paddingValues)
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.create_search_action_type),
|
text = stringResource(R.string.create_search_action_type),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
@ -299,13 +304,13 @@ private fun SelectTypePage(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InitAppSearchPage(viewModel: EditSearchActionSheetVM) {
|
private fun InitAppSearchPage(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val searchableApps by remember { viewModel.getSearchableApps(context) }.collectAsState(null)
|
val searchableApps by remember { viewModel.getSearchableApps(context) }.collectAsState(null)
|
||||||
|
|
||||||
if (searchableApps != null) {
|
if (searchableApps != null) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
contentPadding = PaddingValues(bottom = 16.dp)
|
contentPadding = paddingValues
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
@ -344,12 +349,15 @@ private fun InitAppSearchPage(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InitWebSearchPage(viewModel: EditSearchActionSheetVM) {
|
private fun InitWebSearchPage(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
var url by viewModel.initWebsearchUrl
|
var url by viewModel.initWebsearchUrl
|
||||||
val importError by viewModel.websearchImportError
|
val importError by viewModel.websearchImportError
|
||||||
val loading by viewModel.loadingWebsearch
|
val loading by viewModel.loadingWebsearch
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.create_search_action_website_url),
|
text = stringResource(R.string.create_search_action_website_url),
|
||||||
@ -391,11 +399,14 @@ private fun InitWebSearchPage(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomizeWebSearch(viewModel: EditSearchActionSheetVM) {
|
fun CustomizeWebSearch(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
val searchAction by viewModel.searchAction
|
val searchAction by viewModel.searchAction
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (searchAction != null && searchAction is WebsearchActionBuilder) {
|
if (searchAction != null && searchAction is WebsearchActionBuilder) {
|
||||||
@ -515,7 +526,7 @@ fun CustomizeWebSearch(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) {
|
fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
val searchAction by viewModel.searchAction
|
val searchAction by viewModel.searchAction
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
@ -531,7 +542,10 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
if (searchAction != null) {
|
if (searchAction != null) {
|
||||||
@ -632,7 +646,7 @@ fun CustomizeAppSearch(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM) {
|
fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
val searchAction by viewModel.searchAction
|
val searchAction by viewModel.searchAction
|
||||||
|
|
||||||
val action = searchAction
|
val action = searchAction
|
||||||
@ -642,6 +656,7 @@ fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM) {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.Bottom
|
||||||
@ -715,7 +730,7 @@ fun CustomizeCustomIntent(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PickIcon(viewModel: EditSearchActionSheetVM) {
|
fun PickIcon(viewModel: EditSearchActionSheetVM, paddingValues: PaddingValues) {
|
||||||
val action by viewModel.searchAction
|
val action by viewModel.searchAction
|
||||||
|
|
||||||
val iconSizePx = 20.dp.toPixels()
|
val iconSizePx = 20.dp.toPixels()
|
||||||
@ -730,7 +745,9 @@ fun PickIcon(viewModel: EditSearchActionSheetVM) {
|
|||||||
val availableIcons =
|
val availableIcons =
|
||||||
remember { SearchActionIcon.values().filter { it != SearchActionIcon.Custom } }
|
remember { SearchActionIcon.values().filter { it != SearchActionIcon.Custom } }
|
||||||
|
|
||||||
Column {
|
Column(
|
||||||
|
modifier = Modifier.padding(paddingValues)
|
||||||
|
) {
|
||||||
LazyVerticalGrid(columns = GridCells.Adaptive(64.dp)) {
|
LazyVerticalGrid(columns = GridCells.Adaptive(64.dp)) {
|
||||||
if (action is AppSearchActionBuilder) {
|
if (action is AppSearchActionBuilder) {
|
||||||
item {
|
item {
|
||||||
@ -779,7 +796,8 @@ fun PickIcon(viewModel: EditSearchActionSheetVM) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.padding(paddingValues)
|
||||||
) {
|
) {
|
||||||
SearchActionIconTile {
|
SearchActionIconTile {
|
||||||
SearchActionIcon(builder = action!!, size = 24.dp)
|
SearchActionIcon(builder = action!!, size = 24.dp)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import androidx.compose.animation.AnimatedVisibility
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
@ -102,16 +103,19 @@ fun EditTagSheet(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
when (viewModel.page) {
|
when (viewModel.page) {
|
||||||
EditTagSheetPage.CreateTag -> CreateNewTagPage(viewModel)
|
EditTagSheetPage.CreateTag -> CreateNewTagPage(viewModel, it)
|
||||||
EditTagSheetPage.PickItems -> PickItems(viewModel)
|
EditTagSheetPage.PickItems -> PickItems(viewModel, it)
|
||||||
EditTagSheetPage.CustomizeTag -> CustomizeTag(viewModel)
|
EditTagSheetPage.CustomizeTag -> CustomizeTag(viewModel, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CreateNewTagPage(viewModel: EditTagSheetVM) {
|
fun CreateNewTagPage(viewModel: EditTagSheetVM, paddingValues: PaddingValues) {
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
Column(modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(paddingValues)
|
||||||
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
@ -130,8 +134,8 @@ fun CreateNewTagPage(viewModel: EditTagSheetVM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PickItems(viewModel: EditTagSheetVM) {
|
fun PickItems(viewModel: EditTagSheetVM, paddingValues: PaddingValues) {
|
||||||
LazyColumn(modifier = Modifier.fillMaxWidth()) {
|
LazyColumn(modifier = Modifier.fillMaxWidth(), contentPadding = paddingValues) {
|
||||||
item {
|
item {
|
||||||
Text(stringResource(id = R.string.tag_select_items),
|
Text(stringResource(id = R.string.tag_select_items),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
@ -209,9 +213,13 @@ fun ListItem(
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomizeTag(viewModel: EditTagSheetVM) {
|
fun CustomizeTag(viewModel: EditTagSheetVM, paddingValues: PaddingValues) {
|
||||||
val iconSize = 32.dp.toPixels()
|
val iconSize = 32.dp.toPixels()
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
Column(modifier = Modifier
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(paddingValues)
|
||||||
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user