mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-26 01:31:58 +01:00
Merge pull request #1001 from believethehype/better_gallery_view
Gallery: use FileHeader Info for rendering / faster loading
This commit is contained in:
commit
4bae04ad31
@ -139,8 +139,6 @@ open class Note(
|
||||
var relays = listOf<RelayBriefInfoCache.RelayBriefInfo>()
|
||||
private set
|
||||
|
||||
var associatedNote: Note? = null
|
||||
|
||||
var lastReactionsDownloadTime: Map<String, EOSETime> = emptyMap()
|
||||
|
||||
fun id() = Hex.decode(idHex)
|
||||
|
@ -176,6 +176,69 @@ fun ZoomableContentView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GalleryContentView(
|
||||
content: BaseMediaContent,
|
||||
roundedCorner: Boolean,
|
||||
isFiniteHeight: Boolean,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
when (content) {
|
||||
is MediaUrlImage ->
|
||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
||||
TwoSecondController(content) { controllerVisible ->
|
||||
val mainImageModifier = Modifier.fillMaxWidth()
|
||||
val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth()
|
||||
|
||||
UrlImageView(content, mainImageModifier, loadedImageModifier, isFiniteHeight, controllerVisible, accountViewModel = accountViewModel, gallery = true)
|
||||
}
|
||||
}
|
||||
is MediaUrlVideo ->
|
||||
SensitivityWarning(content.contentWarning != null, accountViewModel) {
|
||||
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||
VideoView(
|
||||
videoUri = content.url,
|
||||
mimeType = content.mimeType,
|
||||
title = content.description,
|
||||
artworkUri = content.artworkUri,
|
||||
gallery = true,
|
||||
authorName = content.authorName,
|
||||
dimensions = content.dim,
|
||||
blurhash = content.blurhash,
|
||||
roundedCorner = roundedCorner,
|
||||
isFiniteHeight = isFiniteHeight,
|
||||
nostrUriCallback = content.uri,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
is MediaLocalImage ->
|
||||
TwoSecondController(content) { controllerVisible ->
|
||||
val mainImageModifier = Modifier.fillMaxWidth()
|
||||
val loadedImageModifier = if (roundedCorner) MaterialTheme.colorScheme.imageModifier else Modifier.fillMaxWidth()
|
||||
|
||||
LocalImageView(content, mainImageModifier, loadedImageModifier, isFiniteHeight, controllerVisible, accountViewModel = accountViewModel)
|
||||
}
|
||||
is MediaLocalVideo ->
|
||||
content.localFile?.let {
|
||||
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||
VideoView(
|
||||
videoUri = it.toUri().toString(),
|
||||
mimeType = content.mimeType,
|
||||
title = content.description,
|
||||
artworkUri = content.artworkUri,
|
||||
authorName = content.authorName,
|
||||
gallery = true,
|
||||
roundedCorner = roundedCorner,
|
||||
isFiniteHeight = isFiniteHeight,
|
||||
nostrUriCallback = content.uri,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TwoSecondController(
|
||||
content: BaseMediaContent,
|
||||
@ -303,6 +366,7 @@ fun UrlImageView(
|
||||
isFiniteHeight: Boolean,
|
||||
controllerVisible: MutableState<Boolean>,
|
||||
accountViewModel: AccountViewModel,
|
||||
gallery: Boolean = false,
|
||||
alwayShowImage: Boolean = false,
|
||||
) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
@ -319,7 +383,14 @@ fun UrlImageView(
|
||||
SubcomposeAsyncImage(
|
||||
model = content.url,
|
||||
contentDescription = content.description,
|
||||
contentScale = if (isFiniteHeight) ContentScale.Fit else ContentScale.FillWidth,
|
||||
contentScale =
|
||||
if (gallery) {
|
||||
ContentScale.Crop
|
||||
} else if (isFiniteHeight) {
|
||||
ContentScale.Fit
|
||||
} else {
|
||||
ContentScale.FillWidth
|
||||
},
|
||||
modifier = mainImageModifier,
|
||||
) {
|
||||
when (painter.state) {
|
||||
|
@ -47,16 +47,7 @@ class UserProfileGalleryFeedFilter(
|
||||
}
|
||||
|
||||
var sorted = sort(notes)
|
||||
var finalnotes = setOf<Note>()
|
||||
for (item in sorted) {
|
||||
val note = (item.event as ProfileGalleryEntryEvent).event()?.let { LocalCache.checkGetOrCreateNote(it) }
|
||||
if (note != null) {
|
||||
note.associatedNote = item
|
||||
finalnotes = finalnotes + note
|
||||
}
|
||||
}
|
||||
|
||||
return finalnotes.toList()
|
||||
return sorted.toList()
|
||||
}
|
||||
|
||||
override fun applyFilter(collection: Set<Note>): Set<Note> = innerApplyFilter(collection)
|
||||
|
@ -45,18 +45,20 @@ import androidx.compose.ui.Alignment.Companion.BottomStart
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.map
|
||||
import coil.compose.AsyncImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage
|
||||
import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo
|
||||
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser.Companion.isVideoUrl
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.components.GalleryContentView
|
||||
import com.vitorpamplona.amethyst.ui.components.SensitivityWarning
|
||||
import com.vitorpamplona.amethyst.ui.components.VideoView
|
||||
import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport
|
||||
import com.vitorpamplona.amethyst.ui.note.ClickableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.LongPressToQuickActionGallery
|
||||
@ -79,7 +81,6 @@ import com.vitorpamplona.quartz.events.ProfileGalleryEntryEvent
|
||||
fun RenderGalleryFeed(
|
||||
viewModel: FeedViewModel,
|
||||
routeForLastRead: String?,
|
||||
forceEventKind: Int?,
|
||||
listState: LazyGridState,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
@ -103,7 +104,6 @@ fun RenderGalleryFeed(
|
||||
state,
|
||||
routeForLastRead,
|
||||
listState,
|
||||
forceEventKind,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@ -121,7 +121,6 @@ private fun GalleryFeedLoaded(
|
||||
state: FeedState.Loaded,
|
||||
routeForLastRead: String?,
|
||||
listState: LazyGridState,
|
||||
forceEventKind: Int?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@ -138,7 +137,6 @@ private fun GalleryFeedLoaded(
|
||||
baseNote = item,
|
||||
routeForLastRead = routeForLastRead,
|
||||
modifier = Modifier,
|
||||
forceEventKind = forceEventKind,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@ -157,7 +155,6 @@ fun GalleryCardCompose(
|
||||
routeForLastRead: String? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
forceEventKind: Int?,
|
||||
isHiddenFeed: Boolean = false,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
@ -172,20 +169,29 @@ fun GalleryCardCompose(
|
||||
nav = nav,
|
||||
) { canPreview ->
|
||||
|
||||
if (baseNote.associatedNote != null) {
|
||||
if (baseNote.associatedNote!!.event != null) {
|
||||
val image = (baseNote.associatedNote!!.event as ProfileGalleryEntryEvent).url()
|
||||
if (image != null) {
|
||||
GalleryCard(
|
||||
galleryNote = baseNote.associatedNote!!,
|
||||
baseNote = baseNote,
|
||||
image = image,
|
||||
modifier = modifier,
|
||||
parentBackgroundColor = parentBackgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
// TODO Vitor, this works, but maybe you know of a better way to run this here in the background
|
||||
// as LocalCache.checkGetOrCreateNote(it) can not run on the main thread
|
||||
var note: Note? = null
|
||||
val thread =
|
||||
Thread {
|
||||
note = (baseNote.event as ProfileGalleryEntryEvent).event()?.let { LocalCache.checkGetOrCreateNote(it) }
|
||||
}
|
||||
thread.start()
|
||||
thread.join()
|
||||
// TODO End
|
||||
|
||||
val image = (baseNote.event as ProfileGalleryEntryEvent).url()
|
||||
if (image != null) {
|
||||
note?.let {
|
||||
GalleryCard(
|
||||
galleryNote = baseNote,
|
||||
baseNote = it,
|
||||
image = image,
|
||||
modifier = modifier,
|
||||
parentBackgroundColor = parentBackgroundColor,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,6 +212,7 @@ fun GalleryCard(
|
||||
LongPressToQuickActionGallery(baseNote = galleryNote, accountViewModel = accountViewModel) { showPopup ->
|
||||
CheckNewAndRenderChannelCard(
|
||||
baseNote,
|
||||
galleryNote,
|
||||
image,
|
||||
modifier,
|
||||
parentBackgroundColor,
|
||||
@ -219,6 +226,7 @@ fun GalleryCard(
|
||||
@Composable
|
||||
private fun CheckNewAndRenderChannelCard(
|
||||
baseNote: Note,
|
||||
galleryNote: Note,
|
||||
image: String,
|
||||
modifier: Modifier = Modifier,
|
||||
parentBackgroundColor: MutableState<Color>? = null,
|
||||
@ -241,7 +249,7 @@ private fun CheckNewAndRenderChannelCard(
|
||||
showPopup = showPopup,
|
||||
nav = nav,
|
||||
) {
|
||||
InnerGalleryCardBox(baseNote, image, accountViewModel, nav)
|
||||
InnerGalleryCardBox(galleryNote, image, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,7 +275,6 @@ data class GalleryThumb(
|
||||
val id: String?,
|
||||
val image: String?,
|
||||
val title: String?,
|
||||
// val price: Price?,
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ -287,7 +294,6 @@ fun RenderGalleryThumb(
|
||||
image = image,
|
||||
title = "",
|
||||
// noteEvent?.title(),
|
||||
// price = noteEvent?.price(),
|
||||
)
|
||||
}.distinctUntilChanged()
|
||||
.observeAsState(
|
||||
@ -298,7 +304,7 @@ fun RenderGalleryThumb(
|
||||
),
|
||||
)
|
||||
|
||||
InnerRenderGalleryThumb(card as GalleryThumb, baseNote, accountViewModel)
|
||||
InnerRenderGalleryThumb(card, baseNote, accountViewModel)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@ -311,7 +317,6 @@ fun RenderGalleryThumbPreview(accountViewModel: AccountViewModel) {
|
||||
id = "",
|
||||
image = null,
|
||||
title = "Like New",
|
||||
// price = Price("800000", "SATS", null),
|
||||
),
|
||||
note = Note("hex"),
|
||||
accountViewModel = accountViewModel,
|
||||
@ -332,27 +337,45 @@ fun InnerRenderGalleryThumb(
|
||||
contentAlignment = BottomStart,
|
||||
) {
|
||||
card.image?.let {
|
||||
var blurHash = (note.event as ProfileGalleryEntryEvent).blurhash()
|
||||
var description = (note.event as ProfileGalleryEntryEvent).content
|
||||
// var hash = (note.event as ProfileGalleryEntryEvent).hash()
|
||||
var dimensions = (note.event as ProfileGalleryEntryEvent).dimensions()
|
||||
var mimeType = (note.event as ProfileGalleryEntryEvent).mimeType()
|
||||
var content: BaseMediaContent? = null
|
||||
|
||||
if (isVideoUrl(it)) {
|
||||
VideoView(
|
||||
videoUri = it,
|
||||
mimeType = null,
|
||||
title = "",
|
||||
authorName = note.author?.toBestDisplayName(),
|
||||
roundedCorner = false,
|
||||
gallery = true,
|
||||
isFiniteHeight = false,
|
||||
alwaysShowVideo = true,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
content =
|
||||
MediaUrlVideo(
|
||||
url = it,
|
||||
description = description,
|
||||
hash = null,
|
||||
blurhash = blurHash,
|
||||
dim = dimensions,
|
||||
uri = null,
|
||||
mimeType = mimeType,
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = it,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
content =
|
||||
MediaUrlImage(
|
||||
url = it,
|
||||
description = description,
|
||||
hash = null, // We don't want to show the hash banner here
|
||||
blurhash = blurHash,
|
||||
dim = dimensions,
|
||||
uri = null,
|
||||
mimeType = mimeType,
|
||||
)
|
||||
}
|
||||
|
||||
GalleryContentView(
|
||||
content = content,
|
||||
roundedCorner = false,
|
||||
isFiniteHeight = false,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
// }
|
||||
?: run { DisplayGalleryAuthorBanner(note) }
|
||||
}
|
||||
}
|
||||
|
@ -240,6 +240,16 @@ fun PrepareViewModels(
|
||||
),
|
||||
)
|
||||
|
||||
val galleryFeedViewModel: NostrUserProfileGalleryFeedViewModel =
|
||||
viewModel(
|
||||
key = baseUser.pubkeyHex + "UserGalleryFeedViewModel",
|
||||
factory =
|
||||
NostrUserProfileGalleryFeedViewModel.Factory(
|
||||
baseUser,
|
||||
accountViewModel.account,
|
||||
),
|
||||
)
|
||||
|
||||
val followersFeedViewModel: NostrUserProfileFollowersUserFeedViewModel =
|
||||
viewModel(
|
||||
key = baseUser.pubkeyHex + "UserProfileFollowersUserFeedViewModel",
|
||||
@ -298,16 +308,6 @@ fun PrepareViewModels(
|
||||
),
|
||||
)
|
||||
|
||||
val galleryFeedViewModel: NostrUserProfileGalleryFeedViewModel =
|
||||
viewModel(
|
||||
key = baseUser.pubkeyHex + "UserGalleryFeedViewModel",
|
||||
factory =
|
||||
NostrUserProfileGalleryFeedViewModel.Factory(
|
||||
baseUser,
|
||||
accountViewModel.account,
|
||||
),
|
||||
)
|
||||
|
||||
val reportsFeedViewModel: NostrUserProfileReportFeedViewModel =
|
||||
viewModel(
|
||||
key = baseUser.pubkeyHex + "UserProfileReportFeedViewModel",
|
||||
@ -1574,7 +1574,6 @@ fun TabGallery(
|
||||
RenderGalleryFeed(
|
||||
feedViewModel,
|
||||
null,
|
||||
0,
|
||||
listState,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
|
Loading…
x
Reference in New Issue
Block a user