NavigationDrawerItemDefaults.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.annotation.FloatRange
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.tv.material3.tokens.Elevation

/**
 * Contains the default values used by selectable [NavigationDrawerItem]
 */
object NavigationDrawerItemDefaults {
    /**
     * The default Icon size used by [NavigationDrawerItem]
     */
    val IconSize = 24.dp

    /**
     * The size of the [NavigationDrawerItem] when the drawer is collapsed
     */
    val CollapsedDrawerItemWidth = 56.dp

    /**
     * The size of the [NavigationDrawerItem] when the drawer is expanded
     */
    val ExpandedDrawerItemWidth = 256.dp

    /**
     * The default content padding [PaddingValues] used by [NavigationDrawerItem] with 1 line when
     * the drawer is expanded
     */
    val ContainerHeightOneLine = 56.dp

    /**
     * The default content padding [PaddingValues] used by [NavigationDrawerItem] with 2 lines when
     * the drawer is expanded
     */
    val ContainerHeightTwoLine = 64.dp

    /**
     * The default elevation used by [NavigationDrawerItem]
     */
    val NavigationDrawerItemElevation = Elevation.Level0

    /**
     * Animation enter default for inner content
     */
    val ContentAnimationEnter = fadeIn() + slideIn { IntOffset(-it.width, 0) }

    /**
     * Animation exit default for inner content
     */
    val ContentAnimationExit = fadeOut() + slideOut { IntOffset(0, 0) }

    /**
     * Default border used by [NavigationDrawerItem]
     */
    val DefaultBorder
        @ReadOnlyComposable
        @Composable get() = Border(
            border = BorderStroke(
                width = 2.dp,
                color = MaterialTheme.colorScheme.border
            ),
        )

    /**
     * The default container color used by [NavigationDrawerItem]'s trailing badge
     */
    val TrailingBadgeContainerColor
        @ReadOnlyComposable
        @Composable get() = MaterialTheme.colorScheme.tertiary

    /**
     * The default text style used by [NavigationDrawerItem]'s trailing badge
     */
    val TrailingBadgeTextStyle
        @ReadOnlyComposable
        @Composable get() = MaterialTheme.typography.labelSmall

    /**
     * The default content color used by [NavigationDrawerItem]'s trailing badge
     */
    val TrailingBadgeContentColor
        @ReadOnlyComposable
        @Composable get() = MaterialTheme.colorScheme.onTertiary

    /**
     * Creates a trailing badge for [NavigationDrawerItem]
     */
    @Composable
    @OptIn(ExperimentalTvMaterial3Api::class) // TODO: This will be removed once Text API is marked as stable
    fun TrailingBadge(
        text: String,
        containerColor: Color = TrailingBadgeContainerColor,
        contentColor: Color = TrailingBadgeContentColor
    ) {
        Box(
            modifier = Modifier
                .background(containerColor, RoundedCornerShape(50))
                .padding(10.dp, 2.dp)
        ) {
            ProvideTextStyle(value = TrailingBadgeTextStyle) {
                Text(
                    text = text,
                    color = contentColor,
                )
            }
        }
    }

    /**
     * Creates a [NavigationDrawerItemShape] that represents the default container shapes
     * used in a selectable [NavigationDrawerItem]
     *
     * @param shape the default shape used when the [NavigationDrawerItem] is enabled
     * @param focusedShape the shape used when the [NavigationDrawerItem] is enabled and focused
     * @param pressedShape the shape used when the [NavigationDrawerItem] is enabled and pressed
     * @param selectedShape the shape used when the [NavigationDrawerItem] is enabled and selected
     * @param disabledShape the shape used when the [NavigationDrawerItem] is not enabled
     * @param focusedSelectedShape the shape used when the [NavigationDrawerItem] is enabled,
     * focused and selected
     * @param focusedDisabledShape the shape used when the [NavigationDrawerItem] is not enabled
     * and focused
     * @param pressedSelectedShape the shape used when the [NavigationDrawerItem] is enabled,
     * pressed and selected
     */
    fun shape(
        shape: Shape = RoundedCornerShape(50),
        focusedShape: Shape = shape,
        pressedShape: Shape = shape,
        selectedShape: Shape = shape,
        disabledShape: Shape = shape,
        focusedSelectedShape: Shape = shape,
        focusedDisabledShape: Shape = disabledShape,
        pressedSelectedShape: Shape = shape
    ) = NavigationDrawerItemShape(
        shape = shape,
        focusedShape = focusedShape,
        pressedShape = pressedShape,
        selectedShape = selectedShape,
        disabledShape = disabledShape,
        focusedSelectedShape = focusedSelectedShape,
        focusedDisabledShape = focusedDisabledShape,
        pressedSelectedShape = pressedSelectedShape
    )

    /**
     * Creates a [NavigationDrawerItemColors] that represents the default container &
     * content colors used in a selectable [NavigationDrawerItem]
     *
     * @param containerColor the default container color used when the [NavigationDrawerItem] is
     * enabled
     * @param contentColor the default content color used when the [NavigationDrawerItem] is enabled
     * @param inactiveContentColor the content color used when none of the navigation items have
     * focus
     * @param focusedContainerColor the container color used when the [NavigationDrawerItem] is
     * enabled and focused
     * @param focusedContentColor the content color used when the [NavigationDrawerItem] is enabled
     * and focused
     * @param pressedContainerColor the container color used when the [NavigationDrawerItem] is
     * enabled and pressed
     * @param pressedContentColor the content color used when the [NavigationDrawerItem] is enabled
     * and pressed
     * @param selectedContainerColor the container color used when the [NavigationDrawerItem] is
     * enabled and selected
     * @param selectedContentColor the content color used when the [NavigationDrawerItem] is
     * enabled and selected
     * @param disabledContainerColor the container color used when the [NavigationDrawerItem] is
     * not enabled
     * @param disabledContentColor the content color used when the [NavigationDrawerItem] is not
     * enabled
     * @param disabledInactiveContentColor the content color used when none of the navigation items
     * have focus and this item is disabled
     * @param focusedSelectedContainerColor the container color used when the
     * NavigationDrawerItem is enabled, focused and selected
     * @param focusedSelectedContentColor the content color used when the [NavigationDrawerItem]
     * is enabled, focused and selected
     * @param pressedSelectedContainerColor the container color used when the
     * [NavigationDrawerItem] is enabled, pressed and selected
     * @param pressedSelectedContentColor the content color used when the [NavigationDrawerItem] is
     * enabled, pressed and selected
     */
    @ReadOnlyComposable
    @Composable
    fun colors(
        containerColor: Color = Color.Transparent,
        contentColor: Color = MaterialTheme.colorScheme.onSurface,
        inactiveContentColor: Color = contentColor.copy(alpha = 0.4f),
        focusedContainerColor: Color = MaterialTheme.colorScheme.inverseSurface,
        focusedContentColor: Color = contentColorFor(focusedContainerColor),
        pressedContainerColor: Color = focusedContainerColor,
        pressedContentColor: Color = contentColorFor(focusedContainerColor),
        selectedContainerColor: Color =
            MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.4f),
        selectedContentColor: Color = MaterialTheme.colorScheme.onSecondaryContainer,
        disabledContainerColor: Color = Color.Transparent,
        disabledContentColor: Color = MaterialTheme.colorScheme.onSurface,
        disabledInactiveContentColor: Color = disabledContentColor.copy(alpha = 0.4f),
        focusedSelectedContainerColor: Color = focusedContainerColor,
        focusedSelectedContentColor: Color = focusedContentColor,
        pressedSelectedContainerColor: Color = pressedContainerColor,
        pressedSelectedContentColor: Color = pressedContentColor
    ) = NavigationDrawerItemColors(
        containerColor = containerColor,
        contentColor = contentColor,
        inactiveContentColor = inactiveContentColor,
        focusedContainerColor = focusedContainerColor,
        focusedContentColor = focusedContentColor,
        pressedContainerColor = pressedContainerColor,
        pressedContentColor = pressedContentColor,
        selectedContainerColor = selectedContainerColor,
        selectedContentColor = selectedContentColor,
        disabledContainerColor = disabledContainerColor,
        disabledContentColor = disabledContentColor,
        disabledInactiveContentColor = disabledInactiveContentColor,
        focusedSelectedContainerColor = focusedSelectedContainerColor,
        focusedSelectedContentColor = focusedSelectedContentColor,
        pressedSelectedContainerColor = pressedSelectedContainerColor,
        pressedSelectedContentColor = pressedSelectedContentColor
    )

    /**
     * Creates a [NavigationDrawerItemScale] that represents the default scales used in a
     * selectable [NavigationDrawerItem]
     *
     * scales are used to modify the size of a composable in different [Interaction] states
     * e.g. `1f` (original) in default state, `1.2f` (scaled up) in focused state, `0.8f` (scaled
     * down) in pressed state, etc.
     *
     * @param scale the scale used when the [NavigationDrawerItem] is enabled
     * @param focusedScale the scale used when the [NavigationDrawerItem] is enabled and focused
     * @param pressedScale the scale used when the [NavigationDrawerItem] is enabled and pressed
     * @param selectedScale the scale used when the [NavigationDrawerItem] is enabled and selected
     * @param disabledScale the scale used when the [NavigationDrawerItem] is not enabled
     * @param focusedSelectedScale the scale used when the [NavigationDrawerItem] is enabled,
     * focused and selected
     * @param focusedDisabledScale the scale used when the [NavigationDrawerItem] is not enabled and
     * focused
     * @param pressedSelectedScale the scale used when the [NavigationDrawerItem] is enabled,
     * pressed and selected
     */
    fun scale(
        @FloatRange(from = 0.0) scale: Float = 1f,
        @FloatRange(from = 0.0) focusedScale: Float = 1.05f,
        @FloatRange(from = 0.0) pressedScale: Float = scale,
        @FloatRange(from = 0.0) selectedScale: Float = scale,
        @FloatRange(from = 0.0) disabledScale: Float = scale,
        @FloatRange(from = 0.0) focusedSelectedScale: Float = focusedScale,
        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale,
        @FloatRange(from = 0.0) pressedSelectedScale: Float = scale
    ) = NavigationDrawerItemScale(
        scale = scale,
        focusedScale = focusedScale,
        pressedScale = pressedScale,
        selectedScale = selectedScale,
        disabledScale = disabledScale,
        focusedSelectedScale = focusedSelectedScale,
        focusedDisabledScale = focusedDisabledScale,
        pressedSelectedScale = pressedSelectedScale
    )

    /**
     * Creates a [NavigationDrawerItemBorder] that represents the default [Border]s
     * applied on a selectable [NavigationDrawerItem] in different [Interaction] states
     *
     * @param border the default [Border] used when the [NavigationDrawerItem] is enabled
     * @param focusedBorder the [Border] used when the [NavigationDrawerItem] is enabled and focused
     * @param pressedBorder the [Border] used when the [NavigationDrawerItem] is enabled and pressed
     * @param selectedBorder the [Border] used when the [NavigationDrawerItem] is enabled and
     * selected
     * @param disabledBorder the [Border] used when the [NavigationDrawerItem] is not enabled
     * @param focusedSelectedBorder the [Border] used when the [NavigationDrawerItem] is enabled,
     * focused and selected
     * @param focusedDisabledBorder the [Border] used when the [NavigationDrawerItem] is not
     * enabled and focused
     * @param pressedSelectedBorder the [Border] used when the [NavigationDrawerItem] is enabled,
     * pressed and selected
     */
    @ReadOnlyComposable
    @Composable
    fun border(
        border: Border = Border.None,
        focusedBorder: Border = border,
        pressedBorder: Border = focusedBorder,
        selectedBorder: Border = border,
        disabledBorder: Border = border,
        focusedSelectedBorder: Border = focusedBorder,
        focusedDisabledBorder: Border = DefaultBorder,
        pressedSelectedBorder: Border = border
    ) = NavigationDrawerItemBorder(
        border = border,
        focusedBorder = focusedBorder,
        pressedBorder = pressedBorder,
        selectedBorder = selectedBorder,
        disabledBorder = disabledBorder,
        focusedSelectedBorder = focusedSelectedBorder,
        focusedDisabledBorder = focusedDisabledBorder,
        pressedSelectedBorder = pressedSelectedBorder
    )

    /**
     * Creates a [NavigationDrawerItemGlow] that represents the default [Glow]s used in a
     * selectable [NavigationDrawerItem]
     *
     * @param glow the [Glow] used when the [NavigationDrawerItem] is enabled, and has no other
     * [Interaction]s
     * @param focusedGlow the [Glow] used when the [NavigationDrawerItem] is enabled and focused
     * @param pressedGlow the [Glow] used when the [NavigationDrawerItem] is enabled and pressed
     * @param selectedGlow the [Glow] used when the [NavigationDrawerItem] is enabled and selected
     * @param focusedSelectedGlow the [Glow] used when the [NavigationDrawerItem] is enabled,
     * focused and selected
     * @param pressedSelectedGlow the [Glow] used when the [NavigationDrawerItem] is enabled,
     * pressed and selected
     */
    fun glow(
        glow: Glow = Glow.None,
        focusedGlow: Glow = glow,
        pressedGlow: Glow = glow,
        selectedGlow: Glow = glow,
        focusedSelectedGlow: Glow = focusedGlow,
        pressedSelectedGlow: Glow = glow
    ) = NavigationDrawerItemGlow(
        glow = glow,
        focusedGlow = focusedGlow,
        pressedGlow = pressedGlow,
        selectedGlow = selectedGlow,
        focusedSelectedGlow = focusedSelectedGlow,
        pressedSelectedGlow = pressedSelectedGlow
    )
}