/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.material3
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material3.tokens.FilledIconButtonTokens
import androidx.compose.material3.tokens.FilledTonalIconButtonTokens
import androidx.compose.material3.tokens.IconButtonTokens
import androidx.compose.material3.tokens.OutlinedIconButtonTokens
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
/**
* Material Design standard icon button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* @sample androidx.compose.material3.samples.IconButtonSample
*
* @param onClick called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.iconButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) {
@Suppress("DEPRECATION_ERROR")
Box(
modifier = modifier
.minimumInteractiveComponentSize()
.size(IconButtonTokens.StateLayerSize)
.clip(IconButtonTokens.StateLayerShape.value)
.background(color = colors.containerColor(enabled))
.clickable(
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = androidx.compose.material.ripple.rememberRipple(
bounded = false,
radius = IconButtonTokens.StateLayerSize / 2
)
),
contentAlignment = Alignment.Center
) {
val contentColor = colors.contentColor(enabled)
CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
}
}
/**
* Material Design standard icon toggle button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* @sample androidx.compose.material3.samples.IconToggleButtonSample
*
* @param checked whether this icon button is toggled on or off
* @param onCheckedChange called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.iconToggleButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@Composable
fun IconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) {
@Suppress("DEPRECATION_ERROR")
Box(
modifier = modifier
.minimumInteractiveComponentSize()
.size(IconButtonTokens.StateLayerSize)
.clip(IconButtonTokens.StateLayerShape.value)
.background(color = colors.containerColor(enabled, checked).value)
.toggleable(
value = checked,
onValueChange = onCheckedChange,
enabled = enabled,
role = Role.Checkbox,
interactionSource = interactionSource,
indication = androidx.compose.material.ripple.rememberRipple(
bounded = false,
radius = IconButtonTokens.StateLayerSize / 2
)
),
contentAlignment = Alignment.Center
) {
val contentColor = colors.contentColor(enabled, checked).value
CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
}
}
/**
* Material Design filled icon button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* Filled icon button sample:
* @sample androidx.compose.material3.samples.FilledIconButtonSample
*
* @param onClick called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container
* @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.filledIconButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@Composable
fun FilledIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled),
contentColor = colors.contentColor(enabled),
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(FilledIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Material Design filled tonal icon button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* A filled tonal icon button is a medium-emphasis icon button that is an alternative middle
* ground between the default [FilledIconButton] and [OutlinedIconButton].
* They can be used in contexts where the lower-priority icon button requires slightly more emphasis
* than an outline would give.
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* Filled tonal icon button sample:
* @sample androidx.compose.material3.samples.FilledTonalIconButtonSample
*
* @param onClick called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container
* @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.filledIconButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@Composable
fun FilledTonalIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled),
contentColor = colors.contentColor(enabled),
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(FilledTonalIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Material Design filled icon toggle button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* Toggleable filled icon button sample:
* @sample androidx.compose.material3.samples.FilledIconToggleButtonSample
*
* @param checked whether this icon button is toggled on or off
* @param onCheckedChange called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container
* @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.filledIconToggleButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilledIconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
colors: IconToggleButtonColors = IconButtonDefaults.filledIconToggleButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
checked = checked,
onCheckedChange = onCheckedChange,
modifier = modifier.semantics { role = Role.Checkbox },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled, checked).value,
contentColor = colors.contentColor(enabled, checked).value,
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(FilledIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Material Design filled tonal icon toggle button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* A filled tonal toggle icon button is a medium-emphasis icon button that is an alternative
* middle ground between the default [FilledIconToggleButton] and [OutlinedIconToggleButton].
* They can be used in contexts where the lower-priority icon button requires slightly more emphasis
* than an outline would give.
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* Toggleable filled tonal icon button sample:
* @sample androidx.compose.material3.samples.FilledTonalIconToggleButtonSample
*
* @param checked whether this icon button is toggled on or off
* @param onCheckedChange called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container
* @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.filledIconToggleButtonColors].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FilledTonalIconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.filledShape,
colors: IconToggleButtonColors = IconButtonDefaults.filledTonalIconToggleButtonColors(),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
checked = checked,
onCheckedChange = onCheckedChange,
modifier = modifier.semantics { role = Role.Checkbox },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled, checked).value,
contentColor = colors.contentColor(enabled, checked).value,
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(FilledTonalIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Material Design outlined icon button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* Use this "contained" icon button when the component requires more visual separation from the
* background.
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* The outlined icon button has an overall minimum touch target size of 48 x 48dp, to meet
* accessibility guidelines.
*
* @sample androidx.compose.material3.samples.OutlinedIconButtonSample
*
* @param onClick called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container and border (when [border] is not
* null)
* @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.outlinedIconButtonColors].
* @param border the border to draw around the container of this icon button. Pass `null` for no
* border. See [IconButtonDefaults.outlinedIconButtonBorder].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@Composable
fun OutlinedIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.outlinedShape,
colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors(),
border: BorderStroke? = IconButtonDefaults.outlinedIconButtonBorder(enabled),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
onClick = onClick,
modifier = modifier.semantics { role = Role.Button },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled),
contentColor = colors.contentColor(enabled),
border = border,
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(OutlinedIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Material Design outlined icon toggle button.
*
* Icon buttons help people take supplementary actions with a single tap. They’re used when a
* compact button is required, such as in a toolbar or image list.
*
* 
*
* [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
* custom icon, note that the typical size for the internal icon is 24 x 24 dp.
* This icon button has an overall minimum touch target size of 48 x 48dp, to meet accessibility
* guidelines.
*
* @sample androidx.compose.material3.samples.OutlinedIconToggleButtonSample
*
* @param checked whether this icon button is toggled on or off
* @param onCheckedChange called when this icon button is clicked
* @param modifier the [Modifier] to be applied to this icon button
* @param enabled controls the enabled state of this icon button. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
* services.
* @param shape defines the shape of this icon button's container and border (when [border] is not
* null)
* @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
* button in different states. See [IconButtonDefaults.outlinedIconToggleButtonColors].
* @param border the border to draw around the container of this icon button. Pass `null` for no
* border. See [IconButtonDefaults.outlinedIconToggleButtonBorder].
* @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
* for this icon button. You can create and pass in your own `remember`ed instance to observe
* [Interaction]s and customize the appearance / behavior of this icon button in different states.
* @param content the content of this icon button, typically an [Icon]
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OutlinedIconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = IconButtonDefaults.outlinedShape,
colors: IconToggleButtonColors = IconButtonDefaults.outlinedIconToggleButtonColors(),
border: BorderStroke? = IconButtonDefaults.outlinedIconToggleButtonBorder(enabled, checked),
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
) = Surface(
checked = checked,
onCheckedChange = onCheckedChange,
modifier = modifier.semantics { role = Role.Checkbox },
enabled = enabled,
shape = shape,
color = colors.containerColor(enabled, checked).value,
contentColor = colors.contentColor(enabled, checked).value,
border = border,
interactionSource = interactionSource
) {
Box(
modifier = Modifier.size(OutlinedIconButtonTokens.ContainerSize),
contentAlignment = Alignment.Center
) {
content()
}
}
/**
* Contains the default values used by all icon button types.
*/
object IconButtonDefaults {
/** Default shape for a filled icon button. */
val filledShape: Shape @Composable get() = FilledIconButtonTokens.ContainerShape.value
/** Default shape for an outlined icon button. */
val outlinedShape: Shape
@Composable get() =
OutlinedIconButtonTokens.ContainerShape.value
/**
* Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
*/
@Composable
fun iconButtonColors(): IconButtonColors {
val colors = MaterialTheme.colorScheme.defaultIconButtonColors
val contentColor = LocalContentColor.current
if (colors.contentColor == contentColor) {
return colors
} else {
return colors.copy(
contentColor = contentColor,
disabledContentColor =
contentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity)
)
}
}
/**
* Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
*/
@Composable
fun iconButtonColors(
containerColor: Color = Color.Unspecified,
contentColor: Color = LocalContentColor.current,
disabledContainerColor: Color = Color.Unspecified,
disabledContentColor: Color =
contentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity)
): IconButtonColors = MaterialTheme.colorScheme.defaultIconButtonColors.copy(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
)
internal val ColorScheme.defaultIconButtonColors: IconButtonColors
@Composable
get() {
return defaultIconButtonColorsCached ?: run {
val localContentColor = LocalContentColor.current
IconButtonColors(
containerColor = Color.Transparent,
contentColor = localContentColor,
disabledContainerColor = Color.Transparent,
disabledContentColor =
localContentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity)
).also {
defaultIconButtonColorsCached = it
}
}
}
/**
* Creates a [IconToggleButtonColors] that represents the default colors used in a
* [IconToggleButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
* @param checkedContainerColor the container color of this icon button when checked.
* @param checkedContentColor the content color of this icon button when checked.
*/
@Composable
fun iconToggleButtonColors(
containerColor: Color = Color.Transparent,
contentColor: Color = LocalContentColor.current,
disabledContainerColor: Color = Color.Transparent,
disabledContentColor: Color =
contentColor.copy(alpha = IconButtonTokens.DisabledIconOpacity),
checkedContainerColor: Color = Color.Transparent,
checkedContentColor: Color = IconButtonTokens.SelectedIconColor.value
): IconToggleButtonColors =
IconToggleButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
checkedContainerColor = checkedContainerColor,
checkedContentColor = checkedContentColor,
)
/**
* Creates a [IconButtonColors] that represents the default colors used in a [FilledIconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
*/
@Composable
fun filledIconButtonColors(
containerColor: Color = FilledIconButtonTokens.ContainerColor.value,
contentColor: Color = contentColorFor(containerColor),
disabledContainerColor: Color = FilledIconButtonTokens.DisabledContainerColor.value
.copy(alpha = FilledIconButtonTokens.DisabledContainerOpacity),
disabledContentColor: Color = FilledIconButtonTokens.DisabledColor.value
.copy(alpha = FilledIconButtonTokens.DisabledOpacity)
): IconButtonColors =
IconButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
)
/**
* Creates a [IconToggleButtonColors] that represents the default colors used in a
* [FilledIconToggleButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
* @param checkedContainerColor the container color of this icon button when checked.
* @param checkedContentColor the content color of this icon button when checked.
*/
@Composable
fun filledIconToggleButtonColors(
containerColor: Color = FilledIconButtonTokens.UnselectedContainerColor.value,
// TODO(b/228455081): Using contentColorFor here will return OnSurfaceVariant,
// while the token value is Primary.
contentColor: Color = FilledIconButtonTokens.ToggleUnselectedColor.value,
disabledContainerColor: Color = FilledIconButtonTokens.DisabledContainerColor.value
.copy(alpha = FilledIconButtonTokens.DisabledContainerOpacity),
disabledContentColor: Color = FilledIconButtonTokens.DisabledColor.value
.copy(alpha = FilledIconButtonTokens.DisabledOpacity),
checkedContainerColor: Color = FilledIconButtonTokens.SelectedContainerColor.value,
checkedContentColor: Color = contentColorFor(checkedContainerColor)
): IconToggleButtonColors =
IconToggleButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
checkedContainerColor = checkedContainerColor,
checkedContentColor = checkedContentColor,
)
/**
* Creates a [IconButtonColors] that represents the default colors used in a
* [FilledTonalIconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
*/
@Composable
fun filledTonalIconButtonColors(
containerColor: Color = FilledTonalIconButtonTokens.ContainerColor.value,
contentColor: Color = contentColorFor(containerColor),
disabledContainerColor: Color = FilledTonalIconButtonTokens.DisabledContainerColor.value
.copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
disabledContentColor: Color = FilledTonalIconButtonTokens.DisabledColor.value
.copy(alpha = FilledTonalIconButtonTokens.DisabledOpacity)
): IconButtonColors =
IconButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
)
/**
* Creates a [IconToggleButtonColors] that represents the default colors used in a
* [FilledTonalIconToggleButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
* @param checkedContainerColor the container color of this icon button when checked.
* @param checkedContentColor the content color of this icon button when checked.
*/
@Composable
fun filledTonalIconToggleButtonColors(
containerColor: Color = FilledTonalIconButtonTokens.UnselectedContainerColor.value,
contentColor: Color = contentColorFor(containerColor),
disabledContainerColor: Color = FilledTonalIconButtonTokens.DisabledContainerColor.value
.copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
disabledContentColor: Color = FilledTonalIconButtonTokens.DisabledColor.value
.copy(alpha = FilledTonalIconButtonTokens.DisabledOpacity),
checkedContainerColor: Color =
FilledTonalIconButtonTokens.SelectedContainerColor.value,
checkedContentColor: Color = FilledTonalIconButtonTokens.ToggleSelectedColor.value
): IconToggleButtonColors =
IconToggleButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
checkedContainerColor = checkedContainerColor,
checkedContentColor = checkedContentColor,
)
/**
* Creates a [IconButtonColors] that represents the default colors used in a
* [OutlinedIconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
*/
@Composable
fun outlinedIconButtonColors(
containerColor: Color = Color.Transparent,
contentColor: Color = LocalContentColor.current,
disabledContainerColor: Color = Color.Transparent,
disabledContentColor: Color =
contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
): IconButtonColors =
IconButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
)
/**
* Creates a [IconToggleButtonColors] that represents the default colors used in a
* [OutlinedIconToggleButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
* @param checkedContainerColor the container color of this icon button when checked.
* @param checkedContentColor the content color of this icon button when checked.
*/
@Composable
fun outlinedIconToggleButtonColors(
containerColor: Color = Color.Transparent,
contentColor: Color = LocalContentColor.current,
disabledContainerColor: Color = Color.Transparent,
disabledContentColor: Color =
contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
checkedContainerColor: Color =
OutlinedIconButtonTokens.SelectedContainerColor.value,
checkedContentColor: Color = contentColorFor(checkedContainerColor)
): IconToggleButtonColors =
IconToggleButtonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = disabledContainerColor,
disabledContentColor = disabledContentColor,
checkedContainerColor = checkedContainerColor,
checkedContentColor = checkedContentColor,
)
/**
* Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] and
* [checked] state.
*
* @param enabled whether the icon button is enabled
* @param checked whether the icon button is checked
*/
@Composable
fun outlinedIconToggleButtonBorder(enabled: Boolean, checked: Boolean): BorderStroke? {
if (checked) {
return null
}
return outlinedIconButtonBorder(enabled)
}
/**
* Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] state.
*
* @param enabled whether the icon button is enabled
*/
@Composable
fun outlinedIconButtonBorder(enabled: Boolean): BorderStroke {
val color: Color = if (enabled) {
LocalContentColor.current
} else {
LocalContentColor.current
.copy(alpha = OutlinedIconButtonTokens.DisabledUnselectedOutlineOpacity)
}
return remember(color) {
BorderStroke(OutlinedIconButtonTokens.UnselectedOutlineWidth, color)
}
}
}
/**
* Represents the container and content colors used in an icon button in different states.
*
* @constructor create an instance with arbitrary colors.
* - See [IconButtonDefaults.filledIconButtonColors] and
* [IconButtonDefaults.filledTonalIconButtonColors] for the default colors used in a
* [FilledIconButton].
* - See [IconButtonDefaults.outlinedIconButtonColors] for the default colors used in an
* [OutlinedIconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
*/
@Immutable
class IconButtonColors constructor(
val containerColor: Color,
val contentColor: Color,
val disabledContainerColor: Color,
val disabledContentColor: Color,
) {
/**
* Returns a copy of this IconButtonColors, optionally overriding some of the values.
* This uses the Color.Unspecified to mean “use the value from the source”
*/
fun copy(
containerColor: Color = this.containerColor,
contentColor: Color = this.contentColor,
disabledContainerColor: Color = this.disabledContainerColor,
disabledContentColor: Color = this.disabledContentColor,
) = IconButtonColors(
containerColor.takeOrElse { this.containerColor },
contentColor.takeOrElse { this.contentColor },
disabledContainerColor.takeOrElse { this.disabledContainerColor },
disabledContentColor.takeOrElse { this.disabledContentColor },
)
/**
* Represents the container color for this icon button, depending on [enabled].
*
* @param enabled whether the icon button is enabled
*/
@Stable
internal fun containerColor(enabled: Boolean): Color =
if (enabled) containerColor else disabledContainerColor
/**
* Represents the content color for this icon button, depending on [enabled].
*
* @param enabled whether the icon button is enabled
*/
@Stable
internal fun contentColor(enabled: Boolean): Color =
if (enabled) contentColor else disabledContentColor
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other !is IconButtonColors) return false
if (containerColor != other.containerColor) return false
if (contentColor != other.contentColor) return false
if (disabledContainerColor != other.disabledContainerColor) return false
if (disabledContentColor != other.disabledContentColor) return false
return true
}
override fun hashCode(): Int {
var result = containerColor.hashCode()
result = 31 * result + contentColor.hashCode()
result = 31 * result + disabledContainerColor.hashCode()
result = 31 * result + disabledContentColor.hashCode()
return result
}
}
/**
* Represents the container and content colors used in a toggleable icon button in
* different states.
*
* @constructor create an instance with arbitrary colors.
* - See [IconButtonDefaults.filledIconToggleButtonColors] and
* [IconButtonDefaults.filledTonalIconToggleButtonColors] for the default colors used in a
* [FilledIconButton].
* - See [IconButtonDefaults.outlinedIconToggleButtonColors] for the default colors used in a
* toggleable [OutlinedIconButton].
*
* @param containerColor the container color of this icon button when enabled.
* @param contentColor the content color of this icon button when enabled.
* @param disabledContainerColor the container color of this icon button when not enabled.
* @param disabledContentColor the content color of this icon button when not enabled.
* @param checkedContainerColor the container color of this icon button when checked.
* @param checkedContentColor the content color of this icon button when checked.
*/
@Immutable
class IconToggleButtonColors constructor(
val containerColor: Color,
val contentColor: Color,
val disabledContainerColor: Color,
val disabledContentColor: Color,
val checkedContainerColor: Color,
val checkedContentColor: Color,
) {
/**
* Represents the container color for this icon button, depending on [enabled] and [checked].
*
* @param enabled whether the icon button is enabled
* @param checked whether the icon button is checked
*/
@Composable
internal fun containerColor(enabled: Boolean, checked: Boolean): State {
val target = when {
!enabled -> disabledContainerColor
!checked -> containerColor
else -> checkedContainerColor
}
return rememberUpdatedState(target)
}
/**
* Represents the content color for this icon button, depending on [enabled] and [checked].
*
* @param enabled whether the icon button is enabled
* @param checked whether the icon button is checked
*/
@Composable
internal fun contentColor(enabled: Boolean, checked: Boolean): State {
val target = when {
!enabled -> disabledContentColor
!checked -> contentColor
else -> checkedContentColor
}
return rememberUpdatedState(target)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other !is IconToggleButtonColors) return false
if (containerColor != other.containerColor) return false
if (contentColor != other.contentColor) return false
if (disabledContainerColor != other.disabledContainerColor) return false
if (disabledContentColor != other.disabledContentColor) return false
if (checkedContainerColor != other.checkedContainerColor) return false
if (checkedContentColor != other.checkedContentColor) return false
return true
}
override fun hashCode(): Int {
var result = containerColor.hashCode()
result = 31 * result + contentColor.hashCode()
result = 31 * result + disabledContainerColor.hashCode()
result = 31 * result + disabledContentColor.hashCode()
result = 31 * result + checkedContainerColor.hashCode()
result = 31 * result + checkedContentColor.hashCode()
return result
}
}