diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt index 3d35c44631..ef08d9374d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/MyAsyncImage.kt @@ -82,8 +82,10 @@ fun MyAsyncImage( Box(contentAlignment = Alignment.Center) { if (onLoadingBackground != null) { onLoadingBackground() + LoadingAnimation(Size40dp, Size6dp) + } else { + DisplayUrlWithLoadingSymbol(imageUrl) } - DisplayUrlWithLoadingSymbol(imageUrl) } } } @@ -96,12 +98,11 @@ fun MyAsyncImage( } } else { Box(loadedImageModifier, contentAlignment = Alignment.Center) { - if (onLoadingBackground != null) { - onLoadingBackground() - } - DisplayUrlWithLoadingSymbol(imageUrl) + onError() } } + } else { + ClickableUrl(urlText = imageUrl, url = imageUrl) } } is AsyncImagePainter.State.Success -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt index 3f5fda703c..cbf68e2dd0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip90DVMs +import android.R.attr.author import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme @@ -35,7 +35,6 @@ import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment.Companion.BottomStart import androidx.compose.ui.Alignment.Companion.CenterVertically 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.text.font.FontWeight @@ -44,10 +43,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout +import com.vitorpamplona.amethyst.ui.navigation.EmptyNav.nav import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction @@ -55,13 +55,14 @@ import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding -import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.RowColSpacing5dp +import com.vitorpamplona.amethyst.ui.theme.SimpleImageBorder import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.ui.theme.grayText import com.vitorpamplona.amethyst.ui.theme.nip05 +import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.EmptyClientListener.onError @Immutable data class DVMCard( @@ -87,25 +88,28 @@ fun RenderContentDVMThumb( onImage = { card.cover?.let { Box(contentAlignment = BottomStart) { - AsyncImage( - model = it, - contentDescription = null, + MyAsyncImage( + imageUrl = it, + contentDescription = card.name, contentScale = ContentScale.Crop, - modifier = - Modifier - .fillMaxSize() - .clip(QuoteBorder), + mainImageModifier = Modifier, + loadedImageModifier = SimpleImageBorder, + accountViewModel = accountViewModel, + onLoadingBackground = { + baseNote.author?.let { author -> + BannerImage(author, SimpleImageBorder, accountViewModel) + } + }, + onError = { + baseNote.author?.let { author -> + BannerImage(author, SimpleImageBorder, accountViewModel) + } + }, ) } } ?: run { - baseNote.author?.let { - BannerImage( - it, - Modifier - .fillMaxSize() - .clip(QuoteBorder), - accountViewModel, - ) + baseNote.author?.let { author -> + BannerImage(author, SimpleImageBorder, accountViewModel) } } }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt index 4f66b17bd3..b9509a2dd4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmContentDiscoveryScreen.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -44,8 +45,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +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.platform.LocalContext @@ -56,7 +57,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -66,17 +66,18 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNo import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.LoadNote +import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.navigation.INav -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture import com.vitorpamplona.amethyst.ui.note.ObserveZapIcon import com.vitorpamplona.amethyst.ui.note.PayViaIntentDialog import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent import com.vitorpamplona.amethyst.ui.note.ZapAmountChoicePopup import com.vitorpamplona.amethyst.ui.note.ZapIcon import com.vitorpamplona.amethyst.ui.note.ZappedIcon +import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.ui.note.elements.customZapClick import com.vitorpamplona.amethyst.ui.note.payViaIntent import com.vitorpamplona.amethyst.ui.screen.RenderFeedState @@ -87,10 +88,9 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.dal.NIP90ContentDiscov import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.ModifierWidth3dp -import com.vitorpamplona.amethyst.ui.theme.QuoteBorder +import com.vitorpamplona.amethyst.ui.theme.SimpleImage75Modifier import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp -import com.vitorpamplona.amethyst.ui.theme.Size75dp import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceErrorResponse import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent @@ -324,16 +324,33 @@ fun FeedDVM( val card = observeAppDefinition(appDefinitionNote, accountViewModel) card.cover?.let { - AsyncImage( - model = it, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = - Modifier - .size(Size75dp) - .clip(QuoteBorder), - ) - } ?: run { NoteAuthorPicture(appDefinitionNote, Size75dp, accountViewModel = accountViewModel, nav = nav) } + Box(contentAlignment = BottomStart) { + MyAsyncImage( + imageUrl = it, + contentDescription = card.name, + contentScale = ContentScale.Crop, + mainImageModifier = Modifier, + loadedImageModifier = SimpleImage75Modifier, + accountViewModel = accountViewModel, + onLoadingBackground = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + }, + onError = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + }, + ) + } + } ?: run { + appDefinitionNote.author?.let { author -> + Box(contentAlignment = BottomStart) { + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + } + } Spacer(modifier = DoubleVertSpacer) @@ -592,16 +609,33 @@ fun FeedEmptyWithStatus( val card = observeAppDefinition(appDefinitionNote, accountViewModel) card.cover?.let { - AsyncImage( - model = it, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = - Modifier - .size(Size75dp) - .clip(QuoteBorder), - ) - } ?: run { NoteAuthorPicture(appDefinitionNote, Size75dp, accountViewModel = accountViewModel, nav = nav) } + Box(contentAlignment = BottomStart) { + MyAsyncImage( + imageUrl = it, + contentDescription = card.name, + contentScale = ContentScale.Crop, + mainImageModifier = Modifier, + loadedImageModifier = SimpleImage75Modifier, + accountViewModel = accountViewModel, + onLoadingBackground = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + }, + onError = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + }, + ) + } + } ?: run { + appDefinitionNote.author?.let { author -> + Box(contentAlignment = BottomStart) { + BannerImage(author, SimpleImage75Modifier, accountViewModel) + } + } + } Spacer(modifier = DoubleVertSpacer) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt index 2440a7a649..f37cfa9705 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/dvms/DvmTopBar.kt @@ -21,23 +21,19 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow -import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.ui.components.LoadNote +import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.TopBarExtensibleWithBackButton -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture +import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer -import com.vitorpamplona.amethyst.ui.theme.Size34dp +import com.vitorpamplona.amethyst.ui.theme.SimpleImage35Modifier @Composable fun DvmTopBar( @@ -52,22 +48,34 @@ fun DvmTopBar( val card = observeAppDefinition(appDefinitionNote, accountViewModel) card.cover?.let { - AsyncImage( - model = it, - contentDescription = null, + MyAsyncImage( + imageUrl = it, + contentDescription = card.name, contentScale = ContentScale.Crop, - modifier = - Modifier - .size(Size34dp) - .clip(shape = CircleShape), + mainImageModifier = Modifier, + loadedImageModifier = SimpleImage35Modifier, + accountViewModel = accountViewModel, + onLoadingBackground = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage35Modifier, accountViewModel) + } + }, + onError = { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage35Modifier, accountViewModel) + } + }, ) - } ?: run { NoteAuthorPicture(baseNote = appDefinitionNote, size = Size34dp, accountViewModel = accountViewModel) } + } ?: run { + appDefinitionNote.author?.let { author -> + BannerImage(author, SimpleImage35Modifier, accountViewModel) + } + } Spacer(modifier = DoubleHorzSpacer) Text( text = card.name, - fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index 23752b92e7..1eaa1d6b38 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -340,6 +340,9 @@ val FollowSetImageModifier = .clip(QuoteBorder) .aspectRatio(ratio = 21f / 9f) +val SimpleImage75Modifier = Modifier.size(Size75dp).clip(QuoteBorder) +val SimpleImage35Modifier = Modifier.size(Size34dp).clip(shape = CircleShape) + val SimpleImageBorder = Modifier.fillMaxSize().clip(QuoteBorder) val SimpleHeaderImage = Modifier.fillMaxWidth().heightIn(max = 200.dp)