feat: replace bounce marquee with constant-speed ticker
Replaces BounceMarqueeText with TickerText that scrolls at a fixed 33 dp/s regardless of text length. Text scrolls left off-screen with a container-width gap before looping. Initial 1.5s delay lets the user read the beginning. Made-with: Cursor
This commit is contained in:
@@ -5,7 +5,6 @@ import android.content.res.Configuration
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
|
||||||
import androidx.compose.animation.core.LinearEasing
|
import androidx.compose.animation.core.LinearEasing
|
||||||
import androidx.compose.animation.core.RepeatMode
|
import androidx.compose.animation.core.RepeatMode
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
@@ -447,12 +446,13 @@ private fun ArtworkImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun BounceMarqueeText(
|
private fun TickerText(
|
||||||
text: String,
|
text: String,
|
||||||
style: TextStyle,
|
style: TextStyle,
|
||||||
color: Color,
|
color: Color,
|
||||||
strokeColor: Color? = null,
|
strokeColor: Color? = null,
|
||||||
strokeWidth: Float = 2f,
|
strokeWidth: Float = 2f,
|
||||||
|
velocityDpPerSecond: Float = 33f,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
@@ -475,25 +475,26 @@ private fun BounceMarqueeText(
|
|||||||
|
|
||||||
if (overflowPx > 0f) {
|
if (overflowPx > 0f) {
|
||||||
key(text) {
|
key(text) {
|
||||||
val scrollMs = ((overflowPx / density.density) * 18f).toInt().coerceIn(2000, 8000)
|
val velocityPxPerMs = with(density) { velocityDpPerSecond.dp.toPx() } / 1000f
|
||||||
val pauseMs = 1500
|
val totalScrollPx = textWidthPx + containerWidthPx
|
||||||
val totalMs = pauseMs + scrollMs + pauseMs + scrollMs
|
val scrollMs = (totalScrollPx / velocityPxPerMs).toInt()
|
||||||
|
val initialDelayMs = 1500
|
||||||
|
val durationMs = initialDelayMs + scrollMs
|
||||||
|
|
||||||
val transition = rememberInfiniteTransition(label = "marquee")
|
val transition = rememberInfiniteTransition(label = "ticker")
|
||||||
val offset by transition.animateFloat(
|
val offset by transition.animateFloat(
|
||||||
initialValue = 0f,
|
initialValue = 0f,
|
||||||
targetValue = 0f,
|
targetValue = 0f,
|
||||||
animationSpec = infiniteRepeatable(
|
animationSpec = infiniteRepeatable(
|
||||||
animation = keyframes {
|
animation = keyframes {
|
||||||
durationMillis = totalMs
|
durationMillis = durationMs
|
||||||
0f at 0 using LinearEasing
|
0f at 0 using LinearEasing
|
||||||
0f at pauseMs using FastOutSlowInEasing
|
0f at initialDelayMs using LinearEasing
|
||||||
-overflowPx at (pauseMs + scrollMs) using LinearEasing
|
-totalScrollPx at durationMs using LinearEasing
|
||||||
-overflowPx at (pauseMs + scrollMs + pauseMs) using FastOutSlowInEasing
|
|
||||||
},
|
},
|
||||||
repeatMode = RepeatMode.Restart
|
repeatMode = RepeatMode.Restart
|
||||||
),
|
),
|
||||||
label = "bounce"
|
label = "ticker"
|
||||||
)
|
)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
@@ -575,7 +576,7 @@ private fun TrackInfoSection(
|
|||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
BounceMarqueeText(
|
TickerText(
|
||||||
text = trackText,
|
text = trackText,
|
||||||
style = trackStyle,
|
style = trackStyle,
|
||||||
color = trackColor,
|
color = trackColor,
|
||||||
|
|||||||
Reference in New Issue
Block a user