I have composable in two rows comprising as follows
- Edit button in one row – when the user clicks this button then
the 2nd row is displayed comprising of
- Delete icon and a Cancel icon
When the user clicks the cancel button, then first row is shown. My composable is shown below
<code>@Composable
fun SelectEditBar(
modifier: Modifier = Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelectionEnabled: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
// if the selection is enabled, then we reset all settings on back navigation
BackHandler(
enabled = isSelectionEnabled
) {
if (isSelectionEnabled) {
onCancel()
}
}
SelectEditTopBar(
modifier = modifier, isSelectionEnabled = isSelectionEnabled, selectedNotifications = selectedNotifications,
selectionBarViewState = selectionBarViewState, onSelect = onSelectionEnabled,
onDelete = onDelete, onCancel = onCancel
)
}
</code>
<code>@Composable
fun SelectEditBar(
modifier: Modifier = Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelectionEnabled: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
// if the selection is enabled, then we reset all settings on back navigation
BackHandler(
enabled = isSelectionEnabled
) {
if (isSelectionEnabled) {
onCancel()
}
}
SelectEditTopBar(
modifier = modifier, isSelectionEnabled = isSelectionEnabled, selectedNotifications = selectedNotifications,
selectionBarViewState = selectionBarViewState, onSelect = onSelectionEnabled,
onDelete = onDelete, onCancel = onCancel
)
}
</code>
@Composable
fun SelectEditBar(
modifier: Modifier = Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelectionEnabled: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
// if the selection is enabled, then we reset all settings on back navigation
BackHandler(
enabled = isSelectionEnabled
) {
if (isSelectionEnabled) {
onCancel()
}
}
SelectEditTopBar(
modifier = modifier, isSelectionEnabled = isSelectionEnabled, selectedNotifications = selectedNotifications,
selectionBarViewState = selectionBarViewState, onSelect = onSelectionEnabled,
onDelete = onDelete, onCancel = onCancel
)
}
composables
<code>private fun SelectEditTopBar(
modifier: Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelect: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
AnimatedVisibility(
visible = !isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
Row(modifier = modifier) {
Spacer(modifier = Modifier.weight(1f))
val minDimensions = dimensionResource(
id =
when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
val selectedBarViewStateRemember by remember {selectionBarViewState}
Button(
modifier = Modifier
.defaultMinSize(minHeight = minDimensions, minWidth = minDimensions)
.wrapContentSize().focusRequester(focusRequester).focusProperties {
canFocus = selectedBarViewStateRemember.isEditButtonInFocus
next =
}
.focusable(),
hierarchy = ButtonHierarchy.Flat,
onClick = onSelect,
color = MyTheme.colors.foregroundPrimary,
text = stringResource(id = com.myproject.R.string.edit),
textStyle = MyTheme.typography.smallBold.copy(
color = MyTheme.colors.foregroundPrimary
)
)
}
}
AnimatedVisibility(
visible = isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val minimumDimensions = dimensionResource(
id = when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
SelectEditInnerTopBar(
modifier = Modifier
.defaultMinSize(minHeight = minimumDimensions, minWidth = minimumDimensions)
.wrapContentWidth(),
selectionBarViewState = selectionBarViewState, focusRequester = focusRequester,
selectedNotifications = selectedNotifications, onDelete = onDelete, onCancel = onCancel
)
}
}
@Composable
private fun SelectEditInnerTopBar(
modifier: Modifier = Modifier, focusRequester: FocusRequester, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onDelete: () -> Unit,
onCancel: () -> Unit
) {
Row(modifier = modifier.then(Modifier.padding(horizontal = MyTheme.dimens.grid_1))) {
val textStyle = when (LocalWindowSizeClassValues.current.windowWidthSizeClass) {
WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded -> MyTheme.typography.mediumRegular
else -> MyTheme.typography.smallRegular
}
val isAnyNotificationSelected by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.isNotEmpty()
}
}
val selectedNotificationsCount by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.size
}
}
QuickFilter(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusable()
,
textStyle = textStyle,
text = "",
enabled = isAnyNotificationSelected,
hierarchy = QuickFilterHierarchy.ACTION,
onCheckedChange = {
onDelete()
}
) { _, _ ->
Icon(
modifier = Modifier.semantics {
drawableId = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp
},
imageVector = ImageVector.vectorResource(id = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp),
contentDescription = null,
tint = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
val quickFilterStateDescription = stringResource(id =
if (isAnyNotificationSelected) {
com.myproject.R.string.enabled_accessibility
} else {
com.myproject.R.string.disabled_accessibility
}
)
Text(
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(
start = dimensionResource(id = com.myproject.R.dimen.marginHalf)
)
.semantics {
stateDescription = quickFilterStateDescription
},
text = stringResource(id = com.myproject.R.string.ui_delete),
style = if (isAnyNotificationSelected) MyTheme.typography.smallRegular else MyTheme.typography.smallRegular.copy(color = MyTheme.colors.foregroundDisabled),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
}
Spacer(modifier = Modifier.weight(1f))
if (isAnyNotificationSelected) {
Text(
modifier = Modifier.align(Alignment.CenterVertically)
.padding(horizontal = MyTheme.dimens.padding)
.defaultMinSize(minHeight = MyTheme.dimens.iconSize)
.wrapContentSize(),
text = pluralStringResource(
id = com.myprojct.R.plurals.selection_count,
selectedNotificationsCount,
selectedNotificationsCount
),
style = MyTheme.typography.smallRegular
)
}
Button(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusProperties {
if (selectionBarViewState.value.isDeleteButtonInFocus) {
canFocus = true
}
}.focusable(),
hierarchy = ButtonHierarchy.Flat,
text = stringResource(id = com.myproject.R.string.cancel),
textStyle = MyTheme.typography.smallRegular.copy(
textDecoration = TextDecoration.Underline,
color = MyTheme.colors.foregroundPrimary
),
onClick = onCancel
)
}
}
</code>
<code>private fun SelectEditTopBar(
modifier: Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelect: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
AnimatedVisibility(
visible = !isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
Row(modifier = modifier) {
Spacer(modifier = Modifier.weight(1f))
val minDimensions = dimensionResource(
id =
when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
val selectedBarViewStateRemember by remember {selectionBarViewState}
Button(
modifier = Modifier
.defaultMinSize(minHeight = minDimensions, minWidth = minDimensions)
.wrapContentSize().focusRequester(focusRequester).focusProperties {
canFocus = selectedBarViewStateRemember.isEditButtonInFocus
next =
}
.focusable(),
hierarchy = ButtonHierarchy.Flat,
onClick = onSelect,
color = MyTheme.colors.foregroundPrimary,
text = stringResource(id = com.myproject.R.string.edit),
textStyle = MyTheme.typography.smallBold.copy(
color = MyTheme.colors.foregroundPrimary
)
)
}
}
AnimatedVisibility(
visible = isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val minimumDimensions = dimensionResource(
id = when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
SelectEditInnerTopBar(
modifier = Modifier
.defaultMinSize(minHeight = minimumDimensions, minWidth = minimumDimensions)
.wrapContentWidth(),
selectionBarViewState = selectionBarViewState, focusRequester = focusRequester,
selectedNotifications = selectedNotifications, onDelete = onDelete, onCancel = onCancel
)
}
}
@Composable
private fun SelectEditInnerTopBar(
modifier: Modifier = Modifier, focusRequester: FocusRequester, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onDelete: () -> Unit,
onCancel: () -> Unit
) {
Row(modifier = modifier.then(Modifier.padding(horizontal = MyTheme.dimens.grid_1))) {
val textStyle = when (LocalWindowSizeClassValues.current.windowWidthSizeClass) {
WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded -> MyTheme.typography.mediumRegular
else -> MyTheme.typography.smallRegular
}
val isAnyNotificationSelected by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.isNotEmpty()
}
}
val selectedNotificationsCount by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.size
}
}
QuickFilter(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusable()
,
textStyle = textStyle,
text = "",
enabled = isAnyNotificationSelected,
hierarchy = QuickFilterHierarchy.ACTION,
onCheckedChange = {
onDelete()
}
) { _, _ ->
Icon(
modifier = Modifier.semantics {
drawableId = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp
},
imageVector = ImageVector.vectorResource(id = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp),
contentDescription = null,
tint = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
val quickFilterStateDescription = stringResource(id =
if (isAnyNotificationSelected) {
com.myproject.R.string.enabled_accessibility
} else {
com.myproject.R.string.disabled_accessibility
}
)
Text(
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(
start = dimensionResource(id = com.myproject.R.dimen.marginHalf)
)
.semantics {
stateDescription = quickFilterStateDescription
},
text = stringResource(id = com.myproject.R.string.ui_delete),
style = if (isAnyNotificationSelected) MyTheme.typography.smallRegular else MyTheme.typography.smallRegular.copy(color = MyTheme.colors.foregroundDisabled),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
}
Spacer(modifier = Modifier.weight(1f))
if (isAnyNotificationSelected) {
Text(
modifier = Modifier.align(Alignment.CenterVertically)
.padding(horizontal = MyTheme.dimens.padding)
.defaultMinSize(minHeight = MyTheme.dimens.iconSize)
.wrapContentSize(),
text = pluralStringResource(
id = com.myprojct.R.plurals.selection_count,
selectedNotificationsCount,
selectedNotificationsCount
),
style = MyTheme.typography.smallRegular
)
}
Button(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusProperties {
if (selectionBarViewState.value.isDeleteButtonInFocus) {
canFocus = true
}
}.focusable(),
hierarchy = ButtonHierarchy.Flat,
text = stringResource(id = com.myproject.R.string.cancel),
textStyle = MyTheme.typography.smallRegular.copy(
textDecoration = TextDecoration.Underline,
color = MyTheme.colors.foregroundPrimary
),
onClick = onCancel
)
}
}
</code>
private fun SelectEditTopBar(
modifier: Modifier, isSelectionEnabled: Boolean, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onSelect: () -> Unit, onDelete: () -> Unit,
onCancel: () -> Unit
) {
AnimatedVisibility(
visible = !isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
Row(modifier = modifier) {
Spacer(modifier = Modifier.weight(1f))
val minDimensions = dimensionResource(
id =
when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
val selectedBarViewStateRemember by remember {selectionBarViewState}
Button(
modifier = Modifier
.defaultMinSize(minHeight = minDimensions, minWidth = minDimensions)
.wrapContentSize().focusRequester(focusRequester).focusProperties {
canFocus = selectedBarViewStateRemember.isEditButtonInFocus
next =
}
.focusable(),
hierarchy = ButtonHierarchy.Flat,
onClick = onSelect,
color = MyTheme.colors.foregroundPrimary,
text = stringResource(id = com.myproject.R.string.edit),
textStyle = MyTheme.typography.smallBold.copy(
color = MyTheme.colors.foregroundPrimary
)
)
}
}
AnimatedVisibility(
visible = isSelectionEnabled,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
val minimumDimensions = dimensionResource(
id = when (windowSizeClass.windowWidthSizeClass) {
WindowWidthSizeClass.Compact -> com.myproject.R.dimen.margin6x
else -> com.myproject.R.dimen.margin4x
}
)
SelectEditInnerTopBar(
modifier = Modifier
.defaultMinSize(minHeight = minimumDimensions, minWidth = minimumDimensions)
.wrapContentWidth(),
selectionBarViewState = selectionBarViewState, focusRequester = focusRequester,
selectedNotifications = selectedNotifications, onDelete = onDelete, onCancel = onCancel
)
}
}
@Composable
private fun SelectEditInnerTopBar(
modifier: Modifier = Modifier, focusRequester: FocusRequester, selectedNotifications: Map<String, FlexNotification>,
selectionBarViewState: State<SelectionBarViewState>, onDelete: () -> Unit,
onCancel: () -> Unit
) {
Row(modifier = modifier.then(Modifier.padding(horizontal = MyTheme.dimens.grid_1))) {
val textStyle = when (LocalWindowSizeClassValues.current.windowWidthSizeClass) {
WindowWidthSizeClass.Medium, WindowWidthSizeClass.Expanded -> MyTheme.typography.mediumRegular
else -> MyTheme.typography.smallRegular
}
val isAnyNotificationSelected by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.isNotEmpty()
}
}
val selectedNotificationsCount by remember(selectedNotifications) {
derivedStateOf {
selectedNotifications.size
}
}
QuickFilter(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusable()
,
textStyle = textStyle,
text = "",
enabled = isAnyNotificationSelected,
hierarchy = QuickFilterHierarchy.ACTION,
onCheckedChange = {
onDelete()
}
) { _, _ ->
Icon(
modifier = Modifier.semantics {
drawableId = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp
},
imageVector = ImageVector.vectorResource(id = com.myproject.R.drawable.ui_ic_playbook_delete_black_16dp),
contentDescription = null,
tint = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
val quickFilterStateDescription = stringResource(id =
if (isAnyNotificationSelected) {
com.myproject.R.string.enabled_accessibility
} else {
com.myproject.R.string.disabled_accessibility
}
)
Text(
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(
start = dimensionResource(id = com.myproject.R.dimen.marginHalf)
)
.semantics {
stateDescription = quickFilterStateDescription
},
text = stringResource(id = com.myproject.R.string.ui_delete),
style = if (isAnyNotificationSelected) MyTheme.typography.smallRegular else MyTheme.typography.smallRegular.copy(color = MyTheme.colors.foregroundDisabled),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = if (isAnyNotificationSelected) {
MyTheme.colors.foregroundPrimary
} else {
MyTheme.colors.foregroundDisabled
}
)
}
Spacer(modifier = Modifier.weight(1f))
if (isAnyNotificationSelected) {
Text(
modifier = Modifier.align(Alignment.CenterVertically)
.padding(horizontal = MyTheme.dimens.padding)
.defaultMinSize(minHeight = MyTheme.dimens.iconSize)
.wrapContentSize(),
text = pluralStringResource(
id = com.myprojct.R.plurals.selection_count,
selectedNotificationsCount,
selectedNotificationsCount
),
style = MyTheme.typography.smallRegular
)
}
Button(
modifier = Modifier
.wrapContentWidth()
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.focusProperties {
if (selectionBarViewState.value.isDeleteButtonInFocus) {
canFocus = true
}
}.focusable(),
hierarchy = ButtonHierarchy.Flat,
text = stringResource(id = com.myproject.R.string.cancel),
textStyle = MyTheme.typography.smallRegular.copy(
textDecoration = TextDecoration.Underline,
color = MyTheme.colors.foregroundPrimary
),
onClick = onCancel
)
}
}
This is what the fist row looks like
If the user clicks the Edit button
This is what I want to do for accessibility purposes
If the user clicks on the Edit button, I want to focus on Delete button. Similarly, if the user clicks Cancel button, I want to focus on Edit button.
Is there a way I can do that in Jetpack compose?