- Migrates Gallery to not play videos and simply display a tumbnail when it is a video
- Fixes incorrect aspect ratios of the AutoNonLazyGrid when multiple images exist for a single entry - Adds Play buttons when the image fails to load so that people click and the post appears.
This commit is contained in:
+7
-9
@@ -24,10 +24,12 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
|||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription
|
||||||
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||||
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
@@ -45,7 +47,6 @@ fun GalleryCardCompose(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
WatchNoteEvent(baseNote = baseNote, accountViewModel = accountViewModel, nav, shortPreview = true) {
|
WatchNoteEvent(baseNote = baseNote, accountViewModel = accountViewModel, nav, shortPreview = true) {
|
||||||
CheckHiddenFeedWatchBlockAndReport(
|
CheckHiddenFeedWatchBlockAndReport(
|
||||||
@@ -66,15 +67,15 @@ fun GalleryCardCompose(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (redirectToEventId != null) {
|
if (redirectToEventId != null) {
|
||||||
LoadNote(baseNoteHex = redirectToEventId, accountViewModel = accountViewModel) { sourceNote ->
|
LoadNote(baseNoteHex = redirectToEventId, accountViewModel = accountViewModel) { baseSourceNote ->
|
||||||
if (sourceNote != null) {
|
if (baseSourceNote != null) {
|
||||||
|
val sourceNote by observeNote(baseSourceNote, accountViewModel)
|
||||||
RedirectableGalleryCard(
|
RedirectableGalleryCard(
|
||||||
galleryNote = baseNote,
|
galleryNote = baseNote,
|
||||||
sourceNote = sourceNote,
|
sourceNote = sourceNote.note,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
ratio = ratio,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
RedirectableGalleryCard(
|
RedirectableGalleryCard(
|
||||||
@@ -83,7 +84,6 @@ fun GalleryCardCompose(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
ratio = ratio,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,6 @@ fun GalleryCardCompose(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
ratio = ratio,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +107,6 @@ fun RedirectableGalleryCard(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
QuickActionGallery(baseNote = galleryNote, accountViewModel = accountViewModel) { showPopup ->
|
QuickActionGallery(baseNote = galleryNote, accountViewModel = accountViewModel) { showPopup ->
|
||||||
ClickableNote(
|
ClickableNote(
|
||||||
@@ -127,7 +125,7 @@ fun RedirectableGalleryCard(
|
|||||||
note = galleryNote,
|
note = galleryNote,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
) {
|
) {
|
||||||
GalleryThumbnail(galleryNote, accountViewModel, nav, ratio = ratio)
|
GalleryThumbnail(galleryNote, accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-114
@@ -20,63 +20,58 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.PlayCircleOutline
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.ui.AspectRatioFrameLayout
|
|
||||||
import androidx.media3.ui.PlayerView
|
|
||||||
import coil3.compose.AsyncImagePainter
|
import coil3.compose.AsyncImagePainter
|
||||||
import coil3.compose.SubcomposeAsyncImage
|
import coil3.compose.SubcomposeAsyncImage
|
||||||
import coil3.compose.SubcomposeAsyncImageContent
|
import coil3.compose.SubcomposeAsyncImageContent
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent
|
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlContent
|
||||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser.Companion.isVideoUrl
|
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser.Companion.isVideoUrl
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.playback.composable.GetVideoController
|
|
||||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem
|
|
||||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNote
|
||||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||||
import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid
|
import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid
|
||||||
import com.vitorpamplona.amethyst.ui.components.ClickableUrl
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash
|
import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash
|
||||||
import com.vitorpamplona.amethyst.ui.components.ImageUrlWithDownloadButton
|
|
||||||
import com.vitorpamplona.amethyst.ui.components.LoadingAnimation
|
import com.vitorpamplona.amethyst.ui.components.LoadingAnimation
|
||||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.note.DownloadForOfflineIcon
|
|
||||||
import com.vitorpamplona.amethyst.ui.note.WatchAuthor
|
import com.vitorpamplona.amethyst.ui.note.WatchAuthor
|
||||||
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
|
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size75dp
|
import com.vitorpamplona.amethyst.ui.theme.Size50Modifier
|
||||||
import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent
|
import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryEvent
|
||||||
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
|
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
|
||||||
import com.vitorpamplona.quartz.nip71Video.VideoEvent
|
import com.vitorpamplona.quartz.nip71Video.VideoEvent
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GalleryThumbnail(
|
fun GalleryThumbnail(
|
||||||
baseNote: Note,
|
baseNote: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: INav,
|
nav: INav,
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
val noteState by observeNote(baseNote, accountViewModel)
|
val noteState by observeNote(baseNote, accountViewModel)
|
||||||
val noteEvent = noteState.note.event ?: return
|
val noteEvent = noteState.note.event ?: return
|
||||||
@@ -137,7 +132,7 @@ fun GalleryThumbnail(
|
|||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerRenderGalleryThumb(content, baseNote, accountViewModel, ratio)
|
InnerRenderGalleryThumb(content, baseNote, accountViewModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -145,10 +140,9 @@ fun InnerRenderGalleryThumb(
|
|||||||
content: List<MediaUrlContent>,
|
content: List<MediaUrlContent>,
|
||||||
note: Note,
|
note: Note,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
if (content.isNotEmpty()) {
|
if (content.isNotEmpty()) {
|
||||||
GalleryContentView(content, accountViewModel, ratio = ratio)
|
GalleryContentView(content, accountViewModel)
|
||||||
} else {
|
} else {
|
||||||
DisplayGalleryAuthorBanner(note, accountViewModel)
|
DisplayGalleryAuthorBanner(note, accountViewModel)
|
||||||
}
|
}
|
||||||
@@ -160,28 +154,30 @@ fun DisplayGalleryAuthorBanner(
|
|||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
) {
|
) {
|
||||||
WatchAuthor(note, accountViewModel) { author ->
|
WatchAuthor(note, accountViewModel) { author ->
|
||||||
BannerImage(author, Modifier.fillMaxSize().clip(QuoteBorder), accountViewModel)
|
BannerImage(
|
||||||
|
author,
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clip(QuoteBorder),
|
||||||
|
accountViewModel,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@androidx.annotation.OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun GalleryContentView(
|
fun GalleryContentView(
|
||||||
contentList: List<MediaUrlContent>,
|
contentList: List<MediaUrlContent>,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
AutoNonlazyGrid(contentList.size) { contentIndex ->
|
AutoNonlazyGrid(contentList.size, modifier = Modifier.fillMaxSize()) { contentIndex ->
|
||||||
when (val content = contentList[contentIndex]) {
|
when (val content = contentList[contentIndex]) {
|
||||||
is MediaUrlImage -> {
|
is MediaUrlContent -> {
|
||||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
val hasSensitiveContent =
|
||||||
UrlImageView(content, accountViewModel, ratio = ratio)
|
(content is MediaUrlVideo && content.contentWarning != null) ||
|
||||||
}
|
(content is MediaUrlImage && content.contentWarning != null)
|
||||||
}
|
SensitivityWarning(hasSensitiveContent, accountViewModel) {
|
||||||
|
UrlImageView(content, accountViewModel)
|
||||||
is MediaUrlVideo -> {
|
|
||||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
|
||||||
UrlVideoView(content, accountViewModel, ratio = ratio)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,17 +186,15 @@ fun GalleryContentView(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UrlImageView(
|
fun UrlImageView(
|
||||||
content: MediaUrlImage,
|
content: MediaUrlContent,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
alwayShowImage: Boolean = false,
|
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
) {
|
||||||
val defaultModifier = Modifier.fillMaxSize().aspectRatio(ratio)
|
val defaultModifier = Modifier.fillMaxSize()
|
||||||
|
|
||||||
val showImage =
|
val showImage =
|
||||||
remember {
|
remember {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
if (alwayShowImage) true else accountViewModel.settings.showImages(),
|
accountViewModel.settings.showImages(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +225,14 @@ fun UrlImageView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is AsyncImagePainter.State.Error -> {
|
is AsyncImagePainter.State.Error -> {
|
||||||
ClickableUrl(urlText = "${content.url} ", url = content.url)
|
Box(defaultModifier, contentAlignment = Alignment.Center) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.PlayCircleOutline,
|
||||||
|
contentDescription = stringRes(id = R.string.play),
|
||||||
|
modifier = Size50Modifier,
|
||||||
|
tint = Color.White,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is AsyncImagePainter.State.Success -> {
|
is AsyncImagePainter.State.Success -> {
|
||||||
@@ -249,86 +250,19 @@ fun UrlImageView(
|
|||||||
ContentScale.Crop,
|
ContentScale.Crop,
|
||||||
defaultModifier.clickable { showImage.value = true },
|
defaultModifier.clickable { showImage.value = true },
|
||||||
)
|
)
|
||||||
IconButton(
|
Icon(
|
||||||
modifier = Modifier.size(Size75dp),
|
imageVector = Icons.Default.PlayCircleOutline,
|
||||||
onClick = { showImage.value = true },
|
contentDescription = stringRes(id = R.string.play),
|
||||||
) {
|
modifier = Size50Modifier,
|
||||||
DownloadForOfflineIcon(Size75dp, Color.White)
|
tint = Color.White,
|
||||||
}
|
)
|
||||||
} else {
|
} else {
|
||||||
ImageUrlWithDownloadButton(content.url, showImage)
|
Icon(
|
||||||
}
|
imageVector = Icons.Default.PlayCircleOutline,
|
||||||
}
|
contentDescription = stringRes(id = R.string.play),
|
||||||
}
|
modifier = Size50Modifier,
|
||||||
}
|
tint = Color.White,
|
||||||
|
)
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
@Composable
|
|
||||||
fun UrlVideoView(
|
|
||||||
content: MediaUrlVideo,
|
|
||||||
accountViewModel: AccountViewModel,
|
|
||||||
ratio: Float = 1.0f,
|
|
||||||
) {
|
|
||||||
val defaultModifier = Modifier.fillMaxSize().aspectRatio(ratio)
|
|
||||||
|
|
||||||
val automaticallyStartPlayback =
|
|
||||||
remember(content) {
|
|
||||||
mutableStateOf<Boolean>(accountViewModel.settings.startVideoPlayback())
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(defaultModifier, contentAlignment = Alignment.Center) {
|
|
||||||
if (content.blurhash != null) {
|
|
||||||
// Always displays Blurharh to avoid size flickering
|
|
||||||
DisplayBlurHash(
|
|
||||||
content.blurhash,
|
|
||||||
null,
|
|
||||||
ContentScale.Crop,
|
|
||||||
defaultModifier,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!automaticallyStartPlayback.value) {
|
|
||||||
IconButton(
|
|
||||||
modifier = Modifier.size(Size75dp),
|
|
||||||
onClick = { automaticallyStartPlayback.value = true },
|
|
||||||
) {
|
|
||||||
DownloadForOfflineIcon(Size75dp, Color.White)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GetMediaItem(
|
|
||||||
videoUri = content.url,
|
|
||||||
title = content.description,
|
|
||||||
artworkUri = content.artworkUri,
|
|
||||||
authorName = content.authorName,
|
|
||||||
callbackUri = content.uri,
|
|
||||||
mimeType = content.mimeType,
|
|
||||||
aspectRatio = ratio,
|
|
||||||
proxyPort = accountViewModel.httpClientBuilder.proxyPortForVideo(content.url),
|
|
||||||
) { mediaItem ->
|
|
||||||
GetVideoController(
|
|
||||||
mediaItem = mediaItem,
|
|
||||||
muted = true,
|
|
||||||
) { controller ->
|
|
||||||
AndroidView(
|
|
||||||
modifier = Modifier,
|
|
||||||
factory = { context: Context ->
|
|
||||||
PlayerView(context).apply {
|
|
||||||
clipToOutline = true
|
|
||||||
player = controller.controller
|
|
||||||
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
|
|
||||||
|
|
||||||
controllerAutoShow = false
|
|
||||||
useController = false
|
|
||||||
|
|
||||||
hideController()
|
|
||||||
|
|
||||||
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL
|
|
||||||
|
|
||||||
controller.controller?.playWhenReady = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -115,7 +115,6 @@ private fun GalleryFeedLoaded(
|
|||||||
.animateItem(),
|
.animateItem(),
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
nav = nav,
|
nav = nav,
|
||||||
ratio = ratio,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ androidx-media3-exoplayer = { group = "androidx.media3", name = "media3-exoplaye
|
|||||||
androidx-media3-exoplayer-hls = { group = "androidx.media3", name = "media3-exoplayer-hls", version.ref = "media3" }
|
androidx-media3-exoplayer-hls = { group = "androidx.media3", name = "media3-exoplayer-hls", version.ref = "media3" }
|
||||||
androidx-media3-session = { group = "androidx.media3", name = "media3-session", version.ref = "media3" }
|
androidx-media3-session = { group = "androidx.media3", name = "media3-session", version.ref = "media3" }
|
||||||
androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3" }
|
androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3" }
|
||||||
|
androidx-media3-ui-compose-material3 = { group = "androidx.media3", name = "media3-ui-compose-material3", version.ref = "media3" }
|
||||||
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
||||||
androidx-runner = { group = "androidx.test", name = "runner", version.ref = "runner" }
|
androidx-runner = { group = "androidx.test", name = "runner", version.ref = "runner" }
|
||||||
androidx-security-crypto-ktx = { group = "androidx.security", name = "security-crypto-ktx", version.ref = "securityCryptoKtx" }
|
androidx-security-crypto-ktx = { group = "androidx.security", name = "security-crypto-ktx", version.ref = "securityCryptoKtx" }
|
||||||
@@ -114,6 +115,7 @@ coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref
|
|||||||
coil-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version.ref = "coil" }
|
coil-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version.ref = "coil" }
|
||||||
coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" }
|
coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" }
|
||||||
coil-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" }
|
coil-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" }
|
||||||
|
coil-video = { group = "io.coil-kt.coil3", name = "coil-video", version.ref = "coil" }
|
||||||
drfonfon-geohash = { group = "com.github.drfonfon", name = "android-kotlin-geohash", version.ref = "androidKotlinGeohash" }
|
drfonfon-geohash = { group = "com.github.drfonfon", name = "android-kotlin-geohash", version.ref = "androidKotlinGeohash" }
|
||||||
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
|
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
|
||||||
firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" }
|
firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging" }
|
||||||
|
|||||||
Reference in New Issue
Block a user