refactor: support code comments and some tweaks for all components

This commit is contained in:
2024-01-06 11:02:25 +08:00
parent 6e04a33fa7
commit 01574c28d3
30 changed files with 1431 additions and 232 deletions

View File

@@ -30,6 +30,10 @@ import androidx.compose.ui.platform.LocalContext
import com.highcapable.betterandroid.ui.extension.component.feature.SystemColors
import com.highcapable.betterandroid.ui.extension.graphics.mixColorOf
/**
* Whether dynamic color is available for current system.
* @return [Boolean]
*/
@Composable
@ReadOnlyComposable
actual fun isDynamicColorAvailable() = SystemColors.isAvailable
@@ -46,8 +50,7 @@ internal actual val DynamicLightColors
themeSecondary = Color(DynamicColors.materialDynamicPrimary(60)).copy(alpha = 0.65f),
themeTertiary = Color(DynamicColors.materialDynamicPrimary(60)).copy(alpha = 0.15f),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
) else DefaultLightColors
internal actual val DynamicDarkColors
@@ -62,8 +65,7 @@ internal actual val DynamicDarkColors
themeSecondary = Color(DynamicColors.materialDynamicSecondary(60)).copy(alpha = 0.65f),
themeTertiary = Color(DynamicColors.materialDynamicSecondary(60)).copy(alpha = 0.25f),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
) else DefaultDarkColors
internal actual val DynamicBlackColors
@@ -78,8 +80,7 @@ internal actual val DynamicBlackColors
themeSecondary = Color(DynamicColors.materialDynamicSecondary(60)).copy(alpha = 0.65f),
themeTertiary = Color(DynamicColors.materialDynamicSecondary(60)).copy(alpha = 0.27f),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
) else DefaultBlackColors
private val DynamicColors

View File

@@ -29,6 +29,9 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
/**
* Colors defines for Flexi UI.
*/
@Stable
data class Colors(
var backgroundPrimary: Color,
@@ -39,8 +42,7 @@ data class Colors(
var themeSecondary: Color,
var themeTertiary: Color,
var textPrimary: Color,
var textSecondary: Color,
var isLight: Boolean
var textSecondary: Color
)
@get:Composable
@@ -64,8 +66,7 @@ internal val DefaultLightColors = Colors(
themeSecondary = Color(0xA6777777),
themeTertiary = Color(0x27777777),
textPrimary = Color(0xFF323B42),
textSecondary = Color(0xFF777777),
isLight = true
textSecondary = Color(0xFF777777)
)
internal val DefaultDarkColors = Colors(
@@ -77,8 +78,7 @@ internal val DefaultDarkColors = Colors(
themeSecondary = Color(0xA6888888),
themeTertiary = Color(0x40888888),
textPrimary = Color(0xFFE3E3E3),
textSecondary = Color(0xFFBBBBBB),
isLight = false
textSecondary = Color(0xFFBBBBBB)
)
internal val DefaultBlackColors = Colors(
@@ -90,8 +90,7 @@ internal val DefaultBlackColors = Colors(
themeSecondary = Color(0xA65B5B5B),
themeTertiary = Color(0x455B5B5B),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val RedLightColors = Colors(
@@ -103,8 +102,7 @@ private val RedLightColors = Colors(
themeSecondary = Color(0xA6FF5545),
themeTertiary = Color(0x27FF5545),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val PinkLightColors = Colors(
@@ -116,8 +114,7 @@ private val PinkLightColors = Colors(
themeSecondary = Color(0xA6FF4E7C),
themeTertiary = Color(0x27FF4E7C),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val PurpleLightColors = Colors(
@@ -129,8 +126,7 @@ private val PurpleLightColors = Colors(
themeSecondary = Color(0xA6A476FF),
themeTertiary = Color(0x27A476FF),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val OrangeLightColors = Colors(
@@ -142,8 +138,7 @@ private val OrangeLightColors = Colors(
themeSecondary = Color(0xA6D27C00),
themeTertiary = Color(0x27D27C00),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val YellowLightColors = Colors(
@@ -155,8 +150,7 @@ private val YellowLightColors = Colors(
themeSecondary = Color(0xA6BA8800),
themeTertiary = Color(0x27BA8800),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val GreenLightColors = Colors(
@@ -168,8 +162,7 @@ private val GreenLightColors = Colors(
themeSecondary = Color(0xA65B9E7A),
themeTertiary = Color(0x275B9E7A),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val BlueLightColors = Colors(
@@ -181,8 +174,7 @@ private val BlueLightColors = Colors(
themeSecondary = Color(0xA60099DF),
themeTertiary = Color(0x270099DF),
textPrimary = DefaultLightColors.textPrimary,
textSecondary = DefaultLightColors.textSecondary,
isLight = true
textSecondary = DefaultLightColors.textSecondary
)
private val RedDarkColors = Colors(
@@ -194,8 +186,7 @@ private val RedDarkColors = Colors(
themeSecondary = Color(0xA6B9856D),
themeTertiary = Color(0x40B9856D),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val PinkDarkColors = Colors(
@@ -207,8 +198,7 @@ private val PinkDarkColors = Colors(
themeSecondary = Color(0xA6BA837B),
themeTertiary = Color(0x40BA837B),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val PurpleDarkColors = Colors(
@@ -220,8 +210,7 @@ private val PurpleDarkColors = Colors(
themeSecondary = Color(0xA69F88AD),
themeTertiary = Color(0x409F88AD),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val OrangeDarkColors = Colors(
@@ -233,8 +222,7 @@ private val OrangeDarkColors = Colors(
themeSecondary = Color(0xA6AE8B5D),
themeTertiary = Color(0x40AE8B5D),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val YellowDarkColors = Colors(
@@ -246,8 +234,7 @@ private val YellowDarkColors = Colors(
themeSecondary = Color(0xA6A18F5C),
themeTertiary = Color(0x40A18F5C),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val GreenDarkColors = Colors(
@@ -259,8 +246,7 @@ private val GreenDarkColors = Colors(
themeSecondary = Color(0xA67F9687),
themeTertiary = Color(0x407F9687),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val BlueDarkColors = Colors(
@@ -272,8 +258,7 @@ private val BlueDarkColors = Colors(
themeSecondary = Color(0xA68091B1),
themeTertiary = Color(0x408091B1),
textPrimary = DefaultDarkColors.textPrimary,
textSecondary = DefaultDarkColors.textSecondary,
isLight = false
textSecondary = DefaultDarkColors.textSecondary
)
private val RedBlackColors = Colors(
@@ -285,8 +270,7 @@ private val RedBlackColors = Colors(
themeSecondary = Color(0xA6B9856D),
themeTertiary = Color(0x45B9856D),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val PinkBlackColors = Colors(
@@ -298,8 +282,7 @@ private val PinkBlackColors = Colors(
themeSecondary = Color(0xA6BA837B),
themeTertiary = Color(0x45BA837B),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val PurpleBlackColors = Colors(
@@ -311,8 +294,7 @@ private val PurpleBlackColors = Colors(
themeSecondary = Color(0xA69F88AD),
themeTertiary = Color(0x459F88AD),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val OrangeBlackColors = Colors(
@@ -324,8 +306,7 @@ private val OrangeBlackColors = Colors(
themeSecondary = Color(0xA6AE8B5D),
themeTertiary = Color(0x45AE8B5D),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val YellowBlackColors = Colors(
@@ -337,8 +318,7 @@ private val YellowBlackColors = Colors(
themeSecondary = Color(0xA6A18F5C),
themeTertiary = Color(0x45A18F5C),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val GreenBlackColors = Colors(
@@ -350,8 +330,7 @@ private val GreenBlackColors = Colors(
themeSecondary = Color(0xA67F9687),
themeTertiary = Color(0x457F9687),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
private val BlueBlackColors = Colors(
@@ -363,14 +342,24 @@ private val BlueBlackColors = Colors(
themeSecondary = Color(0xA68091B1),
themeTertiary = Color(0x458091B1),
textPrimary = DefaultBlackColors.textPrimary,
textSecondary = DefaultBlackColors.textSecondary,
isLight = false
textSecondary = DefaultBlackColors.textSecondary
)
/**
* Whether dynamic color is available for current system.
* @return [Boolean]
*/
@Composable
@ReadOnlyComposable
expect fun isDynamicColorAvailable(): Boolean
/**
* Returns a dynamic color scheme provided by system.
*
* You can use [isDynamicColorAvailable] check it first, otherwise it will return default colors.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
@Composable
@ReadOnlyComposable
fun dynamicColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
@@ -378,41 +367,81 @@ fun dynamicColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = w
else -> DynamicLightColors
}
/**
* Returns a default color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun defaultColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) DefaultBlackColors else DefaultDarkColors
else -> DefaultLightColors
}
/**
* Returns a red color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun redColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) RedBlackColors else RedDarkColors
else -> RedLightColors
}
/**
* Returns a pink color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun pinkColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) PinkBlackColors else PinkDarkColors
else -> PinkLightColors
}
/**
* Returns a purple color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun purpleColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) PurpleBlackColors else PurpleDarkColors
else -> PurpleLightColors
}
/**
* Returns a orange color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun orangeColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) OrangeBlackColors else OrangeDarkColors
else -> OrangeLightColors
}
/**
* Returns a yellow color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun yellowColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) YellowBlackColors else YellowDarkColors
else -> YellowLightColors
}
/**
* Returns a green color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun greenColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) GreenBlackColors else GreenDarkColors
else -> GreenLightColors
}
/**
* Returns a blue color scheme.
* @param darkMode whether to use dark mode color scheme.
* @param blackDarkMode requires [darkMode] is true, whether to use a pure black color scheme.
*/
fun blueColors(darkMode: Boolean = false, blackDarkMode: Boolean = false) = when {
darkMode -> if (blackDarkMode) BlueBlackColors else BlueDarkColors
else -> BlueLightColors

View File

@@ -27,6 +27,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
/**
* Customize Flexi UI theme styles.
*
* Use this function to provide your own theme styles to the content.
* @param colors the colors, default is [FlexiTheme.colors].
* @param shapes the shapes, default is [FlexiTheme.shapes].
* @param typography the typography, default is [FlexiTheme.typography].
* @param content the content.
*/
@Composable
fun FlexiTheme(
colors: Colors = FlexiTheme.colors,
@@ -37,6 +46,17 @@ fun FlexiTheme(
FlexiTheme(colors, shapes, typography, FlexiTheme.sizes, content)
}
/**
* Customize Flexi UI theme styles.
*
* Use this function to provide your own theme styles to the content.
*
* - Note: The [sizes] is experimental for now, its may be change in the future.
* @param colors the colors, default is [FlexiTheme.colors].
* @param shapes the shapes, default is [FlexiTheme.shapes].
* @param sizes the sizes.
* @param typography the typography, default is [FlexiTheme.typography].
*/
@Composable
fun FlexiTheme(
colors: Colors = FlexiTheme.colors,
@@ -53,6 +73,9 @@ fun FlexiTheme(
) { FlexiThemeContent(content) }
}
/**
* Defaults of Flexi UI theme styles.
*/
object FlexiTheme {
val colors: Colors
@Composable

View File

@@ -30,6 +30,9 @@ import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.unit.dp
/**
* Shapes defines for Flexi UI.
*/
@Immutable
data class Shapes(
val primary: CornerBasedShape,

View File

@@ -28,6 +28,9 @@ import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
/**
* Sizes defines for Flexi UI.
*/
@ExperimentalFlexiUISizesApi
@Immutable
data class Sizes(

View File

@@ -30,6 +30,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
/**
* Typography defines for Flexi UI.
*/
@Immutable
data class Typography(
val titlePrimary: TextStyle,

View File

@@ -56,6 +56,12 @@ import com.highcapable.flexiui.resources.Icons
import com.highcapable.flexiui.resources.icon.ArrowNaviUp
import com.highcapable.flexiui.resources.icon.FinishClose
/**
* Colors defines for action bar.
* @param titleTextColor the title text color.
* @param subTextColor the sub text color.
* @param actionContentColor the action content color, usually for icon tint and text color.
*/
@Immutable
data class ActionBarColors(
val titleTextColor: Color,
@@ -63,6 +69,16 @@ data class ActionBarColors(
val actionContentColor: Color
)
/**
* Style defines for action bar.
* @param padding the padding of content.
* @param contentSpacing the spacing between the components of content.
* @param titleTextStyle the title text style.
* @param subTextStyle the sub text style.
* @param actionIconSize the size of action icon.
* @param actionIconPadding the padding of action icon.
* @param actionContentMaxWidth the max width of actions content.
*/
@Immutable
data class ActionBarStyle(
val padding: ComponentPadding,
@@ -74,6 +90,16 @@ data class ActionBarStyle(
val actionContentMaxWidth: Dp
)
/**
* Flexi UI large action bar.
* @see ActionBarDefaults
* @param modifier the [Modifier] to be applied to this action bar.
* @param colors the colors of this action bar, default is [ActionBarDefaults.colors].
* @param style the style of this action bar, default is [ActionBarDefaults.style].
* @param titleText the title text of this action bar, should typically be [Text].
* @param subText the sub text of this action bar, should typically be [Text].
* @param actions the actions displayed at the end of the action bar, should typically be [ActionBarScope.ActionIconButton].
*/
@Composable
fun TopActionBar(
modifier: Modifier = Modifier,
@@ -96,6 +122,18 @@ fun TopActionBar(
)
}
/**
* Flexi UI middle action bar.
* @see TopActionBar
* @param modifier the [Modifier] to be applied to this action bar.
* @param colors the colors of this action bar, default is [ActionBarDefaults.colors].
* @param style the style of this action bar, default is [ActionBarDefaults.style].
* @param titleText the title text of this action bar, should typically be [Text].
* @param subText the sub text of this action bar, should typically be [Text].
* @param finishIcon the finish icon displayed at the start of the action bar, should typically be [ActionBarScope.FinishIconButton].
* @param navigationIcon the navigation icon displayed at the start of the action bar, should typically be [ActionBarScope.NavigationIconButton].
* @param actions the actions displayed at the end of the action bar, should typically be [ActionBarScope.ActionIconButton].
*/
@Composable
fun ActionBar(
modifier: Modifier = Modifier,
@@ -120,6 +158,9 @@ fun ActionBar(
)
}
/**
* Basic action bar for internal use.
*/
@Composable
private fun BasicActionBar(
type: ActionBarType,
@@ -133,8 +174,8 @@ private fun BasicActionBar(
actions: @Composable (ActionBarScope.() -> Unit)?
) {
CompositionLocalProvider(LocalActionBarType provides type) {
val currentColors = colors ?: ActionBar.colors
val currentStyle = style ?: ActionBar.style
val currentColors = colors ?: ActionBarDefaults.colors
val currentStyle = style ?: ActionBarDefaults.style
Box(modifier = modifier.padding(currentStyle.padding)) {
ActionBarImpl(
type = type,
@@ -150,15 +191,27 @@ private fun BasicActionBar(
}
}
/**
* A scope for action bar.
*/
@Stable
interface ActionBarScope {
/**
* Action bar's finish icon button.
* @param onClick the callback when the icon button is clicked.
* @param modifier the [Modifier] to be applied to this icon button.
* @param colors the colors of this icon button, default is [IconButtonDefaults.colors].
* @param style the style of this icon button, default is [IconButtonDefaults.style].
* @param enabled whether this icon button is enabled, default is true.
* @param interactionSource the interaction source of this icon button.
*/
@Composable
fun FinishIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = IconButton.colors,
style: ButtonStyle = IconButton.style,
colors: ButtonColors = IconButtonDefaults.colors,
style: ButtonStyle = IconButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
@@ -172,12 +225,21 @@ interface ActionBarScope {
) { Icon(imageVector = Icons.FinishClose) }
}
/**
* Action bar's navigation icon button.
* @param onClick the callback when the icon button is clicked.
* @param modifier the [Modifier] to be applied to this icon button.
* @param colors the colors of this icon button, default is [IconButtonDefaults.colors].
* @param style the style of this icon button, default is [IconButtonDefaults.style].
* @param enabled whether this icon button is enabled, default is true.
* @param interactionSource the interaction source of this icon button.
*/
@Composable
fun NavigationIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = IconButton.colors,
style: ButtonStyle = IconButton.style,
colors: ButtonColors = IconButtonDefaults.colors,
style: ButtonStyle = IconButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
@@ -191,12 +253,22 @@ interface ActionBarScope {
) { Icon(imageVector = Icons.ArrowNaviUp) }
}
/**
* Action bar's action icon button.
* @param onClick the callback when the icon button is clicked.
* @param modifier the [Modifier] to be applied to this icon button.
* @param colors the colors of this icon button, default is [IconButtonDefaults.colors].
* @param style the style of this icon button, default is [IconButtonDefaults.style].
* @param enabled whether this icon button is enabled, default is true.
* @param interactionSource the interaction source of this icon button.
* @param content the content of the [ActionIconButton], should typically be [Icon].
*/
@Composable
fun ActionIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = IconButton.colors,
style: ButtonStyle = IconButton.style,
colors: ButtonColors = IconButtonDefaults.colors,
style: ButtonStyle = IconButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
@@ -214,6 +286,9 @@ interface ActionBarScope {
}
}
/**
* Action bar's implementation.
*/
@Immutable
private class ActionBarImpl(
val type: ActionBarType,
@@ -226,6 +301,7 @@ private class ActionBarImpl(
val actions: @Composable (ActionBarScope.() -> Unit)?
) : ActionBarScope {
/** Build action bar's content. */
@Composable
fun Content() {
BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
@@ -250,6 +326,7 @@ private class ActionBarImpl(
}
}
/** Build action bar's start content. */
@Composable
private fun StartContent() {
if (type == ActionBarType.MIDDLE && (finishIcon != null || navigationIcon != null))
@@ -264,6 +341,7 @@ private class ActionBarImpl(
}
}
/** Build action bar's center content. */
@Composable
private fun CenterContent() {
Column(
@@ -285,6 +363,7 @@ private class ActionBarImpl(
}
}
/** Build action bar's end content. */
@Composable
private fun EndContent() {
actions?.also { content ->
@@ -297,6 +376,7 @@ private class ActionBarImpl(
}
}
/** Provided the style for action bar's content. */
@Composable
private fun ContentStyle(
color: Color,
@@ -317,7 +397,10 @@ private val ActionBarScope.impl get() = this as? ActionBarImpl? ?: error("Could
@Stable
private enum class ActionBarType { LARGE, MIDDLE }
object ActionBar {
/**
* Defaults of action bar.
*/
object ActionBarDefaults {
val colors: ActionBarColors
@Composable
@ReadOnlyComposable

View File

@@ -55,6 +55,13 @@ import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalShapes
import com.highcapable.flexiui.LocalSizes
/**
* Style defines for area box.
* @param padding the padding of content.
* @param shape the shape of the box.
* @param border the border stroke of the box.
* @param shadowSize the shadow size of the box.
*/
@Immutable
data class AreaBoxStyle(
val padding: ComponentPadding,
@@ -63,12 +70,24 @@ data class AreaBoxStyle(
val shadowSize: Dp
)
/**
* Flexi UI area box of [Box].
* @see AreaRow
* @see AreaColumn
* @param modifier the [Modifier] to be applied to this area box.
* @param initializer the [Modifier] initializer, earlies than [modifier].
* @param color the background color of this area box, default is [AreaBoxDefaults.color].
* @param style the style of this area box, default is [AreaBoxDefaults.style].
* @param contentAlignment the alignment of the content inside this area box, default is [Alignment.TopStart].
* @param propagateMinConstraints whether to propagate the min constraints from the content to this area box.
* @param content the content of the [AreaBox].
*/
@Composable
fun AreaBox(
modifier: Modifier = Modifier,
initializer: @Composable Modifier.() -> Modifier = { Modifier },
color: Color = AreaBox.color,
style: AreaBoxStyle = AreaBox.style,
color: Color = AreaBoxDefaults.color,
style: AreaBoxStyle = AreaBoxDefaults.style,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
@@ -86,12 +105,24 @@ fun AreaBox(
}
}
/**
* Flexi UI area box of [Row].
* @see AreaColumn
* @see AreaBox
* @param modifier the [Modifier] to be applied to this area row.
* @param initializer the [Modifier] initializer, earlies than [modifier].
* @param color the background color of this area row, default is [AreaBoxDefaults.color].
* @param style the style of this area row, default is [AreaBoxDefaults.style].
* @param horizontalArrangement the horizontal arrangement of the content inside this area row, default is [Arrangement.Start].
* @param verticalAlignment the vertical alignment of the content inside this area row, default is [Alignment.Top].
* @param content the content of the [AreaRow].
*/
@Composable
fun AreaRow(
modifier: Modifier = Modifier,
initializer: @Composable Modifier.() -> Modifier = { Modifier },
color: Color = AreaBox.color,
style: AreaBoxStyle = AreaBox.style,
color: Color = AreaBoxDefaults.color,
style: AreaBoxStyle = AreaBoxDefaults.style,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
@@ -109,12 +140,24 @@ fun AreaRow(
}
}
/**
* Flexi UI area box of [Column].
* @see AreaRow
* @see AreaBox
* @param modifier the [Modifier] to be applied to this area column.
* @param initializer the [Modifier] initializer, earlies than [modifier].
* @param color the background color of this area column, default is [AreaBoxDefaults.color].
* @param style the style of this area column, default is [AreaBoxDefaults.style].
* @param verticalArrangement the vertical arrangement of the content inside this area column, default is [Arrangement.Top].
* @param horizontalAlignment the horizontal alignment of the content inside this area column, default is [Alignment.Start].
* @param content the content of the [AreaColumn].
*/
@Composable
fun AreaColumn(
modifier: Modifier = Modifier,
initializer: @Composable Modifier.() -> Modifier = { Modifier },
color: Color = AreaBox.color,
style: AreaBoxStyle = AreaBox.style,
color: Color = AreaBoxDefaults.color,
style: AreaBoxStyle = AreaBoxDefaults.style,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
@@ -153,7 +196,10 @@ private fun Modifier.areaBox(
.padding(style.padding)
}
object AreaBox {
/**
* Defaults of area box.
*/
object AreaBoxDefaults {
val color: Color
@Composable
@ReadOnlyComposable

View File

@@ -51,17 +51,29 @@ import com.highcapable.betterandroid.compose.extension.ui.orNull
import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalShapes
import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.interaction.Interaction
import com.highcapable.flexiui.interaction.InteractionDefaults
import com.highcapable.flexiui.interaction.RippleStyle
import com.highcapable.flexiui.interaction.rippleClickable
import com.highcapable.flexiui.interaction.rippleToggleable
/**
* Colors defines for button.
* @param contentColor the content color, usually for icon tint and text color.
* @param backgroundColor the background color.
*/
@Immutable
data class ButtonColors(
val contentColor: Color,
val backgroundColor: Color
)
/**
* Style defines for button.
* @param rippleStyle the ripple style of this button.
* @param padding the padding of content.
* @param shape the shape.
* @param border the border stroke.
*/
@Immutable
data class ButtonStyle(
val rippleStyle: RippleStyle,
@@ -70,12 +82,26 @@ data class ButtonStyle(
val border: BorderStroke
)
/**
* Flexi UI button.
* @see IconButton
* @see IconToggleButton
* @param onClick the callback when button is clicked.
* @param modifier the [Modifier] to be applied to this button.
* @param colors the colors of this button, default is [ButtonDefaults.colors].
* @param style the style of this button, default is [ButtonDefaults.style].
* @param enabled whether this button is enabled, default is true.
* @param interactionSource the interaction source of this button.
* @param header the header content of the [Button], should typically be [Icon] or [Text].
* @param footer the footer content of the [Button], should typically be [Icon] or [Text].
* @param content the content of the [Button], should typically be [Icon] or [Text].
*/
@Composable
fun Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = Button.colors,
style: ButtonStyle = Button.style,
colors: ButtonColors = ButtonDefaults.colors,
style: ButtonStyle = ButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
header: @Composable () -> Unit = {},
@@ -119,12 +145,24 @@ fun Button(
}
}
/**
* Flexi UI icon button.
* @see IconToggleButton
* @see Button
* @param onClick the callback when button is clicked.
* @param modifier the [Modifier] to be applied to this button.
* @param colors the colors of this button, default is [IconButtonDefaults.colors].
* @param style the style of this button, default is [IconButtonDefaults.style].
* @param enabled whether this button is enabled, default is true.
* @param interactionSource the interaction source of this button.
* @param content the content of the [IconButton], should typically be [Icon].
*/
@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = IconButton.colors,
style: ButtonStyle = IconButton.style,
colors: ButtonColors = IconButtonDefaults.colors,
style: ButtonStyle = IconButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
@@ -151,13 +189,26 @@ fun IconButton(
}
}
/**
* Flexi UI icon toggle button.
* @see IconButton
* @see Button
* @param checked the checked state of this button.
* @param onCheckedChange the callback when checked state is changed.
* @param modifier the [Modifier] to be applied to this button.
* @param colors the colors of this button, default is [IconButtonDefaults.colors].
* @param style the style of this button, default is [IconButtonDefaults.style].
* @param enabled whether this button is enabled, default is true.
* @param interactionSource the interaction source of this button.
* @param content the content of the [IconToggleButton], should typically be [Icon].
*/
@Composable
fun IconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: ButtonColors = IconButton.colors,
style: ButtonStyle = IconButton.style,
colors: ButtonColors = IconButtonDefaults.colors,
style: ButtonStyle = IconButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable () -> Unit
@@ -205,7 +256,10 @@ private fun Modifier.button(
.then(then)
}
object Button {
/**
* Defaults of button.
*/
object ButtonDefaults {
val colors: ButtonColors
@Composable
@ReadOnlyComposable
@@ -216,7 +270,10 @@ object Button {
get() = defaultButtonStyle()
}
object IconButton {
/**
* Defaults of icon button.
*/
object IconButtonDefaults {
val colors: ButtonColors
@Composable
@ReadOnlyComposable
@@ -246,12 +303,16 @@ private fun defaultContentButtonColors() = ButtonColors(
@Composable
@ReadOnlyComposable
private fun defaultPrimaryButtonRippleStyle() =
Interaction.rippleStyle.copy(color = LocalColors.current.foregroundSecondary)
InteractionDefaults.rippleStyle.copy(color = LocalColors.current.foregroundSecondary)
@Composable
@ReadOnlyComposable
private fun defaultContentButtonRippleStyle() =
Interaction.rippleStyle.copy(color = LocalColors.current.themeSecondary)
InteractionDefaults.rippleStyle.copy(color = LocalColors.current.themeSecondary)
@Composable
@ReadOnlyComposable
private fun defaultIconButtonRippleStyle() = InteractionDefaults.rippleStyle.copy(bounded = false)
@Composable
@ReadOnlyComposable
@@ -297,10 +358,6 @@ private fun defaultIconButtonStyle() = ButtonStyle(
border = defaultButtonBorder()
)
@Composable
@ReadOnlyComposable
private fun defaultIconButtonRippleStyle() = Interaction.rippleStyle.copy(bounded = false)
@Composable
@ReadOnlyComposable
private fun defaultButtonBorder() = BorderStroke(LocalSizes.current.borderSizeTertiary, LocalColors.current.textPrimary)

View File

@@ -60,6 +60,12 @@ import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.resources.Icons
import com.highcapable.flexiui.resources.icon.CheckMark
/**
* Colors defines for check box.
* @param contentColor the color of the check mark.
* @param inactiveColor the color of the unchecked box.
* @param activeColor the color of the checked box.
*/
@Immutable
data class CheckBoxColors(
val contentColor: Color,
@@ -67,6 +73,16 @@ data class CheckBoxColors(
val activeColor: Color
)
/**
* Style defines for check box.
* @param contentSpacing the spacing between the check mark and the content.
* @param contentSize the size of the check mark.
* @param strokeSize the stroke size.
* @param pressedGain the gain when pressed.
* @param hoveredGain the gain when hovered.
* @param shape the shape.
* @param border the border stroke.
*/
@Immutable
data class CheckBoxStyle(
val contentSpacing: Dp,
@@ -78,13 +94,24 @@ data class CheckBoxStyle(
val border: BorderStroke
)
/**
* Flexi UI check box.
* @param checked the checked state of this check box.
* @param onCheckedChange the callback when checked state changed.
* @param modifier the [Modifier] to be applied to this check box.
* @param colors the colors of this check box, default is [CheckBoxDefaults.colors].
* @param style the style of this check box, default is [CheckBoxDefaults.style].
* @param enabled whether this check box is enabled, default is true.
* @param interactionSource the interaction source of this check box.
* @param content the content of the [RowScope] to be applied to the [CheckBox], should typically be [Text].
*/
@Composable
fun CheckBox(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: CheckBoxColors = CheckBox.colors,
style: CheckBoxStyle = CheckBox.style,
colors: CheckBoxColors = CheckBoxDefaults.colors,
style: CheckBoxStyle = CheckBoxDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable (RowScope.() -> Unit)? = null
@@ -119,7 +146,7 @@ fun CheckBox(
scaleY = animatedContentLayer
),
imageVector = Icons.CheckMark,
style = Icon.style.copy(tint = colors.contentColor)
style = IconDefaults.style.copy(tint = colors.contentColor)
)
}
content?.also { content ->
@@ -131,7 +158,10 @@ fun CheckBox(
}
}
object CheckBox {
/**
* Defaults of check box.
*/
object CheckBoxDefaults {
val colors: CheckBoxColors
@Composable
@ReadOnlyComposable

View File

@@ -117,6 +117,14 @@ import com.highcapable.flexiui.resources.icon.Dropdown
import kotlin.math.max
import kotlin.math.min
/**
* Colors defines for dropdown list.
* @param endIconInactiveTint the tint of the end icon when inactive.
* @param endIconActiveTint the tint of the end icon when active.
* @param borderInactiveColor the color of the border when inactive.
* @param borderActiveColor the color of the border when active.
* @param backgroundColor the background color.
*/
@Immutable
data class DropdownListColors(
val endIconInactiveTint: Color,
@@ -126,6 +134,12 @@ data class DropdownListColors(
val backgroundColor: Color
)
/**
* Colors defines for dropdown menu.
* @param contentColor the color of the content.
* @param activeColor the color of the active item.
* @param borderColor the color of the border.
*/
@Immutable
data class DropdownMenuColors(
val contentColor: Color,
@@ -133,6 +147,14 @@ data class DropdownMenuColors(
val borderColor: Color
)
/**
* Style defines for dropdown list.
* @param padding the padding of the content.
* @param shape the shape.
* @param endIconSize the size of the end icon.
* @param borderInactive the border stroke when inactive.
* @param borderActive the border stroke when active.
*/
@Immutable
data class DropdownListStyle(
val padding: ComponentPadding,
@@ -142,6 +164,13 @@ data class DropdownListStyle(
val borderActive: BorderStroke
)
/**
* Style defines for dropdown menu.
* @param inTransitionDuration the duration of the in transition.
* @param outTransitionDuration the duration of the out transition.
* @param contentStyle the content style of area box.
* @param borderStyle the brder style of area box.
*/
@Immutable
data class DropdownMenuStyle(
val inTransitionDuration: Int,
@@ -150,15 +179,33 @@ data class DropdownMenuStyle(
val borderStyle: AreaBoxStyle
)
/**
* Flexi UI dropdown list.
* @see DropdownMenu
* @see DropdownMenuItem
* @param expanded whether the dropdown menu is expanded.
* @param onExpandedChange the callback when the expanded state is changed.
* @param modifier the [Modifier] to be applied to this dropdown list.
* @param colors the colors of this dropdown list, default is [DropdownListDefaults.colors].
* @param style the style of this dropdown list, default is [DropdownListDefaults.style].
* @param menuColors the colors of the dropdown menu, default is [DropdownMenuDefaults.colors].
* @param menuStyle the style of the dropdown menu, default is [DropdownMenuDefaults.style].
* @param enabled whether the dropdown list is enabled, default is true.
* @param scrollState the scroll state of the dropdown menu.
* @param properties the popup properties.
* @param interactionSource the interaction source of the dropdown list.
* @param text the text of the [DropdownList], should typically be [Text].
* @param content the content of the [DropdownMenu], should typically be [DropdownMenuItem].
*/
@Composable
fun DropdownList(
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: DropdownListColors = DropdownList.colors,
style: DropdownListStyle = DropdownList.style,
menuColors: DropdownMenuColors = DropdownMenu.colors,
menuStyle: DropdownMenuStyle = DropdownMenu.style,
colors: DropdownListColors = DropdownListDefaults.colors,
style: DropdownListStyle = DropdownListDefaults.style,
menuColors: DropdownMenuColors = DropdownMenuDefaults.colors,
menuStyle: DropdownMenuStyle = DropdownMenuDefaults.style,
enabled: Boolean = true,
scrollState: ScrollState = rememberScrollState(),
properties: PopupProperties = PopupProperties(focusable = true),
@@ -218,7 +265,7 @@ fun DropdownList(
rotationZ = animatedDirection
}.size(style.endIconSize),
imageVector = Icons.Dropdown,
style = Icon.style.copy(tint = animatedEndIconTint)
style = IconDefaults.style.copy(tint = animatedEndIconTint)
)
}
DropdownMenu(
@@ -235,13 +282,27 @@ fun DropdownList(
}
}
/**
* Flexi UI dropdown menu.
* @see DropdownList
* @see DropdownMenuItem
* @param expanded whether the dropdown menu is expanded.
* @param onDismissRequest the callback when the dropdown menu is dismissed.
* @param modifier the [Modifier] to be applied to this dropdown menu.
* @param colors the colors of this dropdown menu, default is [DropdownMenuDefaults.colors].
* @param style the style of this dropdown menu, default is [DropdownMenuDefaults.style].
* @param offset the offset of this dropdown menu.
* @param scrollState the scroll state of the dropdown menu.
* @param properties the popup properties.
* @param content the content of the [DropdownMenu], should typically be [DropdownMenuItem].
*/
@Composable
fun DropdownMenu(
expanded: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
colors: DropdownMenuColors = DropdownMenu.colors,
style: DropdownMenuStyle = DropdownMenu.style,
colors: DropdownMenuColors = DropdownMenuDefaults.colors,
style: DropdownMenuStyle = DropdownMenuDefaults.style,
offset: DpOffset = DpOffset(0.dp, 0.dp),
scrollState: ScrollState = rememberScrollState(),
properties: PopupProperties = PopupProperties(focusable = true),
@@ -278,6 +339,13 @@ fun DropdownMenu(
}
}
/**
* A box for manually measuring the size of the dropdown menu.
* @see DropdownList
* @see DropdownMenu
* @param modifier the [Modifier] to be applied to this box.
* @param content the content for measuring.
*/
@Composable
fun DropdownMenuBox(
modifier: Modifier = Modifier,
@@ -307,6 +375,20 @@ fun DropdownMenuBox(
}
}
/**
* Flexi UI dropdown menu item.
* @see DropdownList
* @see DropdownMenu
* @param onClick the callback when the dropdown menu item is clicked.
* @param modifier the [Modifier] to be applied to this dropdown menu item.
* @param contentColor the color of the content.
* @param activeColor the color of the active item.
* @param contentStyle the style of the content.
* @param enabled whether the dropdown menu item is enabled, default is true.
* @param actived whether the dropdown menu item is actived, default is false.
* @param interactionSource the interaction source of the dropdown menu item.
* @param content the content of the [DropdownMenuItem], should typically be [Icon] or [Text].
*/
@Composable
fun DropdownMenuItem(
onClick: () -> Unit,
@@ -319,9 +401,15 @@ fun DropdownMenuItem(
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) {
val currentColor = contentColor.orNull() ?: LocalDropdownMenuContentColor.current.orNull() ?: DropdownMenu.colors.contentColor
val currentActiveColor = activeColor.orNull() ?: LocalDropdownMenuActiveColor.current.orNull() ?: DropdownMenu.colors.activeColor
val currentStyle = contentStyle ?: LocalDropdownMenuContentStyle.current ?: DropdownMenu.style.contentStyle
val currentColor = contentColor.orNull()
?: LocalDropdownMenuContentColor.current.orNull()
?: DropdownMenuDefaults.colors.contentColor
val currentActiveColor = activeColor.orNull()
?: LocalDropdownMenuActiveColor.current.orNull()
?: DropdownMenuDefaults.colors.activeColor
val currentStyle = contentStyle
?: LocalDropdownMenuContentStyle.current
?: DropdownMenuDefaults.style.contentStyle
AreaRow(
modifier = Modifier.componentState(enabled)
.then(modifier)
@@ -354,6 +442,9 @@ internal expect fun DropdownMenuMeasureBox(
content: @Composable BoxScope.() -> Unit
)
/**
* A scope for dropdown menu box.
*/
@Stable
interface DropdownMenuBoxScope : BoxWithConstraintsScope {
val menuMaxHeight: Dp
@@ -516,7 +607,10 @@ private data class DropdownMenuPositionProvider(
}
}
object DropdownList {
/**
* Defaults of dropdown list.
*/
object DropdownListDefaults {
val colors: DropdownListColors
@Composable
@ReadOnlyComposable
@@ -527,7 +621,10 @@ object DropdownList {
get() = defaultDropdownListStyle()
}
object DropdownMenu {
/**
* Defaults of dropdown menu.
*/
object DropdownMenuDefaults {
val colors: DropdownMenuColors
@Composable
@ReadOnlyComposable
@@ -577,11 +674,11 @@ private fun defaultDropdownListStyle() = DropdownListStyle(
private fun defaultDropdownMenuStyle() = DropdownMenuStyle(
inTransitionDuration = DefaultInTransitionDuration,
outTransitionDuration = DefaultOutTransitionDuration,
contentStyle = AreaBox.style.copy(
contentStyle = AreaBoxDefaults.style.copy(
padding = ComponentPadding(horizontal = DefaultMenuContentPadding),
shape = LocalShapes.current.secondary
),
borderStyle = AreaBox.style.copy(
borderStyle = AreaBoxDefaults.style.copy(
padding = ComponentPadding(LocalSizes.current.spacingTertiary),
shadowSize = LocalSizes.current.zoomSizeTertiary,
shape = LocalShapes.current.primary

View File

@@ -51,31 +51,49 @@ import androidx.compose.ui.unit.isSpecified
import com.highcapable.betterandroid.compose.extension.ui.orNull
import com.highcapable.flexiui.LocalSizes
/**
* Style defines for icon.
* @param size the size.
* @param tint the tint.
*/
@Immutable
data class IconStyle(
val size: Dp,
val tint: Color
)
/**
* Flexi UI basic icon.
* @param imageVector the vector image to be drawn.
* @param contentDescription the content description for this icon.
* @param modifier the [Modifier] to be applied to this icon.
* @param style the style of this icon, default is [IconDefaults.style].
*/
@Composable
fun Icon(
imageVector: ImageVector,
contentDescription: String? = null,
modifier: Modifier = Modifier,
style: IconStyle = Icon.style
style: IconStyle = IconDefaults.style
) {
val painter = rememberVectorPainter(imageVector)
Icon(painter, contentDescription, modifier, style)
}
/**
* Flexi UI basic icon.
* @param painter the painter to be drawn.
* @param contentDescription the content description for this icon.
* @param modifier the [Modifier] to be applied to this icon.
* @param style the style of this icon, default is [IconDefaults.style].
*/
@Composable
fun Icon(
painter: Painter,
contentDescription: String? = null,
modifier: Modifier = Modifier,
style: IconStyle = Icon.style
style: IconStyle = IconDefaults.style
) {
// TODO: b/149735981 semantics for content description
val colorFilter = if (style.tint.isUnspecified) null else ColorFilter.tint(style.tint)
val semantics = if (contentDescription != null)
Modifier.semantics {
@@ -114,7 +132,10 @@ private fun Modifier.defaultSizeFor(
})
}
object Icon {
/**
* Defaults of icon.
*/
object IconDefaults {
val style: IconStyle
@Composable
@ReadOnlyComposable

View File

@@ -23,6 +23,7 @@
package com.highcapable.flexiui.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -47,6 +48,13 @@ import com.highcapable.flexiui.interaction.rippleClickable
import com.highcapable.flexiui.resources.Icons
import com.highcapable.flexiui.resources.icon.ArrowForward
/**
* Colors defines for item box.
* @param backgroundColor the background color.
* @param titleTextColor the title text color.
* @param subTextColor the sub text color.
* @param arrowIconTint the arrow icon tint.
*/
@Immutable
data class ItemBoxColors(
val backgroundColor: Color,
@@ -55,6 +63,13 @@ data class ItemBoxColors(
val arrowIconTint: Color
)
/**
* Style defines for item box.
* @param boxStyle the style of area box.
* @param contentSpacing the spacing between the components of content.
* @param titleTextStyle the title text style.
* @param subTextStyle the sub text style.
*/
@Immutable
data class ItemBoxStyle(
val boxStyle: AreaBoxStyle,
@@ -63,12 +78,26 @@ data class ItemBoxStyle(
val subTextStyle: TextStyle
)
/**
* Flexi UI horizontal item box.
* @see VerticalItemBox
* @param onClick the callback when item is clicked.
* @param modifier the [Modifier] to be applied to this item box.
* @param colors the colors of item box, default is [ItemBoxDefaults.colors].
* @param style the style of item box, default is [ItemBoxDefaults.style].
* @param enabled whether this item box is enabled, default is true.
* @param showArrowIcon whether show arrow icon, default is true.
* @param interactionSource the interaction source of this item box.
* @param logoImage the logo image of the [HorizontalItemBox], should typically be [Icon] or [Image].
* @param titleText the title text of the [HorizontalItemBox], should typically be [Text].
* @param subText the sub text of the [HorizontalItemBox], should typically be [Text].
*/
@Composable
fun HorizontalItemBox(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ItemBoxColors = ItemBox.colors,
style: ItemBoxStyle = ItemBox.style,
colors: ItemBoxColors = ItemBoxDefaults.colors,
style: ItemBoxStyle = ItemBoxDefaults.style,
enabled: Boolean = true,
showArrowIcon: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@@ -105,7 +134,7 @@ fun HorizontalItemBox(
}
if (showArrowIcon) Icon(
imageVector = Icons.ArrowForward,
style = Icon.style.copy(
style = IconDefaults.style.copy(
size = DefaultArrowIconSize,
tint = colors.arrowIconTint
)
@@ -114,12 +143,25 @@ fun HorizontalItemBox(
}
}
/**
* Flexi UI vertical item box.
* @see HorizontalItemBox
* @param onClick the callback when item is clicked.
* @param modifier the [Modifier] to be applied to this item box.
* @param colors the colors of item box, default is [ItemBoxDefaults.colors].
* @param style the style of item box, default is [ItemBoxDefaults.style].
* @param enabled whether this item box is enabled, default is true.
* @param interactionSource the interaction source of this item box.
* @param logoImage the logo image of the [VerticalItemBox], should typically be [Icon] or [Image].
* @param titleText the title text of the [VerticalItemBox], should typically be [Text].
* @param subText the sub text of the [VerticalItemBox], should typically be [Text].
*/
@Composable
fun VerticalItemBox(
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: ItemBoxColors = ItemBox.colors,
style: ItemBoxStyle = ItemBox.style,
colors: ItemBoxColors = ItemBoxDefaults.colors,
style: ItemBoxStyle = ItemBoxDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
logoImage: @Composable (() -> Unit)? = null,
@@ -167,7 +209,10 @@ private fun ItemBoxContent(
}
}
object ItemBox {
/**
* Defaults of item box.
*/
object ItemBoxDefaults {
val colors: ItemBoxColors
@Composable
get() = defaultItemBoxColors()
@@ -179,7 +224,7 @@ object ItemBox {
@Composable
@ReadOnlyComposable
private fun defaultItemBoxColors() = ItemBoxColors(
backgroundColor = AreaBox.color,
backgroundColor = AreaBoxDefaults.color,
titleTextColor = LocalColors.current.textPrimary,
subTextColor = LocalColors.current.textSecondary,
arrowIconTint = LocalColors.current.textSecondary
@@ -188,7 +233,7 @@ private fun defaultItemBoxColors() = ItemBoxColors(
@Composable
@ReadOnlyComposable
private fun defaultItemBoxStyle() = ItemBoxStyle(
boxStyle = AreaBox.style,
boxStyle = AreaBoxDefaults.style,
contentSpacing = LocalSizes.current.spacingSecondary,
titleTextStyle = LocalTypography.current.primary,
subTextStyle = LocalTypography.current.secondary

View File

@@ -60,9 +60,16 @@ import com.highcapable.betterandroid.compose.extension.ui.componentState
import com.highcapable.betterandroid.compose.extension.ui.orNull
import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.interaction.Interaction
import com.highcapable.flexiui.interaction.InteractionDefaults
import com.highcapable.flexiui.interaction.rippleClickable
/**
* Colors defines for navigation bar.
* @param backgroundColor the background color.
* @param indicatorColor the indicator color.
* @param selectedContentColor the selected content color.
* @param unselectedContentColor the unselected content color.
*/
@Immutable
data class NavigationBarColors(
val backgroundColor: Color,
@@ -71,6 +78,13 @@ data class NavigationBarColors(
val unselectedContentColor: Color
)
/**
* Style defines for navigation bar.
* @param boxStyle the style of area box.
* @param contentSpacing the spacing between the components of content.
* @param contentPadding the padding of content.
* @param contentShape the content shape.
*/
@Immutable
data class NavigationBarStyle(
val boxStyle: AreaBoxStyle,
@@ -79,11 +93,21 @@ data class NavigationBarStyle(
val contentShape: Shape
)
/**
* Flexi UI horizontal navigation bar.
* @see NavigationBarColumn
* @see NavigationBarItem
* @param modifier the [Modifier] to be applied to this navigation bar.
* @param colors the colors of this navigation bar, default is [NavigationBarDefaults.colors].
* @param style the style of this navigation bar, default is [NavigationBarDefaults.style].
* @param arrangement the horizontal arrangement of this navigation bar, default is [Arrangement.SpaceBetween].
* @param content the content of the [NavigationBarRow], should typically be [NavigationBarItem].
*/
@Composable
fun NavigationRow(
fun NavigationBarRow(
modifier: Modifier = Modifier,
colors: NavigationBarColors = NavigationBar.colors,
style: NavigationBarStyle = NavigationBar.style,
colors: NavigationBarColors = NavigationBarDefaults.colors,
style: NavigationBarStyle = NavigationBarDefaults.style,
arrangement: Arrangement.Horizontal = Arrangement.SpaceBetween,
content: @Composable RowScope.() -> Unit
) {
@@ -99,11 +123,21 @@ fun NavigationRow(
}
}
/**
* Flexi UI vertical navigation bar.
* @see NavigationBarRow
* @see NavigationBarItem
* @param modifier the [Modifier] to be applied to this navigation bar.
* @param colors the colors of this navigation bar, default is [NavigationBarDefaults.colors].
* @param style the style of this navigation bar, default is [NavigationBarDefaults.style].
* @param arrangement the vertical arrangement of this navigation bar, default is [Arrangement.SpaceBetween].
* @param content the content of the [NavigationBarColumn], should typically be [NavigationBarItem].
*/
@Composable
fun NavigationColumn(
fun NavigationBarColumn(
modifier: Modifier = Modifier,
colors: NavigationBarColors = NavigationBar.colors,
style: NavigationBarStyle = NavigationBar.style,
colors: NavigationBarColors = NavigationBarDefaults.colors,
style: NavigationBarStyle = NavigationBarDefaults.style,
arrangement: Arrangement.Vertical = Arrangement.SpaceBetween,
content: @Composable ColumnScope.() -> Unit
) {
@@ -119,6 +153,23 @@ fun NavigationColumn(
}
}
/**
* Flexi UI navigation bar item.
* @see NavigationBarRow
* @see NavigationBarColumn
* @param selected whether this item is selected.
* @param onClick the callback when item is clicked.
* @param horizontal whether this item is horizontal.
* @param modifier the [Modifier] to be applied to this item.
* @param enabled whether this item is enabled, default is true.
* @param colors the colors of this item.
* @param contentSpacing the spacing between the components of content of this item.
* @param contentPadding the padding of content of this item.
* @param contentShape the content shape of this item.
* @param interactionSource the interaction source of this item.
* @param icon the icon of the [NavigationBarItem], should typically be [Icon].
* @param text the text of the [NavigationBarItem], should typically be [Text].
*/
@Composable
fun NavigationBarItem(
selected: Boolean,
@@ -135,10 +186,16 @@ fun NavigationBarItem(
text: @Composable (() -> Unit)? = null
) {
val currentHorizontal = horizontal ?: LocalHorizontalNavigationBar.current
val currentColors = colors ?: LocalNavigationBarColors.current ?: NavigationBar.colors
val currentContentSpacing = contentSpacing.orNull() ?: LocalNavigationBarContentSpacing.current.orNull() ?: NavigationBar.style.contentSpacing
val currentContentPadding = contentPadding ?: LocalNavigationBarContentPadding.current ?: NavigationBar.style.contentPadding
val currentContentShape = contentShape ?: LocalNavigationBarContentShape.current ?: NavigationBar.style.contentShape
val currentColors = colors ?: LocalNavigationBarColors.current ?: NavigationBarDefaults.colors
val currentContentSpacing = contentSpacing.orNull()
?: LocalNavigationBarContentSpacing.current.orNull()
?: NavigationBarDefaults.style.contentSpacing
val currentContentPadding = contentPadding
?: LocalNavigationBarContentPadding.current
?: NavigationBarDefaults.style.contentPadding
val currentContentShape = contentShape
?: LocalNavigationBarContentShape.current
?: NavigationBarDefaults.style.contentShape
val animatedIndicatorColor by animateColorAsState(if (selected) currentColors.indicatorColor else Color.Transparent)
val animatedContentColor by animateColorAsState(if (selected) currentColors.selectedContentColor else currentColors.unselectedContentColor)
val currentIconStyle = LocalIconStyle.current.copy(tint = animatedContentColor)
@@ -149,7 +206,7 @@ fun NavigationBarItem(
.then(modifier)
.background(animatedIndicatorColor)
.rippleClickable(
rippleStyle = Interaction.rippleStyle.copy(color = currentColors.indicatorColor),
rippleStyle = InteractionDefaults.rippleStyle.copy(color = currentColors.indicatorColor),
enabled = enabled,
role = Role.Tab,
interactionSource = interactionSource,
@@ -214,7 +271,10 @@ private fun NavigationBarStyleBox(
}
}
object NavigationBar {
/**
* Defaults of navigation bar.
*/
object NavigationBarDefaults {
val colors: NavigationBarColors
@Composable
@ReadOnlyComposable
@@ -238,7 +298,7 @@ private val LocalNavigationBarContentShape = compositionLocalOf<Shape?> { null }
@Composable
@ReadOnlyComposable
private fun defaultNavigationBarColors() = NavigationBarColors(
backgroundColor = AreaBox.color,
backgroundColor = AreaBoxDefaults.color,
indicatorColor = LocalColors.current.themeTertiary,
selectedContentColor = LocalColors.current.themePrimary,
unselectedContentColor = LocalColors.current.textSecondary
@@ -247,7 +307,7 @@ private fun defaultNavigationBarColors() = NavigationBarColors(
@Composable
@ReadOnlyComposable
private fun defaultNavigationBarStyle() = NavigationBarStyle(
boxStyle = AreaBox.style,
boxStyle = AreaBoxDefaults.style,
contentSpacing = LocalSizes.current.spacingSecondary,
contentPadding = ComponentPadding(
horizontal = LocalSizes.current.spacingPrimary,

View File

@@ -58,17 +58,30 @@ import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.max
/**
* Style interface for progress indicator.
*/
@Stable
interface ProgressIndicatorStyle {
val strokeWidth: Dp
val strokeCap: StrokeCap
}
/**
* Animation interface for progress indicator.
*/
@Stable
interface ProgressIndicatorAnimation {
val duration: Int
}
/**
* Style defines for circular progress indicator.
* @param strokeWidth the stroke width of indicator.
* @param strokeCap the stroke cap of indicator.
* @param radius the radius of indicator.
* @param animation the animation of indicator.
*/
@Immutable
data class CircularIndicatorStyle(
override val strokeWidth: Dp,
@@ -77,6 +90,13 @@ data class CircularIndicatorStyle(
val animation: CircularIndicatorAnimation
) : ProgressIndicatorStyle
/**
* Style defines for linear progress indicator.
* @param strokeWidth the stroke width of indicator.
* @param strokeCap the stroke cap of indicator.
* @param width the width of indicator.
* @param animation the animation of indicator.
*/
@Immutable
data class LinearIndicatorStyle(
override val strokeWidth: Dp,
@@ -85,6 +105,14 @@ data class LinearIndicatorStyle(
val animation: LinearIndicatorAnimation
) : ProgressIndicatorStyle
/**
* Animation defines for circular progress indicator.
* @param duration the duration of animation.
* @param rotationsPerCycle the rotations per cycle of animation.
* @param startAngleOffset the start angle offset of animation.
* @param baseRotationAngle the base rotation angle of animation.
* @param jumpRotationAngle the jump rotation angle of animation.
*/
@Immutable
data class CircularIndicatorAnimation(
override val duration: Int,
@@ -94,6 +122,18 @@ data class CircularIndicatorAnimation(
val jumpRotationAngle: Float
) : ProgressIndicatorAnimation
/**
* Animation defines for linear progress indicator.
* @param duration the duration of animation.
* @param firstLineHeadDuration the first line head duration of animation.
* @param firstLineTailDuration the first line tail duration of animation.
* @param secondLineHeadDuration the second line head duration of animation.
* @param secondLineTailDuration the second line tail duration of animation.
* @param firstLineHeadDelay the first line head delay of animation.
* @param firstLineTailDelay the first line tail delay of animation.
* @param secondLineHeadDelay the second line head delay of animation.
* @param secondLineTailDelay the second line tail delay of animation.
*/
@Immutable
data class LinearIndicatorAnimation(
override val duration: Int,
@@ -107,25 +147,42 @@ data class LinearIndicatorAnimation(
val secondLineTailDelay: Int
) : ProgressIndicatorAnimation
/**
* Colors defines for progress indicator.
* @param foregroundColor the foreground color of indicator.
* @param backgroundColor the background color of indicator.
*/
@Immutable
data class ProgressIndicatorColors(
val foregroundColor: Color,
val backgroundColor: Color
)
/**
* Flexi UI circular progress indicator.
* @see LinearProgressIndicator
* @param modifier the [Modifier] to be applied to this indicator.
* @param progress the progress of indicator.
* @param min the min of indicator, default is 0f.
* @param max the max of indicator, default is 1f.
* @param indeterminate the indeterminate of indicator, default is false.
* @param colors the colors of indicator, default is [CircularIndicatorDefaults.colors].
* @param style the style of indicator, default is [CircularIndicatorDefaults.style].
*/
@Composable
fun CircularProgressIndicator(
modifier: Modifier = Modifier,
progress: Float = -1f,
min: Float = 0f,
max: Float = 100f,
max: Float = 1f,
indeterminate: Boolean = progress < min,
colors: ProgressIndicatorColors = CircularProgressIndicator.colors,
style: CircularIndicatorStyle = CircularProgressIndicator.style
colors: ProgressIndicatorColors = CircularIndicatorDefaults.colors,
style: CircularIndicatorStyle = CircularIndicatorDefaults.style
) {
val diameter = style.radius * 2
val stroke = with(LocalDensity.current) { Stroke(width = style.strokeWidth.toPx(), cap = style.strokeCap) }
/** Build determinate progress indicator. */
@Composable
fun Determinate() {
val coercedProgress = progress.coerceIn(min, max)
@@ -138,6 +195,7 @@ fun CircularProgressIndicator(
}
}
/** Build indeterminate progress indicator. */
@Composable
fun Indeterminate() {
val transition = rememberInfiniteTransition()
@@ -197,16 +255,28 @@ fun CircularProgressIndicator(
if (indeterminate) Indeterminate() else Determinate()
}
/**
* Flexi UI linear progress indicator.
* @see CircularProgressIndicator
* @param modifier the [Modifier] to be applied to this indicator.
* @param progress the progress of indicator.
* @param min the min of indicator, default is 0f.
* @param max the max of indicator, default is 1f.
* @param indeterminate the indeterminate of indicator, default is false.
* @param colors the colors of indicator, default is [LinearIndicatorDefaults.colors].
* @param style the style of indicator, default is [LinearIndicatorDefaults.style].
*/
@Composable
fun LinearProgressIndicator(
modifier: Modifier = Modifier,
progress: Float = -1f,
min: Float = 0f,
max: Float = 100f,
max: Float = 1f,
indeterminate: Boolean = progress < min,
colors: ProgressIndicatorColors = LinearProgressIndicator.colors,
style: LinearIndicatorStyle = LinearProgressIndicator.style
colors: ProgressIndicatorColors = LinearIndicatorDefaults.colors,
style: LinearIndicatorStyle = LinearIndicatorDefaults.style
) {
/** Build determinate progress indicator. */
@Composable
fun Determinate() {
val coercedProgress = progress.coerceIn(min, max)
@@ -218,6 +288,7 @@ fun LinearProgressIndicator(
}
}
/** Build indeterminate progress indicator. */
@Composable
fun Indeterminate() {
val infiniteTransition = rememberInfiniteTransition()
@@ -347,7 +418,10 @@ private fun DrawScope.drawLinearIndicator(
}
}
object CircularProgressIndicator {
/**
* Defaults of circular progress indicator.
*/
object CircularIndicatorDefaults {
val colors: ProgressIndicatorColors
@Composable
@ReadOnlyComposable
@@ -363,7 +437,10 @@ object CircularProgressIndicator {
get() = defaultCircularIndicatorStyle()
}
object LinearProgressIndicator {
/**
* Defaults of linear progress indicator.
*/
object LinearIndicatorDefaults {
val colors: ProgressIndicatorColors
@Composable
@ReadOnlyComposable

View File

@@ -58,6 +58,12 @@ import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalShapes
import com.highcapable.flexiui.LocalSizes
/**
* Colors defines for radio button.
* @param contentColor the color of the check mark.
* @param inactiveColor the color of the unchecked box.
* @param activeColor the color of the checked box.
*/
@Immutable
data class RadioButtonColors(
val contentColor: Color,
@@ -65,6 +71,16 @@ data class RadioButtonColors(
val activeColor: Color
)
/**
* Style defines for radio button.
* @param contentSpacing the spacing between the check mark and the content.
* @param contentRadius the radius of the check mark.
* @param strokeRadius the radius of the box.
* @param pressedGain the gain when pressed.
* @param hoveredGain the gain when hovered.
* @param shape the shape.
* @param border the border stroke.
*/
@Immutable
data class RadioButtonStyle(
val contentSpacing: Dp,
@@ -77,13 +93,24 @@ data class RadioButtonStyle(
val border: BorderStroke
)
/**
* Flexi UI radio button.
* @param selected the selected state of this button.
* @param onClick the callback when button is clicked.
* @param modifier the [Modifier] to be applied to this button.
* @param colors the colors of this button, default is [RadioButtonDefaults.colors].
* @param style the style of this button, default is [RadioButtonDefaults.style].
* @param enabled whether this button is enabled, default is true.
* @param interactionSource the interaction source of this button.
* @param content the content of the [RowScope] to be applied to the [RadioButton], should typically be [Text].
*/
@Composable
fun RadioButton(
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
colors: RadioButtonColors = RadioButton.colors,
style: RadioButtonStyle = RadioButton.style,
colors: RadioButtonColors = RadioButtonDefaults.colors,
style: RadioButtonStyle = RadioButtonDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable (RowScope.() -> Unit)? = null
@@ -126,7 +153,10 @@ fun RadioButton(
}
}
object RadioButton {
/**
* Defaults of radio button.
*/
object RadioButtonDefaults {
val colors: RadioButtonColors
@Composable
@ReadOnlyComposable

View File

@@ -34,19 +34,42 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.highcapable.betterandroid.compose.extension.ui.ComponentPadding
// TODO: re-made it by SubcomposeLayout.
/**
* Scaffold implements the basic Flexi UI visual layout structure.
*
* You can add your own components into [actionBar], [tab], [navigationBar].
* @see TopActionBar
* @see ActionBar
* @see TabRow
* @see NavigationBarRow
* @see NavigationBarColumn
* @param modifier the [Modifier] to be applied to content.
* @param colors the colors of content, default is [SurfaceDefaults.colors].
* @param padding the padding of content, default is [SurfaceDefaults.padding].
* @param verticalArrangement the vertical arrangement of content, default is [Arrangement.Top].
* @param horizontalAlignment the horizontal alignment of content, default is [Alignment.Start].
* @param actionBar the action bar, should typically be [TopActionBar] or [ActionBar].
* @param tab the tab, should typically be [TabRow].
* @param navigationBar the navigation bar, should typically be [NavigationBarRow] or [NavigationBarColumn].
* @param content the content of the screen.
*/
@Composable
fun Scaffold(
modifier: Modifier = Modifier,
colors: SurfaceColors = Surface.colors,
padding: ComponentPadding = Surface.padding,
colors: SurfaceColors = SurfaceDefaults.colors,
padding: ComponentPadding = SurfaceDefaults.padding,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
actionBar: @Composable () -> Unit = {},
tab: @Composable () -> Unit = {},
navigation: @Composable () -> Unit = {},
navigationBar: @Composable () -> Unit = {},
content: @Composable () -> Unit
) {
// When out of the box, we no need to match the top padding, it should be provided by the action bar.
val outBoxPadding = padding.copy(top = 0.dp)
// When in the box, we no need to match the start and end padding, it should be provided by the surface.
val inBoxPadding = padding.copy(start = 0.dp, end = 0.dp)
Surface(
modifier = modifier,
@@ -60,7 +83,7 @@ fun Scaffold(
actionBar()
tab()
Box(modifier = Modifier.fillMaxSize().padding(inBoxPadding).weight(1f)) { content() }
navigation()
navigationBar()
}
}
}

View File

@@ -69,6 +69,13 @@ import com.highcapable.flexiui.LocalSizes
import kotlin.math.abs
import kotlin.math.roundToInt
/**
* Colors defines for slider.
* @param trackInactiveColor the inactive color of track.
* @param trackActiveColor the active color of track.
* @param thumbColor the color of thumb.
* @param stepColor the color of step.
*/
@Immutable
data class SliderColors(
val trackInactiveColor: Color,
@@ -77,6 +84,20 @@ data class SliderColors(
val stepColor: Color
)
/**
* Style defines for slider.
* @param thumbRadius the radius of thumb.
* @param thumbGain the gain of thumb.
* @param thumbShadowSize the shadow size of thumb.
* @param thumbShape the shape of thumb.
* @param stepShape the shape of step.
* @param trackShape the shape of track.
* @param thumbBorder the border of thumb.
* @param stepBorder the border of step.
* @param trackBorder the border of track.
* @param trackWidth the width of track.
* @param trackHeight the height of track.
*/
@Immutable
data class SliderStyle(
val thumbRadius: Dp,
@@ -92,16 +113,30 @@ data class SliderStyle(
val trackHeight: Dp
)
/**
* Flexi UI slider.
* @param value the value of this slider.
* @param onValueChange the callback when the value changed.
* @param modifier the [Modifier] to be applied to this slider.
* @param colors the colors of this slider, default is [SliderDefaults.colors].
* @param style the style of this slider, default is [SliderDefaults.style].
* @param enabled whether this slider is enabled, default is true.
* @param min the min value of this slider, default is 0f.
* @param max the max value of this slider, default is 1f.
* @param steps the steps of this slider, default is 0.
* @param onValueChangeFinished the callback when the value changed finished.
* @param interactionSource the interaction source of this slider.
*/
@Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
colors: SliderColors = Slider.colors,
style: SliderStyle = Slider.style,
colors: SliderColors = SliderDefaults.colors,
style: SliderStyle = SliderDefaults.style,
enabled: Boolean = true,
min: Float = 0f,
max: Float = 100f,
max: Float = 1f,
steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
@@ -119,6 +154,7 @@ fun Slider(
steppedOffsetXs = List(steps + 2) { index -> index * pOffsetX }
}
/** Get the stepped offset X. */
fun Float.withSteps() =
if (steps > 0)
steppedOffsetXs.minByOrNull { abs(it - this) } ?: this
@@ -131,11 +167,13 @@ fun Slider(
val animatedOffsetX by animateFloatAsState(offsetX)
val adoptedOffsetX = if (tapped && !dragging) animatedOffsetX else offsetX
/** Update the value of slider. */
fun updateValue(offsetX: Float) {
val newValue = (offsetX / maxOffsetX) * (max - min) + min
onValueChange(newValue)
}
/** Build the track of slider. */
@Composable
fun Track(content: @Composable () -> Unit) {
val cornerSize = (style.trackShape as? CornerBasedShape)?.topStart?.toPx(Size.Zero, LocalDensity.current) ?: 0f
@@ -156,6 +194,7 @@ fun Slider(
}
}
/** Build the step of slider. */
@Composable
fun Step() {
if (steps > 0) Row(
@@ -172,6 +211,7 @@ fun Slider(
}
}
/** Build the thumb of slider. */
@Composable
fun Thumb() {
Box(
@@ -231,7 +271,10 @@ fun Slider(
}
}
object Slider {
/**
* Defaults of slider.
*/
object SliderDefaults {
val colors
@Composable
@ReadOnlyComposable

View File

@@ -40,18 +40,33 @@ import com.highcapable.betterandroid.compose.extension.ui.ComponentPadding
import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalSizes
/**
* Colors defines for surface.
* @param contentColor the content color, usually for the text color.
* @param backgroundColor the background color.
*/
@Immutable
data class SurfaceColors(
val contentColor: Color,
val backgroundColor: Color
)
/**
* Flexi UI surface.
*
* A surface have a background color and default padding.
* @param modifier the [Modifier] to be applied to this surface.
* @param initializer the [Modifier] initializer, earlies than [modifier].
* @param colors the colors of surface, default is [SurfaceDefaults.colors].
* @param padding the padding of surface, default is [SurfaceDefaults.padding].
* @param content the content of the [Surface].
*/
@Composable
fun Surface(
modifier: Modifier = Modifier,
initializer: @Composable Modifier.() -> Modifier = { Modifier },
colors: SurfaceColors = Surface.colors,
padding: ComponentPadding = Surface.padding,
colors: SurfaceColors = SurfaceDefaults.colors,
padding: ComponentPadding = SurfaceDefaults.padding,
content: @Composable BoxScope.() -> Unit
) {
CompositionLocalProvider(
@@ -81,7 +96,10 @@ private fun Modifier.surface(
.padding(padding)
}
object Surface {
/**
* Defaults of surface.
*/
object SurfaceDefaults {
val colors: SurfaceColors
@Composable
@ReadOnlyComposable

View File

@@ -67,6 +67,12 @@ import com.highcapable.flexiui.LocalShapes
import com.highcapable.flexiui.LocalSizes
import kotlin.math.roundToInt
/**
* Colors defines for switch.
* @param thumbColor the color of thumb.
* @param trackInactive the color of track when switch is inactive.
* @param trackActive the color of track when switch is active.
*/
@Immutable
data class SwitchColors(
val thumbColor: Color,
@@ -74,6 +80,20 @@ data class SwitchColors(
val trackActive: Color
)
/**
* Style defines for switch.
* @param padding the padding between thumb and track.
* @param contentSpacing the spacing between content and track.
* @param thumbRadius the radius of thumb.
* @param thumbGain the gain of thumb when switch is hovered or dragging.
* @param thumbShadowSize the shadow size of thumb.
* @param thumbShape the shape of thumb.
* @param trackShape the shape of track.
* @param thumbBorder the border of thumb.
* @param trackBorder the border of track.
* @param trackWidth the width of track.
* @param trackHeight the height of track.
*/
@Immutable
data class SwitchStyle(
val padding: ComponentPadding,
@@ -89,13 +109,24 @@ data class SwitchStyle(
val trackHeight: Dp
)
/**
* Flexi UI switch.
* @param checked the checked state of switch.
* @param onCheckedChange the callback when switch checked state changed.
* @param modifier the [Modifier] to be applied to this switch.
* @param colors the colors of switch, default is [SwitchDefaults.colors].
* @param style the style of switch, default is [SwitchDefaults.style].
* @param enabled the enabled state of switch, default is true.
* @param interactionSource the interaction source of switch.
* @param content the content of the [RowScope] to be applied to the [Switch], should typically be [Text].
*/
@Composable
fun Switch(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
colors: SwitchColors = Switch.colors,
style: SwitchStyle = Switch.style,
colors: SwitchColors = SwitchDefaults.colors,
style: SwitchStyle = SwitchDefaults.style,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable (RowScope.() -> Unit)? = null
@@ -112,6 +143,8 @@ fun Switch(
val animatedOffsetX by animateFloatAsState(offsetX)
val animatedScale by animateFloatAsState(if (hovered || dragging) style.thumbGain else 1f)
var trackColor by remember { mutableStateOf(colors.trackInactive) }
/** Update the track color of switch. */
fun updateTrackColor() {
val fraction = (offsetX / maxOffsetX).coerceIn(0f, 1f)
trackColor = lerp(colors.trackInactive, colors.trackActive, fraction)
@@ -120,6 +153,7 @@ fun Switch(
val animatedTrackColor by animateColorAsState(trackColor)
val efficientDragging = dragging && distance > 5
/** Build the track of switch. */
@Composable
fun Track(content: @Composable RowScope.() -> Unit) {
Row(
@@ -140,6 +174,7 @@ fun Switch(
)
}
/** Build the thumb of switch. */
@Composable
fun Thumb() {
Box(
@@ -193,7 +228,10 @@ fun Switch(
}
}
object Switch {
/**
* Defaults of switch.
*/
object SwitchDefaults {
val colors: SwitchColors
@Composable
@ReadOnlyComposable

View File

@@ -80,6 +80,12 @@ import com.highcapable.flexiui.interaction.rippleClickable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
/**
* Colors defines for tab.
* @param indicatorColor the indicator color.
* @param selectedContentColor the selected content color.
* @param unselectedContentColor the unselected content color.
*/
@Immutable
data class TabColors(
val indicatorColor: Color,
@@ -87,6 +93,14 @@ data class TabColors(
val unselectedContentColor: Color
)
/**
* Style defines for tab.
* @param contentPadding the content padding.
* @param contentShape the content shape.
* @param indicatorWidth the indicator width.
* @param indicatorHeight the indicator height.
* @param indicatorShape the indicator shape.
*/
@Immutable
data class TabStyle(
val contentPadding: ComponentPadding,
@@ -96,12 +110,23 @@ data class TabStyle(
val indicatorShape: Shape
)
/**
* Flexi UI fixed tabs.
* @see ScrollableTabRow
* @see Tab
* @param selectedTabIndex the selected tab index.
* @param modifier the [Modifier] to be applied to tabs.
* @param colors the colors of tabs, default is [TabDefaults.colors].
* @param style the style of tabs, default is [TabDefaults.style].
* @param indicator the indicator of the [TabRow], see [TabRowScope.TabIndicator].
* @param tabs the tabs of the [TabRow], should typically be [Tab].
*/
@Composable
fun TabRow(
selectedTabIndex: Int = 0,
modifier: Modifier = Modifier,
colors: TabColors = Tab.colors,
style: TabStyle = Tab.style,
colors: TabColors = TabDefaults.colors,
style: TabStyle = TabDefaults.style,
indicator: @Composable TabRowScope.() -> Unit = { TabIndicator(modifier = Modifier.tabIndicatorOffset()) },
tabs: @Composable () -> Unit
) {
@@ -136,12 +161,24 @@ fun TabRow(
}
}
/**
* Flexi UI scrollable tabs.
* @see TabRow
* @see Tab
* @param selectedTabIndex the selected tab index.
* @param modifier the [Modifier] to be applied to tabs.
* @param colors the colors of tabs, default is [TabDefaults.colors].
* @param style the style of tabs, default is [TabDefaults.style].
* @param scrollState the scroll state of tabs.
* @param indicator the indicator of the [ScrollableTabRow], see [TabRowScope.TabIndicator].
* @param tabs the tabs of the [ScrollableTabRow], should typically be [Tab].
*/
@Composable
fun ScrollableTabRow(
selectedTabIndex: Int = 0,
modifier: Modifier = Modifier,
colors: TabColors = Tab.colors,
style: TabStyle = Tab.style,
colors: TabColors = TabDefaults.colors,
style: TabStyle = TabDefaults.style,
scrollState: ScrollState = rememberScrollState(),
indicator: @Composable TabRowScope.() -> Unit = { TabIndicator(modifier = Modifier.tabIndicatorOffset()) },
tabs: @Composable () -> Unit
@@ -190,6 +227,21 @@ fun ScrollableTabRow(
}
}
/**
* Flexi UI tab.
* @see TabRow
* @see ScrollableTabRow
* @param selected whether this tab is selected.
* @param onClick the callback when this tab is clicked.
* @param modifier the [Modifier] to be applied to this tab.
* @param selectedContentColor the selected content color.
* @param unselectedContentColor the unselected content color.
* @param contentPadding the content padding.
* @param contentShape the content shape.
* @param enabled whether this tab is enabled.
* @param interactionSource the interaction source.
* @param content the content of the [Tab], should typically be [Icon] or [Text].
*/
@Composable
fun Tab(
selected: Boolean,
@@ -204,11 +256,11 @@ fun Tab(
content: @Composable RowScope.() -> Unit
) {
val currentSelectedContentColor = selectedContentColor.orNull()
?: LocalTabSelectedContentColor.current.orNull() ?: Tab.colors.selectedContentColor
?: LocalTabSelectedContentColor.current.orNull() ?: TabDefaults.colors.selectedContentColor
val currentUnselectedContentColor = unselectedContentColor.orNull()
?: LocalTabUnselectedContentColor.current.orNull() ?: Tab.colors.unselectedContentColor
val currentContentPadding = contentPadding ?: LocalTabContentPadding.current ?: Tab.style.contentPadding
val currentContentShape = contentShape ?: LocalTabContentShape.current ?: Tab.style.contentShape
?: LocalTabUnselectedContentColor.current.orNull() ?: TabDefaults.colors.unselectedContentColor
val currentContentPadding = contentPadding ?: LocalTabContentPadding.current ?: TabDefaults.style.contentPadding
val currentContentShape = contentShape ?: LocalTabContentShape.current ?: TabDefaults.style.contentShape
val contentColor by animateColorAsState(if (selected) currentSelectedContentColor else currentUnselectedContentColor)
val contentIconStyle = LocalIconStyle.current.copy(tint = contentColor)
val contentTextStyle = LocalTextStyle.current.copy(color = contentColor)
@@ -257,17 +309,41 @@ private fun rememberScrollableTabData(scrollState: ScrollState): ScrollableTabDa
return remember(scrollState, coroutineScope) { ScrollableTabData(scrollState, coroutineScope) }
}
/**
* Represents the position of a tab.
* @param left the left position.
* @param width the indicator width.
* @param tabWidth the tab width.
*/
@Immutable
data class TabPosition(val left: Dp, val width: Dp, val tabWidth: Dp) {
/**
* Calculates the right of the tab.
* @return [Dp]
*/
val right get() = left + width
/**
* Calculates the center of the tab.
* @param currentWidth the current indicator width.
*/
fun calculateCenter(currentWidth: Dp) = left + width / 2 - currentWidth / 2
}
/**
* A scope for tab.
*/
@Stable
interface TabRowScope {
/**
* Tab indicator.
* @param modifier the [Modifier] to be applied to this tab indicator.
* @param color the color of this tab indicator.
* @param height the height of this tab indicator.
* @param shape the shape of this tab indicator.
*/
@Composable
fun TabIndicator(
modifier: Modifier = Modifier,
@@ -278,6 +354,11 @@ interface TabRowScope {
Box(modifier.height(height).background(color, shape))
}
/**
* [Modifier] that offsets the tab indicator.
* @param currentTabPosition the current tab position.
* @param indicatorWidth the indicator width.
*/
fun Modifier.tabIndicatorOffset(
currentTabPosition: TabPosition = impl.tabPositions[impl.selectedTabIndex],
indicatorWidth: Dp = impl.style.indicatorWidth
@@ -303,6 +384,12 @@ interface TabRowScope {
.width(animatedWidh)
}
/**
* [Modifier] that offsets the pager tab indicator.
* @param pagerState the pager state.
* @param tabPositions the tab positions.
* @param indicatorWidth the indicator width.
*/
fun Modifier.pagerTabIndicatorOffset(
pagerState: PagerState,
tabPositions: List<TabPosition> = impl.tabPositions,
@@ -415,7 +502,10 @@ private class ScrollableTabData(private val scrollState: ScrollState, private va
@Stable
private enum class TabSlots { Tabs, TabsAverage, Indicator }
object Tab {
/**
* Defaults of tab.
*/
object TabDefaults {
val colors: TabColors
@Composable
@ReadOnlyComposable

View File

@@ -26,6 +26,7 @@ package com.highcapable.flexiui.component
import androidx.compose.foundation.text.BasicText
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Modifier
@@ -38,12 +39,26 @@ import com.highcapable.betterandroid.compose.extension.ui.orNull
import com.highcapable.flexiui.DefaultTypography
import com.highcapable.flexiui.LocalColors
/**
* Flexi UI basic text.
* @see BasicText
* @param text the text to be displayed.
* @param modifier the [Modifier] to be applied to this text.
* @param color the color of the text.
* @param style the style of the text.
* @param singleLine whether the text should be displayed on a single line, default is false.
* @param maxLines the maximum number of lines to display, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the minimum number of lines to display, default is 1.
* @param overflow the overflow strategy for displaying the text, default is [TextOverflow.Ellipsis].
* @param softWrap whether the text should break at soft line breaks.
* @param onTextLayout the callback to be invoked when the text layout is ready.
*/
@Composable
fun Text(
text: String,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
style: TextStyle = Text.style,
style: TextStyle? = null,
singleLine: Boolean = false,
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
minLines: Int = 1,
@@ -65,12 +80,27 @@ fun Text(
)
}
/**
* Flexi UI basic text.
* @see BasicText
* @param text the text to be displayed.
* @param modifier the [Modifier] to be applied to this text.
* @param color the color of the text.
* @param style the style of the text.
* @param singleLine whether the text should be displayed on a single line, default is false.
* @param maxLines the maximum number of lines to display, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the minimum number of lines to display, default is 1.
* @param overflow the overflow strategy for displaying the text, default is [TextOverflow.Ellipsis].
* @param softWrap whether the text should break at soft line breaks.
* @param inlineContent map of tags to [InlineTextContent]s that can be used to add composable content to the text.
* @param onTextLayout the callback to be invoked when the text layout is ready.
*/
@Composable
fun Text(
text: AnnotatedString,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
style: TextStyle = Text.style,
style: TextStyle? = null,
singleLine: Boolean = false,
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
minLines: Int = 1,
@@ -79,11 +109,12 @@ fun Text(
inlineContent: Map<String, InlineTextContent> = mapOf(),
onTextLayout: (TextLayoutResult) -> Unit = {}
) {
val currentColor = color.orNull() ?: style.color.orNull() ?: Text.color
val currentStyle = style ?: LocalTextStyle.current
val currentColor = color.orNull() ?: currentStyle.color.orNull() ?: defaultTextColor()
BasicText(
text = text,
modifier = modifier,
style = style.copy(color = currentColor),
style = currentStyle.copy(color = currentColor),
onTextLayout = onTextLayout,
overflow = overflow,
softWrap = softWrap,
@@ -93,21 +124,28 @@ fun Text(
)
}
object Text {
val color: Color
@Composable
@ReadOnlyComposable
get() = defaultTextColor()
val style: TextStyle
@Composable
@ReadOnlyComposable
get() = LocalTextStyle.current
/**
* CompositionLocal containing the preferred [TextStyle]
* that will be used by text by default.
*/
val LocalTextStyle = compositionLocalOf { DefaultTextStyle }
/**
* This function is used to set the current value of [LocalTextStyle], merging the given style
* with the current style values for any missing attributes. Any [Text] components included in
* this component's [content] will be styled with this style unless styled explicitly.
* @see LocalTextStyle
* @param value the merged text style to set.
* @param content the composable content.
*/
@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
val mergedStyle = LocalTextStyle.current.merge(value)
CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
}
@Composable
@ReadOnlyComposable
internal fun defaultTextColor() = LocalColors.current.textPrimary
internal val LocalTextStyle = compositionLocalOf { DefaultTextStyle }
private val DefaultTextStyle = DefaultTypography.primary

View File

@@ -97,6 +97,19 @@ import com.highcapable.flexiui.resources.icon.Backspace
import com.highcapable.flexiui.resources.icon.ViewerClose
import com.highcapable.flexiui.resources.icon.ViewerOpen
/**
* Colors defines for text field.
* @param textColor the text color.
* @param cursorColor the cursor color.
* @param selectionColors the selection colors.
* @param completionColors the completion colors.
* @param placeholderContentColor the placeholder content color, usually for text color.
* @param decorInactiveTint the decoration inactive tint.
* @param decorActiveTint the decoration active tint.
* @param borderInactiveColor the border inactive color.
* @param borderActiveColor the border active color.
* @param backgroundColor the background color.
*/
@Immutable
data class TextFieldColors(
val textColor: Color,
@@ -111,12 +124,26 @@ data class TextFieldColors(
val backgroundColor: Color
)
/**
* Colors defines for auto complete box.
* @param highlightContentColor the highlight content color, usually for text color.
* @param menuColors the dropdown menu colors.
*/
@Immutable
data class AutoCompleteBoxColors(
val highlightContentColor: Color,
val menuColors: DropdownMenuColors
)
/**
* Style defines for text field.
* @param textStyle the text style.
* @param padding the padding of content.
* @param shape the shape.
* @param borderInactive the inactive border stroke.
* @param borderActive the active border stroke.
* @param completionStyle the completion dropdown menu style.
*/
@Immutable
data class TextFieldStyle(
val textStyle: TextStyle,
@@ -127,6 +154,13 @@ data class TextFieldStyle(
val completionStyle: DropdownMenuStyle
)
/**
* Options defines for auto complete.
* @param checkCase whether to check case, default is true.
* @param checkStartSpace whether to check start space, default is true.
* @param checkEndSpace whether to check end space, default is true.
* @param threshold the threshold, default is 2.
*/
@Immutable
data class AutoCompleteOptions(
val checkCase: Boolean = true,
@@ -135,14 +169,41 @@ data class AutoCompleteOptions(
val threshold: Int = 2
)
/**
* Flexi UI text field.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the text field value.
* @param onValueChange the text field value change callback.
* @param completionValues the auto complete values, when you want to use auto complete.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param completionOptions the auto complete options.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param singleLine whether this text field is single line, default is false.
* @param maxLines the max lines of this text field, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the min lines of this text field, default is 1.
* @param visualTransformation the visual transformation, default is [VisualTransformation.None].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
* @param footer the footer of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun TextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
completionValues: List<String> = emptyList(),
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
completionOptions: AutoCompleteOptions = AutoCompleteOptions(),
@@ -257,14 +318,41 @@ fun TextField(
}
}
/**
* Flexi UI text field.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the value of text.
* @param onValueChange the text field value change callback.
* @param completionValues the auto complete values, when you want to use auto complete.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param completionOptions the auto complete options.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param singleLine whether this text field is single line, default is false.
* @param maxLines the max lines of this text field, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the min lines of this text field, default is 1.
* @param visualTransformation the visual transformation, default is [VisualTransformation.None].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
* @param footer the footer of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun TextField(
value: String,
onValueChange: (String) -> Unit,
completionValues: List<String> = emptyList(),
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
completionOptions: AutoCompleteOptions = AutoCompleteOptions(),
@@ -310,14 +398,37 @@ fun TextField(
)
}
/**
* Flexi UI password text field.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the text field value.
* @param onValueChange the text field value change callback.
* @param defaultPasswordVisible the default password visible, default is false.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param normalVisualTransformation the normal visual transformation, default is [VisualTransformation.None].
* @param secretVisualTransformation the secret visual transformation, default is [PasswordVisualTransformation].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun PasswordTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
defaultPasswordVisible: Boolean = false,
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
@@ -364,7 +475,7 @@ fun PasswordTextField(
if (value.text.isEmpty() && animatedSize == 0.dp) passwordVisible = defaultPasswordVisible
IconToggleButton(
modifier = Modifier.size(animatedSize).pointerHoverState(TextFieldPointerState.Common),
style = IconButton.style.copy(padding = TextDecorIconPadding),
style = IconButtonDefaults.style.copy(padding = TextDecorIconPadding),
checked = passwordVisible,
onCheckedChange = {
passwordVisible = it
@@ -378,14 +489,37 @@ fun PasswordTextField(
)
}
/**
* Flexi UI password text field.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the value of text.
* @param onValueChange the text field value change callback.
* @param defaultPasswordVisible the default password visible, default is false.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param normalVisualTransformation the normal visual transformation, default is [VisualTransformation.None].
* @param secretVisualTransformation the secret visual transformation, default is [PasswordVisualTransformation].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun PasswordTextField(
value: String,
onValueChange: (String) -> Unit,
defaultPasswordVisible: Boolean = false,
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
@@ -423,14 +557,40 @@ fun PasswordTextField(
)
}
/**
* Flexi UI text field with backspace icon.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the text field value.
* @param onValueChange the text field value change callback.
* @param completionValues the auto complete values, when you want to use auto complete.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param completionOptions the auto complete options.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param singleLine whether this text field is single line, default is false.
* @param maxLines the max lines of this text field, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the min lines of this text field, default is 1.
* @param visualTransformation the visual transformation, default is [VisualTransformation.None].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun BackspaceTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
completionValues: List<String> = emptyList(),
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
completionOptions: AutoCompleteOptions = AutoCompleteOptions(),
@@ -487,7 +647,7 @@ fun BackspaceTextField(
focusRequester.requestFocus()
},
modifier = Modifier.width(animatedSize).pointerHoverState(TextFieldPointerState.Common),
style = IconButton.style.copy(padding = TextDecorIconPadding),
style = IconButtonDefaults.style.copy(padding = TextDecorIconPadding),
enabled = enabled,
interactionSource = cInteractionSource
) { Icon(imageVector = Icons.Backspace) }
@@ -496,14 +656,40 @@ fun BackspaceTextField(
)
}
/**
* Flexi UI text field with backspace icon.
* @see TextField
* @see PasswordTextField
* @see BackspaceTextField
* @param value the value of text.
* @param onValueChange the text field value change callback.
* @param completionValues the auto complete values, when you want to use auto complete.
* @param modifier the [Modifier] to be applied to this text field.
* @param colors the colors of this text field, default is [TextFieldDefaults.colors].
* @param style the style of this text field, default is [TextFieldDefaults.style].
* @param enabled whether this text field is enabled, default is true.
* @param readOnly whether this text field is read only, default is false.
* @param completionOptions the auto complete options.
* @param keyboardOptions the keyboard options, default is [KeyboardOptions.Default].
* @param keyboardActions the keyboard actions, default is [KeyboardActions.Default].
* @param singleLine whether this text field is single line, default is false.
* @param maxLines the max lines of this text field, when [singleLine] is false default is [Int.MAX_VALUE].
* @param minLines the min lines of this text field, default is 1.
* @param visualTransformation the visual transformation, default is [VisualTransformation.None].
* @param onTextLayout the callback to be invoked when the text layout is ready.
* @param focusRequester the focus requester of this text field.
* @param interactionSource the interaction source of this text field.
* @param header the header of the [TextField], should typically be [Icon] or [Text].
* @param placeholder the placeholder of the [TextField], should typically be [Icon] or [Text].
*/
@Composable
fun BackspaceTextField(
value: String,
onValueChange: (String) -> Unit,
completionValues: List<String> = emptyList(),
modifier: Modifier = Modifier,
colors: TextFieldColors = TextField.colors,
style: TextFieldStyle = TextField.style,
colors: TextFieldColors = TextFieldDefaults.colors,
style: TextFieldStyle = TextFieldDefaults.style,
enabled: Boolean = true,
readOnly: Boolean = false,
completionOptions: AutoCompleteOptions = AutoCompleteOptions(),
@@ -563,7 +749,7 @@ private fun AutoCompleteTextFieldBox(
if (completionValues.isEmpty()) return
// We need to use some "last" to remember the last using data,
// because we need to mantain the animation state of the dropdown menu.
// This allows the animation to finish playing due to the next composable event.
// This allows the animation to finish playing due to the next compostion.
var lastHandingModified by remember { mutableStateOf(false) }
var lastMatchedValue by remember { mutableStateOf("") }
var lastInputLength by remember { mutableStateOf(0) }
@@ -597,9 +783,13 @@ private fun AutoCompleteTextFieldBox(
lastHandingModified = false
lastMatchedValue = ""
} else selection = -1
/** Collapse the dropdown menu. */
fun collapse() {
lastMatchedValue = inputText
}
/** Select and collapse the dropdown menu. */
fun selectAndCollapse(position: Int) {
if (position < 0) return
val newValue = TextFieldValue(matchedValues[position], TextRange(matchedValues[position].length))
@@ -746,7 +936,10 @@ private fun Modifier.textFieldPadding(
}
}
object TextField {
/**
* Defaults of text field.
*/
object TextFieldDefaults {
val colors: TextFieldColors
@Composable
@ReadOnlyComposable
@@ -768,7 +961,7 @@ private fun defaultTextFieldColors() = TextFieldColors(
),
completionColors = AutoCompleteBoxColors(
highlightContentColor = LocalColors.current.themePrimary,
menuColors = DropdownMenu.colors
menuColors = DropdownMenuDefaults.colors
),
placeholderContentColor = LocalColors.current.textSecondary,
decorInactiveTint = LocalColors.current.themeSecondary,
@@ -786,7 +979,7 @@ private fun defaultTextFieldStyle() = TextFieldStyle(
shape = withAreaBoxShape(),
borderInactive = defaultTextFieldInactiveBorder(),
borderActive = defaultTextFieldActiveBorder(),
completionStyle = DropdownMenu.style
completionStyle = DropdownMenuDefaults.style
)
@Composable

View File

@@ -23,6 +23,7 @@
package com.highcapable.flexiui.interaction
import androidx.compose.foundation.Indication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
@@ -41,6 +42,12 @@ import com.highcapable.betterandroid.compose.extension.ui.toggleable
import com.highcapable.flexiui.LocalColors
import androidx.compose.material.ripple.rememberRipple as materialRememberRipple
/**
* Style defines for ripple.
* @param bounded whether the ripple is bounded.
* @param radius the radius.
* @param color the color.
*/
@Immutable
data class RippleStyle(
val bounded: Boolean,
@@ -48,9 +55,26 @@ data class RippleStyle(
val color: Color
)
/**
* Creates and remember a ripple effect [Indication] with the given [style].
* @see materialRememberRipple
* @param style the style, default is [InteractionDefaults.rippleStyle].
* @return [Indication]
*/
@Composable
fun rememberRipple(style: RippleStyle) = materialRememberRipple(style.bounded, style.radius, style.color)
fun rememberRipple(style: RippleStyle = InteractionDefaults.rippleStyle) =
materialRememberRipple(style.bounded, style.radius, style.color)
/**
* The clickable modifier has a ripple effect.
* @see Modifier.clickable
* @param rippleStyle the ripple style, default is [InteractionDefaults.rippleStyle].
* @param interactionSource the interaction source.
* @param enabled whether to enable the event, default is true.
* @param onClickLabel the click label.
* @param role the role.
* @param onClick the click event.
*/
fun Modifier.rippleClickable(
rippleStyle: RippleStyle? = null,
interactionSource: MutableInteractionSource? = null,
@@ -69,7 +93,7 @@ fun Modifier.rippleClickable(
properties["onClick"] = onClick
}
) {
val currentRippleStyle = rippleStyle ?: Interaction.rippleStyle
val currentRippleStyle = rippleStyle ?: InteractionDefaults.rippleStyle
val currentIndication = rememberRipple(currentRippleStyle)
clickable(
onClick = onClick,
@@ -81,6 +105,19 @@ fun Modifier.rippleClickable(
)
}
/**
* The combined clickable modifier has a ripple effect.
* @see Modifier.combinedClickable
* @param rippleStyle the ripple style, default is [InteractionDefaults.rippleStyle].
* @param interactionSource the interaction source.
* @param enabled whether to enable the event, default is true.
* @param onClickLabel the click label.
* @param role the role.
* @param onLongClickLabel the long click label.
* @param onLongClick the long click event.
* @param onDoubleClick the double click event.
* @param onClick the click event.
*/
fun Modifier.rippleCombinedClickable(
rippleStyle: RippleStyle? = null,
interactionSource: MutableInteractionSource? = null,
@@ -105,7 +142,7 @@ fun Modifier.rippleCombinedClickable(
properties["onClick"] = onClick
}
) {
val currentRippleStyle = rippleStyle ?: Interaction.rippleStyle
val currentRippleStyle = rippleStyle ?: InteractionDefaults.rippleStyle
val currentIndication = rememberRipple(currentRippleStyle)
combinedClickable(
onClick = onClick,
@@ -120,6 +157,15 @@ fun Modifier.rippleCombinedClickable(
)
}
/**
* The toggleable modifier has a ripple effect.
* @see Modifier.toggleable
* @param rippleStyle the ripple style, default is [InteractionDefaults.rippleStyle].
* @param interactionSource the interaction source.
* @param enabled whether to enable the event, default is true.
* @param role the role.
* @param onValueChange the value change event.
*/
fun Modifier.rippleToggleable(
value: Boolean,
rippleStyle: RippleStyle? = null,
@@ -138,7 +184,7 @@ fun Modifier.rippleToggleable(
properties["onValueChange"] = onValueChange
}
) {
val currentRippleStyle = rippleStyle ?: Interaction.rippleStyle
val currentRippleStyle = rippleStyle ?: InteractionDefaults.rippleStyle
val currentIndication = rememberRipple(currentRippleStyle)
toggleable(
value = value,
@@ -150,6 +196,15 @@ fun Modifier.rippleToggleable(
)
}
/**
* The selectable modifier has a ripple effect.
* @see Modifier.selectable
* @param rippleStyle the ripple style, default is [InteractionDefaults.rippleStyle].
* @param interactionSource the interaction source.
* @param enabled whether to enable the event, default is true.
* @param role the role.
* @param onClick the click event.
*/
fun Modifier.rippleSelectable(
selected: Boolean,
rippleStyle: RippleStyle? = null,
@@ -168,7 +223,7 @@ fun Modifier.rippleSelectable(
properties["onClick"] = onClick
}
) {
val currentRippleStyle = rippleStyle ?: Interaction.rippleStyle
val currentRippleStyle = rippleStyle ?: InteractionDefaults.rippleStyle
val currentIndication = rememberRipple(currentRippleStyle)
selectable(
selected = selected,
@@ -180,13 +235,20 @@ fun Modifier.rippleSelectable(
)
}
object Interaction {
/**
* Defaults of interaction.
*/
object InteractionDefaults {
val rippleStyle: RippleStyle
@Composable
@ReadOnlyComposable
get() = LocalRippleStyle.current ?: defaultRippleStyle()
}
/**
* CompositionLocal containing the preferred [RippleStyle]
* that will be used by interaction by default.
*/
val LocalRippleStyle = compositionLocalOf<RippleStyle?> { null }
@Composable

View File

@@ -31,6 +31,8 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
@@ -55,17 +57,40 @@ import com.highcapable.flexiui.LocalColors
import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.LocalTypography
import com.highcapable.flexiui.component.AreaBox
import com.highcapable.flexiui.component.AreaBoxDefaults
import com.highcapable.flexiui.component.AreaBoxStyle
import com.highcapable.flexiui.component.Button
import com.highcapable.flexiui.component.Icon
import com.highcapable.flexiui.component.LocalIconStyle
import com.highcapable.flexiui.component.LocalPrimaryButton
import com.highcapable.flexiui.component.LocalTextStyle
import com.highcapable.flexiui.component.Text
import com.highcapable.flexiui.utils.SubcomposeRow
/**
* Colors defines for flexi dialog.
* @param titleTextColor the title text color.
* @param titleIconTint the title icon tint.
* @param contentTextColor the content text color.
*/
@Immutable
data class FlexiDialogColors(
val titleTextColor: Color,
val titleIconTint: Color,
val contentTextColor: Color
)
/**
* Style defines for flexi dialog.
* @param boxStyle the style of area box.
* @param titleTextStyle the title text style.
* @param contentTextStyle the content text style.
* @param maxWidth the dialog's max width.
* @param outPadding the dialog's out padding.
* @param titlePadding the title padding.
* @param contentPadding the content padding.
* @param buttonsSpacing the spacing between buttons.
*/
@Immutable
data class FlexiDialogStyle(
val boxStyle: AreaBoxStyle,
@@ -78,29 +103,50 @@ data class FlexiDialogStyle(
val buttonsSpacing: Dp
)
/**
* Flexi UI dialog.
* @param visible the visible state of dialog.
* @param onDismissRequest the callback when dismiss dialog.
* @param modifier the [Modifier] to be applied to this dialog.
* @param animated whether to animate the dialog, default is true.
* @param colors the colors of dialog, default is [FlexiDialogDefaults.colors].
* @param style the style of dialog, default is [FlexiDialogDefaults.style].
* @param contentAlignment the alignment of dialog content, default is [Alignment.TopStart].
* @param properties the properties of dialog, default is [DefaultDialogProperties].
* @param title the title of the [FlexiDialog], should typically be [Icon] or [Text].
* @param content the content of the [FlexiDialog].
* @param confirmButton the confirm button of the [FlexiDialog], should typically be [Button].
* @param cancelButton the cancel button of the [FlexiDialog], should typically be [Button].
* @param neutralButton the neutral button of the [FlexiDialog], should typically be [Button].
*/
@Composable
fun FlexiDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
animated: Boolean = true,
colors: FlexiDialogColors = FlexiDialog.colors,
style: FlexiDialogStyle = FlexiDialog.style,
colors: FlexiDialogColors = FlexiDialogDefaults.colors,
style: FlexiDialogStyle = FlexiDialogDefaults.style,
contentAlignment: Alignment = Alignment.TopStart,
properties: DialogPropertiesWrapper = DefaultDialogProperties,
title: (@Composable () -> Unit)? = null,
title: (@Composable RowScope.() -> Unit)? = null,
content: @Composable () -> Unit,
confirmButton: @Composable (() -> Unit)? = null,
cancelButton: @Composable (() -> Unit)? = null,
neutralButton: @Composable (() -> Unit)? = null
) {
/** Build the content of dialog. */
@Composable
fun Content() {
title?.also { content ->
Box(modifier = Modifier.padding(style.titlePadding)) {
CompositionLocalProvider(
LocalTextStyle provides style.titleTextStyle.copy(color = colors.titleTextColor),
content = content
title?.also { titleContent ->
CompositionLocalProvider(
LocalIconStyle provides LocalIconStyle.current.copy(tint = colors.titleIconTint),
LocalTextStyle provides style.titleTextStyle.copy(color = colors.titleTextColor)
) {
Row(
modifier = Modifier.padding(style.titlePadding),
verticalAlignment = Alignment.CenterVertically,
content = titleContent
)
}
}
@@ -112,16 +158,17 @@ fun FlexiDialog(
}
}
/** Build the buttons of dialog. */
@Composable
fun Buttons() {
Column(
modifier = Modifier.padding(top = style.buttonsSpacing),
horizontalAlignment = Alignment.CenterHorizontally
) {
neutralButton?.also { content ->
neutralButton?.also { button ->
SubcomposeRow(
modifier = Modifier.fillMaxWidth().padding(bottom = style.buttonsSpacing),
content = content
content = button
)
}
SubcomposeRow(
@@ -130,10 +177,10 @@ fun FlexiDialog(
spacingBetween = style.buttonsSpacing
) {
cancelButton?.invoke()
confirmButton?.also { content ->
confirmButton?.also { button ->
CompositionLocalProvider(
LocalPrimaryButton provides true,
content = content
content = button
)
}
}
@@ -157,16 +204,19 @@ fun FlexiDialog(
}
}
/**
* Basic flexi dialog for internal use.
*/
@Composable
fun BasicFlexiDialog(
private fun BasicFlexiDialog(
visible: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
animated: Boolean = true,
boxStyle: AreaBoxStyle = AreaBox.style,
maxWidth: Dp = DefaultMaxWidth,
contentAlignment: Alignment = Alignment.TopStart,
properties: DialogPropertiesWrapper = DefaultDialogProperties,
modifier: Modifier,
animated: Boolean,
boxStyle: AreaBoxStyle,
maxWidth: Dp,
contentAlignment: Alignment,
properties: DialogPropertiesWrapper,
content: @Composable () -> Unit
) {
val animatedAlpha by animateFloatAsState(if (visible) 1f else 0f, tween(AnimationDuration))
@@ -205,7 +255,10 @@ fun BasicFlexiDialog(
}
}
object FlexiDialog {
/**
* Defaults of flexi dialog.
*/
object FlexiDialogDefaults {
val colors: FlexiDialogColors
@Composable
@ReadOnlyComposable
@@ -220,13 +273,14 @@ object FlexiDialog {
@ReadOnlyComposable
private fun defaultFlexiDialogColors() = FlexiDialogColors(
titleTextColor = LocalColors.current.textPrimary,
titleIconTint = LocalColors.current.textPrimary,
contentTextColor = LocalColors.current.textSecondary
)
@Composable
@ReadOnlyComposable
private fun defaultFlexiDialogStyle() = FlexiDialogStyle(
boxStyle = AreaBox.style.copy(padding = ComponentPadding(LocalSizes.current.spacingSecondary)),
boxStyle = AreaBoxDefaults.style.copy(padding = ComponentPadding(LocalSizes.current.spacingSecondary)),
titleTextStyle = LocalTypography.current.titleSecondary,
contentTextStyle = LocalTypography.current.primary,
maxWidth = DefaultMaxWidth,

View File

@@ -26,6 +26,10 @@ package com.highcapable.flexiui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
/**
* Whether dynamic color is available for current system.
* @return [Boolean]
*/
@Composable
@ReadOnlyComposable
actual fun isDynamicColorAvailable() = false

View File

@@ -26,7 +26,7 @@ package com.highcapable.flexiui
import androidx.compose.foundation.LocalContextMenuRepresentation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import com.highcapable.flexiui.component.DesktopContextMenu
import com.highcapable.flexiui.component.DesktopContextMenuDefaults
import com.highcapable.flexiui.component.DesktopContextMenuRepresentation
import com.highcapable.flexiui.component.LocalContextMenuColors
import com.highcapable.flexiui.component.LocalContextMenuStyle
@@ -42,8 +42,8 @@ internal actual fun FlexiThemeContent(content: @Composable () -> Unit) {
CompositionLocalProvider(
LocalContextMenuRepresentation provides
DesktopContextMenuRepresentation(
colors = DesktopContextMenu.colors,
style = DesktopContextMenu.style
colors = DesktopContextMenuDefaults.colors,
style = DesktopContextMenuDefaults.style
),
content = content
)

View File

@@ -68,12 +68,22 @@ import com.highcapable.flexiui.LocalSizes
import com.highcapable.flexiui.interaction.rippleClickable
import java.awt.event.KeyEvent
/**
* Colors defines for the context menu.
* @param contentColor the content color, usually for the text color.
* @param borderColor the border color.
*/
@Immutable
data class ContextMenuColors(
val contentColor: Color,
val borderColor: Color
)
/**
* Style defines for the context menu.
* @param contentStyle the content style of area box.
* @param borderStyle the border style of area box.
*/
@Immutable
data class ContextMenuStyle(
val contentStyle: AreaBoxStyle?,
@@ -172,7 +182,10 @@ private fun Modifier.onHover(onHover: (Boolean) -> Unit) = pointerInput(Unit) {
}
}
object DesktopContextMenu {
/**
* Defaults of context menu.
*/
object DesktopContextMenuDefaults {
val colors: ContextMenuColors
@Composable
@ReadOnlyComposable
@@ -183,6 +196,10 @@ object DesktopContextMenu {
get() = LocalContextMenuStyle.current
}
/**
* CompositionLocal containing the preferred [ContextMenuColors]
* that will be used by context menu by default.
*/
val LocalContextMenuColors = compositionLocalOf {
ContextMenuColors(
borderColor = Color.Unspecified,
@@ -190,6 +207,10 @@ val LocalContextMenuColors = compositionLocalOf {
)
}
/**
* CompositionLocal containing the preferred [ContextMenuStyle]
* that will be used by context menu by default.
*/
val LocalContextMenuStyle = compositionLocalOf {
ContextMenuStyle(
contentStyle = null,
@@ -207,11 +228,11 @@ internal fun defaultContextMenuColors() = ContextMenuColors(
@Composable
@ReadOnlyComposable
internal fun defaultContextMenuStyle() = ContextMenuStyle(
contentStyle = LocalContextMenuStyle.current.contentStyle ?: AreaBox.style.copy(
contentStyle = LocalContextMenuStyle.current.contentStyle ?: AreaBoxDefaults.style.copy(
padding = ComponentPadding(horizontal = DefaultMenuContentPadding),
shape = LocalShapes.current.secondary
),
borderStyle = LocalContextMenuStyle.current.borderStyle ?: AreaBox.style.copy(
borderStyle = LocalContextMenuStyle.current.borderStyle ?: AreaBoxDefaults.style.copy(
padding = ComponentPadding(LocalSizes.current.spacingTertiary),
shadowSize = LocalSizes.current.zoomSizeTertiary,
shape = LocalShapes.current.primary

View File

@@ -26,6 +26,10 @@ package com.highcapable.flexiui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
/**
* Whether dynamic color is available for current system.
* @return [Boolean]
*/
@Composable
@ReadOnlyComposable
actual fun isDynamicColorAvailable() = false

View File

@@ -23,4 +23,7 @@
package com.highcapable.flexiui.resources
/**
* The default icon resources for Flexi UI.
*/
object Icons