Merge pull request #2817 from davotoula/fix/gallery-forward-thumbhash
fix(gallery): forward imeta hashes through gallery
This commit is contained in:
+11
-1
@@ -70,6 +70,7 @@ fun VideoView(
|
||||
alwaysShowVideo: Boolean = false,
|
||||
thumbhash: String? = null,
|
||||
isLiveStream: Boolean = false,
|
||||
hash: String? = null,
|
||||
) {
|
||||
val borderModifier =
|
||||
if (roundedCorner) {
|
||||
@@ -80,7 +81,7 @@ fun VideoView(
|
||||
Modifier
|
||||
}
|
||||
|
||||
VideoView(videoUri, mimeType, title, thumb, borderModifier, contentScale, waveform, artworkUri, authorName, dimensions, blurhash, nostrUriCallback, onDialog, alwaysShowVideo, accountViewModel = accountViewModel, thumbhash = thumbhash, isLiveStream = isLiveStream)
|
||||
VideoView(videoUri, mimeType, title, thumb, borderModifier, contentScale, waveform, artworkUri, authorName, dimensions, blurhash, nostrUriCallback, onDialog, alwaysShowVideo, accountViewModel = accountViewModel, thumbhash = thumbhash, isLiveStream = isLiveStream, hash = hash)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -103,6 +104,7 @@ fun VideoView(
|
||||
isLiveStream: Boolean = false,
|
||||
accountViewModel: AccountViewModel,
|
||||
thumbhash: String? = null,
|
||||
hash: String? = null,
|
||||
) {
|
||||
val initialAutoStart = if (alwaysShowVideo) true else accountViewModel.settings.startVideoPlayback()
|
||||
// Reset the manual-show toggle when the video URI changes so a recycled feed slot
|
||||
@@ -160,6 +162,10 @@ fun VideoView(
|
||||
isLiveStream = isLiveStream,
|
||||
onZoom = onDialog,
|
||||
hasBlurhash = false,
|
||||
blurhash = blurhash,
|
||||
dim = dimensions,
|
||||
hash = hash,
|
||||
thumbhash = thumbhash,
|
||||
accountViewModel = accountViewModel,
|
||||
showControls = showControls,
|
||||
)
|
||||
@@ -207,6 +213,10 @@ fun VideoView(
|
||||
isLiveStream = isLiveStream,
|
||||
onZoom = onDialog,
|
||||
hasBlurhash = true,
|
||||
blurhash = blurhash,
|
||||
dim = dimensions,
|
||||
hash = hash,
|
||||
thumbhash = thumbhash,
|
||||
accountViewModel = accountViewModel,
|
||||
showControls = showControls,
|
||||
)
|
||||
|
||||
+9
@@ -31,6 +31,7 @@ import com.vitorpamplona.amethyst.service.playback.composable.controls.VideoQual
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mainVideo.VideoPlayerActiveMutex
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
|
||||
val DEFAULT_MUTED_SETTING = mutableStateOf(true)
|
||||
|
||||
@@ -54,6 +55,10 @@ fun VideoViewInner(
|
||||
onZoom: (() -> Unit)? = null,
|
||||
hasBlurhash: Boolean = false,
|
||||
isFullscreen: Boolean = false,
|
||||
blurhash: String? = null,
|
||||
dim: DimensionTag? = null,
|
||||
hash: String? = null,
|
||||
thumbhash: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
// keeps a copy of the value to avoid recompositions here when the DEFAULT value changes
|
||||
@@ -76,6 +81,10 @@ fun VideoViewInner(
|
||||
keepPlaying = true,
|
||||
waveformData = waveform,
|
||||
isLiveStream = isLiveStream,
|
||||
blurhash = blurhash,
|
||||
dim = dim,
|
||||
hash = hash,
|
||||
thumbhash = thumbhash,
|
||||
) { mediaItem ->
|
||||
GetVideoController(
|
||||
mediaItem = mediaItem,
|
||||
|
||||
+7
-3
@@ -303,9 +303,9 @@ fun RenderTopButtons(
|
||||
popupExpanded = shareDialogVisible,
|
||||
videoUri = mediaData.videoUri,
|
||||
postNostrUri = mediaData.callbackUri,
|
||||
blurhash = null,
|
||||
dim = null,
|
||||
hash = null,
|
||||
blurhash = mediaData.blurhash,
|
||||
dim = mediaData.dim,
|
||||
hash = mediaData.hash,
|
||||
mimeType = mediaData.mimeType,
|
||||
onDismiss = { shareDialogVisible.value = false },
|
||||
content =
|
||||
@@ -316,6 +316,10 @@ fun RenderTopButtons(
|
||||
authorName = mediaData.authorName,
|
||||
description = mediaData.title,
|
||||
uri = mediaData.callbackUri,
|
||||
blurhash = mediaData.blurhash,
|
||||
dim = mediaData.dim,
|
||||
hash = mediaData.hash,
|
||||
thumbhash = mediaData.thumbhash,
|
||||
),
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
|
||||
+9
@@ -25,6 +25,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.commons.compose.produceCachedState
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.WaveformData
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
|
||||
val mediaItemCache = MediaItemCache()
|
||||
|
||||
@@ -41,6 +42,10 @@ fun GetMediaItem(
|
||||
keepPlaying: Boolean = false,
|
||||
waveformData: WaveformData? = null,
|
||||
isLiveStream: Boolean = false,
|
||||
blurhash: String? = null,
|
||||
dim: DimensionTag? = null,
|
||||
hash: String? = null,
|
||||
thumbhash: String? = null,
|
||||
inner: @Composable (LoadedMediaItem) -> Unit,
|
||||
) {
|
||||
val data =
|
||||
@@ -57,6 +62,10 @@ fun GetMediaItem(
|
||||
keepPlaying = keepPlaying,
|
||||
waveformData = waveformData,
|
||||
isLiveStream = isLiveStream,
|
||||
blurhash = blurhash,
|
||||
dim = dim,
|
||||
hash = hash,
|
||||
thumbhash = thumbhash,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service.playback.composable.mediaitem
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.media3.common.MediaItem
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.WaveformData
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
|
||||
@Immutable
|
||||
data class MediaItemData(
|
||||
@@ -40,6 +41,13 @@ data class MediaItemData(
|
||||
// (e.g. multi-rendition NIP-71 videos) must leave this false so that
|
||||
// ExoPlayer's SimpleCache can cache their immutable segments.
|
||||
val isLiveStream: Boolean = false,
|
||||
// Source-imeta visual fields — carried through so the player's "Add to Gallery" /
|
||||
// "Share" actions can publish a richer ProfileGalleryEntryEvent. Optional; null when
|
||||
// the surface that constructed this MediaItemData didn't have them.
|
||||
val blurhash: String? = null,
|
||||
val dim: DimensionTag? = null,
|
||||
val hash: String? = null,
|
||||
val thumbhash: String? = null,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
|
||||
+14
-3
@@ -48,6 +48,8 @@ data class PreviewHashes(
|
||||
}
|
||||
|
||||
object PreviewMetadataCalculator {
|
||||
private const val LOG_TAG = "PreviewMetadataCalc"
|
||||
|
||||
private fun isImage(mimeType: String?) = mimeType?.startsWith("image/", ignoreCase = true) == true
|
||||
|
||||
private fun isVideo(mimeType: String?) = mimeType?.startsWith("video/", ignoreCase = true) == true
|
||||
@@ -117,7 +119,7 @@ object PreviewMetadataCalculator {
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w("PreviewMetadataCalc", "Failed to compute metadata from uri", e)
|
||||
Log.w(LOG_TAG, "Failed to compute metadata from uri", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -133,8 +135,14 @@ object PreviewMetadataCalculator {
|
||||
private fun processBitmap(bitmap: Bitmap?): PreviewHashes =
|
||||
if (bitmap != null) {
|
||||
try {
|
||||
val blurhash = runCatching { BlurhashWrapper(bitmap.toBlurhash()) }.getOrNull()
|
||||
val thumbhash = runCatching { ThumbhashWrapper(bitmap.toThumbhash()) }.getOrNull()
|
||||
val blurhash =
|
||||
runCatching { BlurhashWrapper(bitmap.toBlurhash()) }
|
||||
.onFailure { Log.w(LOG_TAG, "blurhash generation failed", it) }
|
||||
.getOrNull()
|
||||
val thumbhash =
|
||||
runCatching { ThumbhashWrapper(bitmap.toThumbhash()) }
|
||||
.onFailure { Log.w(LOG_TAG, "thumbhash generation failed", it) }
|
||||
.getOrNull()
|
||||
PreviewHashes(
|
||||
blurhash = blurhash,
|
||||
thumbhash = thumbhash,
|
||||
@@ -153,6 +161,9 @@ object PreviewMetadataCalculator {
|
||||
): PreviewHashes {
|
||||
val dim = retriever.prepareDimFromVideo() ?: dimPrecomputed
|
||||
val thumb = retriever.getThumbnail()
|
||||
if (thumb == null) {
|
||||
Log.w(LOG_TAG) { "video frame extraction returned null; no blurhash/thumbhash will be generated" }
|
||||
}
|
||||
val hashes = processBitmap(thumb)
|
||||
val finalDim = if (dim?.hasSize() == true) dim else hashes.dim
|
||||
return hashes.copy(dim = finalDim)
|
||||
|
||||
+5
-1
@@ -226,6 +226,7 @@ fun ZoomableContentView(
|
||||
accountViewModel = accountViewModel,
|
||||
thumbhash = content.thumbhash,
|
||||
isLiveStream = content.isLiveStream,
|
||||
hash = content.hash,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -961,7 +962,10 @@ fun ShareMediaAction(
|
||||
// still — the .m3u8 URL itself is a text manifest. Only
|
||||
// MediaUrlVideo carries an artworkUri.
|
||||
val posterUrl = (content as? MediaUrlVideo)?.artworkUri
|
||||
accountViewModel.addMediaToGallery(n19.hex, videoUri, n19.relay.getOrNull(0), blurhash, dim, hash, mimeType, image = posterUrl)
|
||||
val thumbhashFromContent =
|
||||
(content as? MediaUrlVideo)?.thumbhash
|
||||
?: (content as? MediaUrlImage)?.thumbhash
|
||||
accountViewModel.addMediaToGallery(n19.hex, videoUri, n19.relay.getOrNull(0), blurhash, dim, hash, mimeType, thumbhash = thumbhashFromContent, image = posterUrl)
|
||||
accountViewModel.toastManager.toast(R.string.media_added, R.string.media_added_to_profile_gallery)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -896,8 +896,9 @@ class AccountViewModel(
|
||||
dim: DimensionTag?,
|
||||
hash: String?,
|
||||
mimeType: String?,
|
||||
thumbhash: String? = null,
|
||||
image: String? = null,
|
||||
) = launchSigner { account.addToGallery(hex, url, relay, blurhash, dim, hash, mimeType, image = image) }
|
||||
) = launchSigner { account.addToGallery(hex, url, relay, blurhash, dim, hash, mimeType, thumbhash = thumbhash, image = image) }
|
||||
|
||||
fun removeFromMediaGallery(note: Note) = launchSigner { account.removeFromGallery(note) }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user