From 817a29a9f102371f6deddefeac8d31f2500b6abf Mon Sep 17 00:00:00 2001 From: SerraMorec Date: Mon, 4 May 2026 07:21:19 +0300 Subject: [PATCH 1/2] feat(sdds-acore/uikit-compose): Motion API was added in Cell --- .../kotlin/com/sdds/compose/uikit/Cell.kt | 39 ++- .../com/sdds/compose/uikit/CellStyle.kt | 271 ++++++++++++++---- .../motion/components/cell/CellMotion.kt | 22 ++ .../motion/components/cell/CellMotionStyle.kt | 212 ++++++++++++++ 4 files changed, 486 insertions(+), 58 deletions(-) create mode 100644 sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotion.kt create mode 100644 sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Cell.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Cell.kt index a4a50e1cd..eaf2cb7d3 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Cell.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Cell.kt @@ -14,6 +14,11 @@ import androidx.compose.ui.text.AnnotatedString import com.sdds.compose.uikit.internal.cell.BaseCell import com.sdds.compose.uikit.internal.cell.CellCenterContent import com.sdds.compose.uikit.internal.common.StyledText +import com.sdds.compose.uikit.motion.Motion +import com.sdds.compose.uikit.motion.components.cell.CellMotionStyle +import com.sdds.compose.uikit.motion.components.cell.rememberCellMotion +import com.sdds.compose.uikit.motion.getBrushAsState +import com.sdds.compose.uikit.motion.rememberMotionContext /** * Компонент Cell. @@ -28,6 +33,7 @@ import com.sdds.compose.uikit.internal.common.StyledText * @param startContent контент в начале * @param endContent контент в конце * @param interactionSource источник взаимодействий + * @param motion объект анимаций */ @Composable fun Cell( @@ -41,6 +47,9 @@ fun Cell( startContent: (@Composable RowScope.() -> Unit)? = null, endContent: (@Composable RowScope.() -> Unit)? = null, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + motion: Motion = rememberCellMotion( + motionContext = rememberMotionContext(interactionSource), + ), ) { BaseCell( modifier = modifier, @@ -59,7 +68,7 @@ fun Cell( endContent = endContent, disclosureEnabled = disclosureContent != null, disclosureContent = disclosureContent, - interactionSource = interactionSource, + interactionSource = motion.context.interactionSource, ) } @@ -93,6 +102,9 @@ fun Cell( startContent: (@Composable RowScope.() -> Unit)? = null, endContent: (@Composable RowScope.() -> Unit)? = null, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + motion: Motion = rememberCellMotion( + motionContext = rememberMotionContext(interactionSource), + ), ) { BaseCell( modifier = modifier, @@ -104,33 +116,37 @@ fun Cell( label = label, subtitle = subtitle, style = style, - interactionSource = interactionSource, + interactionSource = motion.context.interactionSource, ) }, startContent = startContent, endContent = endContent, disclosureEnabled = disclosureContentEnabled, disclosureContent = { + val textColor = style.colors.disclosureTextBrush.getBrushAsState( + motion.context, + motion.style.disclosureTextColor, + ) StyledText( text = disclosureText, textStyle = style.disclosureTextStyle, - textColor = style.colors.disclosureTextColor.colorForInteraction( - interactionSource, - ), + textColor = textColor.value, ) val iconRes = disclosureIconRes ?: style.disclosureIconRes val painter = iconRes?.let { painterResource(it) } ?: style.disclosureIcon painter?.let { + val iconColor = style.colors.disclosureIconBrush.getBrushAsState( + motion.context, + motion.style.disclosureIconColor, + ) Icon( painter = it, contentDescription = "", - tint = style.colors.disclosureIconColor.colorForInteraction( - interactionSource, - ), + brush = { iconColor.value }, ) } }, - interactionSource = interactionSource, + interactionSource = motion.context.interactionSource, ) } @@ -233,6 +249,9 @@ fun Cell( centerContent: (@Composable ColumnScope.() -> Unit)? = null, endContent: (@Composable RowScope.() -> Unit)? = null, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + motion: Motion = rememberCellMotion( + motionContext = rememberMotionContext(interactionSource), + ), ) { BaseCell( modifier = modifier, @@ -243,7 +262,7 @@ fun Cell( startContent = startContent, centerContent = centerContent, endContent = endContent, - interactionSource = interactionSource, + interactionSource = motion.context.interactionSource, ) } diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt index fbfabf4a0..a7838aa3d 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt @@ -6,14 +6,17 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable 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.painter.Painter import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +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 @@ -32,6 +35,12 @@ interface CellStyle : Style { /** * Стиль лэйбла */ + @Deprecated( + "Use labelStyles", + replaceWith = ReplaceWith( + "labelStyles", + ), + ) val labelStyle: TextStyle /** @@ -42,6 +51,12 @@ interface CellStyle : Style { /** * Стиль тайтла */ + @Deprecated( + "Use titleStyle", + replaceWith = ReplaceWith( + "titleStyle", + ), + ) val titleStyle: TextStyle /** @@ -52,6 +67,12 @@ interface CellStyle : Style { /** * Стиль сабйтайтла */ + @Deprecated( + "Use subtitleStyles", + replaceWith = ReplaceWith( + "subtitleStyles", + ), + ) val subtitleStyle: TextStyle /** @@ -67,6 +88,12 @@ interface CellStyle : Style { /** * Стили disclosure */ + @Deprecated( + "Use disclosureTextStyles", + replaceWith = ReplaceWith( + "disclosureTextStyles", + ), + ) val disclosureTextStyles: StatefulValue /** @@ -369,13 +396,31 @@ interface CellDimensions { /** * Отступ между контентом вначале и контентом по середине */ + @Deprecated( + "Use contentPaddingStartValues", + replaceWith = ReplaceWith("contentPaddingStartValues"), + ) val contentPaddingStart: Dp + /** + * Отступ между контентом вначале и контентом по середине + */ + val contentPaddingStartValues: StatefulValue + /** * Отступ между контентом вначале и контентом в конце */ + @Deprecated( + "Use contentPaddingEndValues", + replaceWith = ReplaceWith("contentPaddingEndValues"), + ) val contentPaddingEnd: Dp + /** + * Отступ между контентом вначале и контентом в конце + */ + val contentPaddingEndValues: StatefulValue + companion object { /** @@ -393,12 +438,24 @@ interface CellDimensionsBuilder { /** * Устанавливает отступ между контентом вначале и контентом по середине */ - fun contentPaddingStart(contentPaddingStart: Dp): CellDimensionsBuilder + fun contentPaddingStart(contentPaddingStart: Dp): CellDimensionsBuilder = + contentPaddingStart(contentPaddingStart.asStatefulValue()) + + /** + * Устанавливает отступ между контентом вначале и контентом по середине + */ + fun contentPaddingStart(values: StatefulValue): CellDimensionsBuilder /** * Устанавливает отступ между контентом по середине и контентом в конце */ - fun contentPaddingEnd(contentPaddingEnd: Dp): CellDimensionsBuilder + fun contentPaddingEnd(contentPaddingEnd: Dp): CellDimensionsBuilder = + contentPaddingEnd(contentPaddingEnd.asStatefulValue()) + + /** + * Устанавливает отступ между контентом по середине и контентом в конце + */ + fun contentPaddingEnd(values: StatefulValue): CellDimensionsBuilder /** * Создаёт экземпляр [CellDimensions] @@ -408,25 +465,38 @@ interface CellDimensionsBuilder { @Immutable private class DefaultCellDimensions( - override val contentPaddingStart: Dp, - override val contentPaddingEnd: Dp, + override val contentPaddingStartValues: StatefulValue, + override val contentPaddingEndValues: StatefulValue, + ) : CellDimensions { + @Deprecated( + "Use contentPaddingStartValues", + replaceWith = ReplaceWith("contentPaddingStartValues"), + ) + override val contentPaddingStart: Dp = 16.dp + + @Deprecated( + "Use contentPaddingEndValues", + replaceWith = ReplaceWith("contentPaddingEndValues"), + ) + override val contentPaddingEnd: Dp = 16.dp + class Builder : CellDimensionsBuilder { - private var contentPaddingStart: Dp? = null - private var contentPaddingEnd: Dp? = null + private var contentPaddingStart: StatefulValue? = null + private var contentPaddingEnd: StatefulValue? = null - override fun contentPaddingStart(contentPaddingStart: Dp) = apply { - this.contentPaddingStart = contentPaddingStart + override fun contentPaddingStart(values: StatefulValue): CellDimensionsBuilder = apply { + this.contentPaddingStart = values } - override fun contentPaddingEnd(contentPaddingEnd: Dp) = apply { - this.contentPaddingEnd = contentPaddingEnd + override fun contentPaddingEnd(values: StatefulValue): CellDimensionsBuilder = apply { + this.contentPaddingEnd = values } override fun build(): CellDimensions { return DefaultCellDimensions( - contentPaddingStart = contentPaddingStart ?: 16.dp, - contentPaddingEnd = contentPaddingEnd ?: 16.dp, + contentPaddingStartValues = contentPaddingStart ?: 16.dp.asStatefulValue(), + contentPaddingEndValues = contentPaddingEnd ?: 16.dp.asStatefulValue(), ) } } @@ -441,28 +511,73 @@ interface CellColors { /** * Цвет тайтла */ + @Deprecated( + "Use titleBrush", + replaceWith = ReplaceWith("titleBrush"), + ) val titleColor: InteractiveColor + /** + * Кисть тайтла + */ + val titleBrush: StatefulValue + /** * Цвет лэйбла */ + @Deprecated( + "Use labelBrush", + replaceWith = ReplaceWith("labelBrush"), + ) val labelColor: InteractiveColor + /** + * Кистmь лэйбла + */ + val labelBrush: StatefulValue + /** * Цвет сабтайтла */ + @Deprecated( + "Use subtitleBrush", + replaceWith = ReplaceWith("subtitleBrush"), + ) val subtitleColor: InteractiveColor + /** + * Кисть сабтайтла + */ + val subtitleBrush: StatefulValue + /** * Цвет текста disclosure */ + @Deprecated( + "Use disclosureTextBrush", + replaceWith = ReplaceWith("disclosureTextBrush"), + ) val disclosureTextColor: InteractiveColor + /** + * Кисть текста disclosure + */ + val disclosureTextBrush: StatefulValue + /** * Цвет иконки disclosure */ + @Deprecated( + "Use disclosureIconBrush", + replaceWith = ReplaceWith("disclosureIconBrush"), + ) val disclosureIconColor: InteractiveColor + /** + * Кисть иконки disclosure + */ + val disclosureIconBrush: StatefulValue + companion object { /** @@ -481,56 +596,86 @@ interface CellColorsBuilder { * Устанавливает цвет тайтла */ fun titleColor(titleColor: Color): CellColorsBuilder = - titleColor(titleColor.asInteractive()) + titleBrush(titleColor.asStatefulBrush()) /** * Устанавливает цвет тайтла */ - fun titleColor(titleColor: InteractiveColor): CellColorsBuilder + fun titleColor(titleColor: InteractiveColor): CellColorsBuilder = + titleBrush(titleColor.asStatefulBrush()) + + /** + * Устанавливает кисть тайтла компонента [brush] + */ + fun titleBrush(brush: StatefulValue): CellColorsBuilder /** * Устанавливает цвет лэйбла */ fun labelColor(labelColor: Color): CellColorsBuilder = - labelColor(labelColor.asInteractive()) + labelBrush(labelColor.asStatefulBrush()) /** * Устанавливает цвет лэйбла */ - fun labelColor(labelColor: InteractiveColor): CellColorsBuilder + fun labelColor(labelColor: InteractiveColor): CellColorsBuilder = + labelBrush(labelColor.asStatefulBrush()) + + /** + * Устанавливает кисть лэйбла компонента [brush] + */ + fun labelBrush(brush: StatefulValue): CellColorsBuilder /** * Устанавливает цвет сабтайтла */ fun subtitleColor(subtitleColor: Color): CellColorsBuilder = - subtitleColor(subtitleColor.asInteractive()) + subtitleBrush(subtitleColor.asStatefulBrush()) /** * Устанавливает цвет сабтайтла */ - fun subtitleColor(subtitleColor: InteractiveColor): CellColorsBuilder + fun subtitleColor(subtitleColor: InteractiveColor): CellColorsBuilder = + subtitleBrush(subtitleColor.asStatefulBrush()) + + /** + * Устанавливает кисть сабтайтла компонента [brush] + */ + fun subtitleBrush(brush: StatefulValue): CellColorsBuilder /** * Устанавливает цвет текста disclosure */ fun disclosureTextColor(disclosureTextColor: Color): CellColorsBuilder = - disclosureTextColor(disclosureTextColor.asInteractive()) + disclosureTextBrush(disclosureTextColor.asStatefulBrush()) /** * Устанавливает цвет текста disclosure */ - fun disclosureTextColor(disclosureTextColor: InteractiveColor): CellColorsBuilder + fun disclosureTextColor(disclosureTextColor: InteractiveColor): CellColorsBuilder = + disclosureTextBrush(disclosureTextColor.asStatefulBrush()) + + /** + * Устанавливает кисть текста disclosure компонента [brush] + */ + fun disclosureTextBrush(brush: StatefulValue): CellColorsBuilder /** * Устанавливает цвет иконки disclosure */ fun disclosureIconColor(disclosureIconColor: Color): CellColorsBuilder = - disclosureIconColor(disclosureIconColor.asInteractive()) + disclosureIconBrush(disclosureIconColor.asStatefulBrush()) /** * Устанавливает цвет иконки disclosure */ - fun disclosureIconColor(disclosureIconColor: InteractiveColor): CellColorsBuilder + fun disclosureIconColor(disclosureIconColor: InteractiveColor): CellColorsBuilder = + disclosureIconBrush(disclosureIconColor.asStatefulBrush()) + + /** + * Устанавливает кисть иконки disclosure компонента [brush] + */ + fun disclosureIconBrush(brush: StatefulValue): CellColorsBuilder /** * Возвращает [CellColors] @@ -540,46 +685,76 @@ interface CellColorsBuilder { @Immutable private class DefaultCellColors( - override val titleColor: InteractiveColor, - override val labelColor: InteractiveColor, - override val subtitleColor: InteractiveColor, - override val disclosureTextColor: InteractiveColor, - override val disclosureIconColor: InteractiveColor, + override val titleBrush: StatefulValue, + override val labelBrush: StatefulValue, + override val subtitleBrush: StatefulValue, + override val disclosureTextBrush: StatefulValue, + override val disclosureIconBrush: StatefulValue, ) : CellColors { + @Deprecated( + "Use titleBrush", + replaceWith = ReplaceWith("titleBrush"), + ) + override val titleColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated( + "Use labelBrush", + replaceWith = ReplaceWith("labelBrush"), + ) + override val labelColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated( + "Use subtitleBrush", + replaceWith = ReplaceWith("subtitleBrush"), + ) + override val subtitleColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated( + "Use disclosureTextBrush", + replaceWith = ReplaceWith("disclosureTextBrush"), + ) + override val disclosureTextColor: InteractiveColor = Color.Transparent.asInteractive() + + @Deprecated( + "Use disclosureIconBrush", + replaceWith = ReplaceWith("disclosureIconBrush"), + ) + override val disclosureIconColor: InteractiveColor = Color.Transparent.asInteractive() + class Builder : CellColorsBuilder { - private var titleColor: InteractiveColor? = null - private var labelColor: InteractiveColor? = null - private var subtitleColor: InteractiveColor? = null - private var disclosureTextColor: InteractiveColor? = null - private var disclosureIconColor: InteractiveColor? = null - - override fun titleColor(titleColor: InteractiveColor) = apply { - this.titleColor = titleColor + private var titleColor: StatefulValue? = null + private var labelColor: StatefulValue? = null + private var subtitleColor: StatefulValue? = null + private var disclosureTextColor: StatefulValue? = null + private var disclosureIconColor: StatefulValue? = null + + override fun titleBrush(brush: StatefulValue) = apply { + this.titleColor = brush } - override fun labelColor(labelColor: InteractiveColor) = apply { - this.labelColor = labelColor + override fun labelBrush(brush: StatefulValue) = apply { + this.labelColor = brush } - override fun subtitleColor(subtitleColor: InteractiveColor) = apply { - this.subtitleColor = subtitleColor + override fun subtitleBrush(brush: StatefulValue) = apply { + this.subtitleColor = brush } - override fun disclosureTextColor(disclosureTextColor: InteractiveColor) = apply { - this.disclosureTextColor = disclosureTextColor + override fun disclosureTextBrush(brush: StatefulValue) = apply { + this.disclosureTextColor = brush } - override fun disclosureIconColor(disclosureIconColor: InteractiveColor) = apply { - this.disclosureIconColor = disclosureIconColor + override fun disclosureIconBrush(brush: StatefulValue) = apply { + this.disclosureIconColor = brush } override fun build(): CellColors { return DefaultCellColors( - titleColor = titleColor ?: Color.Black.asInteractive(), - labelColor = labelColor ?: Color.Black.asInteractive(), - subtitleColor = subtitleColor ?: Color.Black.asInteractive(), - disclosureTextColor = disclosureTextColor ?: Color.Black.asInteractive(), - disclosureIconColor = disclosureIconColor ?: Color.Black.asInteractive(), + titleBrush = titleColor ?: Color.Black.asStatefulBrush(), + labelBrush = labelColor ?: Color.Black.asStatefulBrush(), + subtitleBrush = subtitleColor ?: Color.Black.asStatefulBrush(), + disclosureTextBrush = disclosureTextColor ?: Color.Black.asStatefulBrush(), + disclosureIconBrush = disclosureIconColor ?: Color.Black.asStatefulBrush(), ) } } diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotion.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotion.kt new file mode 100644 index 000000000..6d722276f --- /dev/null +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotion.kt @@ -0,0 +1,22 @@ +package com.sdds.compose.uikit.motion.components.cell + +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] для [Cell] + * @param motionContext контекст анимации + * @param style стиль анимации [Cell] + */ +@Composable +@NonRestartableComposable +fun rememberCellMotion( + style: CellMotionStyle = LocalCellMotionStyle.current, + motionContext: MotionContext = rememberMotionContext(), +): Motion { + return rememberMotion(style, motionContext) +} diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt new file mode 100644 index 000000000..30d9d6597 --- /dev/null +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt @@ -0,0 +1,212 @@ +package com.sdds.compose.uikit.motion.components.cell + +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, предоставляющий текущий [CellMotionStyle]. + * Используется для доступа к анимационным свойствам Cell внутри Compose-иерархии. + */ +val LocalCellMotionStyle = compositionLocalOf { CellMotionStyle.builder().style() } + +/** + * Описывает анимационные (motion) свойства для элемента Cell. + * Содержит набор [MotionProperty], определяющих поведение цветов и вложенных компонентов + * при различных состояниях (например, выбран, нажат и т.д.). + */ +@Stable +interface CellMotionStyle : MotionStyle { + + /** + * Анимационное свойство цвета заголовка (title) Cell. + */ + val titleColor: MotionProperty + + /** + * Анимационное свойство стиля заголовка (title) Cell. + */ + val titleStyle: MotionProperty + + /** + * Анимационное свойство цвета основного текста (label) Cell. + */ + val labelColor: MotionProperty + + /** + * Анимационное свойство стиля основного текста (label) Cell. + */ + val labelStyle: MotionProperty + + /** + * Анимационное свойство цвета подзаголовка (subtitle) Cell. + */ + val subtitleColor: MotionProperty + + /** + * Анимационное свойство стиля подзаголовка (subtitle) Cell. + */ + val subtitleStyle: MotionProperty + + /** + * Анимационное свойство цвета текста disclosure Cell. + */ + val disclosureTextColor: MotionProperty + + /** + * Анимационное свойство стиля текста disclosure Cell. + */ + val disclosureTextStyle: MotionProperty + + /** + * Анимационное свойство иконки disclosure Cell. + */ + val disclosureIconColor: MotionProperty + +// /** +// * Анимационный стиль счетчика, отображаемого внутри Cell. +// * Может быть `null`, если счетчик не используется. +// */ +// val counterMotionStyle: CounterMotionStyle? + + companion object { + /** + * Создает билдер для построения [CellMotionStyle]. + */ + fun builder(): CellMotionStyleBuilder = CellMotionStyleImpl.Builder() + } +} + +/** + * Билдер для поэтапной конфигурации [CellMotionStyle]. + */ +@Stable +interface CellMotionStyleBuilder : MotionStyleBuilder { + + /** + * Устанавливает анимационное свойство цвета title. + */ + fun titleColor(color: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля title. + */ + fun titleStyle(style: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета label. + */ + fun labelColor(color: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля label. + */ + fun labelStyle(style: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета subTitle. + */ + fun subtitleColor(color: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля subTitle. + */ + fun subtitleStyle(style: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета текста disclosure. + */ + fun disclosureTextColor(color: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство стиля текста disclosure. + */ + fun disclosureTextStyle(style: MotionProperty): CellMotionStyleBuilder + + /** + * Устанавливает анимационное свойство цвета иконки disclosure. + */ + fun disclosureIconColor(color: MotionProperty): CellMotionStyleBuilder +} + +@Immutable +private class CellMotionStyleImpl( + override val titleColor: MotionProperty, + override val titleStyle: MotionProperty, + override val labelColor: MotionProperty, + override val labelStyle: MotionProperty, + override val subtitleColor: MotionProperty, + override val subtitleStyle: MotionProperty, + override val disclosureTextColor: MotionProperty, + override val disclosureTextStyle: MotionProperty, + override val disclosureIconColor: MotionProperty, +) : CellMotionStyle { + + class Builder : CellMotionStyleBuilder { + private var labelColor: MotionProperty? = null + private var titleColor: MotionProperty? = null + private var subtitleColor: MotionProperty? = null + private var disclosureTextColor: MotionProperty? = null + private var disclosureIconColor: MotionProperty? = null + private var labelStyle: MotionProperty? = null + private var titleStyle: MotionProperty? = null + private var subtitleStyle: MotionProperty? = null + private var disclosureTextStyle: MotionProperty? = null + + override fun titleColor(color: MotionProperty): CellMotionStyleBuilder = apply { + this.titleColor = color + } + + override fun titleStyle(style: MotionProperty): CellMotionStyleBuilder = apply { + this.titleStyle = style + } + + override fun labelColor(color: MotionProperty) = apply { + this.labelColor = color + } + + override fun labelStyle(style: MotionProperty) = apply { + this.labelStyle = style + } + + override fun subtitleColor(color: MotionProperty): CellMotionStyleBuilder = apply { + this.subtitleColor = color + } + + override fun subtitleStyle(style: MotionProperty): CellMotionStyleBuilder = apply { + this.subtitleStyle = style + } + + override fun disclosureTextColor(color: MotionProperty): CellMotionStyleBuilder = apply { + this.disclosureTextColor = color + } + + override fun disclosureTextStyle(style: MotionProperty): CellMotionStyleBuilder = apply { + this.disclosureTextStyle = style + } + + override fun disclosureIconColor(color: MotionProperty): CellMotionStyleBuilder = apply { + this.disclosureIconColor = color + } + + override fun style(): CellMotionStyle { + return CellMotionStyleImpl( + labelColor = labelColor ?: noMotion(), + labelStyle = labelStyle ?: noMotion(), + titleColor = titleColor ?: noMotion(), + titleStyle = titleStyle ?: noMotion(), + subtitleColor = subtitleColor ?: noMotion(), + subtitleStyle = subtitleStyle ?: noMotion(), + disclosureTextColor = disclosureTextColor ?: noMotion(), + disclosureTextStyle = disclosureTextStyle ?: noMotion(), + disclosureIconColor = disclosureIconColor ?: noMotion(), + ) + } + } +} From 6bd506c0cacf39ad30b48abd16fea6962338c4e9 Mon Sep 17 00:00:00 2001 From: SerraMorec Date: Wed, 6 May 2026 12:15:55 +0300 Subject: [PATCH 2/2] feat(sdds-acore/uikit-compose): LocalTinTBrushProducer was added in File and BaseCell --- .../uikit/fixtures/testcases/FileTestCases.kt | 18 ++++---- .../com/sdds/compose/uikit/CellStyle.kt | 41 +++++++++---------- .../kotlin/com/sdds/compose/uikit/Drawer.kt | 3 +- .../kotlin/com/sdds/compose/uikit/File.kt | 15 +++++-- .../compose/uikit/internal/cell/BaseCell.kt | 27 ++++++------ .../motion/components/cell/CellMotionStyle.kt | 6 --- 6 files changed, 58 insertions(+), 52 deletions(-) diff --git a/integration-core/uikit-compose-testcases/src/main/kotlin/com/sdds/compose/uikit/fixtures/testcases/FileTestCases.kt b/integration-core/uikit-compose-testcases/src/main/kotlin/com/sdds/compose/uikit/fixtures/testcases/FileTestCases.kt index c252cf484..506b1d250 100644 --- a/integration-core/uikit-compose-testcases/src/main/kotlin/com/sdds/compose/uikit/fixtures/testcases/FileTestCases.kt +++ b/integration-core/uikit-compose-testcases/src/main/kotlin/com/sdds/compose/uikit/fixtures/testcases/FileTestCases.kt @@ -1,7 +1,6 @@ package com.sdds.compose.uikit.fixtures.testcases import androidx.compose.runtime.Composable -import androidx.compose.ui.res.painterResource import com.sdds.compose.uikit.CircularProgressBar import com.sdds.compose.uikit.File import com.sdds.compose.uikit.FileActionPlacement @@ -9,6 +8,7 @@ import com.sdds.compose.uikit.FileStyle import com.sdds.compose.uikit.Icon import com.sdds.compose.uikit.IconButton import com.sdds.compose.uikit.ProgressBar +import com.sdds.compose.uikit.resourceImageSource import com.sdds.icons.R /** @@ -32,7 +32,7 @@ fun FileCircularProgressIsLoadingStart(style: FileStyle) { progress = 0.5f, valueContent = { Icon( - painter = painterResource(id = R.drawable.ic_close_16), + source = resourceImageSource(id = R.drawable.ic_close_16), contentDescription = "", ) }, @@ -53,7 +53,7 @@ fun FileLinearProgressIsLoadingHasImageEnd(style: FileStyle) { description = "1.2MB", image = { Icon( - painterResource(R.drawable.ic_file_check_fill_36), + source = resourceImageSource(R.drawable.ic_file_check_fill_36), contentDescription = "", ) }, @@ -84,7 +84,7 @@ fun FileCircularProgressHasImageEnd(style: FileStyle) { description = "1.2MB", image = { Icon( - painterResource(R.drawable.ic_file_check_fill_36), + resourceImageSource(R.drawable.ic_file_check_fill_36), contentDescription = "", ) }, @@ -94,7 +94,7 @@ fun FileCircularProgressHasImageEnd(style: FileStyle) { progress = 0.5f, valueContent = { Icon( - painter = painterResource(id = R.drawable.ic_close_16), + source = resourceImageSource(id = R.drawable.ic_close_16), contentDescription = "", ) }, @@ -121,7 +121,7 @@ fun FileLinearProgressIsLoadingStart(style: FileStyle) { description = "1.2MB", image = { Icon( - painterResource(R.drawable.ic_file_check_fill_36), + resourceImageSource(R.drawable.ic_file_check_fill_36), contentDescription = "", ) }, @@ -157,7 +157,7 @@ fun FileCircularProgressIsLoadingEndLongText(style: FileStyle) { progress = 0.5f, valueContent = { Icon( - painter = painterResource(id = R.drawable.ic_close_16), + source = resourceImageSource(id = R.drawable.ic_close_16), contentDescription = "", ) }, @@ -178,7 +178,7 @@ fun FileCircularProgressIsLoadingHasImageNoDesc(style: FileStyle) { description = "", image = { Icon( - painterResource(R.drawable.ic_file_check_fill_36), + resourceImageSource(R.drawable.ic_file_check_fill_36), contentDescription = "", ) }, @@ -188,7 +188,7 @@ fun FileCircularProgressIsLoadingHasImageNoDesc(style: FileStyle) { progress = 0.5f, valueContent = { Icon( - painter = painterResource(id = R.drawable.ic_close_16), + source = resourceImageSource(id = R.drawable.ic_close_16), contentDescription = "", ) }, diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt index a7838aa3d..b2a37527f 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/CellStyle.kt @@ -83,17 +83,17 @@ interface CellStyle : Style { /** * Cтиль текста disclosure */ - val disclosureTextStyle: TextStyle - - /** - * Стили disclosure - */ @Deprecated( "Use disclosureTextStyles", replaceWith = ReplaceWith( "disclosureTextStyles", ), ) + val disclosureTextStyle: TextStyle + + /** + * Стили disclosure + */ val disclosureTextStyles: StatefulValue /** @@ -175,9 +175,16 @@ private data class DefaultCellStyle( override val counterStyle: CounterStyle, ) : CellStyle { + @Deprecated("Use labelStyles", replaceWith = ReplaceWith("labelStyles")) override val labelStyle: TextStyle get() = labelStyles.getDefaultValue() + + @Deprecated("Use titleStyles", replaceWith = ReplaceWith("titleStyles")) override val titleStyle: TextStyle get() = titleStyles.getDefaultValue() + + @Deprecated("Use subtitleStyles", replaceWith = ReplaceWith("subtitleStyles")) override val subtitleStyle: TextStyle get() = subtitleStyles.getDefaultValue() + + @Deprecated("Use disclosureTextStyles", replaceWith = ReplaceWith("disclosureTextStyles")) override val disclosureTextStyle: TextStyle get() = disclosureTextStyles.getDefaultValue() class Builder : CellStyleBuilder { @@ -196,30 +203,18 @@ private data class DefaultCellStyle( private var switchStyle: SwitchStyle? = null private var counterStyle: CounterStyle? = null - override fun labelStyle(labelStyle: TextStyle) = - labelStyle(labelStyle.asStatefulValue()) - override fun labelStyle(labelStyle: StatefulValue) = apply { this.labelStyle = labelStyle } - override fun titleStyle(titleStyle: TextStyle): CellStyleBuilder = - titleStyle(titleStyle.asStatefulValue()) - override fun titleStyle(titleStyle: StatefulValue) = apply { this.titleStyle = titleStyle } - override fun subtitleStyle(subtitleStyle: TextStyle) = - subtitleStyle(subtitleStyle.asStatefulValue()) - override fun subtitleStyle(subtitleStyle: StatefulValue) = apply { this.subtitleStyle = subtitleStyle } - override fun disclosureTextStyle(disclosureStyle: TextStyle) = - disclosureTextStyle(disclosureStyle.asStatefulValue()) - override fun disclosureTextStyle(disclosureStyle: StatefulValue) = apply { this.disclosureStyle = disclosureStyle } @@ -296,7 +291,8 @@ interface CellStyleBuilder : StyleBuilder { /** * Устанавливает стиль лэйбла */ - fun labelStyle(labelStyle: TextStyle): CellStyleBuilder + fun labelStyle(labelStyle: TextStyle): CellStyleBuilder = + labelStyle(labelStyle.asStatefulValue()) /** * Устанавливает стили лэйбла @@ -306,7 +302,8 @@ interface CellStyleBuilder : StyleBuilder { /** * Устанавливает стиль тайтла */ - fun titleStyle(titleStyle: TextStyle): CellStyleBuilder + fun titleStyle(titleStyle: TextStyle): CellStyleBuilder = + titleStyle(titleStyle.asStatefulValue()) /** * Устанавливает стили тайтла @@ -316,7 +313,8 @@ interface CellStyleBuilder : StyleBuilder { /** * Устанавливает стиль сабтайтла */ - fun subtitleStyle(subtitleStyle: TextStyle): CellStyleBuilder + fun subtitleStyle(subtitleStyle: TextStyle): CellStyleBuilder = + subtitleStyle(subtitleStyle.asStatefulValue()) /** * Устанавливает стили сабтайтла @@ -326,7 +324,8 @@ interface CellStyleBuilder : StyleBuilder { /** * Устанавливает стиль текста disclosure */ - fun disclosureTextStyle(disclosureStyle: TextStyle): CellStyleBuilder + fun disclosureTextStyle(disclosureStyle: TextStyle): CellStyleBuilder = + disclosureTextStyle(disclosureStyle.asStatefulValue()) /** * Устанавливает стили текста disclosure diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Drawer.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Drawer.kt index 711d03998..43a17ded6 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Drawer.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/Drawer.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource @@ -328,7 +329,7 @@ private fun getCloseIcon( { val interactionSource = remember { MutableInteractionSource() } val color by closeIconColor.colorForInteractionAsState(interactionSource) - CompositionLocalProvider(LocalTint provides color) { + CompositionLocalProvider(LocalTintBrushProducer provides { SolidColor(color) }) { closeIcon?.invoke() ?: getDefaultCloseIcon(closeIconRes, interactionSource, onClose)?.invoke() } } diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/File.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/File.kt index 337222730..6c44a24e9 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/File.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/File.kt @@ -15,8 +15,11 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.NonRestartableComposable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp +import com.sdds.compose.uikit.interactions.StatefulValue +import com.sdds.compose.uikit.interactions.asStatefulValue import com.sdds.compose.uikit.internal.cell.BaseCell /** @@ -85,7 +88,11 @@ fun File( gravity = CellGravity.Center, dimensions = object : CellDimensions { override val contentPaddingStart: Dp = style.dimensions.startContentPadding + override val contentPaddingStartValues: StatefulValue = + style.dimensions.startContentPadding.asStatefulValue() override val contentPaddingEnd: Dp = style.dimensions.endContentPadding + override val contentPaddingEndValues: StatefulValue = + style.dimensions.endContentPadding.asStatefulValue() }, startContent = startContent( style = style, @@ -227,7 +234,9 @@ private fun startContent( val imageOrNull: (@Composable RowScope.() -> Unit)? = image?.let { { val color = style.colors.iconColor.colorForInteraction(interactionSource) - CompositionLocalProvider(LocalTint provides color) { + CompositionLocalProvider( + LocalTintBrushProducer provides { SolidColor(color) }, + ) { image.invoke() } } @@ -312,7 +321,7 @@ private fun inlineProgress( return { val iconColor = style.colors.iconColor.colorForInteraction(interactionSource) CompositionLocalProvider( - LocalTint provides iconColor, + LocalTintBrushProducer provides { SolidColor(iconColor) }, LocalCircularProgressBarStyle provides style.circularProgressBarStyle, ) { progress.invoke() @@ -329,7 +338,7 @@ private fun action( return { val iconColor = style.colors.iconColor.colorForInteraction(interactionSource) CompositionLocalProvider( - LocalTint provides iconColor, + LocalTintBrushProducer provides { SolidColor(iconColor) }, LocalIconButtonStyle provides style.actionButtonStyle, ) { action.invoke() diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/internal/cell/BaseCell.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/internal/cell/BaseCell.kt index ac629b610..dea56217d 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/internal/cell/BaseCell.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/internal/cell/BaseCell.kt @@ -33,7 +33,7 @@ import com.sdds.compose.uikit.LocalCounterStyle import com.sdds.compose.uikit.LocalIconButtonStyle import com.sdds.compose.uikit.LocalRadioBoxStyle import com.sdds.compose.uikit.LocalSwitchStyle -import com.sdds.compose.uikit.LocalTint +import com.sdds.compose.uikit.LocalTintBrushProducer import com.sdds.compose.uikit.ProvideTextStyle import com.sdds.compose.uikit.interactions.getValue import com.sdds.compose.uikit.internal.common.StyledText @@ -54,7 +54,9 @@ internal fun BaseCell( endContent: (@Composable RowScope.() -> Unit)? = null, interactionSource: InteractionSource = remember { MutableInteractionSource() }, ) { - val iconTint = style.colors.titleColor.colorForInteraction(interactionSource) + val iconTint = style.colors.titleBrush.getValue(interactionSource) + val contentPaddingStart = dimensions.contentPaddingStartValues.getValue(interactionSource) + val contentPaddingEnd = dimensions.contentPaddingEndValues.getValue(interactionSource) CompositionLocalProvider( LocalAvatarStyle provides style.avatarStyle, LocalIconButtonStyle provides style.iconButtonStyle, @@ -71,10 +73,10 @@ internal fun BaseCell( Row( modifier = Modifier .layoutId("StartContent") - .padding(end = dimensions.contentPaddingStart), + .padding(end = contentPaddingStart), verticalAlignment = Alignment.CenterVertically, ) { - CompositionLocalProvider(LocalTint provides iconTint) { + CompositionLocalProvider(LocalTintBrushProducer provides { iconTint }) { startContent() } } @@ -90,11 +92,11 @@ internal fun BaseCell( if (endContent != null || (disclosureEnabled && disclosureContent != null)) { Row( modifier = Modifier - .padding(start = dimensions.contentPaddingEnd) + .padding(start = contentPaddingEnd) .layoutId("EndContent"), verticalAlignment = Alignment.CenterVertically, ) { - CompositionLocalProvider(LocalTint provides iconTint) { + CompositionLocalProvider(LocalTintBrushProducer provides { iconTint }) { endContent?.invoke(this) } if (disclosureEnabled && disclosureContent != null) { @@ -193,17 +195,17 @@ internal fun ColumnScope.CellCenterContent( StyledText( text = label, textStyle = style.labelStyles.getValue(interactionSource), - textColor = colors.labelColor.colorForInteraction(interactionSource), + textColor = colors.labelBrush.getValue(interactionSource), ) StyledText( text = title, textStyle = style.titleStyles.getValue(interactionSource), - textColor = colors.titleColor.colorForInteraction(interactionSource), + textColor = colors.titleBrush.getValue(interactionSource), ) StyledText( text = subtitle, textStyle = style.subtitleStyles.getValue(interactionSource), - textColor = colors.subtitleColor.colorForInteraction(interactionSource), + textColor = colors.subtitleBrush.getValue(interactionSource), ) } @@ -216,10 +218,11 @@ internal fun ColumnScope.CellCenterContent( subtitleContent: (@Composable () -> Unit)? = null, ) { val colors = style.colors + val labelBrush = colors.labelBrush.getValue(interactionSource) if (labelContent != null) { ProvideTextStyle( style.labelStyles.getValue(interactionSource), - colors.labelColor.colorForInteraction(interactionSource), + brush = { labelBrush }, labelContent, ) } @@ -227,7 +230,7 @@ internal fun ColumnScope.CellCenterContent( if (titleContent != null) { ProvideTextStyle( style.titleStyles.getValue(interactionSource), - colors.titleColor.colorForInteraction(interactionSource), + brush = { labelBrush }, titleContent, ) } @@ -235,7 +238,7 @@ internal fun ColumnScope.CellCenterContent( if (subtitleContent != null) { ProvideTextStyle( style.subtitleStyles.getValue(interactionSource), - colors.subtitleColor.colorForInteraction(interactionSource), + brush = { labelBrush }, subtitleContent, ) } diff --git a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt index 30d9d6597..374c25936 100644 --- a/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt +++ b/sdds-core/uikit-compose/src/main/kotlin/com/sdds/compose/uikit/motion/components/cell/CellMotionStyle.kt @@ -69,12 +69,6 @@ interface CellMotionStyle : MotionStyle { */ val disclosureIconColor: MotionProperty -// /** -// * Анимационный стиль счетчика, отображаемого внутри Cell. -// * Может быть `null`, если счетчик не используется. -// */ -// val counterMotionStyle: CounterMotionStyle? - companion object { /** * Создает билдер для построения [CellMotionStyle].