commit 8c6bdf95da7975bbd7e69323cf8d1c172923fbb7
parent 8caf08560218ea2c1c68100cbf356194de04ccd4
Author: Devota Aabel <daabel@mozilla.com>
Date: Thu, 4 Dec 2025 16:32:56 +0000
Bug 1991955- move skeleton loader to AC. r=gl,android-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D269779
Diffstat:
3 files changed, 45 insertions(+), 44 deletions(-)
diff --git a/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/modifier/Modifier.kt b/mobile/android/android-components/components/compose/base/src/main/java/mozilla/components/compose/base/modifier/Modifier.kt
@@ -7,7 +7,15 @@ package mozilla.components.compose.base.modifier
import android.graphics.Rect
import android.os.SystemClock
import androidx.annotation.FloatRange
+import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
@@ -257,6 +265,41 @@ fun Modifier.horizontalFadeGradient(
)
/**
+ * Applies a shimmering skeleton loading effect to the current [Modifier].
+ *
+ * This can be used as a placeholder for UI elements while their content is loading.
+ *
+ * @param durationMillis The duration in milliseconds of the shimmer animation cycle.
+ * Defaults to `1000`.
+ * @param initialColor The starting color of the gradient animation. Defaults to [Color.LightGray].
+ * @param targetColor The ending color of the gradient animation. Defaults to [Color.White].
+ *
+ * @return A [Modifier] that displays a skeleton loader effect.
+ */
+@Composable
+fun Modifier.skeletonLoader(
+ durationMillis: Int = 1000,
+ initialColor: Color = MaterialTheme.colorScheme.surfaceContainerHighest,
+ targetColor: Color = Color.White,
+): Modifier {
+ val transition = rememberInfiniteTransition(label = "infinite")
+
+ val color by transition.animateColor(
+ initialValue = initialColor,
+ targetValue = targetColor,
+ animationSpec = infiniteRepeatable(
+ animation = tween(durationMillis, easing = LinearEasing),
+ repeatMode = RepeatMode.Reverse,
+ ),
+ label = "color",
+ )
+
+ return drawBehind {
+ drawRect(color = color)
+ }
+}
+
+/**
* Describes the direction of fade for [Modifier.horizontalFadeGradient].
*/
enum class FadeDirection {
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/compose/ListItemTabSurface.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/compose/ListItemTabSurface.kt
@@ -4,12 +4,6 @@
package org.mozilla.fenix.compose
-import androidx.compose.animation.animateColor
-import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.RepeatMode
-import androidx.compose.animation.core.infiniteRepeatable
-import androidx.compose.animation.core.rememberInfiniteTransition
-import androidx.compose.animation.core.tween
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -29,16 +23,15 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import mozilla.components.compose.base.modifier.skeletonLoader
import mozilla.components.compose.base.modifier.thenConditional
import org.mozilla.fenix.theme.FirefoxTheme
@@ -141,38 +134,3 @@ private fun ListItemTabSurfaceWithCustomBackgroundPreview() {
}
}
}
-
-/**
- * Applies a shimmering skeleton loading effect to the current [Modifier].
- *
- * This can be used as a placeholder for UI elements while their content is loading.
- *
- * @param durationMillis The duration in milliseconds of the shimmer animation cycle.
- * Defaults to `1000`.
- * @param initialColor The starting color of the gradient animation.
- * @param targetColor The ending color of the gradient animation.
- *
- * @return A [Modifier] that displays a skeleton loader effect.
- */
-@Composable
-fun Modifier.skeletonLoader(
- durationMillis: Int = 1000,
- initialColor: Color = MaterialTheme.colorScheme.surfaceContainerHighest,
- targetColor: Color = Color.White,
-): Modifier {
- val transition = rememberInfiniteTransition(label = "")
-
- val color by transition.animateColor(
- initialValue = initialColor,
- targetValue = targetColor,
- animationSpec = infiniteRepeatable(
- animation = tween(durationMillis, easing = LinearEasing),
- repeatMode = RepeatMode.Reverse,
- ),
- label = "",
- )
-
- return drawBehind {
- drawRect(color = color)
- }
-}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/ui/StoryCard.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/pocket/ui/StoryCard.kt
@@ -27,6 +27,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
+import mozilla.components.compose.base.modifier.skeletonLoader
import mozilla.components.service.pocket.PocketStory
import mozilla.components.service.pocket.PocketStory.ContentRecommendation
import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory
@@ -34,7 +35,6 @@ import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory
import mozilla.components.service.pocket.PocketStory.SponsoredContent
import org.mozilla.fenix.compose.Favicon
import org.mozilla.fenix.compose.Image
-import org.mozilla.fenix.compose.skeletonLoader
import org.mozilla.fenix.home.fake.FakeHomepagePreview
import org.mozilla.fenix.theme.FirefoxTheme
import kotlin.math.roundToInt