diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 91955251..0ef2064a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,7 @@ android:name=".ui.MainActivity" android:configChanges="keyboardHidden|orientation|screenSize" android:exported="true" + android:supportsPictureInPicture="true" android:enableOnBackInvokedCallback="true" android:launchMode="singleTask"> diff --git a/app/src/main/java/com/maxrave/simpmusic/extension/UIExt.kt b/app/src/main/java/com/maxrave/simpmusic/extension/UIExt.kt index 471a5278..2e71a127 100644 --- a/app/src/main/java/com/maxrave/simpmusic/extension/UIExt.kt +++ b/app/src/main/java/com/maxrave/simpmusic/extension/UIExt.kt @@ -1,12 +1,14 @@ package com.maxrave.simpmusic.extension import android.app.Activity +import android.app.PictureInPictureParams import android.content.Context import android.content.ContextWrapper import android.graphics.Point import android.os.Build import android.util.Log -import android.view.View +import android.view.WindowManager +import androidx.activity.ComponentActivity import androidx.annotation.ColorInt import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable @@ -18,10 +20,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyListItemInfo import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -48,8 +50,6 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.IntSize -import androidx.compose.ui.unit.dp -import androidx.compose.ui.viewinterop.AndroidView import androidx.core.graphics.ColorUtils import com.kmpalette.palette.graphics.Palette import com.maxrave.simpmusic.ui.theme.md_theme_dark_background @@ -395,10 +395,16 @@ fun LazyListState.animateScrollAndCentralizeItem( } @Composable -fun KeepScreenOn() = AndroidView( - factory = { View(it).apply { keepScreenOn = true } }, - modifier = Modifier.size(0.1.dp) -) +fun KeepScreenOn() { + val context = LocalContext.current + DisposableEffect(Unit) { + val window = context.findActivity().window + window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + onDispose { + window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + } +} @Composable fun LazyListState.isScrollingUp(): Boolean { @@ -470,10 +476,51 @@ fun Palette?.getColorFromPalette(): Color { return Color(ColorUtils.setAlphaComponent(startColor, 255)) } -fun Context.findActivity(): Activity? = when (this) { - is Activity -> this - is ContextWrapper -> baseContext.findActivity() - else -> null +fun Context.findActivity(): ComponentActivity { + var context = this + while (context is ContextWrapper) { + if (context is ComponentActivity) return context + context = context.baseContext + } + throw IllegalStateException("Picture in picture should be called in the context of an Activity") +} + +@Composable +fun PipListenerPreAPI12() { + // [START android_compose_pip_pre12_listener] + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + val context = LocalContext.current + DisposableEffect(context) { + val onUserLeaveBehavior: () -> Unit = { + context.findActivity() + .enterPictureInPictureMode(PictureInPictureParams.Builder().build()) + } + context.findActivity().addOnUserLeaveHintListener( + onUserLeaveBehavior + ) + onDispose { + context.findActivity().removeOnUserLeaveHintListener( + onUserLeaveBehavior + ) + } + } + } else { + Log.i("PiP info", "API does not support PiP") + } + // [END android_compose_pip_pre12_listener] +} + +/** + * Android 12 and above Picture in Picture mode + */ +fun Modifier.pipModifier(context: Context) = this.onGloballyPositioned { layoutCoordinates -> + val builder = PictureInPictureParams.Builder() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + builder.setAutoEnterEnabled(true) + } + Log.w("PiP info", "layoutCoordinates: $layoutCoordinates") + context.findActivity().setPictureInPictureParams(builder.build()) } @RequiresOptIn( diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/component/MediaPlayerView.kt b/app/src/main/java/com/maxrave/simpmusic/ui/component/MediaPlayerView.kt index 147793ad..268075e3 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/component/MediaPlayerView.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/component/MediaPlayerView.kt @@ -1,5 +1,6 @@ package com.maxrave.simpmusic.ui.component +import android.os.Build import android.util.Log import android.view.TextureView import androidx.compose.animation.Crossfade @@ -45,7 +46,9 @@ import coil3.request.crossfade import coil3.toCoilUri import com.maxrave.simpmusic.common.Config import com.maxrave.simpmusic.extension.KeepScreenOn +import com.maxrave.simpmusic.extension.PipListenerPreAPI12 import com.maxrave.simpmusic.extension.getScreenSizeInfo +import com.maxrave.simpmusic.extension.pipModifier import org.koin.compose.koinInject import org.koin.core.qualifier.named import kotlin.math.roundToInt @@ -166,7 +169,9 @@ fun MediaPlayerView( fun MediaPlayerView( player: ExoPlayer, modifier: Modifier = Modifier, + pipSupport: Boolean = false, ) { + val context = LocalContext.current var videoRatio by rememberSaveable { mutableFloatStateOf(16f / 9) } @@ -179,6 +184,10 @@ fun MediaPlayerView( mutableStateOf(false) } + if (pipSupport) { + PipListenerPreAPI12() + } + val playerListener = remember { object : Player.Listener { @@ -220,7 +229,13 @@ fun MediaPlayerView( } Box( - modifier, + modifier.then( + if (pipSupport && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Modifier.pipModifier(context) + } else { + Modifier + } + ), contentAlignment = Alignment.Center ) { if (keepScreenOn) { diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/screen/player/FullscreenPlayer.kt b/app/src/main/java/com/maxrave/simpmusic/ui/screen/player/FullscreenPlayer.kt index 4781af0d..c01e8b7b 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/screen/player/FullscreenPlayer.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/screen/player/FullscreenPlayer.kt @@ -39,6 +39,8 @@ import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Replay5 import androidx.compose.material.icons.filled.SkipNext import androidx.compose.material.icons.filled.SkipPrevious +import androidx.compose.material.icons.filled.Subtitles +import androidx.compose.material.icons.filled.SubtitlesOff import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.Icon @@ -57,6 +59,7 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -71,6 +74,7 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @@ -126,7 +130,7 @@ fun FullscreenPlayer( } LaunchedEffect(true) { - val activity = context.findActivity() ?: return@LaunchedEffect + val activity = context.findActivity() val window = activity.window val insetsController = WindowCompat.getInsetsController(window, window.decorView) insetsController.apply { @@ -194,15 +198,110 @@ fun FullscreenPlayer( } } + var currentLineIndex by rememberSaveable { + mutableIntStateOf(-1) + } + var shouldShowSubtitle by rememberSaveable { + mutableStateOf(true) + } + LaunchedEffect(key1 = timelineState) { + val lines = nowPlayingState.lyricsData?.lyrics?.lines ?: return@LaunchedEffect + if (timelineState.current > 0L) { + lines.indices.forEach { i -> + val sentence = lines[i] + val startTimeMs = sentence.startTimeMs.toLong() + + // estimate the end time of the current sentence based on the start time of the next sentence + val endTimeMs = + if (i < lines.size - 1) { + lines[i + 1].startTimeMs.toLong() + } else { + // if this is the last sentence, set the end time to be some default value (e.g., 1 minute after the start time) + startTimeMs + 60000 + } + if (timelineState.current in startTimeMs..endTimeMs) { + currentLineIndex = i + } + } + if (lines.isNotEmpty() && + ( + timelineState.current in ( + 0..( + lines.getOrNull(0)?.startTimeMs + ?: "0" + ).toLong() + ) + ) + ) { + currentLineIndex = -1 + } + } else { + currentLineIndex = -1 + } + } + Box { MediaPlayerView( player = player, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), + pipSupport = true ) + if (nowPlayingState.lyricsData != null && !context.findActivity().isInPictureInPictureMode && shouldShowSubtitle) { + Crossfade(currentLineIndex != -1) { + val lines = nowPlayingState.lyricsData?.lyrics?.lines ?: return@Crossfade + if (it) { + Box( + Modifier.fillMaxWidth() + .fillMaxHeight() + .padding(bottom = 40.dp) + .align(Alignment.BottomCenter), + contentAlignment = Alignment.BottomCenter + ) { + Box(Modifier.fillMaxWidth(0.7f)) { + Column( + Modifier.align(Alignment.BottomCenter), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = lines.getOrNull(currentLineIndex)?.words ?: return@Crossfade, + style = typo.bodyLarge, + color = Color.White, + textAlign = TextAlign.Center, + modifier = Modifier + .padding(4.dp) + .background(Color.Black.copy(alpha = 0.5f)) + .wrapContentWidth() + ) + Crossfade(nowPlayingState.lyricsData?.translatedLyrics?.lines != null, label = "") { translate -> + val translateLines = nowPlayingState.lyricsData?.translatedLyrics?.lines ?: return@Crossfade + if (translate) { + Text( + text = translateLines.getOrNull(currentLineIndex)?.words ?: return@Crossfade, + style = typo.bodyMedium, + color = Color.Yellow, + textAlign = TextAlign.Center, + modifier = Modifier + .background(Color.Black.copy(alpha = 0.5f)) + .wrapContentWidth() + ) + } + } + } + } + } + } + } + } Row(Modifier.fillMaxSize()) { // Left side Box( Modifier.fillMaxHeight().weight(1f) + .clip( + RoundedCornerShape( + topEndPercent = 10, + bottomEndPercent = 10 + ) + ) .indication( interactionSource = interactionSourceBackward, indication = ripple() @@ -249,6 +348,12 @@ fun FullscreenPlayer( } Box( Modifier.fillMaxHeight().weight(1f) + .clip( + RoundedCornerShape( + topStartPercent = 10, + bottomStartPercent = 10 + ) + ) .indication( interactionSource = interactionSourceForward, indication = ripple() @@ -517,31 +622,75 @@ fun FullscreenPlayer( style = typo.bodySmall ) } - FilledTonalIconButton( - colors = - IconButtonDefaults.iconButtonColors().copy( - containerColor = Color.Transparent, - ), - modifier = + Row( Modifier - .size(32.dp) - .aspectRatio(1f) - .clip( - CircleShape, - ) .align(Alignment.CenterEnd), - onClick = { - navController.navigateUp() - }, + verticalAlignment = Alignment.CenterVertically, ) { - Icon( - imageVector = Icons.Filled.FullscreenExit, - tint = Color.White, - contentDescription = "", + FilledTonalIconButton( + colors = + IconButtonDefaults.iconButtonColors().copy( + containerColor = Color.Transparent, + ), modifier = Modifier - .size(24.dp) - ) + .size(32.dp) + .aspectRatio(1f) + .clip( + CircleShape, + ), + onClick = { + shouldShowSubtitle = !shouldShowSubtitle + }, + ) { + Crossfade(shouldShowSubtitle) { + if (it) { + Icon( + imageVector = Icons.Filled.SubtitlesOff, + tint = Color.White, + contentDescription = "", + modifier = + Modifier + .size(24.dp) + ) + } else { + Icon( + imageVector = Icons.Filled.Subtitles, + tint = Color.White, + contentDescription = "", + modifier = + Modifier + .size(24.dp) + ) + } + } + } + Spacer(Modifier.width(8.dp)) + FilledTonalIconButton( + colors = + IconButtonDefaults.iconButtonColors().copy( + containerColor = Color.Transparent, + ), + modifier = + Modifier + .size(32.dp) + .aspectRatio(1f) + .clip( + CircleShape, + ), + onClick = { + navController.navigateUp() + }, + ) { + Icon( + imageVector = Icons.Filled.FullscreenExit, + tint = Color.White, + contentDescription = "", + modifier = + Modifier + .size(24.dp) + ) + } } } Box( diff --git a/app/src/main/res/raw/aboutlibraries.json b/app/src/main/res/raw/aboutlibraries.json index 24c5b76b..e2ebef21 100644 --- a/app/src/main/res/raw/aboutlibraries.json +++ b/app/src/main/res/raw/aboutlibraries.json @@ -348,14 +348,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose animation library", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Animation", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-animation#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-animation#1.7.6", "licenses": [ "Apache-2.0" ], @@ -373,14 +373,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Animation engine and animation primitives that are the building blocks of the Compose animation library", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Animation Core", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-animation#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-animation#1.7.6", "licenses": [ "Apache-2.0" ], @@ -398,14 +398,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Foundation", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.7.6", "licenses": [ "Apache-2.0" ], @@ -423,14 +423,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose layout implementations", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Layouts", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.7.6", "licenses": [ "Apache-2.0" ], @@ -498,14 +498,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose Material Design Components library", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Material Components", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.6", "licenses": [ "Apache-2.0" ], @@ -523,14 +523,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose Material Design core icons. This module contains the most commonly used set of Material icons.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Material Icons Core", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.6", "licenses": [ "Apache-2.0" ], @@ -548,14 +548,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose Material Design extended icons. This module contains all Material icons. It is a very large dependency and should not be included directly.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Material Icons Extended", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.6", "licenses": [ "Apache-2.0" ], @@ -573,14 +573,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Material ripple used to build interactive components", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Material Ripple", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-material#1.7.6", "licenses": [ "Apache-2.0" ], @@ -598,14 +598,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Tree composition support for code generated by the Compose compiler plugin and corresponding public API", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Runtime", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.7.6", "licenses": [ "Apache-2.0" ], @@ -623,14 +623,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose components that allow saving and restoring the local ui state", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Saveable", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.7.6", "licenses": [ "Apache-2.0" ], @@ -648,14 +648,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose UI", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -673,14 +673,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose classes related to dimensions without units", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Geometry", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -698,14 +698,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose graphics", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Graphics", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -723,14 +723,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose Text primitives and utilities", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose UI Text", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -748,14 +748,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose tooling library API. This library provides the API required to declare @Preview composables in user apps.", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose UI Preview Tooling", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -773,14 +773,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Compose classes for simple units", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Unit", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -798,14 +798,39 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "1.7.5", + "artifactVersion": "1.7.6", "description": "Internal Compose utilities used by other modules", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Compose Util", - "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.5", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", + "licenses": [ + "Apache-2.0" + ], + "organization": { + "name": "The Android Open Source Project" + } + }, + { + "uniqueId": "androidx.compose.ui:ui-viewbinding", + "funding": [ + + ], + "developers": [ + { + "name": "The Android Open Source Project" + } + ], + "artifactVersion": "1.7.6", + "description": "Compose integration with ViewBinding", + "scm": { + "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", + "url": "https://cs.android.com/androidx/platform/frameworks/support" + }, + "name": "Compose ViewBinding", + "website": "https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.6", "licenses": [ "Apache-2.0" ], @@ -821,7 +846,7 @@ "developers": [ ], - "artifactVersion": "2024.11.00", + "artifactVersion": "2024.12.01", "description": "A compatible set of Jetpack Compose libraries.", "name": "Jetpack Compose Libraries BOM", "website": "https://developer.android.com/jetpack", @@ -2429,14 +2454,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Common", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Common", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2454,14 +2479,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Common-Ktx", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Common Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2479,14 +2504,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Fragment", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Fragment", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2504,14 +2529,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Fragment-Ktx", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Fragment Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2529,14 +2554,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Runtime", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Runtime", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2554,14 +2579,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-Runtime-Ktx", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation Runtime Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2579,14 +2604,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-UI", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation UI", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2604,14 +2629,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "2.8.4", + "artifactVersion": "2.8.5", "description": "Android Navigation-UI-Ktx", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Navigation UI Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.4", + "website": "https://developer.android.com/jetpack/androidx/releases/navigation#2.8.5", "licenses": [ "Apache-2.0" ], @@ -2629,14 +2654,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.3.4", + "artifactVersion": "3.3.5", "description": "Android Paging-Common", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Paging-Common", - "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.4", + "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.5", "licenses": [ "Apache-2.0" ], @@ -2654,14 +2679,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.3.4", + "artifactVersion": "3.3.5", "description": "Kotlin extensions for 'paging-common' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Paging-Common Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.4", + "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.5", "licenses": [ "Apache-2.0" ], @@ -2679,14 +2704,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.3.4", + "artifactVersion": "3.3.5", "description": "Compose integration with Paging", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Paging-Compose", - "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.4", + "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.5", "licenses": [ "Apache-2.0" ], @@ -2704,14 +2729,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.3.4", + "artifactVersion": "3.3.5", "description": "Android Paging-Runtime", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Paging-Runtime", - "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.4", + "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.5", "licenses": [ "Apache-2.0" ], @@ -2729,14 +2754,14 @@ "name": "The Android Open Source Project" } ], - "artifactVersion": "3.3.4", + "artifactVersion": "3.3.5", "description": "Kotlin extensions for 'paging-runtime' artifact", "scm": { "connection": "scm:git:https://android.googlesource.com/platform/frameworks/support", "url": "https://cs.android.com/androidx/platform/frameworks/support" }, "name": "Paging-Runtime Kotlin Extensions", - "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.4", + "website": "https://developer.android.com/jetpack/androidx/releases/paging#3.3.5", "licenses": [ "Apache-2.0" ],