IconButton.kt

/*
 * Copyright 2023 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.tv.material3

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics

/**
 * Material Design standard icon button for TV.
 *
 * 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]. If using a custom icon, note that the typical size for
 * the internal icon is 24 x 24 dp.
 *
 * The default text style for internal [Text] components will be set to [Typography.labelLarge].
 *
 * @param onClick called when this button is clicked
 * @param modifier the [Modifier] to be applied to this button
 * @param enabled controls the enabled state of this button. When `false`, this component will not
 * respond to user input, and it will appear visually disabled and disabled to accessibility
 * services.
 * @param scale Defines size of the Button relative to its original size.
 * @param glow Shadow to be shown behind the Button.
 * @param shape Defines the Button's shape.
 * @param colors Color to be used for background and content of the Button
 * @param border Defines a border around the Button.
 * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
 * for this button. You can create and pass in your own `remember`ed instance to observe
 * [Interaction]s and customize the appearance / behavior of this button in different states.
 * @param content the content of the button, typically an [Icon]
 */
@ExperimentalTvMaterial3Api
@NonRestartableComposable
@Composable
fun IconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    scale: ButtonScale = IconButtonDefaults.scale(),
    glow: ButtonGlow = IconButtonDefaults.glow(),
    shape: ButtonShape = IconButtonDefaults.shape(),
    colors: ButtonColors = IconButtonDefaults.colors(),
    border: ButtonBorder = IconButtonDefaults.border(),
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable BoxScope.() -> Unit
) {
    Surface(
        modifier = modifier
            .semantics { role = Role.Button }
            .size(IconButtonDefaults.MediumButtonSize),
        onClick = onClick,
        enabled = enabled,
        shape = shape.toClickableSurfaceShape(),
        color = colors.toClickableSurfaceContainerColor(),
        contentColor = colors.toClickableSurfaceContentColor(),
        scale = scale.toClickableSurfaceScale(),
        border = border.toClickableSurfaceBorder(),
        glow = glow.toClickableSurfaceGlow(),
        interactionSource = interactionSource
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center,
            content = content
        )
    }
}

/**
 * Material Design standard icon button for TV.
 *
 * 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]. 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.
 *
 * The default text style for internal [Text] components will be set to [Typography.labelLarge].
 *
 * @param onClick called when this button is clicked
 * @param modifier the [Modifier] to be applied to this button
 * @param enabled controls the enabled state of this button. When `false`, this component will not
 * respond to user input, and it will appear visually disabled and disabled to accessibility
 * services.
 * @param scale Defines size of the Button relative to its original size
 * @param glow Shadow to be shown behind the Button.
 * @param shape Defines the Button's shape.
 * @param colors Color to be used for background and content of the Button
 * @param border Defines a border around the Button.
 * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
 * for this button. You can create and pass in your own `remember`ed instance to observe
 * [Interaction]s and customize the appearance / behavior of this button in different states.
 * @param content the content of the button, typically an [Icon]
 */
@ExperimentalTvMaterial3Api
@NonRestartableComposable
@Composable
fun OutlinedIconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    scale: ButtonScale = OutlinedIconButtonDefaults.scale(),
    glow: ButtonGlow = OutlinedIconButtonDefaults.glow(),
    shape: ButtonShape = OutlinedIconButtonDefaults.shape(),
    colors: ButtonColors = OutlinedIconButtonDefaults.colors(),
    border: ButtonBorder = OutlinedIconButtonDefaults.border(),
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable BoxScope.() -> Unit
) {
    Surface(
        modifier = modifier
            .semantics { role = Role.Button }
            .size(OutlinedIconButtonDefaults.MediumButtonSize),
        onClick = onClick,
        enabled = enabled,
        shape = shape.toClickableSurfaceShape(),
        color = colors.toClickableSurfaceContainerColor(),
        contentColor = colors.toClickableSurfaceContentColor(),
        scale = scale.toClickableSurfaceScale(),
        border = border.toClickableSurfaceBorder(),
        glow = glow.toClickableSurfaceGlow(),
        interactionSource = interactionSource
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center,
            content = content
        )
    }
}