diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/Note.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/Note.kt index 29b2d602d..dd0e2d7ef 100644 --- a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/Note.kt +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/Note.kt @@ -1,6 +1,5 @@ package com.sdds.compose.uikit -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.InteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource @@ -13,11 +12,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds -import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.MeasurePolicy @@ -34,12 +33,18 @@ import androidx.compose.ui.unit.constrainWidth import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.offset import com.sdds.compose.uikit.graphics.LocalIndication -import com.sdds.compose.uikit.graphics.brush.BrushProducer +import com.sdds.compose.uikit.graphics.backgroundBrush import com.sdds.compose.uikit.interactions.MutableSemanticStateSource import com.sdds.compose.uikit.interactions.SemanticStateSource -import com.sdds.compose.uikit.interactions.getValue +import com.sdds.compose.uikit.interactions.getValueAsState import com.sdds.compose.uikit.internal.heightOrZero import com.sdds.compose.uikit.internal.widthOrZero +import com.sdds.compose.uikit.motion.Motion +import com.sdds.compose.uikit.motion.components.note.NoteMotionStyle +import com.sdds.compose.uikit.motion.components.note.rememberNoteMotion +import com.sdds.compose.uikit.motion.getBrushAsState +import com.sdds.compose.uikit.motion.getTextStyleAsState +import com.sdds.compose.uikit.motion.rememberMotionContext /** * Компонент [Note] @@ -146,7 +151,6 @@ fun Note( * @param semanticStateSource источник состояния семантики * @param contentAfter контент за текстовым блоком */ -@Suppress("LongMethod") @Composable fun Note( titleContent: @Composable () -> Unit, @@ -160,132 +164,148 @@ fun Note( semanticStateSource: SemanticStateSource = remember { MutableSemanticStateSource() }, contentAfter: (@Composable BoxScope.() -> Unit)? = null, ) { - val backgroundColor = style.colors.backgroundColor.getValue(interactionSource) - val iconColor = style.colors.iconColor.colorForInteraction(interactionSource) - val disclosureColor = style.colors.disclosureColor.colorForInteraction(interactionSource) + val fallbackSource = remember { MutableInteractionSource() } + val fallbackSemantic = remember { MutableSemanticStateSource() } + Note( + motion = rememberNoteMotion( + motionContext = rememberMotionContext( + semanticStateSource = (semanticStateSource as? MutableSemanticStateSource) + ?: fallbackSemantic, + interactionSource = (interactionSource as? MutableInteractionSource) + ?: fallbackSource, + ), + ), + titleContent = titleContent, + modifier = modifier, + style = style, + textContent = textContent, + closeIcon = closeIcon, + contentBefore = contentBefore, + action = action, + contentAfter = contentAfter, + ) +} + +/** + * Компонент [Note] + * + * Нота оборачивает контент по умолчанию: текстовый блок зажат между [contentBefore] и + * [contentAfter], который стоит сразу за текстом. Если ширину задать извне + * (`modifier = Modifier.fillMaxWidth()`), нота растянется, а [contentAfter] прижмётся к её концу. + * + * @param motion объект анимаций + * @param modifier модификатор + * @param style стиль компонента + * @param titleContent заголовок + * @param textContent текст + * @param closeIcon иконка закрытия + * @param contentBefore контент перед текстовым блоком + * @param action дополнительный контент для взаимодейстивия с компонентом + * @param contentAfter контент за текстовым блоком + */ +@Composable +fun Note( + motion: Motion, + titleContent: @Composable () -> Unit, + modifier: Modifier = Modifier, + style: NoteStyle = LocalNoteStyle.current, + textContent: (@Composable () -> Unit)? = null, + closeIcon: (@Composable BoxScope.() -> Unit)? = null, + contentBefore: (@Composable BoxScope.() -> Unit)? = null, + action: (@Composable BoxScope.() -> Unit)? = null, + contentAfter: (@Composable BoxScope.() -> Unit)? = null, +) { + val backgroundColor = style.colors.backgroundColor.getBrushAsState(motion.context, motion.style.backgroundColor) val contentBeforeArrangement = style.contentBeforeArrangement - val extraBottomPadding = (style.dimensions.paddingTop - style.dimensions.paddingBottom).coerceAtLeast(0.dp) + val top by style.dimensions.paddingTopValues.getValueAsState(motion.context) + val bottom by style.dimensions.paddingBottomValues.getValueAsState(motion.context) + val extraBottomPadding = (top - bottom).coerceAtLeast(0.dp) val spacerHeight = with(LocalDensity.current) { extraBottomPadding.roundToPx() } val measurePolicy = remember(contentBeforeArrangement, spacerHeight) { NoteMeasurePolicy(contentBeforeArrangement, spacerHeight) } Box( - modifier = modifier.background(backgroundColor, style.shape), + modifier = modifier + .backgroundBrush( + { backgroundColor.value }, + style.shapes.getValueAsState(motion.context).value, + ), // Нота по умолчанию оборачивает контент и растягивается только тогда, когда ширину // требует родитель (например модификатором fillMaxWidth) propagateMinConstraints = true, ) { if (closeIcon != null) { - val closeSize = style.dimensions.closeSize + val iconTopP by style.dimensions.closeTopMarginValues.getValueAsState(motion.context) + val iconEndP by style.dimensions.closeEndMarginValues.getValueAsState(motion.context) Box( modifier = Modifier .align(Alignment.TopEnd) // Слот close — оверлей, он не должен наследовать родительские min-ограничения .width(IntrinsicSize.Min) .height(IntrinsicSize.Min) - .padding(top = style.dimensions.closeTopMargin, end = style.dimensions.closeEndMargin) + .padding(top = iconTopP, end = iconEndP) .defaultMinSize(), ) { + val closeSize by style.dimensions.closeSizeValues.getValueAsState(motion.context) + val closeBrush = style.colors.closeBrush.getBrushAsState(motion.context, motion.style.closeColor) CompositionLocalProvider( + LocalTintBrushProducer provides { closeBrush.value }, LocalIconDefaultSize provides DpSize(closeSize, closeSize), ) { closeIcon() } } } + val startP by style.dimensions.paddingStartValues.getValueAsState(motion.context) + val endP by style.dimensions.paddingEndValues.getValueAsState(motion.context) Layout( modifier = Modifier .padding( - start = style.dimensions.paddingStart, - end = style.dimensions.paddingEnd, - top = style.dimensions.paddingTop, - bottom = style.dimensions.paddingBottom, + start = startP, + end = endP, + top = top, + bottom = bottom, ) .clipToBounds(), measurePolicy = measurePolicy, content = { - contentBefore?.let { - Box( - modifier = Modifier - .layoutId(CONTENT_BEFORE) - .padding( - end = style.dimensions.contentBeforeEndMargin, - ), - ) { - val iconSize = style.dimensions.iconSize - val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize - CompositionLocalProvider( - LocalTint provides iconColor, - LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), - ) { - contentBefore.invoke(this) - } - } - } - - Box( - modifier = Modifier - .layoutId(TITLE) - .padding(end = style.dimensions.titlePaddingEnd), - ) { - ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { - val textColor = style.colors.titleColor.colorForInteractionAsState( - interactionSource, - semanticStateSource, - ) - ProvideTextStyle(style.titleStyle, color = { textColor.value }) { - titleContent() - } - } + contentBefore?.let { content -> + ContentBefore( + modifier = Modifier.layoutId(CONTENT_BEFORE), + style = style, + motion = motion, + contentBefore = content, + ) } - if (textContent != null) { - Box( - modifier = Modifier - .layoutId(TEXT) - .padding(top = style.dimensions.textTopMargin), - ) { - ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { - val textColor = style.colors.textColor.colorForInteractionAsState( - interactionSource, - semanticStateSource, - ) - ProvideTextStyle(style.textStyle, color = { textColor.value }) { - textContent() - } - } - } + Title( + modifier = Modifier.layoutId(TITLE), + style = style, + motion = motion, + titleContent = titleContent, + ) + textContent?.let { content -> + ContentText( + modifier = Modifier.layoutId(TEXT), + style = style, + motion = motion, + textContent = content, + ) } action?.let { - Box( - modifier = Modifier - .layoutId(ACTION) - .padding(top = style.dimensions.actionTopMargin), - ) { - CompositionLocalProvider( - LocalLinkButtonStyle provides style.linkButtonStyle, - ) { - action.invoke(this) - } - } + Action( + modifier = Modifier.layoutId(ACTION), + style = style, + motion = motion, + action = action, + ) } - contentAfter?.let { - Box( - modifier = Modifier - .layoutId(CONTENT_AFTER) - .padding( - start = style.dimensions.contentAfterStartMargin, - end = style.dimensions.contentAfterEndMargin, - ), - ) { - val iconSize = style.dimensions.disclosureSize - val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize - CompositionLocalProvider( - LocalTint provides disclosureColor, - LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), - ) { - it.invoke(this) - } - } + contentAfter?.let { content -> + ContentAfter( + modifier = Modifier.layoutId(CONTENT_AFTER), + style = style, + motion = motion, + contentAfter = content, + ) } }, ) @@ -320,7 +340,7 @@ private fun BoxScope.CloseIcon( onClose: (() -> Unit)?, ) { val closeInteractionSource = remember { MutableInteractionSource() } - val closeColor = style.colors.closeColor.colorForInteraction(closeInteractionSource) + val closeColor = style.colors.closeBrush.getValueAsState(closeInteractionSource) Icon( modifier = Modifier .align(Alignment.TopEnd) @@ -330,7 +350,7 @@ private fun BoxScope.CloseIcon( ) { onClose?.invoke() }, source = closeIconSource, contentDescription = "", - brush = BrushProducer { SolidColor(closeColor) }, + brush = { closeColor.value }, ) } @@ -417,6 +437,130 @@ private class NoteMeasurePolicy( } } +@Composable +private fun ContentBefore( + modifier: Modifier, + style: NoteStyle, + motion: Motion, + contentBefore: @Composable BoxScope.() -> Unit, +) { + val end by style.dimensions.contentBeforeEndMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding( + end = end, + ), + ) { + val iconColor = + style.colors.iconBrush.getBrushAsState(motion.context, motion.style.contentBeforeColor) + val iconSize by style.dimensions.iconSizeValues.getValueAsState(motion.context) + val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize + CompositionLocalProvider( + LocalTintBrushProducer provides { iconColor.value }, + LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), + ) { + contentBefore() + } + } +} + +@Composable +private fun Title( + modifier: Modifier, + style: NoteStyle, + motion: Motion, + titleContent: @Composable () -> Unit, +) { + val titleEndP by style.dimensions.titlePaddingEndValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(end = titleEndP), + ) { + ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { + val textColor = style.colors.titleBrush.getBrushAsState(motion.context, motion.style.titleColor) + val titleStyle by style.titleStyles.getTextStyleAsState(motion.context, motion.style.titleStyle) + ProvideTextStyle(titleStyle, brush = { textColor.value }) { + titleContent() + } + } + } +} + +@Composable +private fun ContentText( + modifier: Modifier, + style: NoteStyle, + motion: Motion, + textContent: @Composable () -> Unit, +) { + val textTop by style.dimensions.textTopMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(top = textTop), + ) { + ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { + val textColor = + style.colors.textBrush.getBrushAsState(motion.context, motion.style.textColor) + val textStyle by style.textStyles.getTextStyleAsState( + motion.context, + motion.style.textStyle, + ) + ProvideTextStyle(textStyle, brush = { textColor.value }) { + textContent() + } + } + } +} + +@Composable +private fun Action( + modifier: Modifier, + style: NoteStyle, + motion: Motion, + action: @Composable BoxScope.() -> Unit, +) { + val actionTop by style.dimensions.actionTopMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(top = actionTop), + ) { + CompositionLocalProvider( + LocalLinkButtonStyle provides style.linkButtonStyle, + ) { + action() + } + } +} + +@Composable +private fun ContentAfter( + modifier: Modifier, + style: NoteStyle, + motion: Motion, + contentAfter: @Composable BoxScope.() -> Unit, +) { + val startM by style.dimensions.contentAfterStartMarginValues.getValueAsState(motion.context) + val endM by style.dimensions.contentAfterEndMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding( + start = startM, + end = endM, + ), + ) { + val iconSize by style.dimensions.disclosureSizeValues.getValueAsState(motion.context) + val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize + val disclosureColor = + style.colors.disclosureBrush.getBrushAsState(motion.context, motion.style.contentAfterColor) + CompositionLocalProvider( + LocalTintBrushProducer provides { disclosureColor.value }, + LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), + ) { + contentAfter() + } + } +} + private const val CONTENT_BEFORE = "contentBefore" private const val CONTENT_AFTER = "contentAfter" private const val TITLE = "title" diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompact.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompact.kt index a3fe398fb..96a5b89dd 100644 --- a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompact.kt +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompact.kt @@ -1,6 +1,5 @@ package com.sdds.compose.uikit -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.InteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource @@ -10,10 +9,10 @@ import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds -import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.MeasurePolicy @@ -30,12 +29,19 @@ import androidx.compose.ui.unit.constrainWidth import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.offset import com.sdds.compose.uikit.graphics.LocalIndication -import com.sdds.compose.uikit.graphics.brush.BrushProducer +import com.sdds.compose.uikit.graphics.backgroundBrush import com.sdds.compose.uikit.interactions.MutableSemanticStateSource import com.sdds.compose.uikit.interactions.SemanticStateSource import com.sdds.compose.uikit.interactions.getValue +import com.sdds.compose.uikit.interactions.getValueAsState import com.sdds.compose.uikit.internal.heightOrZero import com.sdds.compose.uikit.internal.widthOrZero +import com.sdds.compose.uikit.motion.Motion +import com.sdds.compose.uikit.motion.components.note.NoteMotionStyle +import com.sdds.compose.uikit.motion.components.note.rememberNoteMotion +import com.sdds.compose.uikit.motion.getBrushAsState +import com.sdds.compose.uikit.motion.getTextStyleAsState +import com.sdds.compose.uikit.motion.rememberMotionContext /** * Компонент [NoteCompact] @@ -50,7 +56,6 @@ import com.sdds.compose.uikit.internal.widthOrZero * @param interactionSource источник взаимодействий * @param action дополнительный контент для взаимодейстивия с компонентом */ -@Suppress("LongMethod") @Composable fun NoteCompact( modifier: Modifier = Modifier, @@ -94,7 +99,6 @@ fun NoteCompact( * @param interactionSource источник взаимодействий * @param action дополнительный контент для взаимодейстивия с компонентом */ -@Suppress("LongMethod") @Composable fun NoteCompact( modifier: Modifier = Modifier, @@ -144,7 +148,6 @@ fun NoteCompact( * @param semanticStateSource источник состояния семантики * @param contentAfter контент за текстовым блоком */ -@Suppress("LongMethod") @Composable fun NoteCompact( titleContent: @Composable () -> Unit, @@ -158,123 +161,130 @@ fun NoteCompact( semanticStateSource: SemanticStateSource = remember { MutableSemanticStateSource() }, contentAfter: (@Composable BoxScope.() -> Unit)? = null, ) { - val iconColor = style.colors.iconColor.colorForInteraction(interactionSource) - val disclosureColor = style.colors.disclosureColor.colorForInteraction(interactionSource) + val fallbackSource = remember { MutableInteractionSource() } + val fallbackSemantic = remember { MutableSemanticStateSource() } + NoteCompact( + motion = rememberNoteMotion( + motionContext = rememberMotionContext( + semanticStateSource = (semanticStateSource as? MutableSemanticStateSource) + ?: fallbackSemantic, + interactionSource = (interactionSource as? MutableInteractionSource) + ?: fallbackSource, + ), + ), + titleContent = titleContent, + modifier = modifier, + style = style, + textContent = textContent, + closeIcon = closeIcon, + contentBefore = contentBefore, + action = action, + contentAfter = contentAfter, + ) +} + +/** + * Компонент [NoteCompact] + * + * Нота оборачивает контент по умолчанию: текстовый блок зажат между [contentBefore] и слотами + * [contentAfter], [action], [closeIcon], которые стоят сразу за текстом. Если ширину задать извне + * (`modifier = Modifier.fillMaxWidth()`), нота растянется, а эти слоты прижмутся к её концу. + * + * @param motion объект анимаций + * @param modifier модификатор + * @param style стиль компонента + * @param titleContent заголовок + * @param textContent текст + * @param closeIcon иконка закрытия + * @param contentBefore контент перед текстовым блоком + * @param action дополнительный контент для взаимодейстивия с компонентом + * @param contentAfter контент за текстовым блоком + */ +@Composable +fun NoteCompact( + motion: Motion, + titleContent: @Composable () -> Unit, + modifier: Modifier = Modifier, + style: NoteCompactStyle = LocalNoteCompactStyle.current, + textContent: (@Composable () -> Unit)? = null, + closeIcon: (@Composable BoxScope.() -> Unit)? = null, + contentBefore: (@Composable BoxScope.() -> Unit)? = null, + action: (@Composable BoxScope.() -> Unit)? = null, + contentAfter: (@Composable BoxScope.() -> Unit)? = null, +) { val contentBeforeArrangement = style.contentBeforeArrangement - val backgroundColor = style.colors.backgroundColor.getValue(interactionSource) - val extraTopPadding = (style.dimensions.paddingBottom - style.dimensions.paddingTop).coerceAtLeast(0.dp) + val backgroundColor = style.colors.backgroundColor.getBrushAsState(motion.context, motion.style.backgroundColor) + val topP by style.dimensions.paddingTopValues.getValueAsState(motion.context) + val bottomP by style.dimensions.paddingBottomValues.getValueAsState(motion.context) + val extraTopPadding = (bottomP - topP).coerceAtLeast(0.dp) val spacerHeight = with(LocalDensity.current) { extraTopPadding.roundToPx() } val measurePolicy = remember(contentBeforeArrangement, spacerHeight) { NoteCompactMeasurePolicy(contentBeforeArrangement, spacerHeight) } + val startP by style.dimensions.paddingStartValues.getValueAsState(motion.context) + val endP by style.dimensions.paddingEndValues.getValueAsState(motion.context) // Нота оборачивает контент и растягивается только тогда, когда ширину требует родитель // (например модификатором fillMaxWidth) Layout( modifier = modifier - .background(backgroundColor, style.shape) + .backgroundBrush( + { backgroundColor.value }, + style.shapes.getValueAsState(motion.context).value, + ) .padding( - start = style.dimensions.paddingStart, - end = style.dimensions.paddingEnd, - top = style.dimensions.paddingTop, - bottom = style.dimensions.paddingBottom, + start = startP, + end = endP, + top = topP, + bottom = bottomP, ) .clipToBounds(), measurePolicy = measurePolicy, content = { - contentBefore?.let { - Box( - modifier = Modifier - .layoutId(CONTENT_BEFORE) - .padding( - end = style.dimensions.contentBeforeEndMargin, - ), - ) { - val iconSize = style.dimensions.iconSize - val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize - CompositionLocalProvider( - LocalTint provides iconColor, - LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), - ) { - contentBefore.invoke(this) - } - } + contentBefore?.let { content -> + ContentBefore( + modifier = Modifier.layoutId(CONTENT_BEFORE), + style = style, + motion = motion, + contentBefore = content, + ) } - Box( + Title( modifier = Modifier.layoutId(TITLE), - ) { - ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { - val textColor = style.colors.titleColor.colorForInteractionAsState( - interactionSource, - semanticStateSource, - ) - ProvideTextStyle(style.titleStyle, color = { textColor.value }) { - titleContent() - } - } - } - if (textContent != null) { - Box( - modifier = Modifier - .layoutId(TEXT) - .padding(top = style.dimensions.textTopMargin), - ) { - ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { - val textColor = style.colors.textColor.colorForInteractionAsState( - interactionSource, - semanticStateSource, - ) - ProvideTextStyle(style.textStyle, color = { textColor.value }) { - textContent() - } - } - } + style = style, + motion = motion, + titleContent = titleContent, + ) + textContent?.let { content -> + ContentText( + modifier = Modifier.layoutId(TEXT), + style = style, + motion = motion, + textContent = content, + ) } - contentAfter?.let { - Box( - modifier = Modifier - .layoutId(CONTENT_AFTER) - .padding(start = style.dimensions.contentAfterStartMargin), - ) { - val iconSize = style.dimensions.disclosureSize - val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize - CompositionLocalProvider( - LocalTint provides disclosureColor, - LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), - ) { - it.invoke(this) - } - } + contentAfter?.let { content -> + ContentAfter( + modifier = Modifier.layoutId(CONTENT_AFTER), + style = style, + motion = motion, + contentAfter = content, + ) } action?.let { - Box( - modifier = Modifier - .layoutId(ACTION) - .padding( - start = style.dimensions.actionStartMargin, - end = style.dimensions.actionEndMargin, - ), - ) { - CompositionLocalProvider( - LocalLinkButtonStyle provides style.linkButtonStyle, - ) { - action.invoke(this) - } - } + Action( + modifier = Modifier.layoutId(ACTION), + style = style, + motion = motion, + action = action, + ) } - if (closeIcon != null) { - val closeSize = style.dimensions.closeSize - Box( - modifier = Modifier - .layoutId(CLOSE) - .padding(start = style.dimensions.closeStartMargin) - .defaultMinSize(), - ) { - CompositionLocalProvider( - LocalIconDefaultSize provides DpSize(closeSize, closeSize), - ) { - closeIcon() - } - } + closeIcon?.let { content -> + CustomCloseIcon( + modifier = Modifier.layoutId(CLOSE), + style = style, + motion = motion, + closeIcon = content, + ) } }, ) @@ -288,7 +298,7 @@ private fun BoxScope.CloseIcon( ) { if (closeIconSource == null) return val closeInteractionSource = remember { MutableInteractionSource() } - val closeColor = style.colors.closeColor.colorForInteraction(closeInteractionSource) + val closeColor = style.colors.closeBrush.getValueAsState(closeInteractionSource) Icon( modifier = Modifier .clickable( @@ -297,7 +307,7 @@ private fun BoxScope.CloseIcon( ) { onClose?.invoke() }, source = closeIconSource, contentDescription = "", - brush = BrushProducer { SolidColor(closeColor) }, + brush = { closeColor.value }, ) } @@ -395,6 +405,150 @@ private class NoteCompactMeasurePolicy( } } +@Composable +private fun ContentBefore( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + contentBefore: @Composable BoxScope.() -> Unit, +) { + val end by style.dimensions.contentBeforeEndMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding( + end = end, + ), + ) { + val iconColor = + style.colors.iconBrush.getBrushAsState(motion.context, motion.style.contentBeforeColor) + val iconSize by style.dimensions.iconSizeValues.getValueAsState(motion.context) + val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize + CompositionLocalProvider( + LocalTintBrushProducer provides { iconColor.value }, + LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), + ) { + contentBefore() + } + } +} + +@Composable +private fun Title( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + titleContent: @Composable () -> Unit, +) { + Box(modifier = modifier) { + ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { + val textColor = style.colors.titleBrush.getBrushAsState(motion.context, motion.style.titleColor) + val titleStyle by style.titleStyles.getTextStyleAsState(motion.context, motion.style.titleStyle) + ProvideTextStyle(titleStyle, brush = { textColor.value }) { + titleContent() + } + } + } +} + +@Composable +private fun ContentText( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + textContent: @Composable () -> Unit, +) { + val textTop by style.dimensions.textTopMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(top = textTop), + ) { + ProvideTextBehaviour(behaviour = TextBehaviour(overflow = TextOverflow.Ellipsis)) { + val textColor = + style.colors.textBrush.getBrushAsState(motion.context, motion.style.textColor) + val textStyle by style.textStyles.getTextStyleAsState( + motion.context, + motion.style.textStyle, + ) + ProvideTextStyle(textStyle, brush = { textColor.value }) { + textContent() + } + } + } +} + +@Composable +private fun Action( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + action: @Composable BoxScope.() -> Unit, +) { + val startM by style.dimensions.actionStartMarginValues.getValueAsState(motion.context) + val endM by style.dimensions.actionEndMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding( + start = startM, + end = endM, + ), + ) { + CompositionLocalProvider( + LocalLinkButtonStyle provides style.linkButtonStyle, + ) { + action() + } + } +} + +@Composable +private fun ContentAfter( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + contentAfter: @Composable BoxScope.() -> Unit, +) { + val startM by style.dimensions.contentAfterStartMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(start = startM), + ) { + val iconSize by style.dimensions.disclosureSizeValues.getValueAsState(motion.context) + val actualIconSize = if (iconSize == 0.dp) Dp.Unspecified else iconSize + val disclosureColor = + style.colors.disclosureBrush.getBrushAsState(motion.context, motion.style.contentAfterColor) + CompositionLocalProvider( + LocalTintBrushProducer provides { disclosureColor.value }, + LocalIconDefaultSize provides DpSize(actualIconSize, actualIconSize), + ) { + contentAfter() + } + } +} + +@Composable +private fun CustomCloseIcon( + modifier: Modifier, + style: NoteCompactStyle, + motion: Motion, + closeIcon: @Composable BoxScope.() -> Unit, +) { + val startP by style.dimensions.closeStartMarginValues.getValueAsState(motion.context) + Box( + modifier = modifier + .padding(start = startP) + .defaultMinSize(), + ) { + val closeSize by style.dimensions.closeSizeValues.getValueAsState(motion.context) + val closeBrush = style.colors.closeBrush.getBrushAsState(motion.context, motion.style.closeColor) + CompositionLocalProvider( + LocalTintBrushProducer provides { closeBrush.value }, + LocalIconDefaultSize provides DpSize(closeSize, closeSize), + ) { + closeIcon() + } + } +} + private const val CONTENT_BEFORE = "contentBefore" private const val CONTENT_AFTER = "contentAfter" private const val TITLE = "title" diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompactStyle.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompactStyle.kt index ec8d2edd4..e0456109c 100644 --- a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompactStyle.kt +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteCompactStyle.kt @@ -14,9 +14,11 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.sdds.api.info.compose.ApiInfo import com.sdds.compose.uikit.annotations.DrawableRes +import com.sdds.compose.uikit.graphics.brush.asStatefulBrush import com.sdds.compose.uikit.interactions.InteractiveColor import com.sdds.compose.uikit.interactions.StatefulValue import com.sdds.compose.uikit.interactions.asInteractive +import com.sdds.compose.uikit.interactions.asStatefulBrush import com.sdds.compose.uikit.interactions.asStatefulValue import com.sdds.compose.uikit.style.Style import com.sdds.compose.uikit.style.StyleBuilder @@ -35,8 +37,14 @@ interface NoteCompactStyle : Style { /** * Форма компонента */ + @Deprecated("Use shapes", replaceWith = ReplaceWith("shapes")) val shape: CornerBasedShape + /** + * Форма компонента + */ + val shapes: StatefulValue + /** * Расположение contentBefore */ @@ -50,13 +58,25 @@ interface NoteCompactStyle : Style { /** * Стиль заголовка */ + @Deprecated("Use titleStyles", replaceWith = ReplaceWith("titleStyles")) val titleStyle: TextStyle + /** + * Стиль заголовка + */ + val titleStyles: StatefulValue + /** * Стиль текста */ + @Deprecated("Use textStyles", replaceWith = ReplaceWith("textStyles")) val textStyle: TextStyle + /** + * Стиль текста + */ + val textStyles: StatefulValue + /** * Ресурс иконки close */ @@ -98,7 +118,13 @@ interface NoteCompactStyleBuilder : StyleBuilder { /** * Устанавливает форму [shape] компонента */ - fun shape(shape: CornerBasedShape): NoteCompactStyleBuilder + fun shape(shape: CornerBasedShape): NoteCompactStyleBuilder = + shape(shape.asStatefulValue()) + + /** + * Устанавливает форму [shape] компонента + */ + fun shape(shape: StatefulValue): NoteCompactStyleBuilder /** * Устанавливает расположение [contentBeforeArrangement] @@ -113,12 +139,24 @@ interface NoteCompactStyleBuilder : StyleBuilder { /** * Устанавливает стиль заголовка [titleStyle] */ - fun titleStyle(titleStyle: TextStyle): NoteCompactStyleBuilder + fun titleStyle(titleStyle: TextStyle): NoteCompactStyleBuilder = + titleStyle(titleStyle.asStatefulValue()) + + /** + * Устанавливает стиль заголовка [titleStyle] + */ + fun titleStyle(titleStyle: StatefulValue): NoteCompactStyleBuilder + + /** + * Устанавливает стиль текста [textStyle] + */ + fun textStyle(textStyle: TextStyle): NoteCompactStyleBuilder = + textStyle(textStyle.asStatefulValue()) /** * Устанавливает стиль текста [textStyle] */ - fun textStyle(textStyle: TextStyle): NoteCompactStyleBuilder + fun textStyle(textStyle: StatefulValue): NoteCompactStyleBuilder /** * Устанавливает источник изображения иконки close [closeIcon] @@ -149,29 +187,38 @@ interface NoteCompactStyleBuilder : StyleBuilder { } private class DefaultNoteCompactStyle( - override val shape: CornerBasedShape, override val contentBeforeArrangement: ContentBeforeVerticalArrangement, - override val titleStyle: TextStyle, - override val textStyle: TextStyle, override val colors: NoteCompactColors, override val dimensions: NoteCompactDimensions, override val linkButtonStyle: ButtonStyle, override val closeIconSource: ImageSource?, + override val shapes: StatefulValue, + override val titleStyles: StatefulValue, + override val textStyles: StatefulValue, ) : NoteCompactStyle { @Deprecated("Use closeIconSource", replaceWith = ReplaceWith("closeIconSource")) override val closeIcon: Int? = null + @Deprecated("Use shapes", replaceWith = ReplaceWith("shapes")) + override val shape: CornerBasedShape = shapes.getDefaultValue() + + @Deprecated("Use titleStyles", replaceWith = ReplaceWith("titleStyles")) + override val titleStyle: TextStyle = titleStyles.getDefaultValue() + + @Deprecated("Use textStyles", replaceWith = ReplaceWith("textStyles")) + override val textStyle: TextStyle = textStyles.getDefaultValue() + class Builder : NoteCompactStyleBuilder { - private var shape: CornerBasedShape? = null + private var shape: StatefulValue? = null private var contentBeforeArrangement: ContentBeforeVerticalArrangement? = null private val colorsBuilder = NoteCompactColors.builder() private val dimensionsBuilder = NoteCompactDimensions.builder() - private var titleStyle: TextStyle? = null - private var textStyle: TextStyle? = null + private var titleStyle: StatefulValue? = null + private var textStyle: StatefulValue? = null private var linkButtonStyle: ButtonStyle? = null private var closeIconSource: ImageSource? = null - override fun shape(shape: CornerBasedShape) = apply { + override fun shape(shape: StatefulValue) = apply { this.shape = shape } @@ -183,11 +230,11 @@ private class DefaultNoteCompactStyle( this.linkButtonStyle = linkButtonStyle } - override fun titleStyle(titleStyle: TextStyle) = apply { + override fun titleStyle(titleStyle: StatefulValue) = apply { this.titleStyle = titleStyle } - override fun textStyle(textStyle: TextStyle) = apply { + override fun textStyle(textStyle: StatefulValue) = apply { this.textStyle = textStyle } @@ -208,12 +255,12 @@ private class DefaultNoteCompactStyle( override fun style(): NoteCompactStyle { return DefaultNoteCompactStyle( - shape = shape ?: RoundedCornerShape(15), + shapes = shape ?: RoundedCornerShape(15).asStatefulValue(), contentBeforeArrangement = contentBeforeArrangement ?: ContentBeforeVerticalArrangement.Top, colors = colorsBuilder.build(), dimensions = dimensionsBuilder.build(), - titleStyle = titleStyle ?: TextStyle.Default, - textStyle = textStyle ?: TextStyle.Default, + titleStyles = titleStyle ?: TextStyle.Default.asStatefulValue(), + textStyles = textStyle ?: TextStyle.Default.asStatefulValue(), linkButtonStyle = linkButtonStyle ?: ButtonStyle.linkButtonBuilder().style(), closeIconSource = closeIconSource, ) @@ -229,23 +276,47 @@ interface NoteCompactColors { /** * Цвет заголовка */ + @Deprecated("Use titleBrush", replaceWith = ReplaceWith("titleBrush")) val titleColor: InteractiveColor + /** + * Цвет заголовка + */ + val titleBrush: StatefulValue + /** * Цвет текста */ + @Deprecated("Use textBrush", replaceWith = ReplaceWith("textBrush")) val textColor: InteractiveColor + /** + * Цвет текста + */ + val textBrush: StatefulValue + /** * Цвет иконки */ + @Deprecated("Use iconBrush", replaceWith = ReplaceWith("iconBrush")) val iconColor: InteractiveColor + /** + * Цвет иконки + */ + val iconBrush: StatefulValue + /** * Цвет иконки disclosure */ + @Deprecated("Use disclosureBrush", replaceWith = ReplaceWith("disclosureBrush")) val disclosureColor: InteractiveColor + /** + * Цвет иконки disclosure + */ + val disclosureBrush: StatefulValue + /** * Цвет фона */ @@ -254,8 +325,14 @@ interface NoteCompactColors { /** * Цвет кнопки закрытия */ + @Deprecated("Use closeBrush", replaceWith = ReplaceWith("closeBrush")) val closeColor: InteractiveColor + /** + * Цвет кнопки закрытия + */ + val closeBrush: StatefulValue + companion object { /** * Возвращает экземпляр [NoteCompactColorsBuilder] @@ -272,46 +349,94 @@ interface NoteCompactColorsBuilder { /** * Устанавливает цвет заголовка [titleColor] */ - fun titleColor(titleColor: InteractiveColor): NoteCompactColorsBuilder + fun titleColor(titleColor: InteractiveColor): NoteCompactColorsBuilder = + titleColor(titleColor.asStatefulBrush()) /** * Устанавливает цвет заголовка [titleColor] */ fun titleColor(titleColor: Color): NoteCompactColorsBuilder = - titleColor(titleColor.asInteractive()) + titleColor(titleColor.asStatefulBrush()) + + /** + * Устанавливает цвет заголовка [titleColor] + */ + fun titleColor(titleColor: Brush): NoteCompactColorsBuilder = + titleColor(titleColor.asStatefulValue()) + + /** + * Устанавливает цвет заголовка [titleColor] + */ + fun titleColor(titleColor: StatefulValue): NoteCompactColorsBuilder /** * Устанавливает цвет текста [textColor] */ - fun textColor(textColor: InteractiveColor): NoteCompactColorsBuilder + fun textColor(textColor: InteractiveColor): NoteCompactColorsBuilder = + textColor(textColor.asStatefulBrush()) /** * Устанавливает цвет текста [textColor] */ fun textColor(textColor: Color): NoteCompactColorsBuilder = - textColor(textColor.asInteractive()) + textColor(textColor.asStatefulBrush()) + + /** + * Устанавливает цвет текста [textColor] + */ + fun textColor(textColor: Brush): NoteCompactColorsBuilder = + textColor(textColor.asStatefulValue()) + + /** + * Устанавливает цвет текста [textColor] + */ + fun textColor(textColor: StatefulValue): NoteCompactColorsBuilder /** * Устанавливает цвет иконки [iconColor] */ - fun iconColor(iconColor: InteractiveColor): NoteCompactColorsBuilder + fun iconColor(iconColor: InteractiveColor): NoteCompactColorsBuilder = + iconColor(iconColor.asStatefulBrush()) /** * Устанавливает цвет иконки [iconColor] */ fun iconColor(iconColor: Color): NoteCompactColorsBuilder = - iconColor(iconColor.asInteractive()) + iconColor(iconColor.asStatefulBrush()) + + /** + * Устанавливает цвет иконки [iconColor] + */ + fun iconColor(iconColor: Brush): NoteCompactColorsBuilder = + iconColor(iconColor.asStatefulValue()) + + /** + * Устанавливает цвет иконки [iconColor] + */ + fun iconColor(iconColor: StatefulValue): NoteCompactColorsBuilder /** * Устанавливает цвет иконки disclosure [disclosureColor] */ - fun disclosureColor(disclosureColor: InteractiveColor): NoteCompactColorsBuilder + fun disclosureColor(disclosureColor: InteractiveColor): NoteCompactColorsBuilder = + disclosureColor(disclosureColor.asStatefulBrush()) /** * Устанавливает цвет иконки disclosure[disclosureColor] */ fun disclosureColor(disclosureColor: Color): NoteCompactColorsBuilder = - disclosureColor(disclosureColor.asInteractive()) + disclosureColor(disclosureColor.asStatefulBrush()) + + /** + * Устанавливает цвет иконки disclosure [disclosureColor] + */ + fun disclosureColor(disclosureColor: Brush): NoteCompactColorsBuilder = + disclosureColor(disclosureColor.asStatefulValue()) + + /** + * Устанавливает цвет иконки disclosure [disclosureColor] + */ + fun disclosureColor(disclosureColor: StatefulValue): NoteCompactColorsBuilder /** * Устанавливает фон [backgroundColor] компонента. @@ -328,12 +453,24 @@ interface NoteCompactColorsBuilder { * Устанавливает цвет кнопки закрытия [closeColor]. */ fun closeColor(closeColor: Color): NoteCompactColorsBuilder = - closeColor(closeColor.asInteractive()) + closeColor(closeColor.asStatefulBrush()) + + /** + * Устанавливает цвет кнопки закрытия [closeColor]. + */ + fun closeColor(closeColor: InteractiveColor): NoteCompactColorsBuilder = + closeColor(closeColor.asStatefulBrush()) /** * Устанавливает цвет кнопки закрытия [closeColor]. */ - fun closeColor(closeColor: InteractiveColor): NoteCompactColorsBuilder + fun closeColor(closeColor: Brush): NoteCompactColorsBuilder = + closeColor(closeColor.asStatefulValue()) + + /** + * Устанавливает цвет кнопки закрытия [closeColor]. + */ + fun closeColor(closeColor: StatefulValue): NoteCompactColorsBuilder /** * Вернёт [NoteCompactColors] @@ -344,34 +481,49 @@ interface NoteCompactColorsBuilder { @Immutable private data class DefaultNoteCompactColors( override val backgroundColor: StatefulValue, - override val closeColor: InteractiveColor, - override val titleColor: InteractiveColor, - override val textColor: InteractiveColor, - override val iconColor: InteractiveColor, - override val disclosureColor: InteractiveColor, + override val closeBrush: StatefulValue, + override val titleBrush: StatefulValue, + override val textBrush: StatefulValue, + override val iconBrush: StatefulValue, + override val disclosureBrush: StatefulValue, ) : NoteCompactColors { + @Deprecated("Use closeBrush", replaceWith = ReplaceWith("closeBrush")) + override val closeColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use titleBrush", replaceWith = ReplaceWith("titleBrush")) + override val titleColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use textBrush", replaceWith = ReplaceWith("textBrush")) + override val textColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use iconBrush", replaceWith = ReplaceWith("iconBrush")) + override val iconColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use disclosureBrush", replaceWith = ReplaceWith("disclosureBrush")) + override val disclosureColor: InteractiveColor = Color.Transparent.asInteractive() + class Builder : NoteCompactColorsBuilder { private var backgroundColor: StatefulValue? = null - private var closeColor: InteractiveColor? = null - private var titleColor: InteractiveColor? = null - private var textColor: InteractiveColor? = null - private var iconColor: InteractiveColor? = null - private var disclosureColor: InteractiveColor? = null + private var closeColor: StatefulValue? = null + private var titleColor: StatefulValue? = null + private var textColor: StatefulValue? = null + private var iconColor: StatefulValue? = null + private var disclosureColor: StatefulValue? = null - override fun titleColor(titleColor: InteractiveColor): NoteCompactColorsBuilder = apply { + override fun titleColor(titleColor: StatefulValue): NoteCompactColorsBuilder = apply { this.titleColor = titleColor } - override fun textColor(textColor: InteractiveColor): NoteCompactColorsBuilder = apply { + override fun textColor(textColor: StatefulValue): NoteCompactColorsBuilder = apply { this.textColor = textColor } - override fun iconColor(iconColor: InteractiveColor): NoteCompactColorsBuilder = apply { + override fun iconColor(iconColor: StatefulValue): NoteCompactColorsBuilder = apply { this.iconColor = iconColor } - override fun disclosureColor(disclosureColor: InteractiveColor): NoteCompactColorsBuilder = apply { + override fun disclosureColor(disclosureColor: StatefulValue): NoteCompactColorsBuilder = apply { this.disclosureColor = disclosureColor } @@ -379,18 +531,18 @@ private data class DefaultNoteCompactColors( this.backgroundColor = backgroundColor } - override fun closeColor(closeColor: InteractiveColor) = apply { + override fun closeColor(closeColor: StatefulValue) = apply { this.closeColor = closeColor } override fun build(): NoteCompactColors { return DefaultNoteCompactColors( backgroundColor = backgroundColor ?: SolidColor(Color.White).asStatefulValue(), - closeColor = closeColor ?: Color.LightGray.asInteractive(), - titleColor = titleColor ?: Color.Black.asInteractive(), - textColor = textColor ?: Color.DarkGray.asInteractive(), - iconColor = iconColor ?: Color.DarkGray.asInteractive(), - disclosureColor = disclosureColor ?: Color.DarkGray.asInteractive(), + closeBrush = closeColor ?: Color.LightGray.asStatefulBrush(), + titleBrush = titleColor ?: Color.Black.asStatefulBrush(), + textBrush = textColor ?: Color.DarkGray.asStatefulBrush(), + iconBrush = iconColor ?: Color.DarkGray.asStatefulBrush(), + disclosureBrush = disclosureColor ?: Color.DarkGray.asStatefulBrush(), ) } } @@ -404,68 +556,161 @@ interface NoteCompactDimensions { /** * Размер иконки close */ + @Deprecated("Use closeSizeValues", replaceWith = ReplaceWith("closeSizeValues")) val closeSize: Dp + /** + * Размер иконки close + */ + val closeSizeValues: StatefulValue + /** * Размер иконки для contentBefore */ + @Deprecated("Use iconSizeValues", replaceWith = ReplaceWith("iconSizeValues")) val iconSize: Dp + /** + * Размер иконки для contentBefore + */ + val iconSizeValues: StatefulValue + /** * Размер иконки для contentAfter */ + @Deprecated("Use disclosureSizeValues", replaceWith = ReplaceWith("disclosureSizeValues")) val disclosureSize: Dp /** - * Отступ вначале иконки close + * Размер иконки для contentAfter */ + val disclosureSizeValues: StatefulValue + + /** + * Отступ иконки close от верхнего края компонента + */ + @Deprecated("Use closeTopMarginValues", replaceWith = ReplaceWith("closeTopMarginValues")) val closeStartMargin: Dp + /** + * Отступ иконки close от верхнего края компонента + */ + val closeStartMarginValues: StatefulValue + /** * Отступ вконце contentBefore */ + @Deprecated( + "Use contentBeforeEndMarginValues", + replaceWith = ReplaceWith("contentBeforeEndMarginValues"), + ) val contentBeforeEndMargin: Dp /** - * Отступ вначале contentAfter + * Отступ вконце contentBefore + */ + val contentBeforeEndMarginValues: StatefulValue + + /** + * Отступ вначле contentAfter */ + @Deprecated( + "Use contentAfterStartMarginValues", + replaceWith = ReplaceWith("contentAfterStartMarginValues"), + ) val contentAfterStartMargin: Dp + /** + * Отступ вначле contentAfter + */ + val contentAfterStartMarginValues: StatefulValue + /** * Отступ между text и title */ + @Deprecated( + "Use textTopMarginValues", + replaceWith = ReplaceWith("textTopMarginValues"), + ) val textTopMargin: Dp /** - * Отступ между блоком, содержащим title с text, и action + * Отступ между text и title + */ + val textTopMarginValues: StatefulValue + + /** + * Отступ между text и action */ + @Deprecated( + "Use actionTopMarginValues", + replaceWith = ReplaceWith("actionTopMarginValues"), + ) val actionStartMargin: Dp /** - * Отступ между action и close + * Отступ между text и action */ + val actionStartMarginValues: StatefulValue + + /** + * Отступ между text и action + */ + @Deprecated( + "Use actionTopMarginValues", + replaceWith = ReplaceWith("actionTopMarginValues"), + ) val actionEndMargin: Dp + /** + * Отступ между text и action + */ + val actionEndMarginValues: StatefulValue + /** * Отступ контента в начале */ + @Deprecated("Use paddingStartValues", replaceWith = ReplaceWith("paddingStartValues")) val paddingStart: Dp + /** + * Отступ контента в начале + */ + val paddingStartValues: StatefulValue + /** * Отступ контента в конце */ + @Deprecated("Use paddingEndValues", replaceWith = ReplaceWith("paddingEndValues")) val paddingEnd: Dp + /** + * Отступ контента в конце + */ + val paddingEndValues: StatefulValue + /** * Отступ контента сверху */ + @Deprecated("Use paddingTopValues", replaceWith = ReplaceWith("paddingTopValues")) val paddingTop: Dp + /** + * Отступ контента сверху + */ + val paddingTopValues: StatefulValue + /** * Отступ контента снизу */ + @Deprecated("Use paddingBottomValues", replaceWith = ReplaceWith("paddingBottomValues")) val paddingBottom: Dp + /** + * Отступ контента снизу + */ + val paddingBottomValues: StatefulValue + companion object { /** * Возвращает экземпляр [NoteCompactDimensionsBuilder] @@ -482,67 +727,145 @@ interface NoteCompactDimensionsBuilder { /** * Устанавливает размер иконки close [closeSize] */ - fun closeSize(closeSize: Dp): NoteCompactDimensionsBuilder + fun closeSize(closeSize: Dp): NoteCompactDimensionsBuilder = + closeSize(closeSize.asStatefulValue()) + + /** + * Устанавливает размер иконки close [closeSize] + */ + fun closeSize(closeSize: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает размер иконки для contentBefore [iconSize] + */ + fun iconSize(iconSize: Dp): NoteCompactDimensionsBuilder = + iconSize(iconSize.asStatefulValue()) /** * Устанавливает размер иконки для contentBefore [iconSize] */ - fun iconSize(iconSize: Dp): NoteCompactDimensionsBuilder + fun iconSize(iconSize: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает размер иконки для contentAfter [disclosureSize] */ - fun disclosureSize(disclosureSize: Dp): NoteCompactDimensionsBuilder + fun disclosureSize(disclosureSize: Dp): NoteCompactDimensionsBuilder = + disclosureSize(disclosureSize.asStatefulValue()) + + /** + * Устанавливает размер иконки для contentAfter [disclosureSize] + */ + fun disclosureSize(disclosureSize: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает отступ в начале иконки закрытия [closeStartMargin] */ - fun closeStartMargin(closeStartMargin: Dp): NoteCompactDimensionsBuilder + fun closeStartMargin(closeStartMargin: Dp): NoteCompactDimensionsBuilder = + closeStartMargin(closeStartMargin.asStatefulValue()) + + /** + * Устанавливает отступ в начале иконки закрытия [closeStartMargin] + */ + fun closeStartMargin(closeStartMargin: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает отступ вконце contentBefore [contentBeforeEndMargin] */ - fun contentBeforeEndMargin(contentBeforeEndMargin: Dp): NoteCompactDimensionsBuilder + fun contentBeforeEndMargin(contentBeforeEndMargin: Dp): NoteCompactDimensionsBuilder = + contentBeforeEndMargin(contentBeforeEndMargin.asStatefulValue()) + + /** + * Устанавливает отступ вконце contentBefore [contentBeforeEndMargin] + */ + fun contentBeforeEndMargin(contentBeforeEndMargin: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает отступ вначале contentAfter [contentAfterStartMargin] + */ + fun contentAfterStartMargin(contentAfterStartMargin: Dp): NoteCompactDimensionsBuilder = + contentAfterStartMargin(contentAfterStartMargin.asStatefulValue()) /** * Устанавливает отступ вначале contentAfter [contentAfterStartMargin] */ - fun contentAfterStartMargin(contentAfterStartMargin: Dp): NoteCompactDimensionsBuilder + fun contentAfterStartMargin(contentAfterStartMargin: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает отступ между text и title [textTopMargin] + */ + fun textTopMargin(textTopMargin: Dp): NoteCompactDimensionsBuilder = + textTopMargin(textTopMargin.asStatefulValue()) /** * Устанавливает отступ между text и title [textTopMargin] */ - fun textTopMargin(textTopMargin: Dp): NoteCompactDimensionsBuilder + fun textTopMargin(textTopMargin: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает отступ между блоком, содержащим title с text, и action [actionStartMargin] */ - fun actionStartMargin(actionStartMargin: Dp): NoteCompactDimensionsBuilder + fun actionStartMargin(actionStartMargin: Dp): NoteCompactDimensionsBuilder = + actionStartMargin(actionStartMargin.asStatefulValue()) + + /** + * Устанавливает отступ между блоком, содержащим title с text, и action [actionStartMargin] + */ + fun actionStartMargin(actionStartMargin: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает отступ между action и close [actionEndMargin] */ - fun actionEndMargin(actionEndMargin: Dp): NoteCompactDimensionsBuilder + fun actionEndMargin(actionEndMargin: Dp): NoteCompactDimensionsBuilder = + actionEndMargin(actionEndMargin.asStatefulValue()) + + /** + * Устанавливает отступ между action и close [actionEndMargin] + */ + fun actionEndMargin(actionEndMargin: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает отступ в начале [paddingStart] + */ + fun paddingStart(paddingStart: Dp): NoteCompactDimensionsBuilder = + paddingStart(paddingStart.asStatefulValue()) /** * Устанавливает отступ в начале [paddingStart] */ - fun paddingStart(paddingStart: Dp): NoteCompactDimensionsBuilder + fun paddingStart(paddingStart: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает отступ в конце [paddingEnd] + */ + fun paddingEnd(paddingEnd: Dp): NoteCompactDimensionsBuilder = + paddingEnd(paddingEnd.asStatefulValue()) /** * Устанавливает отступ в конце [paddingEnd] */ - fun paddingEnd(paddingEnd: Dp): NoteCompactDimensionsBuilder + fun paddingEnd(paddingEnd: StatefulValue): NoteCompactDimensionsBuilder + + /** + * Устанавливает отступ сверху [paddingTop] + */ + fun paddingTop(paddingTop: Dp): NoteCompactDimensionsBuilder = + paddingTop(paddingTop.asStatefulValue()) /** * Устанавливает отступ сверху [paddingTop] */ - fun paddingTop(paddingTop: Dp): NoteCompactDimensionsBuilder + fun paddingTop(paddingTop: StatefulValue): NoteCompactDimensionsBuilder /** * Устанавливает отступ снизу [paddingBottom] */ - fun paddingBottom(paddingBottom: Dp): NoteCompactDimensionsBuilder + fun paddingBottom(paddingBottom: Dp): NoteCompactDimensionsBuilder = + paddingBottom(paddingBottom.asStatefulValue()) + + /** + * Устанавливает отступ снизу [paddingBottom] + */ + fun paddingBottom(paddingBottom: StatefulValue): NoteCompactDimensionsBuilder /** * Создает экземпляр [NoteCompactDimensions] @@ -551,104 +874,148 @@ interface NoteCompactDimensionsBuilder { } private class DefaultNoteCompactDimensions( - override val paddingStart: Dp, - override val paddingEnd: Dp, - override val paddingTop: Dp, - override val paddingBottom: Dp, - override val closeSize: Dp, - override val iconSize: Dp, - override val textTopMargin: Dp, - override val actionStartMargin: Dp, - override val closeStartMargin: Dp, - override val contentBeforeEndMargin: Dp, - override val actionEndMargin: Dp, - override val disclosureSize: Dp, - override val contentAfterStartMargin: Dp, + override val paddingStartValues: StatefulValue, + override val paddingEndValues: StatefulValue, + override val paddingTopValues: StatefulValue, + override val paddingBottomValues: StatefulValue, + override val closeSizeValues: StatefulValue, + override val iconSizeValues: StatefulValue, + override val textTopMarginValues: StatefulValue, + override val actionStartMarginValues: StatefulValue, + override val closeStartMarginValues: StatefulValue, + override val contentBeforeEndMarginValues: StatefulValue, + override val actionEndMarginValues: StatefulValue, + override val disclosureSizeValues: StatefulValue, + override val contentAfterStartMarginValues: StatefulValue, + ) : NoteCompactDimensions { + @Deprecated("Use paddingStartValues", replaceWith = ReplaceWith("paddingStartValues")) + override val paddingStart: Dp = paddingStartValues.getDefaultValue() + + @Deprecated("Use paddingEndValues", replaceWith = ReplaceWith("paddingEndValues")) + override val paddingEnd: Dp = paddingEndValues.getDefaultValue() + + @Deprecated("Use paddingTopValues", replaceWith = ReplaceWith("paddingTopValues")) + override val paddingTop: Dp = paddingTopValues.getDefaultValue() + @Deprecated("Use paddingBottomValues", replaceWith = ReplaceWith("paddingBottomValues")) + override val paddingBottom: Dp = paddingBottomValues.getDefaultValue() + + @Deprecated("Use closeSizeValues", replaceWith = ReplaceWith("closeSizeValues")) + override val closeSize: Dp = closeSizeValues.getDefaultValue() + + @Deprecated("Use iconSizeValues", replaceWith = ReplaceWith("iconSizeValues")) + override val iconSize: Dp = iconSizeValues.getDefaultValue() + + @Deprecated("Use textTopMarginValues", replaceWith = ReplaceWith("textTopMarginValues")) + override val textTopMargin: Dp = textTopMarginValues.getDefaultValue() + + @Deprecated("Use actionStartMarginValues", replaceWith = ReplaceWith("actionStartMarginValues")) + override val actionStartMargin: Dp = actionStartMarginValues.getDefaultValue() + + @Deprecated("Use closeStartMarginValues", replaceWith = ReplaceWith("closeStartMarginValues")) + override val closeStartMargin: Dp = closeStartMarginValues.getDefaultValue() + + @Deprecated( + "Use contentBeforeEndMarginValues", + replaceWith = ReplaceWith("contentBeforeEndMarginValues"), + ) + override val contentBeforeEndMargin: Dp = contentBeforeEndMarginValues.getDefaultValue() + + @Deprecated("Use actionEndMarginValues", replaceWith = ReplaceWith("actionEndMarginValues")) + override val actionEndMargin: Dp = actionEndMarginValues.getDefaultValue() + + @Deprecated("Use disclosureSizeValues", replaceWith = ReplaceWith("disclosureSizeValues")) + override val disclosureSize: Dp = disclosureSizeValues.getDefaultValue() + + @Deprecated( + "Use contentAfterStartMarginValues", + replaceWith = ReplaceWith("contentAfterStartMarginValues"), + ) + override val contentAfterStartMargin: Dp = contentAfterStartMarginValues.getDefaultValue() class Builder : NoteCompactDimensionsBuilder { - private var closeSize: Dp? = null - private var iconSize: Dp? = null - private var disclosureSize: Dp? = null - private var closeStartMargin: Dp? = null - private var contentBeforeEndMargin: Dp? = null - private var contentAfterStartMargin: Dp? = null - private var paddingStart: Dp? = null - private var paddingEnd: Dp? = null - private var paddingTop: Dp? = null - private var paddingBottom: Dp? = null - private var textTopMargin: Dp? = null - private var actionStartMargin: Dp? = null - private var actionEndMargin: Dp? = null - - override fun closeSize(closeSize: Dp) = apply { + private var closeSize: StatefulValue? = null + private var iconSize: StatefulValue? = null + private var disclosureSize: StatefulValue? = null + private var closeStartMargin: StatefulValue? = null + private var contentBeforeEndMargin: StatefulValue? = null + private var contentAfterStartMargin: StatefulValue? = null + private var paddingStart: StatefulValue? = null + private var paddingEnd: StatefulValue? = null + private var paddingTop: StatefulValue? = null + private var paddingBottom: StatefulValue? = null + private var textTopMargin: StatefulValue? = null + private var actionStartMargin: StatefulValue? = null + private var actionEndMargin: StatefulValue? = null + + override fun closeSize(closeSize: StatefulValue) = apply { this.closeSize = closeSize } - override fun iconSize(iconSize: Dp) = apply { + override fun iconSize(iconSize: StatefulValue) = apply { this.iconSize = iconSize } - override fun disclosureSize(disclosureSize: Dp) = apply { + override fun disclosureSize(disclosureSize: StatefulValue) = apply { this.disclosureSize = disclosureSize } - override fun closeStartMargin(closeStartMargin: Dp) = apply { + override fun closeStartMargin(closeStartMargin: StatefulValue) = apply { this.closeStartMargin = closeStartMargin } - override fun contentBeforeEndMargin(contentBeforeEndMargin: Dp) = apply { + override fun contentBeforeEndMargin(contentBeforeEndMargin: StatefulValue) = apply { this.contentBeforeEndMargin = contentBeforeEndMargin } - override fun contentAfterStartMargin(contentAfterStartMargin: Dp) = apply { + override fun contentAfterStartMargin(contentAfterStartMargin: StatefulValue) = apply { this.contentAfterStartMargin = contentAfterStartMargin } - override fun textTopMargin(textTopMargin: Dp) = apply { + override fun textTopMargin(textTopMargin: StatefulValue) = apply { this.textTopMargin = textTopMargin } - override fun actionStartMargin(actionStartMargin: Dp) = apply { + override fun actionStartMargin(actionStartMargin: StatefulValue) = apply { this.actionStartMargin = actionStartMargin } - override fun actionEndMargin(actionEndMargin: Dp) = apply { + override fun actionEndMargin(actionEndMargin: StatefulValue) = apply { this.actionEndMargin = actionEndMargin } - override fun paddingStart(paddingStart: Dp) = apply { + override fun paddingStart(paddingStart: StatefulValue) = apply { this.paddingStart = paddingStart } - override fun paddingEnd(paddingEnd: Dp) = apply { + override fun paddingEnd(paddingEnd: StatefulValue) = apply { this.paddingEnd = paddingEnd } - override fun paddingTop(paddingTop: Dp) = apply { + override fun paddingTop(paddingTop: StatefulValue) = apply { this.paddingTop = paddingTop } - override fun paddingBottom(paddingBottom: Dp) = apply { + override fun paddingBottom(paddingBottom: StatefulValue) = apply { this.paddingBottom = paddingBottom } override fun build(): NoteCompactDimensions { return DefaultNoteCompactDimensions( - paddingStart = paddingStart ?: 0.dp, - paddingEnd = paddingEnd ?: 0.dp, - paddingTop = paddingTop ?: 0.dp, - paddingBottom = paddingBottom ?: 0.dp, - closeSize = closeSize ?: 24.dp, - iconSize = iconSize ?: Dp.Unspecified, - disclosureSize = disclosureSize ?: Dp.Unspecified, - closeStartMargin = closeStartMargin ?: 0.dp, - contentBeforeEndMargin = contentBeforeEndMargin ?: 0.dp, - contentAfterStartMargin = contentAfterStartMargin ?: 0.dp, - textTopMargin = textTopMargin ?: 0.dp, - actionStartMargin = actionStartMargin ?: 0.dp, - actionEndMargin = actionEndMargin ?: 0.dp, + paddingStartValues = paddingStart ?: 0.dp.asStatefulValue(), + paddingEndValues = paddingEnd ?: 0.dp.asStatefulValue(), + paddingTopValues = paddingTop ?: 0.dp.asStatefulValue(), + paddingBottomValues = paddingBottom ?: 0.dp.asStatefulValue(), + closeSizeValues = closeSize ?: 24.dp.asStatefulValue(), + iconSizeValues = iconSize ?: Dp.Unspecified.asStatefulValue(), + disclosureSizeValues = disclosureSize ?: Dp.Unspecified.asStatefulValue(), + closeStartMarginValues = closeStartMargin ?: 0.dp.asStatefulValue(), + contentBeforeEndMarginValues = contentBeforeEndMargin ?: 0.dp.asStatefulValue(), + contentAfterStartMarginValues = contentAfterStartMargin ?: 0.dp.asStatefulValue(), + textTopMarginValues = textTopMargin ?: 0.dp.asStatefulValue(), + actionStartMarginValues = actionStartMargin ?: 0.dp.asStatefulValue(), + actionEndMarginValues = actionEndMargin ?: 0.dp.asStatefulValue(), ) } } diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteStyle.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteStyle.kt index 9626de81e..1aec7c852 100644 --- a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteStyle.kt +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/NoteStyle.kt @@ -8,15 +8,16 @@ import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.structuralEqualityPolicy import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.sdds.api.info.compose.ApiInfo import com.sdds.compose.uikit.annotations.DrawableRes +import com.sdds.compose.uikit.graphics.brush.asStatefulBrush import com.sdds.compose.uikit.interactions.InteractiveColor import com.sdds.compose.uikit.interactions.StatefulValue import com.sdds.compose.uikit.interactions.asInteractive +import com.sdds.compose.uikit.interactions.asStatefulBrush import com.sdds.compose.uikit.interactions.asStatefulValue import com.sdds.compose.uikit.style.Style import com.sdds.compose.uikit.style.StyleBuilder @@ -35,8 +36,14 @@ interface NoteStyle : Style { /** * Форма компонента */ + @Deprecated("Use shapes", replaceWith = ReplaceWith("shapes")) val shape: CornerBasedShape + /** + * Форма компонента + */ + val shapes: StatefulValue + /** * Расположение contentBefore */ @@ -50,13 +57,25 @@ interface NoteStyle : Style { /** * Стиль заголовка */ + @Deprecated("Use titleStyles", replaceWith = ReplaceWith("titleStyles")) val titleStyle: TextStyle + /** + * Стиль заголовка + */ + val titleStyles: StatefulValue + /** * Стиль текста */ + @Deprecated("Use textStyles", replaceWith = ReplaceWith("textStyles")) val textStyle: TextStyle + /** + * Стиль текста + */ + val textStyles: StatefulValue + /** * Ресурс иконки close */ @@ -98,7 +117,13 @@ interface NoteStyleBuilder : StyleBuilder { /** * Устанавливает форму [shape] компонента */ - fun shape(shape: CornerBasedShape): NoteStyleBuilder + fun shape(shape: CornerBasedShape): NoteStyleBuilder = + shape(shape.asStatefulValue()) + + /** + * Устанавливает форму [shape] компонента + */ + fun shape(shape: StatefulValue): NoteStyleBuilder /** * Устанавливает расположение [contentBeforeArrangement] @@ -113,12 +138,24 @@ interface NoteStyleBuilder : StyleBuilder { /** * Устанавливает стиль заголовка [titleStyle] */ - fun titleStyle(titleStyle: TextStyle): NoteStyleBuilder + fun titleStyle(titleStyle: TextStyle): NoteStyleBuilder = + titleStyle(titleStyle.asStatefulValue()) + + /** + * Устанавливает стиль заголовка [titleStyle] + */ + fun titleStyle(titleStyle: StatefulValue): NoteStyleBuilder + + /** + * Устанавливает стиль текста [textStyle] + */ + fun textStyle(textStyle: TextStyle): NoteStyleBuilder = + textStyle(textStyle.asStatefulValue()) /** * Устанавливает стиль текста [textStyle] */ - fun textStyle(textStyle: TextStyle): NoteStyleBuilder + fun textStyle(textStyle: StatefulValue): NoteStyleBuilder /** * Устанавливает источник изображения иконки close [closeIcon] @@ -149,10 +186,10 @@ interface NoteStyleBuilder : StyleBuilder { } private class DefaultNoteStyle( - override val shape: CornerBasedShape, + override val shapes: StatefulValue, override val contentBeforeArrangement: ContentBeforeVerticalArrangement, - override val titleStyle: TextStyle, - override val textStyle: TextStyle, + override val titleStyles: StatefulValue, + override val textStyles: StatefulValue, override val colors: NoteColors, override val dimensions: NoteDimensions, override val linkButtonStyle: ButtonStyle, @@ -161,17 +198,26 @@ private class DefaultNoteStyle( @Deprecated("Use closeIconSource", replaceWith = ReplaceWith("closeIconSource")) override val closeIcon: Int? = null + @Deprecated("Use shapes", replaceWith = ReplaceWith("shapes")) + override val shape: CornerBasedShape = shapes.getDefaultValue() + + @Deprecated("Use titleStyles", replaceWith = ReplaceWith("titleStyles")) + override val titleStyle: TextStyle = titleStyles.getDefaultValue() + + @Deprecated("Use textStyles", replaceWith = ReplaceWith("textStyles")) + override val textStyle: TextStyle = textStyles.getDefaultValue() + class Builder : NoteStyleBuilder { - private var shape: CornerBasedShape? = null + private var shape: StatefulValue? = null private var contentBeforeArrangement: ContentBeforeVerticalArrangement? = null private val colorsBuilder = NoteColors.builder() private val dimensionsBuilder = NoteDimensions.builder() - private var titleStyle: TextStyle? = null - private var textStyle: TextStyle? = null + private var titleStyle: StatefulValue? = null + private var textStyle: StatefulValue? = null private var linkButtonStyle: ButtonStyle? = null private var closeIconSource: ImageSource? = null - override fun shape(shape: CornerBasedShape) = apply { + override fun shape(shape: StatefulValue) = apply { this.shape = shape } @@ -183,11 +229,11 @@ private class DefaultNoteStyle( this.linkButtonStyle = linkButtonStyle } - override fun titleStyle(titleStyle: TextStyle) = apply { + override fun titleStyle(titleStyle: StatefulValue) = apply { this.titleStyle = titleStyle } - override fun textStyle(textStyle: TextStyle) = apply { + override fun textStyle(textStyle: StatefulValue) = apply { this.textStyle = textStyle } @@ -208,12 +254,12 @@ private class DefaultNoteStyle( override fun style(): NoteStyle { return DefaultNoteStyle( - shape = shape ?: RoundedCornerShape(15), + shapes = shape ?: RoundedCornerShape(15).asStatefulValue(), contentBeforeArrangement = contentBeforeArrangement ?: ContentBeforeVerticalArrangement.Top, colors = colorsBuilder.build(), dimensions = dimensionsBuilder.build(), - titleStyle = titleStyle ?: TextStyle.Default, - textStyle = textStyle ?: TextStyle.Default, + titleStyles = titleStyle ?: TextStyle.Default.asStatefulValue(), + textStyles = textStyle ?: TextStyle.Default.asStatefulValue(), linkButtonStyle = linkButtonStyle ?: ButtonStyle.linkButtonBuilder().style(), closeIconSource = closeIconSource, ) @@ -229,23 +275,47 @@ interface NoteColors { /** * Цвет заголовка */ + @Deprecated("Use titleBrush", replaceWith = ReplaceWith("titleBrush")) val titleColor: InteractiveColor + /** + * Цвет заголовка + */ + val titleBrush: StatefulValue + /** * Цвет текста */ + @Deprecated("Use textBrush", replaceWith = ReplaceWith("textBrush")) val textColor: InteractiveColor + /** + * Цвет текста + */ + val textBrush: StatefulValue + /** * Цвет иконки */ + @Deprecated("Use iconBrush", replaceWith = ReplaceWith("iconBrush")) val iconColor: InteractiveColor + /** + * Цвет иконки + */ + val iconBrush: StatefulValue + /** * Цвет иконки disclosure */ + @Deprecated("Use disclosureBrush", replaceWith = ReplaceWith("disclosureBrush")) val disclosureColor: InteractiveColor + /** + * Цвет иконки disclosure + */ + val disclosureBrush: StatefulValue + /** * Цвет фона */ @@ -254,8 +324,14 @@ interface NoteColors { /** * Цвет кнопки закрытия */ + @Deprecated("Use closeBrush", replaceWith = ReplaceWith("closeBrush")) val closeColor: InteractiveColor + /** + * Цвет кнопки закрытия + */ + val closeBrush: StatefulValue + companion object { /** * Возвращает экземпляр [NoteColorsBuilder] @@ -272,46 +348,106 @@ interface NoteColorsBuilder { /** * Устанавливает цвет заголовка [titleColor] */ - fun titleColor(titleColor: InteractiveColor): NoteColorsBuilder + fun titleColor(titleColor: InteractiveColor): NoteColorsBuilder = + titleColor(titleColor.asStatefulBrush()) /** * Устанавливает цвет заголовка [titleColor] */ fun titleColor(titleColor: Color): NoteColorsBuilder = - titleColor(titleColor.asInteractive()) + titleColor(titleColor.asStatefulBrush()) + + /** + * Устанавливает цвет заголовка [titleColor] + */ + fun titleColor(titleColor: Brush): NoteColorsBuilder = + titleColor(titleColor.asStatefulValue()) + + /** + * Устанавливает цвет заголовка [titleColor] + */ + fun titleColor(titleColor: StatefulValue): NoteColorsBuilder /** * Устанавливает цвет текста [textColor] */ - fun textColor(textColor: InteractiveColor): NoteColorsBuilder + fun textColor(textColor: InteractiveColor): NoteColorsBuilder = + textColor(textColor.asStatefulBrush()) /** * Устанавливает цвет текста [textColor] */ fun textColor(textColor: Color): NoteColorsBuilder = - textColor(textColor.asInteractive()) + textColor(textColor.asStatefulBrush()) + + /** + * Устанавливает цвет текста [textColor] + */ + fun textColor(textColor: Brush): NoteColorsBuilder = + textColor(textColor.asStatefulValue()) + + /** + * Устанавливает цвет текста [textColor] + */ + fun textColor(textColor: StatefulValue): NoteColorsBuilder /** * Устанавливает цвет иконки disclosure [disclosureColor] */ - fun disclosureColor(disclosureColor: InteractiveColor): NoteColorsBuilder + fun disclosureColor(disclosureColor: InteractiveColor): NoteColorsBuilder = + disclosureColor(disclosureColor.asStatefulBrush()) /** * Устанавливает цвет иконки disclosure[disclosureColor] */ fun disclosureColor(disclosureColor: Color): NoteColorsBuilder = - disclosureColor(disclosureColor.asInteractive()) + disclosureColor(disclosureColor.asStatefulBrush()) + + /** + * Устанавливает цвет иконки disclosure [disclosureColor] + */ + fun disclosureColor(disclosureColor: Brush): NoteColorsBuilder = + disclosureColor(disclosureColor.asStatefulValue()) + + /** + * Устанавливает цвет иконки disclosure [disclosureColor] + */ + fun disclosureColor(disclosureColor: StatefulValue): NoteColorsBuilder /** * Устанавливает цвет иконки [iconColor] */ - fun iconColor(iconColor: InteractiveColor): NoteColorsBuilder + fun iconColor(iconColor: InteractiveColor): NoteColorsBuilder = + iconColor(iconColor.asStatefulBrush()) /** * Устанавливает цвет иконки [iconColor] */ fun iconColor(iconColor: Color): NoteColorsBuilder = - iconColor(iconColor.asInteractive()) + iconColor(iconColor.asStatefulBrush()) + + /** + * Устанавливает цвет иконки [iconColor] + */ + fun iconColor(iconColor: Brush): NoteColorsBuilder = + iconColor(iconColor.asStatefulValue()) + + /** + * Устанавливает цвет иконки [iconColor] + */ + fun iconColor(iconColor: StatefulValue): NoteColorsBuilder + + /** + * Устанавливает фон [backgroundColor] компонента. + */ + fun backgroundColor(backgroundColor: InteractiveColor): NoteColorsBuilder = + backgroundColor(backgroundColor.asStatefulBrush()) + + /** + * Устанавливает фон [backgroundColor] компонента. + */ + fun backgroundColor(backgroundColor: Color): NoteColorsBuilder = + backgroundColor(backgroundColor.asStatefulBrush()) /** * Устанавливает фон [backgroundColor] компонента. @@ -328,12 +464,24 @@ interface NoteColorsBuilder { * Устанавливает цвет кнопки закрытия [closeColor]. */ fun closeColor(closeColor: Color): NoteColorsBuilder = - closeColor(closeColor.asInteractive()) + closeColor(closeColor.asStatefulBrush()) + + /** + * Устанавливает цвет кнопки закрытия [closeColor]. + */ + fun closeColor(closeColor: InteractiveColor): NoteColorsBuilder = + closeColor(closeColor.asStatefulBrush()) + + /** + * Устанавливает цвет кнопки закрытия [closeColor]. + */ + fun closeColor(closeColor: Brush): NoteColorsBuilder = + closeColor(closeColor.asStatefulValue()) /** * Устанавливает цвет кнопки закрытия [closeColor]. */ - fun closeColor(closeColor: InteractiveColor): NoteColorsBuilder + fun closeColor(closeColor: StatefulValue): NoteColorsBuilder /** * Вернёт [NoteColors] @@ -344,34 +492,48 @@ interface NoteColorsBuilder { @Immutable private data class DefaultNoteColors( override val backgroundColor: StatefulValue, - override val closeColor: InteractiveColor, - override val titleColor: InteractiveColor, - override val textColor: InteractiveColor, - override val iconColor: InteractiveColor, - override val disclosureColor: InteractiveColor, + override val closeBrush: StatefulValue, + override val titleBrush: StatefulValue, + override val textBrush: StatefulValue, + override val iconBrush: StatefulValue, + override val disclosureBrush: StatefulValue, + ) : NoteColors { + @Deprecated("Use closeBrush", replaceWith = ReplaceWith("closeBrush")) + override val closeColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use titleBrush", replaceWith = ReplaceWith("titleBrush")) + override val titleColor: InteractiveColor = Color.Transparent.asInteractive() + @Deprecated("Use textBrush", replaceWith = ReplaceWith("textBrush")) + override val textColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use iconBrush", replaceWith = ReplaceWith("iconBrush")) + override val iconColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated("Use disclosureBrush", replaceWith = ReplaceWith("disclosureBrush")) + override val disclosureColor: InteractiveColor = Color.Transparent.asInteractive() class Builder : NoteColorsBuilder { private var backgroundColor: StatefulValue? = null - private var closeColor: InteractiveColor? = null - private var titleColor: InteractiveColor? = null - private var textColor: InteractiveColor? = null - private var iconColor: InteractiveColor? = null - private var disclosureColor: InteractiveColor? = null + private var closeColor: StatefulValue? = null + private var titleColor: StatefulValue? = null + private var textColor: StatefulValue? = null + private var iconColor: StatefulValue? = null + private var disclosureColor: StatefulValue? = null - override fun titleColor(titleColor: InteractiveColor): NoteColorsBuilder = apply { + override fun titleColor(titleColor: StatefulValue): NoteColorsBuilder = apply { this.titleColor = titleColor } - override fun textColor(textColor: InteractiveColor): NoteColorsBuilder = apply { + override fun textColor(textColor: StatefulValue): NoteColorsBuilder = apply { this.textColor = textColor } - override fun iconColor(iconColor: InteractiveColor): NoteColorsBuilder = apply { + override fun iconColor(iconColor: StatefulValue): NoteColorsBuilder = apply { this.iconColor = iconColor } - override fun disclosureColor(disclosureColor: InteractiveColor): NoteColorsBuilder = apply { + override fun disclosureColor(disclosureColor: StatefulValue): NoteColorsBuilder = apply { this.disclosureColor = disclosureColor } @@ -379,18 +541,18 @@ private data class DefaultNoteColors( this.backgroundColor = backgroundColor } - override fun closeColor(closeColor: InteractiveColor) = apply { + override fun closeColor(closeColor: StatefulValue) = apply { this.closeColor = closeColor } override fun build(): NoteColors { return DefaultNoteColors( - backgroundColor = backgroundColor ?: SolidColor(Color.White).asStatefulValue(), - closeColor = closeColor ?: Color.LightGray.asInteractive(), - titleColor = titleColor ?: Color.Black.asInteractive(), - textColor = textColor ?: Color.DarkGray.asInteractive(), - iconColor = iconColor ?: Color.DarkGray.asInteractive(), - disclosureColor = disclosureColor ?: Color.DarkGray.asInteractive(), + backgroundColor = backgroundColor ?: Color.White.asStatefulBrush(), + closeBrush = closeColor ?: Color.LightGray.asStatefulBrush(), + titleBrush = titleColor ?: Color.Black.asStatefulBrush(), + textBrush = textColor ?: Color.DarkGray.asStatefulBrush(), + iconBrush = iconColor ?: Color.DarkGray.asStatefulBrush(), + disclosureBrush = disclosureColor ?: Color.DarkGray.asStatefulBrush(), ) } } @@ -404,78 +566,183 @@ interface NoteDimensions { /** * Размер иконки close */ + @Deprecated("Use closeSizeValues", replaceWith = ReplaceWith("closeSizeValues")) val closeSize: Dp + /** + * Размер иконки close + */ + val closeSizeValues: StatefulValue + /** * Размер иконки для contentBefore */ + @Deprecated("Use iconSizeValues", replaceWith = ReplaceWith("iconSizeValues")) val iconSize: Dp + /** + * Размер иконки для contentBefore + */ + val iconSizeValues: StatefulValue + /** * Размер иконки для contentAfter */ + @Deprecated("Use disclosureSizeValues", replaceWith = ReplaceWith("disclosureSizeValues")) val disclosureSize: Dp + /** + * Размер иконки для contentAfter + */ + val disclosureSizeValues: StatefulValue + /** * Отступ иконки close от верхнего края компонента */ + @Deprecated("Use closeTopMarginValues", replaceWith = ReplaceWith("closeTopMarginValues")) val closeTopMargin: Dp + /** + * Отступ иконки close от верхнего края компонента + */ + val closeTopMarginValues: StatefulValue + /** * Отступ иконки close от края в конце компонента */ + @Deprecated("Use closeEndMarginValues", replaceWith = ReplaceWith("closeEndMarginValues")) val closeEndMargin: Dp + /** + * Отступ иконки close от края в конце компонента + */ + val closeEndMarginValues: StatefulValue + /** * Отступ вконце contentBefore */ + @Deprecated( + "Use contentBeforeEndMarginValues", + replaceWith = ReplaceWith("contentBeforeEndMarginValues"), + ) val contentBeforeEndMargin: Dp + /** + * Отступ вконце contentBefore + */ + val contentBeforeEndMarginValues: StatefulValue + /** * Отступ вначле contentAfter */ + @Deprecated( + "Use contentAfterStartMarginValues", + replaceWith = ReplaceWith("contentAfterStartMarginValues"), + ) val contentAfterStartMargin: Dp + /** + * Отступ вначле contentAfter + */ + val contentAfterStartMarginValues: StatefulValue + /** * Отступ вконце contentAfter */ + @Deprecated( + "Use contentAfterEndMarginValues", + replaceWith = ReplaceWith("contentAfterEndMarginValues"), + ) val contentAfterEndMargin: Dp + /** + * Отступ вконце contentAfter + */ + val contentAfterEndMarginValues: StatefulValue + /** * Отступ между text и title */ + @Deprecated( + "Use textTopMarginValues", + replaceWith = ReplaceWith("textTopMarginValues"), + ) val textTopMargin: Dp + /** + * Отступ между text и title + */ + val textTopMarginValues: StatefulValue + /** * Отступ между text и action */ + @Deprecated( + "Use actionTopMarginValues", + replaceWith = ReplaceWith("actionTopMarginValues"), + ) val actionTopMargin: Dp + /** + * Отступ между text и action + */ + val actionTopMarginValues: StatefulValue + /** * Отступ контента в начале */ + @Deprecated("Use paddingStartValues", replaceWith = ReplaceWith("paddingStartValues")) val paddingStart: Dp + /** + * Отступ контента в начале + */ + val paddingStartValues: StatefulValue + /** * Отступ контента в конце */ + @Deprecated("Use paddingEndValues", replaceWith = ReplaceWith("paddingEndValues")) val paddingEnd: Dp + /** + * Отступ контента в конце + */ + val paddingEndValues: StatefulValue + /** * Отступ контента сверху */ + @Deprecated("Use paddingTopValues", replaceWith = ReplaceWith("paddingTopValues")) val paddingTop: Dp + /** + * Отступ контента сверху + */ + val paddingTopValues: StatefulValue + /** * Отступ контента снизу */ + @Deprecated("Use paddingBottomValues", replaceWith = ReplaceWith("paddingBottomValues")) val paddingBottom: Dp + /** + * Отступ контента снизу + */ + val paddingBottomValues: StatefulValue + /** * Отступ title в конце при наличии иконки закрытия */ + @Deprecated("Use titlePaddingEndValues", replaceWith = ReplaceWith("titlePaddingEndValues")) val titlePaddingEnd: Dp + /** + * Отступ title в конце при наличии иконки закрытия + */ + val titlePaddingEndValues: StatefulValue + companion object { /** * Возвращает экземпляр [NoteDimensionsBuilder] @@ -492,77 +759,167 @@ interface NoteDimensionsBuilder { /** * Устанавливает размер иконки close [closeSize] */ - fun closeSize(closeSize: Dp): NoteDimensionsBuilder + fun closeSize(closeSize: Dp): NoteDimensionsBuilder = + closeSize(closeSize.asStatefulValue()) + + /** + * Устанавливает размер иконки close [closeSize] + */ + fun closeSize(closeSize: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает размер иконки для contentBefore [iconSize] + */ + fun iconSize(iconSize: Dp): NoteDimensionsBuilder = + iconSize(iconSize.asStatefulValue()) /** * Устанавливает размер иконки для contentBefore [iconSize] */ - fun iconSize(iconSize: Dp): NoteDimensionsBuilder + fun iconSize(iconSize: StatefulValue): NoteDimensionsBuilder /** * Устанавливает размер иконки для contentAfter [disclosureSize] */ - fun disclosureSize(disclosureSize: Dp): NoteDimensionsBuilder + fun disclosureSize(disclosureSize: Dp): NoteDimensionsBuilder = + disclosureSize(disclosureSize.asStatefulValue()) + + /** + * Устанавливает размер иконки для contentAfter [disclosureSize] + */ + fun disclosureSize(disclosureSize: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ иконки закрытия от края [closeSize] + */ + fun closeTopMargin(closeTopMargin: Dp): NoteDimensionsBuilder = + closeTopMargin(closeTopMargin.asStatefulValue()) + + /** + * Устанавливает отступ иконки закрытия от края [closeSize] + */ + fun closeTopMargin(closeTopMargin: StatefulValue): NoteDimensionsBuilder /** * Устанавливает отступ иконки закрытия от края [closeSize] */ - fun closeTopMargin(closeTopMargin: Dp): NoteDimensionsBuilder + fun closeEndMargin(closeEndMargin: Dp): NoteDimensionsBuilder = + closeEndMargin(closeEndMargin.asStatefulValue()) /** * Устанавливает отступ иконки закрытия от края [closeSize] */ - fun closeEndMargin(closeEndMargin: Dp): NoteDimensionsBuilder + fun closeEndMargin(closeEndMargin: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ вконце contentBefore [contentBeforeEndMargin] + */ + fun contentBeforeEndMargin(contentBeforeEndMargin: Dp): NoteDimensionsBuilder = + contentBeforeEndMargin(contentBeforeEndMargin.asStatefulValue()) /** * Устанавливает отступ вконце contentBefore [contentBeforeEndMargin] */ - fun contentBeforeEndMargin(contentBeforeEndMargin: Dp): NoteDimensionsBuilder + fun contentBeforeEndMargin(contentBeforeEndMargin: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ вначале contentAfter [contentAfterStartMargin] + */ + fun contentAfterStartMargin(contentAfterStartMargin: Dp): NoteDimensionsBuilder = + contentAfterStartMargin(contentAfterStartMargin.asStatefulValue()) + + /** + * Устанавливает отступ вначале contentAfter [contentAfterStartMargin] + */ + fun contentAfterStartMargin(contentAfterStartMargin: StatefulValue): NoteDimensionsBuilder /** - * Устанавливает отступ вначале contentAfter [contentAfterEndMargin] + * Устанавливает отступ вконце contentAfter [contentAfterEndMargin] */ - fun contentAfterStartMargin(contentAfterStartMargin: Dp): NoteDimensionsBuilder + fun contentAfterEndMargin(contentAfterEndMargin: Dp): NoteDimensionsBuilder = + contentAfterEndMargin(contentAfterEndMargin.asStatefulValue()) /** * Устанавливает отступ вконце contentAfter [contentAfterEndMargin] */ - fun contentAfterEndMargin(contentAfterEndMargin: Dp): NoteDimensionsBuilder + fun contentAfterEndMargin(contentAfterEndMargin: StatefulValue): NoteDimensionsBuilder /** * Устанавливает отступ между text и title [textTopMargin] */ - fun textTopMargin(textTopMargin: Dp): NoteDimensionsBuilder + fun textTopMargin(textTopMargin: Dp): NoteDimensionsBuilder = + textTopMargin(textTopMargin.asStatefulValue()) + + /** + * Устанавливает отступ между text и title [textTopMargin] + */ + fun textTopMargin(textTopMargin: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ мужду text и action [actionTopMargin] + */ + fun actionTopMargin(actionTopMargin: Dp): NoteDimensionsBuilder = + actionTopMargin(actionTopMargin.asStatefulValue()) /** * Устанавливает отступ мужду text и action [actionTopMargin] */ - fun actionTopMargin(actionTopMargin: Dp): NoteDimensionsBuilder + fun actionTopMargin(actionTopMargin: StatefulValue): NoteDimensionsBuilder /** * Устанавливает отступ в начале [paddingStart] */ - fun paddingStart(paddingStart: Dp): NoteDimensionsBuilder + fun paddingStart(paddingStart: Dp): NoteDimensionsBuilder = + paddingStart(paddingStart.asStatefulValue()) + + /** + * Устанавливает отступ в начале [paddingStart] + */ + fun paddingStart(paddingStart: StatefulValue): NoteDimensionsBuilder /** * Устанавливает отступ в конце [paddingEnd] */ - fun paddingEnd(paddingEnd: Dp): NoteDimensionsBuilder + fun paddingEnd(paddingEnd: Dp): NoteDimensionsBuilder = + paddingEnd(paddingEnd.asStatefulValue()) + + /** + * Устанавливает отступ в конце [paddingEnd] + */ + fun paddingEnd(paddingEnd: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ сверху [paddingTop] + */ + fun paddingTop(paddingTop: Dp): NoteDimensionsBuilder = + paddingTop(paddingTop.asStatefulValue()) /** * Устанавливает отступ сверху [paddingTop] */ - fun paddingTop(paddingTop: Dp): NoteDimensionsBuilder + fun paddingTop(paddingTop: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ снизу [paddingBottom] + */ + fun paddingBottom(paddingBottom: Dp): NoteDimensionsBuilder = + paddingBottom(paddingBottom.asStatefulValue()) /** * Устанавливает отступ снизу [paddingBottom] */ - fun paddingBottom(paddingBottom: Dp): NoteDimensionsBuilder + fun paddingBottom(paddingBottom: StatefulValue): NoteDimensionsBuilder + + /** + * Устанавливает отступ title в конце при наличии иконки закрытия [titlePaddingEnd] + */ + fun titlePaddingEnd(titlePaddingEnd: Dp): NoteDimensionsBuilder = + titlePaddingEnd(titlePaddingEnd.asStatefulValue()) /** * Устанавливает отступ title в конце при наличии иконки закрытия [titlePaddingEnd] */ - fun titlePaddingEnd(titlePaddingEnd: Dp): NoteDimensionsBuilder + fun titlePaddingEnd(titlePaddingEnd: StatefulValue): NoteDimensionsBuilder /** * Создает экземпляр [NoteDimensions] @@ -572,118 +929,171 @@ interface NoteDimensionsBuilder { @Suppress("CyclomaticComplexMethod") private class DefaultNoteDimensions( - override val paddingStart: Dp, - override val paddingEnd: Dp, - override val paddingTop: Dp, - override val paddingBottom: Dp, - override val closeSize: Dp, - override val iconSize: Dp, - override val textTopMargin: Dp, - override val actionTopMargin: Dp, - override val closeTopMargin: Dp, - override val closeEndMargin: Dp, - override val titlePaddingEnd: Dp, - override val contentBeforeEndMargin: Dp, - override val disclosureSize: Dp, - override val contentAfterEndMargin: Dp, - override val contentAfterStartMargin: Dp, + override val paddingStartValues: StatefulValue, + override val paddingEndValues: StatefulValue, + override val paddingTopValues: StatefulValue, + override val paddingBottomValues: StatefulValue, + override val closeSizeValues: StatefulValue, + override val iconSizeValues: StatefulValue, + override val textTopMarginValues: StatefulValue, + override val actionTopMarginValues: StatefulValue, + override val closeTopMarginValues: StatefulValue, + override val closeEndMarginValues: StatefulValue, + override val titlePaddingEndValues: StatefulValue, + override val contentBeforeEndMarginValues: StatefulValue, + override val disclosureSizeValues: StatefulValue, + override val contentAfterEndMarginValues: StatefulValue, + override val contentAfterStartMarginValues: StatefulValue, + ) : NoteDimensions { + @Deprecated("Use paddingStartValues", replaceWith = ReplaceWith("paddingStartValues")) + override val paddingStart: Dp = paddingStartValues.getDefaultValue() + + @Deprecated("Use paddingEndValues", replaceWith = ReplaceWith("paddingEndValues")) + override val paddingEnd: Dp = paddingEndValues.getDefaultValue() + + @Deprecated("Use paddingTopValues", replaceWith = ReplaceWith("paddingTopValues")) + override val paddingTop: Dp = paddingTopValues.getDefaultValue() + + @Deprecated("Use paddingBottomValues", replaceWith = ReplaceWith("paddingBottomValues")) + override val paddingBottom: Dp = paddingBottomValues.getDefaultValue() + + @Deprecated("Use closeSizeValues", replaceWith = ReplaceWith("closeSizeValues")) + override val closeSize: Dp = closeSizeValues.getDefaultValue() + @Deprecated("Use iconSizeValues", replaceWith = ReplaceWith("iconSizeValues")) + override val iconSize: Dp = iconSizeValues.getDefaultValue() + + @Deprecated("Use textTopMarginValues", replaceWith = ReplaceWith("textTopMarginValues")) + override val textTopMargin: Dp = textTopMarginValues.getDefaultValue() + + @Deprecated("Use actionTopMarginValues", replaceWith = ReplaceWith("actionTopMarginValues")) + override val actionTopMargin: Dp = actionTopMarginValues.getDefaultValue() + + @Deprecated("Use closeTopMarginValues", replaceWith = ReplaceWith("closeTopMarginValues")) + override val closeTopMargin: Dp = closeTopMarginValues.getDefaultValue() + + @Deprecated("Use closeEndMarginValues", replaceWith = ReplaceWith("closeEndMarginValues")) + override val closeEndMargin: Dp = closeEndMarginValues.getDefaultValue() + + @Deprecated("Use titlePaddingEndValues", replaceWith = ReplaceWith("titlePaddingEndValues")) + override val titlePaddingEnd: Dp = titlePaddingEndValues.getDefaultValue() + + @Deprecated( + "Use contentBeforeEndMarginValues", + replaceWith = ReplaceWith("contentBeforeEndMarginValues"), + ) + override val contentBeforeEndMargin: Dp = contentBeforeEndMarginValues.getDefaultValue() + + @Deprecated("Use disclosureSizeValues", replaceWith = ReplaceWith("disclosureSizeValues")) + override val disclosureSize: Dp = disclosureSizeValues.getDefaultValue() + + @Deprecated( + "Use contentAfterEndMarginValues", + replaceWith = ReplaceWith("contentAfterEndMarginValues"), + ) + override val contentAfterEndMargin: Dp = contentAfterEndMarginValues.getDefaultValue() + + @Deprecated( + "Use contentAfterStartMarginValues", + replaceWith = ReplaceWith("contentAfterStartMarginValues"), + ) + override val contentAfterStartMargin: Dp = contentAfterStartMarginValues.getDefaultValue() class Builder : NoteDimensionsBuilder { - private var closeSize: Dp? = null - private var iconSize: Dp? = null - private var disclosureSize: Dp? = null - private var closeTopMargin: Dp? = null - private var closeEndMargin: Dp? = null - private var contentBeforeEndMargin: Dp? = null - private var contentAfterStartMargin: Dp? = null - private var contentAfterEndMargin: Dp? = null - private var paddingStart: Dp? = null - private var paddingEnd: Dp? = null - private var paddingTop: Dp? = null - private var paddingBottom: Dp? = null - private var textTopMargin: Dp? = null - private var actionTopMargin: Dp? = null - private var titlePaddingEnd: Dp? = null - - override fun closeSize(closeSize: Dp) = apply { + private var closeSize: StatefulValue? = null + private var iconSize: StatefulValue? = null + private var disclosureSize: StatefulValue? = null + private var closeTopMargin: StatefulValue? = null + private var closeEndMargin: StatefulValue? = null + private var contentBeforeEndMargin: StatefulValue? = null + private var contentAfterStartMargin: StatefulValue? = null + private var contentAfterEndMargin: StatefulValue? = null + private var paddingStart: StatefulValue? = null + private var paddingEnd: StatefulValue? = null + private var paddingTop: StatefulValue? = null + private var paddingBottom: StatefulValue? = null + private var textTopMargin: StatefulValue? = null + private var actionTopMargin: StatefulValue? = null + private var titlePaddingEnd: StatefulValue? = null + + override fun closeSize(closeSize: StatefulValue) = apply { this.closeSize = closeSize } - override fun iconSize(iconSize: Dp) = apply { + override fun iconSize(iconSize: StatefulValue) = apply { this.iconSize = iconSize } - override fun disclosureSize(disclosureSize: Dp) = apply { + override fun disclosureSize(disclosureSize: StatefulValue) = apply { this.disclosureSize = disclosureSize } - override fun closeTopMargin(closeTopMargin: Dp) = apply { + override fun closeTopMargin(closeTopMargin: StatefulValue) = apply { this.closeTopMargin = closeTopMargin } - override fun closeEndMargin(closeEndMargin: Dp) = apply { + override fun closeEndMargin(closeEndMargin: StatefulValue) = apply { this.closeEndMargin = closeEndMargin } - override fun contentBeforeEndMargin(contentBeforeEndMargin: Dp) = apply { + override fun contentBeforeEndMargin(contentBeforeEndMargin: StatefulValue) = apply { this.contentBeforeEndMargin = contentBeforeEndMargin } - override fun contentAfterStartMargin(contentAfterStartMargin: Dp) = apply { + override fun contentAfterStartMargin(contentAfterStartMargin: StatefulValue) = apply { this.contentAfterStartMargin = contentAfterStartMargin } - override fun contentAfterEndMargin(contentAfterEndMargin: Dp) = apply { + override fun contentAfterEndMargin(contentAfterEndMargin: StatefulValue) = apply { this.contentAfterEndMargin = contentAfterEndMargin } - override fun textTopMargin(textTopMargin: Dp) = apply { + override fun textTopMargin(textTopMargin: StatefulValue) = apply { this.textTopMargin = textTopMargin } - override fun actionTopMargin(actionTopMargin: Dp) = apply { + override fun actionTopMargin(actionTopMargin: StatefulValue) = apply { this.actionTopMargin = actionTopMargin } - override fun paddingStart(paddingStart: Dp) = apply { + override fun paddingStart(paddingStart: StatefulValue) = apply { this.paddingStart = paddingStart } - override fun paddingEnd(paddingEnd: Dp) = apply { + override fun paddingEnd(paddingEnd: StatefulValue) = apply { this.paddingEnd = paddingEnd } - override fun paddingTop(paddingTop: Dp) = apply { + override fun paddingTop(paddingTop: StatefulValue) = apply { this.paddingTop = paddingTop } - override fun paddingBottom(paddingBottom: Dp) = apply { + override fun paddingBottom(paddingBottom: StatefulValue) = apply { this.paddingBottom = paddingBottom } - override fun titlePaddingEnd(titlePaddingEnd: Dp) = apply { + override fun titlePaddingEnd(titlePaddingEnd: StatefulValue) = apply { this.titlePaddingEnd = titlePaddingEnd } override fun build(): NoteDimensions { return DefaultNoteDimensions( - paddingStart = paddingStart ?: 0.dp, - paddingEnd = paddingEnd ?: 0.dp, - paddingTop = paddingTop ?: 0.dp, - paddingBottom = paddingBottom ?: 0.dp, - closeSize = closeSize ?: 24.dp, - iconSize = iconSize ?: Dp.Unspecified, - disclosureSize = disclosureSize ?: Dp.Unspecified, - closeTopMargin = closeTopMargin ?: 0.dp, - closeEndMargin = closeEndMargin ?: 0.dp, - contentBeforeEndMargin = contentBeforeEndMargin ?: 0.dp, - contentAfterEndMargin = contentAfterEndMargin ?: 0.dp, - contentAfterStartMargin = contentAfterStartMargin ?: 0.dp, - textTopMargin = textTopMargin ?: 0.dp, - actionTopMargin = actionTopMargin ?: 0.dp, - titlePaddingEnd = titlePaddingEnd ?: 0.dp, + paddingStartValues = paddingStart ?: 0.dp.asStatefulValue(), + paddingEndValues = paddingEnd ?: 0.dp.asStatefulValue(), + paddingTopValues = paddingTop ?: 0.dp.asStatefulValue(), + paddingBottomValues = paddingBottom ?: 0.dp.asStatefulValue(), + closeSizeValues = closeSize ?: 24.dp.asStatefulValue(), + iconSizeValues = iconSize ?: Dp.Unspecified.asStatefulValue(), + disclosureSizeValues = disclosureSize ?: Dp.Unspecified.asStatefulValue(), + closeTopMarginValues = closeTopMargin ?: 0.dp.asStatefulValue(), + closeEndMarginValues = closeEndMargin ?: 0.dp.asStatefulValue(), + contentBeforeEndMarginValues = contentBeforeEndMargin ?: 0.dp.asStatefulValue(), + contentAfterEndMarginValues = contentAfterEndMargin ?: 0.dp.asStatefulValue(), + contentAfterStartMarginValues = contentAfterStartMargin ?: 0.dp.asStatefulValue(), + textTopMarginValues = textTopMargin ?: 0.dp.asStatefulValue(), + actionTopMarginValues = actionTopMargin ?: 0.dp.asStatefulValue(), + titlePaddingEndValues = titlePaddingEnd ?: 0.dp.asStatefulValue(), ) } } diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotion.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotion.kt new file mode 100644 index 000000000..770638b46 --- /dev/null +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotion.kt @@ -0,0 +1,22 @@ +package com.sdds.compose.uikit.motion.components.note + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.NonRestartableComposable +import com.sdds.compose.uikit.motion.Motion +import com.sdds.compose.uikit.motion.MotionContext +import com.sdds.compose.uikit.motion.rememberMotion +import com.sdds.compose.uikit.motion.rememberMotionContext + +/** + * Создает [Motion] для [Note] + * @param motionContext контекст анимации + * @param style стиль анимации [Note] + */ +@Composable +@NonRestartableComposable +fun rememberNoteMotion( + style: NoteMotionStyle = LocalNoteMotionStyle.current, + motionContext: MotionContext = rememberMotionContext(), +): Motion { + return rememberMotion(style, motionContext) +} diff --git a/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotionStyle.kt b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotionStyle.kt new file mode 100644 index 000000000..5097df582 --- /dev/null +++ b/sdds-core/uikit-compose/src/commonMain/kotlin/com/sdds/compose/uikit/motion/components/note/NoteMotionStyle.kt @@ -0,0 +1,189 @@ +package com.sdds.compose.uikit.motion.components.note + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.text.TextStyle +import com.sdds.compose.uikit.motion.MotionProperty +import com.sdds.compose.uikit.motion.MotionStyle +import com.sdds.compose.uikit.motion.MotionStyleBuilder +import com.sdds.compose.uikit.motion.noMotion + +/** + * CompositionLocal, предоставляющий текущий [NoteMotionStyle]. + * Используется для доступа к анимационным свойствам Note внутри Compose-иерархии. + */ +val LocalNoteMotionStyle = compositionLocalOf { NoteMotionStyle.builder().style() } + +/** + * Описывает анимационные (motion) свойства для элемента Note. + * Содержит набор [MotionProperty], определяющих поведение цветов и вложенных компонентов + * при различных состояниях (например, выбран, нажат и т.д.). + */ +@Stable +interface NoteMotionStyle : MotionStyle { + + /** + * Анимационное свойство цвета заголовка (title) Note. + */ + val titleColor: MotionProperty + + /** + * Анимационное свойство стиля заголовка (title) Note. + */ + val titleStyle: MotionProperty + + /** + * Анимационное свойство цвета текста (label) Note. + */ + val textColor: MotionProperty + + /** + * Анимационное свойство стиля текста (label) Note. + */ + val textStyle: MotionProperty + + /** + * Анимационное свойство цвета contentAfterColor Note. + */ + val contentAfterColor: MotionProperty + + /** + * Анимационное свойство иконки contentBefore Note. + */ + val contentBeforeColor: MotionProperty + + /** + * Анимационное свойство цвета иконки закрытия Note. + */ + val closeColor: MotionProperty + + /** + * Анимационное свойство цвета фона Note. + */ + val backgroundColor: MotionProperty + + companion object { + /** + * Создает билдер для построения [NoteMotionStyle]. + */ + fun builder(): NoteMotionStyleBuilder = NoteMotionStyleImpl.Builder() + } +} + +/** + * Билдер для поэтапной конфигурации [NoteMotionStyle]. + */ +@Stable +interface NoteMotionStyleBuilder : MotionStyleBuilder { + + /** + * Устанавливает анимационное свойство цвета title. + */ + fun titleColor(color: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля title. + */ + fun titleStyle(style: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета text. + */ + fun textColor(color: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля text. + */ + fun textStyle(style: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета contentAfterColor. + */ + fun contentAfterColor(color: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета contentBeforeColor. + */ + fun contentBeforeColor(color: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета иконки закрытия в начале. + */ + fun closeColor(color: MotionProperty): NoteMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета фона. + */ + fun backgroundColor(color: MotionProperty): NoteMotionStyleBuilder +} + +@Immutable +private class NoteMotionStyleImpl( + override val titleColor: MotionProperty, + override val titleStyle: MotionProperty, + override val textColor: MotionProperty, + override val textStyle: MotionProperty, + override val contentAfterColor: MotionProperty, + override val contentBeforeColor: MotionProperty, + override val closeColor: MotionProperty, + override val backgroundColor: MotionProperty, +) : NoteMotionStyle { + + class Builder : NoteMotionStyleBuilder { + private var textColor: MotionProperty? = null + private var titleColor: MotionProperty? = null + private var contentAfterColor: MotionProperty? = null + private var contentBeforeColor: MotionProperty? = null + private var closeColor: MotionProperty? = null + private var backgroundColor: MotionProperty? = null + private var textStyle: MotionProperty? = null + private var titleStyle: MotionProperty? = null + + override fun titleColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.titleColor = color + } + + override fun titleStyle(style: MotionProperty): NoteMotionStyleBuilder = apply { + this.titleStyle = style + } + + override fun textColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.textColor = color + } + + override fun textStyle(style: MotionProperty): NoteMotionStyleBuilder = apply { + this.textStyle = style + } + + override fun contentAfterColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.contentAfterColor = color + } + + override fun contentBeforeColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.contentBeforeColor = color + } + + override fun closeColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.closeColor = color + } + + override fun backgroundColor(color: MotionProperty): NoteMotionStyleBuilder = apply { + this.backgroundColor = color + } + + override fun style(): NoteMotionStyle { + return NoteMotionStyleImpl( + textColor = textColor ?: noMotion(), + textStyle = textStyle ?: noMotion(), + titleColor = titleColor ?: noMotion(), + titleStyle = titleStyle ?: noMotion(), + contentAfterColor = contentAfterColor ?: noMotion(), + contentBeforeColor = contentBeforeColor ?: noMotion(), + closeColor = closeColor ?: noMotion(), + backgroundColor = backgroundColor ?: noMotion(), + ) + } + } +}