Use FixedMotionDurationScale for playback and timer animations

(cherry picked from commit 60036036a6)
This commit is contained in:
Niels van Velzen committed 2026-04-18 14:22:48 +02:00
1 parent ce77ed83b2
commit 136a54ebc1
4 files changed
+35 -15

No files matched your search

@@ -0,0 +1,11 @@
package org.jellyfin.androidtv.ui.composable
import androidx.compose.ui.MotionDurationScale
/**
* A [MotionDurationScale] implementation that always returns a fixed scale factor of 1f. To be used for animations that should ignore the
* system animator duration scale.
*/
object FixedMotionDurationScale : MotionDurationScale {
override val scaleFactor: Float = 1f
}
@@ -8,6 +8,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import kotlinx.coroutines.withContext
import org.jellyfin.playback.core.PlaybackManager
import org.jellyfin.playback.core.model.PlayState
import org.jellyfin.playback.core.queue.queue
@@ -52,7 +53,7 @@ fun rememberPlayerProgress(
if (active == Duration.ZERO) animatable.snapTo(0f)
else animatable.snapTo((activeMs / durationMs).coerceIn(0f, 1f))
if (playing) {
if (playing) withContext(FixedMotionDurationScale) {
animatable.animateTo(
targetValue = 1f,
animationSpec = tween(
@@ -37,6 +37,7 @@ import androidx.compose.ui.unit.sp
import androidx.fragment.app.Fragment
import androidx.fragment.compose.content
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.data.service.BackgroundService
import org.jellyfin.androidtv.preference.UserPreferences
@@ -49,6 +50,7 @@ import org.jellyfin.androidtv.ui.base.Text
import org.jellyfin.androidtv.ui.base.button.Button
import org.jellyfin.androidtv.ui.base.button.ProgressButton
import org.jellyfin.androidtv.ui.composable.AsyncImage
import org.jellyfin.androidtv.ui.composable.FixedMotionDurationScale
import org.jellyfin.androidtv.ui.composable.modifier.overscan
import org.jellyfin.androidtv.ui.navigation.Destinations
import org.jellyfin.androidtv.ui.navigation.NavigationRepository
@@ -142,13 +144,15 @@ fun NextUpOverlay(
// Make sure to cancel any running timer
confirmTimer.snapTo(0f)
} else {
confirmTimer.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = durationMillis,
easing = LinearEasing,
),
)
withContext(FixedMotionDurationScale) {
confirmTimer.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = durationMillis,
easing = LinearEasing,
),
)
}
onConfirm()
}
}
@@ -37,6 +37,7 @@ import androidx.compose.ui.unit.sp
import androidx.fragment.app.Fragment
import androidx.fragment.compose.content
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.data.service.BackgroundService
import org.jellyfin.androidtv.ui.background.AppBackground
@@ -47,6 +48,7 @@ import org.jellyfin.androidtv.ui.base.Text
import org.jellyfin.androidtv.ui.base.button.Button
import org.jellyfin.androidtv.ui.base.button.ProgressButton
import org.jellyfin.androidtv.ui.composable.AsyncImage
import org.jellyfin.androidtv.ui.composable.FixedMotionDurationScale
import org.jellyfin.androidtv.ui.composable.modifier.overscan
import org.jellyfin.androidtv.ui.navigation.Destinations
import org.jellyfin.androidtv.ui.navigation.NavigationRepository
@@ -137,13 +139,15 @@ fun StillWatchingOverlay(
val api = koinInject<ApiClient>()
val endWatchingTimer = remember { Animatable(0f) }
LaunchedEffect(item) {
endWatchingTimer.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = TIMEOUT_IN_MS,
easing = LinearEasing,
),
)
withContext(FixedMotionDurationScale) {
endWatchingTimer.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = TIMEOUT_IN_MS,
easing = LinearEasing,
),
)
}
onCancel()
}