From b90dc081b7e27f3a9df3174fe5d3f9b338c2b7c7 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Fri, 17 Oct 2025 12:10:13 +0200 Subject: [PATCH] Fix media viewer not being dismissed with reduced motion enabled (#5555) This is also called 'remove animations' in some Android versions. It seems like the associated coroutine dispatcher never allows the `delay` calls to complete, or maybe they take too long and the coroutine is cancelled before they finish. --- .../androidutils/system/Accessibility.kt | 19 +++++++++++++++++++ .../impl/viewer/MediaViewerFlickToDismiss.kt | 8 +++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/Accessibility.kt diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/Accessibility.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/Accessibility.kt new file mode 100644 index 0000000000..90bb13a703 --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/Accessibility.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.androidutils.system + +import android.content.Context +import android.provider.Settings + +fun Context.getAnimationScale(): Float { + return Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) +} + +fun Context.areAnimationsEnabled(): Boolean { + return getAnimationScale() > 0f +} diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerFlickToDismiss.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerFlickToDismiss.kt index 43880809d9..bd8c5eaae4 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerFlickToDismiss.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerFlickToDismiss.kt @@ -16,7 +16,9 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.androidutils.system.areAnimationsEnabled import kotlinx.coroutines.delay import me.saket.telephoto.ExperimentalTelephotoApi import me.saket.telephoto.flick.FlickToDismiss @@ -34,10 +36,14 @@ fun MediaViewerFlickToDismiss( content: @Composable BoxScope.() -> Unit, ) { val flickState = rememberFlickToDismissState(dismissThresholdRatio = 0.1f, rotateOnDrag = false) + val context = LocalContext.current DismissFlickEffects( flickState = flickState, onDismissing = { animationDuration -> - delay(animationDuration / 3) + // Only add the delay if an animation should be played, otherwise `onDismiss` will never be called + if (context.areAnimationsEnabled()) { + delay(animationDuration / 3) + } onDismiss() }, onDragging = onDragging,