diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt index 2ec7ab8e1c..27e2015329 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt @@ -80,6 +80,7 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_invoice import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.service.upload.ui.StrippingFailureDialog +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -100,7 +101,6 @@ import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.playback.composable.VideoView import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery -import com.vitorpamplona.amethyst.ui.components.BechLink import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt index de83ab8df7..0f4ac5d7fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt @@ -21,22 +21,17 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists -import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.richtext.BlossomUriSegment import com.vitorpamplona.amethyst.commons.richtext.BuzzInviteLinkSegment -import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser import com.vitorpamplona.amethyst.commons.richtext.CashuSegment import com.vitorpamplona.amethyst.commons.richtext.ClinkOfferSegment import com.vitorpamplona.amethyst.commons.richtext.ConcordInviteLinkSegment @@ -52,6 +47,7 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState import com.vitorpamplona.amethyst.commons.richtext.SecretEmoji import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail @@ -59,17 +55,16 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer +import com.vitorpamplona.amethyst.commons.ui.components.TagLink import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextInteractions -import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextSegmentRenderer -import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextPlatform import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextSegmentRenderer import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown import com.vitorpamplona.amethyst.ui.note.creators.invoice.ClinkOfferPreview import com.vitorpamplona.amethyst.ui.note.creators.invoice.MayBeInvoicePreview -import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsRichTextViewer /** * The Android implementation of the shared [RichTextSegmentRenderer] contract: it @@ -79,7 +74,7 @@ import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsR * leaves need but that the cross-platform contract deliberately keeps out of its * method signatures. * - * Recreate one per [CommonsBackedRichTextViewer] call (it captures per-call state); + * Recreate one per [RichTextViewer] call (it captures per-call state); * it is cheap and [remember]ed against its inputs so the CompositionLocal doesn't * churn its readers. */ @@ -255,63 +250,27 @@ class AmethystRichTextSegmentRenderer( } /** - * Renders rich text through the shared cross-platform [CommonsRichTextViewer] core. - * This is the production plain-text path that [RichTextViewer] delegates to: it - * parses with the existing [CachedRichTextParser], keeps the markdown path native, - * and for plain rich text provides the Android segment renderer - * ([AmethystRichTextSegmentRenderer]) plus the universal interactions into the two - * CompositionLocals the core reads. - * - * The core renders text, custom emoji, and hashtags (with their shared inline - * icons) itself; every divergent segment routes back to Amethyst's existing - * leaves through the renderer. Note: url/email/phone open via the platform URI - * handler rather than Amethyst's per-type Clickable* composables, so their tap - * behavior is the generic open action (rendering is unchanged clickable text). + * Android's [RichTextPlatform]: its segment renderer ([AmethystRichTextSegmentRenderer]) and its + * markdown renderer. Installed in the app theme, so every screen's rich text gets them. */ -@Composable -fun CommonsBackedRichTextViewer( - content: String, - canPreview: Boolean, - quotesLeft: Int, - modifier: Modifier, - tags: ImmutableListOfLists, - backgroundColor: MutableState, - callbackUri: String? = null, - authorPubKey: String? = null, - accountViewModel: AccountViewModel, - nav: INav, -) { - Column(modifier = modifier) { - if (remember(content) { CachedRichTextParser.isMarkdown(content) }) { - RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) - return@Column - } +object AndroidRichTextPlatform : RichTextPlatform { + override fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer = AmethystRichTextSegmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) - val state by remember(content, tags) { - mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) - } - - val renderer = - remember(accountViewModel, nav, backgroundColor, callbackUri, canPreview) { - AmethystRichTextSegmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) - } - - val interactions = - remember(nav) { - RichTextInteractions( - onClickHashtag = { nav.nav(Route.Hashtag(it.lowercase())) }, - ) - } - - CompositionLocalProvider( - LocalRichTextSegmentRenderer provides renderer, - LocalRichTextInteractions provides interactions, - ) { - CommonsRichTextViewer( - state = state, - canPreview = canPreview, - quotesLeft = quotesLeft, - ) - } - } + @Composable + override fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) = RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index 153dcba569..26676f1aa5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.show_more import com.vitorpamplona.amethyst.commons.richtext.ExpandableTextCutOffCalculator +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.ButtonBorder diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt index 9adcf6bf96..624d36eed9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/InlineQuoteRenderer.kt @@ -21,44 +21,12 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.compositionLocalOf -import androidx.compose.ui.graphics.Color -import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.components.InlineQuoteRenderer import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier -import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.types.ReplyRenderType -/** - * Strategy for rendering a note quoted inline in another note's text (a - * `nostr:nevent1...`/`nostr:note1...` mention with preview budget left, or a - * legacy `#[index]` event tag). - * - * Both rich-text paths (plain and markdown) funnel through [DisplayFullNote], - * which reads [LocalInlineQuoteRenderer], so providing a different renderer - * re-skins inline quotes for a whole subtree without threading a parameter - * through the parser stack. Chat bubbles use this to keep a quoted chat - * message in the chat reply design instead of the default quoted-note card - * (see `chatInlineQuoteRenderer`). - * - * A renderer draws only the quoted note itself; any leftover characters - * around the mention stay with the caller ([DisplayFullNote]). - */ -fun interface InlineQuoteRenderer { - @Composable - fun Render( - note: Note, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, - ) -} - -/** The quoted-note card used everywhere outside chats. */ +/** The quoted-note card used everywhere outside chats; the app installs it in its theme root. */ val DefaultInlineQuoteRenderer = InlineQuoteRenderer { note, quotesLeft, backgroundColor, accountViewModel, nav -> NoteCompose( @@ -72,5 +40,3 @@ val DefaultInlineQuoteRenderer = nav = nav, ) } - -val LocalInlineQuoteRenderer = compositionLocalOf { DefaultInlineQuoteRenderer } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt similarity index 64% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt index 4167e001b6..827943aedd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextPlatformLeaves.kt @@ -22,21 +22,13 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.text.InlineTextContent -import androidx.compose.foundation.text.appendInlineContent -import androidx.compose.material3.Icon import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue @@ -48,32 +40,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalFontFamilyResolver -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextMeasurer -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withStyle import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.em import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder import com.vitorpamplona.amethyst.commons.model.EmptyTagList import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists -import com.vitorpamplona.amethyst.commons.model.Note -import com.vitorpamplona.amethyst.commons.model.User -import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route -import com.vitorpamplona.amethyst.commons.model.navigation.routeFor -import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname -import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.richtext.Base64Segment import com.vitorpamplona.amethyst.commons.richtext.BechSegment import com.vitorpamplona.amethyst.commons.richtext.BlossomUriSegment @@ -92,7 +66,6 @@ import com.vitorpamplona.amethyst.commons.richtext.InvoiceSegment import com.vitorpamplona.amethyst.commons.richtext.LinkSegment import com.vitorpamplona.amethyst.commons.richtext.MathSegment import com.vitorpamplona.amethyst.commons.richtext.NowhereLinkSegment -import com.vitorpamplona.amethyst.commons.richtext.ParagraphState import com.vitorpamplona.amethyst.commons.richtext.PdfSegment import com.vitorpamplona.amethyst.commons.richtext.PhoneSegment import com.vitorpamplona.amethyst.commons.richtext.RegularTextSegment @@ -105,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.VideoSegment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius +import com.vitorpamplona.amethyst.commons.ui.components.BechLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail @@ -112,63 +86,27 @@ import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary -import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableText +import com.vitorpamplona.amethyst.commons.ui.components.HashTag import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard +import com.vitorpamplona.amethyst.commons.ui.components.RenderCustomEmoji +import com.vitorpamplona.amethyst.commons.ui.components.RenderRegular +import com.vitorpamplona.amethyst.commons.ui.components.RenderTextParagraph +import com.vitorpamplona.amethyst.commons.ui.components.TagLink +import com.vitorpamplona.amethyst.commons.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor -import com.vitorpamplona.amethyst.commons.ui.note.LoadUser -import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji -import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji -import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon -import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon -import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState import com.vitorpamplona.amethyst.commons.ui.theme.CashuCardBorders import com.vitorpamplona.amethyst.commons.ui.theme.HalfVertPadding -import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.commons.ui.theme.inlinePlaceholder -import com.vitorpamplona.amethyst.commons.util.toShortDisplay import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.uploads.blossom.bud10.openBlossomUriAsIntent import com.vitorpamplona.amethyst.ui.note.creators.invoice.ClinkOfferPreview import com.vitorpamplona.amethyst.ui.note.creators.invoice.MayBeInvoicePreview import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel -import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nipB7Blossom.BlossomUri import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -/** - * Renders Nostr rich text. The plain (non-markdown) path now runs through the - * cross-platform [com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer] - * core via [CommonsBackedRichTextViewer]; this entry is kept so its ~55 call sites - * are untouched. The Android-specific markdown path stays here. - */ -@Composable -fun RichTextViewer( - content: String, - canPreview: Boolean, - quotesLeft: Int, - modifier: Modifier, - tags: ImmutableListOfLists, - backgroundColor: MutableState, - callbackUri: String? = null, - authorPubKey: String? = null, - accountViewModel: AccountViewModel, - nav: INav, -) = CommonsBackedRichTextViewer( - content = content, - canPreview = canPreview, - quotesLeft = quotesLeft, - modifier = modifier, - tags = tags, - backgroundColor = backgroundColor, - callbackUri = callbackUri, - authorPubKey = authorPubKey, - accountViewModel = accountViewModel, - nav = nav, -) - @Preview @Composable fun RenderStrangeNamePreview() { @@ -356,88 +294,6 @@ fun RenderRegularPreview3() { } } -@Composable -fun RenderTextParagraph( - paragraph: ParagraphState, - spaceWidth: Dp, - modifier: Modifier, - renderWord: @Composable (word: Segment) -> Unit, -) { - FlowRow( - modifier = modifier, - horizontalArrangement = Arrangement.spacedBy(spaceWidth), - // Center items on the cross axis so a taller item (an equation, whose image - // is taller than a text line) sits centered on the line instead of hanging - // below the baseline. No-op for the common all-text row. - itemVerticalAlignment = Alignment.CenterVertically, - ) { - paragraph.words.forEach { word -> - renderWord(word) - } - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -fun RenderRegular( - content: String, - tags: ImmutableListOfLists, - callbackUri: String? = null, - authorPubKey: String? = null, - renderParagraph: @Composable (ParagraphState, state: RichTextViewerState, Dp, modifier: Modifier) -> Unit, -) { - val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) } - - val spaceWidth = measureSpaceWidth(LocalTextStyle.current) - - val currentTextStyle = LocalTextStyle.current - - val textStyle = - remember(currentTextStyle) { - currentTextStyle.copy( - lineHeight = 1.3.em, - ) - } - - Column { - // FlowRow doesn't work well with paragraphs. So we need to split them - state.paragraphs.forEach { paragraph -> - CompositionLocalProvider( - LocalLayoutDirection provides - if (paragraph.isRTL) { - LayoutDirection.Rtl - } else { - LayoutDirection.Ltr - }, - LocalTextStyle provides textStyle, - ) { - renderParagraph( - paragraph, - state, - spaceWidth, - Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), - ) - } - } - } -} - -@Composable -fun measureSpaceWidth(textStyle: TextStyle): Dp { - val fontFamilyResolver = LocalFontFamilyResolver.current - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - - return remember(fontFamilyResolver, density, layoutDirection, textStyle) { - val widthPx = - TextMeasurer(fontFamilyResolver, density, layoutDirection, 1) - .measure(" ", textStyle) - .size - .width - with(density) { widthPx.toDp() } - } -} - @Composable private fun RenderWordWithoutPreview( word: Segment, @@ -640,76 +496,6 @@ private fun NoProtocolUrlRenderer(url: String) { ClickableUrl(url, "https://$url") } -@Composable -fun RenderCustomEmoji( - word: String, - state: RichTextViewerState, -) { - CreateTextWithEmoji( - text = word, - emojis = state.customEmoji, - ) -} - -@Composable -fun BechLink( - word: String, - canPreview: Boolean, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - val loadedLink by produceCachedState(cache = accountViewModel.bechLinkCache, key = word) - - val baseNote = loadedLink?.baseNote - - // Preload the placeholder's author NIP-65 outbox so a missing quoted event can be fetched from there. - baseNote?.author?.let { author -> - UserFinderFilterAssemblerSubscription(author, accountViewModel) - } - - if (canPreview && quotesLeft > 0 && baseNote != null) { - Row { - DisplayFullNote( - note = baseNote, - extraChars = loadedLink?.nip19?.additionalChars?.ifBlank { null }, - quotesLeft = quotesLeft, - backgroundColor = backgroundColor, - accountViewModel = accountViewModel, - nav = nav, - ) - } - } else if (loadedLink?.nip19 != null) { - ClickableRoute(word, loadedLink?.nip19!!, accountViewModel, nav) - } else { - val text = - remember(word) { - if (word.length > 16) { - word.replaceRange(8, word.length - 8, ":") - } else { - word - } - } - - Text(text = text, maxLines = 1) - } -} - -@Composable -fun DisplayFullNote( - note: Note, - extraChars: String?, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - LocalInlineQuoteRenderer.current.Render(note, quotesLeft, backgroundColor, accountViewModel, nav) - - extraChars?.let { Text(it) } -} - @Composable fun DisplaySecretEmoji( segment: SecretEmoji, @@ -803,197 +589,3 @@ fun CoreSecretMessage( } } } - -@Composable -fun HashTag( - segment: HashTagSegment, - nav: INav, -) { - val primary = MaterialTheme.colorScheme.primary - val background = MaterialTheme.colorScheme.onBackground - val hashtagIcon: HashtagIcon? = checkForHashtagWithIcon(segment.hashtag) - - val annotatedTermsString = - remember(segment.segmentText) { - buildAnnotatedString { - withStyle(SpanStyle(color = primary)) { - pushStringAnnotation("routeToHashtag", "") - append("#${segment.hashtag}") - pop() - } - - if (hashtagIcon != null) { - withStyle(SpanStyle(color = primary)) { - pushStringAnnotation("routeToHashtag", "") - appendInlineContent("inlineContent", "[icon]") - pop() - } - } - - segment.extras?.let { withStyle(SpanStyle(color = background)) { append(it) } } - } - } - - Text( - text = annotatedTermsString, - modifier = - remember { - Modifier.clickable { - nav.nav(Route.Hashtag(segment.hashtag.lowercase())) - } - }, - inlineContent = - if (hashtagIcon != null) { - mapOf("inlineContent" to inlineIcon(hashtagIcon)) - } else { - emptyMap() - }, - ) -} - -@Composable -private fun inlineIcon(hashtagIcon: HashtagIcon) = - InlineTextContent(inlinePlaceholder) { - Icon( - imageVector = hashtagIcon.icon, - contentDescription = hashtagIcon.description, - tint = Color.Unspecified, - modifier = hashtagIcon.modifier, - ) - } - -@Composable -fun TagLink( - word: HashIndexUserSegment, - accountViewModel: AccountViewModel, - nav: INav, -) { - LoadUser(baseUserHex = word.hex) { - if (it == null) { - Text(text = word.segmentText) - } else { - Row { - DisplayUserFromTag(it, accountViewModel, nav) - word.extras?.let { it2 -> - Text(text = it2) - } - } - } - } -} - -@Composable -fun LoadNote( - baseNoteHex: String, - content: @Composable (Note?) -> Unit, -) { - var note by - remember(baseNoteHex) { mutableStateOf(LocalCache.getNoteIfExists(baseNoteHex)) } - - if (note == null) { - LaunchedEffect(key1 = baseNoteHex) { - note = LocalCache.checkGetOrCreateNote(baseNoteHex) - } - } - - content(note) -} - -@Composable -fun TagLink( - word: HashIndexEventSegment, - canPreview: Boolean, - quotesLeft: Int, - backgroundColor: MutableState, - accountViewModel: AccountViewModel, - nav: INav, -) { - LoadNote(baseNoteHex = word.hex) { - if (it == null) { - Text(text = remember { word.segmentText.toShortDisplay() }) - } else { - Row { - DisplayNoteFromTag( - it, - word.extras, - canPreview, - quotesLeft, - accountViewModel, - backgroundColor, - nav, - ) - } - } - } -} - -@Preview -@Composable -fun DisplayNoteFromTagPreview() { - val dummyPost = - TextNoteEvent( - id = "0b6d941c46411a95edb1c93da7ad6ca26370497d8c7b7d621f5cb59f48841bad", - pubKey = "6dd3b72e325da7383b275eef1c66131ba4664326e162bc060527509b4e33ae43", - createdAt = 1753988264, - tags = emptyArray(), - content = "test", - sig = "ec39e60722a083cccbd2d82d2827e13f5499fa7cbcedac5b76011a844c077473adb629d50d01fab147835ac6c8a3d5ba9aaddd87d6723f0c3c864b9119fc4356", - ) - - LocalCache.justConsume(dummyPost, null, true) - val note = LocalCache.getOrCreateNote(dummyPost.id) - - ThemeComparisonColumn( - toPreview = { - ClickableTextPrimary( - text = "@${note.idNote().toShortDisplay()}", - onClick = { }, - ) - }, - ) -} - -@Composable -private fun DisplayNoteFromTag( - baseNote: Note, - addedChars: String?, - canPreview: Boolean, - quotesLeft: Int, - accountViewModel: AccountViewModel, - backgroundColor: MutableState, - nav: INav, -) { - if (canPreview && quotesLeft > 0) { - LocalInlineQuoteRenderer.current.Render(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) - } else { - ClickableTextPrimary( - text = "@${baseNote.idNote().toShortDisplay()}", - onClick = { routeFor(baseNote, accountViewModel.account)?.let { nav.nav(it) } }, - ) - } - - addedChars?.ifBlank { null }?.let { Text(text = it) } -} - -@Composable -private fun DisplayUserFromTag( - baseUser: User, - accountViewModel: AccountViewModel, - nav: INav, -) { - val meta by observeUserInfo(baseUser, accountViewModel) - val nickname by observeUserDisplayNickname(baseUser, accountViewModel) - val petName = nickname?.petName - - CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag") { - Row { - CreateClickableTextWithEmoji( - clickablePart = remember(meta, petName) { petName ?: it?.info?.bestName() ?: baseUser.pubkeyDisplayHex() }, - maxLines = 1, - route = remember(baseUser) { routeFor(baseUser) }, - nav = nav, - tags = if (petName != null) nickname?.tags else it?.tags, - ) - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt index 1aac646d47..f4ccaa1359 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/MarkdownMediaRenderer.kt @@ -36,6 +36,8 @@ import com.halilibo.richtext.ui.string.RichTextString import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.DisplayFullNote +import com.vitorpamplona.amethyst.commons.ui.components.DisplayUser import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon @@ -44,8 +46,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size17Modifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.LoadedBechLink import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.DisplayFullNote -import com.vitorpamplona.amethyst.ui.components.DisplayUser import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.fragmentHashtagOrNull diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index 58f4426d56..4a214409b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -61,6 +61,7 @@ import com.vitorpamplona.amethyst.commons.resources.nip05_failed import com.vitorpamplona.amethyst.commons.resources.nip05_verified import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote @@ -78,7 +79,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.nip05 import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedAddress diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index 216c968f7a..d715cd288c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.and import com.vitorpamplona.amethyst.commons.resources.replying_to +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableTextWithEmoji import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji @@ -48,7 +49,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt index 2a307ef088..0f8bde1ce0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/ForkInfo.kt @@ -30,13 +30,13 @@ import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.forked_from +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.QuietMark import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.quartz.experimental.forks.IForkableEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt index d7f9315af1..69b3d43b0f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsImageScreen.kt @@ -90,6 +90,7 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_image import com.vitorpamplona.amethyst.commons.resources.share_as_image_generating import com.vitorpamplona.amethyst.commons.resources.share_as_image_url import com.vitorpamplona.amethyst.commons.resources.share_as_image_watermark +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.TextSpinner import com.vitorpamplona.amethyst.commons.ui.components.TitleExplainer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -101,7 +102,6 @@ import com.vitorpamplona.amethyst.service.uploads.CompressorQuality import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.service.uploads.UploadingState import com.vitorpamplona.amethyst.ui.actions.uploads.UploadProgressIndicator -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.NoteCompose import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt index 2cfe54091a..9044bcecb9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/share/ShareNoteAsQrScreen.kt @@ -58,11 +58,11 @@ import com.vitorpamplona.amethyst.commons.resources.share_as_qr_hint_nostr import com.vitorpamplona.amethyst.commons.resources.share_as_qr_hint_web import com.vitorpamplona.amethyst.commons.resources.share_as_qr_mode_nostr import com.vitorpamplona.amethyst.commons.resources.share_as_qr_mode_web +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.KeepScreenBrightAndAwake import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt index 436809a064..751fd843aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Attestation.kt @@ -69,6 +69,7 @@ import com.vitorpamplona.amethyst.commons.resources.attestation_valid_to import com.vitorpamplona.amethyst.commons.resources.attestor_proficiency import com.vitorpamplona.amethyst.commons.resources.attestor_recommendation import com.vitorpamplona.amethyst.commons.resources.attestor_recommendation_for_kinds +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote @@ -78,7 +79,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.UserCompose diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index 80ff2388a4..5e99f039c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -78,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.profile_image import com.vitorpamplona.amethyst.commons.resources.quick_action_share import com.vitorpamplona.amethyst.commons.resources.quick_action_share_browser_link +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor @@ -102,7 +103,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.commons.util.equalImmutableLists import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.components.RichTextViewer import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt index 701d416ae0..b6ba9537b2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/EntityRating.kt @@ -64,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for import com.vitorpamplona.amethyst.commons.resources.rating_stars_out_of_five +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote @@ -75,7 +76,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.quartz.experimental.publications.PublicationIndexEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt index f5c15af3db..9e5588742a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/FileStorage.kt @@ -32,8 +32,8 @@ import com.vitorpamplona.amethyst.commons.richtext.BaseMediaContent import com.vitorpamplona.amethyst.commons.richtext.MediaLocalImage import com.vitorpamplona.amethyst.commons.richtext.MediaLocalVideo import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index f9a4e6aca6..25beb559ee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -54,6 +54,9 @@ import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.components.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.components.RenderUserAsClickableText +import com.vitorpamplona.amethyst.commons.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor @@ -64,10 +67,7 @@ import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmo import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.ClickableUrl -import com.vitorpamplona.amethyst.ui.components.CreateClickableTextWithEmoji -import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer -import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.ui.components.rememberTranslation import com.vitorpamplona.amethyst.ui.note.nip22Comments.DisplayExternalId import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt index 41bea616d1..05a30c8c97 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicPlaylist.kt @@ -73,6 +73,7 @@ import com.vitorpamplona.amethyst.commons.resources.music_playlist_private import com.vitorpamplona.amethyst.commons.resources.music_playlist_track_count import com.vitorpamplona.amethyst.commons.resources.music_playlist_unknown_track import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.BaseUserPicture @@ -86,7 +87,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageBanner diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt index f17fbeb5e6..a495e6188a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/MusicTrack.kt @@ -61,6 +61,7 @@ import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.music.formatTrackDuration import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.preview_card_image_for +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -76,7 +77,6 @@ import com.vitorpamplona.amethyst.service.playback.composable.PauseControllerWhe import com.vitorpamplona.amethyst.service.playback.composable.VideoView import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem import com.vitorpamplona.amethyst.service.playback.composable.wavefront.syntheticWaveformFor -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.elements.DefaultImageHeader diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt index 231e641117..9a0e46ca07 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt @@ -35,11 +35,11 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.HalfHalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt index 97db8fe241..53e4cfd621 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Publication.kt @@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.resources.publication_contents import com.vitorpamplona.amethyst.commons.resources.publication_more_sections import com.vitorpamplona.amethyst.commons.resources.publication_section_count import com.vitorpamplona.amethyst.commons.resources.publication_untitled_section +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.pluralStringRes @@ -70,7 +71,6 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.quartz.experimental.library.BlossomPieceIndexEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt index a32889e78a..d457e5bb4f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicationSection.kt @@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.publication_untitled_section import com.vitorpamplona.amethyst.commons.richtext.CachedAsciiDocToMarkdown +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote @@ -60,7 +61,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown import com.vitorpamplona.quartz.experimental.publications.PublicationContentEvent import com.vitorpamplona.quartz.experimental.publications.PublicationIndexEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt index 1547d45ece..cec727b108 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RenderVideoCurationSet.kt @@ -48,6 +48,7 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.video_curation_set_private_items import com.vitorpamplona.amethyst.commons.resources.video_curation_set_video_count +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.pluralStringRes @@ -55,7 +56,6 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.components.DisplayBlurHash -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt index 2b278bf70c..a2b0589f99 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/SnoPalettes.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.note.types import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPalette import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteEventReader import com.vitorpamplona.quartz.cyberspace.deck0003Sno.SnoPaletteRef diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt index 5d83bd3484..895fbc53d8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt @@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.accept_the_suggestion import com.vitorpamplona.amethyst.commons.resources.proposal_to_edit import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -61,7 +62,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.commons.ui.theme.innerPostModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.ui.actions.EditPostView -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.NoteBody import com.vitorpamplona.amethyst.ui.note.observeEdits diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt index f3724f5263..006c7db35a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.torrent_file import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor @@ -60,7 +61,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.util.countToHumanReadableBytes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt index afd02a92c1..b5aa732632 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/WikiCollaboration.kt @@ -46,13 +46,13 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteEvent +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.theme.Size5dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.replyModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip54Wiki.WikiArticleEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt index 618b9376f3..d5915e4e28 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/ListItemRows.kt @@ -34,12 +34,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.commons.ui.note.LoadUser import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.quartz.nip01Core.core.Address diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt index a2f4cf65bf..30f8d0978c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/lists/MuteList.kt @@ -29,10 +29,10 @@ import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.kind_mute_list +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.muteList.tags.EventTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt index c0e9ae970d..01e44fc9dc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt @@ -131,6 +131,7 @@ import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted_explainer import com.vitorpamplona.amethyst.commons.resources.backup_review_was_named import com.vitorpamplona.amethyst.commons.resources.backup_review_words_and_hashtags +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor @@ -142,7 +143,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.elements.BannerImage diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt index 050613849a..5557788cf9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt @@ -87,6 +87,7 @@ import com.vitorpamplona.amethyst.commons.resources.backup_conflict_restore_mine import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app import com.vitorpamplona.amethyst.commons.resources.backup_review_title_cleared import com.vitorpamplona.amethyst.commons.resources.backup_review_title_updated +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor @@ -102,7 +103,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.util.toShortDisplay import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt index 60e3e6044f..5f2beeadcd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/bookmarkgroups/membershipManagement/PostBookmarkListManagementScreen.kt @@ -42,13 +42,13 @@ import com.vitorpamplona.amethyst.commons.nip51Lists.ui.BookmarkGroupManagementI import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.bookmarks_title import com.vitorpamplona.amethyst.commons.resources.post_bookmark_management_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.bottombars.FabBottomBarPadded import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.NewListButton import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt index 1796e4b562..f3c76cb798 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatInlineQuoteRenderer.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.components.InlineQuoteRenderer import com.vitorpamplona.amethyst.ui.components.DefaultInlineQuoteRenderer -import com.vitorpamplona.amethyst.ui.components.InlineQuoteRenderer import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt index 61105998c9..8132870a1f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/ChatMessageCompose.kt @@ -53,12 +53,12 @@ import com.vitorpamplona.amethyst.commons.model.latestBuzzEdit import com.vitorpamplona.amethyst.commons.model.latestConcordEdit import com.vitorpamplona.amethyst.commons.model.latestMarmotEdit import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.theme.ReactionRowZapraiser import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LocalInlineQuoteRenderer import com.vitorpamplona.amethyst.ui.note.RenderZapRaiser import com.vitorpamplona.amethyst.ui.note.WatchBlockAndReport import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt index 9db5f6e313..ee2302fecf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/LongPublicChatChannelHeader.kt @@ -51,6 +51,7 @@ import com.vitorpamplona.amethyst.commons.resources.channel_image import com.vitorpamplona.amethyst.commons.resources.created_at import com.vitorpamplona.amethyst.commons.resources.groups_no_descriptor import com.vitorpamplona.amethyst.commons.resources.owner +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.NoteAuthorPicture @@ -65,7 +66,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.largeProfilePictureModifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip28PublicChat.header.actions.LinkChatButton diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt index e031472a0f..4e6e5f623e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/header/ShortPublicChatChannelHeader.kt @@ -42,6 +42,7 @@ import com.vitorpamplona.amethyst.commons.model.nip28PublicChats.PublicChatChann import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserIsFollowingChannel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_image +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings @@ -52,7 +53,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt index 6bc704cdd2..3646efc0ed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LiveStreamGoalHeader.kt @@ -39,13 +39,13 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.nip53LiveActivities.LiveActivitiesChannel +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.ZapReaction import com.vitorpamplona.amethyst.ui.note.types.GoalProgressBar import com.vitorpamplona.quartz.nip75ZapGoals.ZapGoalEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt index 8f8ced784b..ccd2bd2946 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/NewCommunityNoteButton.kt @@ -30,12 +30,12 @@ import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.new_community_note +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.Size26Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.painterRes @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt index c9dd501b36..5ac12bff3b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/contactList/ContactListUsersScreen.kt @@ -39,12 +39,12 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.contact_list_screen_title import com.vitorpamplona.amethyst.commons.resources.contact_list_screen_title_with_count import com.vitorpamplona.amethyst.commons.resources.fetching_follow_list +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import kotlinx.collections.immutable.ImmutableList 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 03f792ea0b..2ca5eb15c0 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 @@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.resources.nwc_payment_request import com.vitorpamplona.amethyst.commons.resources.wallet_connect_pay_invoice_error_error import com.vitorpamplona.amethyst.commons.service.nwc.nwcFailureDetail import com.vitorpamplona.amethyst.commons.service.nwc.nwcTimeoutMessage +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold @@ -77,7 +78,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImage75Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size35dp import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.ReusableZapButton import com.vitorpamplona.amethyst.ui.components.ZapButtonConfig 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 0823605f10..28be318024 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 @@ -30,13 +30,13 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.relayClient.event.observeNoteAndMap +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.MyExtensibleTopAppBar import com.vitorpamplona.amethyst.commons.ui.note.ArrowBackIcon import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.SimpleImage35Modifier import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.note.elements.BannerImage import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt index 63c81b7480..204d228e21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitFileViewer.kt @@ -70,12 +70,12 @@ import com.vitorpamplona.amethyst.commons.resources.git_repo_code_loading import com.vitorpamplona.amethyst.commons.resources.git_repo_copy_file import com.vitorpamplona.amethyst.commons.resources.git_repo_file_load_error import com.vitorpamplona.amethyst.commons.resources.git_repo_plain_text +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.components.util.setText import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.RichTextViewer import com.vitorpamplona.quartz.nip34Git.git.GitRepoSnapshot import com.vitorpamplona.quartz.nip34Git.git.GitTreeEntry import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt index b1ccd8507f..30ec3d6466 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/gitRepo/code/GitReadmeTab.kt @@ -40,10 +40,10 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.git_repo_code_loading import com.vitorpamplona.amethyst.commons.resources.git_repo_file_load_error import com.vitorpamplona.amethyst.commons.resources.git_repo_readme_missing +import com.vitorpamplona.amethyst.commons.ui.components.RichTextViewer import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.RichTextViewer import com.vitorpamplona.quartz.nip34Git.git.GitRepoSnapshot import com.vitorpamplona.quartz.nip34Git.git.GitTreeEntry import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt index 7ddb368818..77e241e9a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/AlgoFeedStatusBanner.kt @@ -51,13 +51,13 @@ import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_processing import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_requesting import com.vitorpamplona.amethyst.commons.resources.dvm_home_status_requesting_all import com.vitorpamplona.amethyst.commons.resources.dvm_offline_banner +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.LoadingAnimation import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.DvmPaymentActions import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.rememberDvmHeartbeatFresh import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt index 171c9e70de..2903ef7c3d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ShowDonationCard.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote @Composable fun ShowDonationCard( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt index 14da60fc52..4313e2c8dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/donations/ZapTheDevsCard.kt @@ -66,6 +66,7 @@ import com.vitorpamplona.amethyst.commons.resources.this_version_brought_to_you_ import com.vitorpamplona.amethyst.commons.resources.version_name import com.vitorpamplona.amethyst.commons.resources.zap_the_devs_description import com.vitorpamplona.amethyst.commons.resources.zap_the_devs_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.components.appendLink import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -77,7 +78,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.ReusableZapButton import com.vitorpamplona.amethyst.ui.components.ZapButtonConfig import com.vitorpamplona.amethyst.ui.note.creators.zapsplits.DisplayZapSplits diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt index f07f651977..99894d5207 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/pictures/PictureCardComposePreview.kt @@ -34,9 +34,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip68Picture.PictureEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt index 482b90af0b..e11c65e917 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/polls/results/PollResultsScreen.kt @@ -94,6 +94,7 @@ import com.vitorpamplona.amethyst.commons.resources.poll_results_selections import com.vitorpamplona.amethyst.commons.resources.poll_results_title import com.vitorpamplona.amethyst.commons.resources.poll_results_your_pick import com.vitorpamplona.amethyst.commons.resources.poll_single_choice +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton @@ -118,7 +119,6 @@ import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollOptionResult import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollResultsUiState import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollResultsViewModel import com.vitorpamplona.amethyst.commons.viewmodels.nip88Polls.PollVoterRow -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.UserLine import com.vitorpamplona.amethyst.ui.note.elements.MoreOptionsButton import com.vitorpamplona.amethyst.ui.note.types.UserGallery diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt index 5dfe235f55..1b6dfafd6a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/gallery/GalleryCardCompose.kt @@ -30,11 +30,11 @@ import androidx.compose.ui.Modifier import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.relayClient.event.observeNote +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt index 795ae757bb..9a20f90a6d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/redirect/LoadRedirectScreen.kt @@ -43,13 +43,13 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.looking_for_event import com.vitorpamplona.amethyst.commons.resources.looking_for_event_title import com.vitorpamplona.amethyst.commons.resources.looking_for_private_event +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensibleWithBackButton import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt index 965c0abd81..2ce5d78e52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt @@ -94,6 +94,7 @@ import com.vitorpamplona.amethyst.commons.resources.send_the_seller_a_message import com.vitorpamplona.amethyst.commons.resources.thread_collapsed_reply_count import com.vitorpamplona.amethyst.commons.richtext.MediaUrlImage import com.vitorpamplona.amethyst.commons.ui.components.GenericLoadable +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav @@ -139,7 +140,6 @@ import com.vitorpamplona.amethyst.commons.util.showAmount import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.thread.LevelFeedViewModel import com.vitorpamplona.amethyst.ui.components.AutoNonlazyGrid -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.components.MyAsyncImage import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.note.CheckAndDisplayEditStatus diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt index a1c170a7f6..7d2d224a21 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadScreen.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.thread_title +import com.vitorpamplona.amethyst.commons.ui.components.LoadNote import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel import com.vitorpamplona.amethyst.commons.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -32,7 +33,6 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarExtensible import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderFilterAssemblerSubscription -import com.vitorpamplona.amethyst.ui.components.LoadNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal.ThreadFeedViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssemblerSubscription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index d10655579f..4a3b824c64 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.theme import android.app.Activity import androidx.compose.material3.ColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -38,6 +39,8 @@ import com.vitorpamplona.amethyst.commons.model.AccentColorType import com.vitorpamplona.amethyst.commons.model.FontFamilyType import com.vitorpamplona.amethyst.commons.model.FontSizeType import com.vitorpamplona.amethyst.commons.model.ThemeType +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform import com.vitorpamplona.amethyst.commons.ui.screen.DisplaySettings import com.vitorpamplona.amethyst.commons.ui.screen.collectDisplaySettings import com.vitorpamplona.amethyst.commons.ui.theme.AmethystMaterialTheme @@ -46,6 +49,8 @@ import com.vitorpamplona.amethyst.commons.ui.theme.amethystLightColors import com.vitorpamplona.amethyst.commons.ui.theme.isDarkTheme import com.vitorpamplona.amethyst.commons.ui.theme.isLight import com.vitorpamplona.amethyst.commons.ui.theme.transparentBackground +import com.vitorpamplona.amethyst.ui.components.AndroidRichTextPlatform +import com.vitorpamplona.amethyst.ui.components.DefaultInlineQuoteRenderer val chartLightColors = VicoTheme( @@ -120,8 +125,15 @@ fun AmethystTheme( // ImageLoaderSetup registers the avatar thumbnail cache and the local Blossom bridge. profilePictureCache = true, colors = colors, - content = content, - ) + ) { + // The platform halves of the shared note and rich-text renderers: media, LaTeX, payments, + // link previews, and the quoted-note card. Every Activity root goes through this theme. + CompositionLocalProvider( + LocalRichTextPlatform provides AndroidRichTextPlatform, + LocalInlineQuoteRenderer provides DefaultInlineQuoteRenderer, + content = content, + ) + } val view = LocalView.current if (!view.isInEditMode) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt index 4280982f69..784fae2dd7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRoute.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt new file mode 100644 index 0000000000..1e00429e14 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/InlineQuoteRenderer.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Color +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.util.toShortDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * Strategy for rendering a note quoted inline in another note's text (a + * `nostr:nevent1...`/`nostr:note1...` mention with preview budget left, or a + * legacy `#[index]` event tag). + * + * Both rich-text paths (plain and markdown) funnel through [DisplayFullNote], + * which reads [LocalInlineQuoteRenderer], so providing a different renderer + * re-skins inline quotes for a whole subtree without threading a parameter + * through the parser stack. Chat bubbles use this to keep a quoted chat + * message in the chat reply design instead of the default quoted-note card + * (see `chatInlineQuoteRenderer`). + * + * A renderer draws only the quoted note itself; any leftover characters + * around the mention stay with the caller ([DisplayFullNote]). + */ +fun interface InlineQuoteRenderer { + @Composable + fun Render( + note: Note, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, + ) +} + +/** + * A link to the quoted note, for front ends that install no card renderer of their own (Android + * installs its quoted-note card in its theme root). + */ +val PlainInlineQuoteRenderer = + InlineQuoteRenderer { note, _, _, accountViewModel, nav -> + ClickableTextPrimary( + text = "@${note.idNote().toShortDisplay()}", + onClick = { routeFor(note, accountViewModel.account)?.let { nav.nav(it) } }, + ) + } + +val LocalInlineQuoteRenderer = compositionLocalOf { PlainInlineQuoteRenderer } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt new file mode 100644 index 0000000000..c95a05d178 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/RichTextViewer.kt @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.text.InlineTextContent +import androidx.compose.foundation.text.appendInlineContent +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFontFamilyResolver +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextMeasurer +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.em +import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists +import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache +import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.relayClient.user.UserFinderFilterAssemblerSubscription +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserDisplayNickname +import com.vitorpamplona.amethyst.commons.relayClient.user.observeUserInfo +import com.vitorpamplona.amethyst.commons.richtext.CachedRichTextParser +import com.vitorpamplona.amethyst.commons.richtext.HashIndexEventSegment +import com.vitorpamplona.amethyst.commons.richtext.HashIndexUserSegment +import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment +import com.vitorpamplona.amethyst.commons.richtext.ParagraphState +import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState +import com.vitorpamplona.amethyst.commons.richtext.Segment +import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled +import com.vitorpamplona.amethyst.commons.ui.components.LocalInlineQuoteRenderer +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.ui.navigation.routes.routeFor +import com.vitorpamplona.amethyst.commons.ui.note.LoadUser +import com.vitorpamplona.amethyst.commons.ui.richtext.CreateClickableTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.richtext.CreateTextWithEmoji +import com.vitorpamplona.amethyst.commons.ui.richtext.HashtagIcon +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextPlatform +import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextSegmentRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextInteractions +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextSegmentRenderer +import com.vitorpamplona.amethyst.commons.ui.richtext.checkForHashtagWithIcon +import com.vitorpamplona.amethyst.commons.ui.state.produceCachedState +import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.commons.ui.theme.inlinePlaceholder +import com.vitorpamplona.amethyst.commons.util.toShortDisplay +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel +import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent +import com.vitorpamplona.amethyst.commons.ui.richtext.RichTextViewer as CommonsRichTextViewer + +/** + * Renders Nostr rich text. Markdown goes to the front end's renderer; plain rich text is parsed + * once ([CachedRichTextParser]) and laid out by the shared [CommonsRichTextViewer] core, which + * renders text, emoji, hashtags and mentions itself and hands every platform segment (media, + * LaTeX, payments, link previews) to the [RichTextSegmentRenderer] the front end's + * [LocalRichTextPlatform] builds for this call. + */ +@Composable +fun RichTextViewer( + content: String, + canPreview: Boolean, + quotesLeft: Int, + modifier: Modifier, + tags: ImmutableListOfLists, + backgroundColor: MutableState, + callbackUri: String? = null, + authorPubKey: String? = null, + accountViewModel: AccountViewModel, + nav: INav, +) { + val platform = LocalRichTextPlatform.current + + Column(modifier = modifier) { + if (remember(content) { CachedRichTextParser.isMarkdown(content) }) { + platform.Markdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav) + return@Column + } + + val state by remember(content, tags) { + mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) + } + + val renderer = + remember(platform, accountViewModel, nav, backgroundColor, callbackUri, canPreview) { + platform.segmentRenderer(accountViewModel, nav, backgroundColor, callbackUri, canPreview) + } + + val interactions = + remember(nav) { + RichTextInteractions( + onClickHashtag = { nav.nav(Route.Hashtag(it.lowercase())) }, + ) + } + + CompositionLocalProvider( + LocalRichTextSegmentRenderer provides renderer, + LocalRichTextInteractions provides interactions, + ) { + CommonsRichTextViewer( + state = state, + canPreview = canPreview, + quotesLeft = quotesLeft, + ) + } + } +} + +@Composable +fun RenderTextParagraph( + paragraph: ParagraphState, + spaceWidth: Dp, + modifier: Modifier, + renderWord: @Composable (word: Segment) -> Unit, +) { + FlowRow( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(spaceWidth), + // Center items on the cross axis so a taller item (an equation, whose image + // is taller than a text line) sits centered on the line instead of hanging + // below the baseline. No-op for the common all-text row. + itemVerticalAlignment = Alignment.CenterVertically, + ) { + paragraph.words.forEach { word -> + renderWord(word) + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun RenderRegular( + content: String, + tags: ImmutableListOfLists, + callbackUri: String? = null, + authorPubKey: String? = null, + renderParagraph: @Composable (ParagraphState, state: RichTextViewerState, Dp, modifier: Modifier) -> Unit, +) { + val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri, authorPubKey)) } + + val spaceWidth = measureSpaceWidth(LocalTextStyle.current) + + val currentTextStyle = LocalTextStyle.current + + val textStyle = + remember(currentTextStyle) { + currentTextStyle.copy( + lineHeight = 1.3.em, + ) + } + + Column { + // FlowRow doesn't work well with paragraphs. So we need to split them + state.paragraphs.forEach { paragraph -> + CompositionLocalProvider( + LocalLayoutDirection provides + if (paragraph.isRTL) { + LayoutDirection.Rtl + } else { + LayoutDirection.Ltr + }, + LocalTextStyle provides textStyle, + ) { + renderParagraph( + paragraph, + state, + spaceWidth, + Modifier.align(if (paragraph.isRTL) Alignment.End else Alignment.Start), + ) + } + } + } +} + +@Composable +fun measureSpaceWidth(textStyle: TextStyle): Dp { + val fontFamilyResolver = LocalFontFamilyResolver.current + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + + return remember(fontFamilyResolver, density, layoutDirection, textStyle) { + val widthPx = + TextMeasurer(fontFamilyResolver, density, layoutDirection, 1) + .measure(" ", textStyle) + .size + .width + with(density) { widthPx.toDp() } + } +} + +@Composable +fun RenderCustomEmoji( + word: String, + state: RichTextViewerState, +) { + CreateTextWithEmoji( + text = word, + emojis = state.customEmoji, + ) +} + +@Composable +fun BechLink( + word: String, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + val loadedLink by produceCachedState(cache = accountViewModel.bechLinkCache, key = word) + + val baseNote = loadedLink?.baseNote + + // Preload the placeholder's author NIP-65 outbox so a missing quoted event can be fetched from there. + baseNote?.author?.let { author -> + UserFinderFilterAssemblerSubscription(author, accountViewModel) + } + + if (canPreview && quotesLeft > 0 && baseNote != null) { + Row { + DisplayFullNote( + note = baseNote, + extraChars = loadedLink?.nip19?.additionalChars?.ifBlank { null }, + quotesLeft = quotesLeft, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, + ) + } + } else if (loadedLink?.nip19 != null) { + ClickableRoute(word, loadedLink?.nip19!!, accountViewModel, nav) + } else { + val text = + remember(word) { + if (word.length > 16) { + word.replaceRange(8, word.length - 8, ":") + } else { + word + } + } + + Text(text = text, maxLines = 1) + } +} + +@Composable +fun DisplayFullNote( + note: Note, + extraChars: String?, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + LocalInlineQuoteRenderer.current.Render(note, quotesLeft, backgroundColor, accountViewModel, nav) + + extraChars?.let { Text(it) } +} + +@Composable +fun HashTag( + segment: HashTagSegment, + nav: INav, +) { + val primary = MaterialTheme.colorScheme.primary + val background = MaterialTheme.colorScheme.onBackground + val hashtagIcon: HashtagIcon? = checkForHashtagWithIcon(segment.hashtag) + + val annotatedTermsString = + remember(segment.segmentText) { + buildAnnotatedString { + withStyle(SpanStyle(color = primary)) { + pushStringAnnotation("routeToHashtag", "") + append("#${segment.hashtag}") + pop() + } + + if (hashtagIcon != null) { + withStyle(SpanStyle(color = primary)) { + pushStringAnnotation("routeToHashtag", "") + appendInlineContent("inlineContent", "[icon]") + pop() + } + } + + segment.extras?.let { withStyle(SpanStyle(color = background)) { append(it) } } + } + } + + Text( + text = annotatedTermsString, + modifier = + remember { + Modifier.clickable { + nav.nav(Route.Hashtag(segment.hashtag.lowercase())) + } + }, + inlineContent = + if (hashtagIcon != null) { + mapOf("inlineContent" to inlineIcon(hashtagIcon)) + } else { + emptyMap() + }, + ) +} + +@Composable +private fun inlineIcon(hashtagIcon: HashtagIcon) = + InlineTextContent(inlinePlaceholder) { + Icon( + imageVector = hashtagIcon.icon, + contentDescription = hashtagIcon.description, + tint = Color.Unspecified, + modifier = hashtagIcon.modifier, + ) + } + +@Composable +fun TagLink( + word: HashIndexUserSegment, + accountViewModel: AccountViewModel, + nav: INav, +) { + LoadUser(baseUserHex = word.hex) { + if (it == null) { + Text(text = word.segmentText) + } else { + Row { + DisplayUserFromTag(it, accountViewModel, nav) + word.extras?.let { it2 -> + Text(text = it2) + } + } + } + } +} + +@Composable +fun LoadNote( + baseNoteHex: String, + content: @Composable (Note?) -> Unit, +) { + var note by + remember(baseNoteHex) { mutableStateOf(LocalCache.getNoteIfExists(baseNoteHex)) } + + if (note == null) { + LaunchedEffect(key1 = baseNoteHex) { + note = LocalCache.checkGetOrCreateNote(baseNoteHex) + } + } + + content(note) +} + +@Composable +fun TagLink( + word: HashIndexEventSegment, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + LoadNote(baseNoteHex = word.hex) { + if (it == null) { + Text(text = remember { word.segmentText.toShortDisplay() }) + } else { + Row { + DisplayNoteFromTag( + it, + word.extras, + canPreview, + quotesLeft, + accountViewModel, + backgroundColor, + nav, + ) + } + } + } +} + +@Preview +@Composable +fun DisplayNoteFromTagPreview() { + val dummyPost = + TextNoteEvent( + id = "0b6d941c46411a95edb1c93da7ad6ca26370497d8c7b7d621f5cb59f48841bad", + pubKey = "6dd3b72e325da7383b275eef1c66131ba4664326e162bc060527509b4e33ae43", + createdAt = 1753988264, + tags = emptyArray(), + content = "test", + sig = "ec39e60722a083cccbd2d82d2827e13f5499fa7cbcedac5b76011a844c077473adb629d50d01fab147835ac6c8a3d5ba9aaddd87d6723f0c3c864b9119fc4356", + ) + + LocalCache.justConsume(dummyPost, null, true) + val note = LocalCache.getOrCreateNote(dummyPost.id) + + ThemeComparisonColumn( + toPreview = { + ClickableTextPrimary( + text = "@${note.idNote().toShortDisplay()}", + onClick = { }, + ) + }, + ) +} + +@Composable +private fun DisplayNoteFromTag( + baseNote: Note, + addedChars: String?, + canPreview: Boolean, + quotesLeft: Int, + accountViewModel: AccountViewModel, + backgroundColor: MutableState, + nav: INav, +) { + if (canPreview && quotesLeft > 0) { + LocalInlineQuoteRenderer.current.Render(baseNote, quotesLeft, backgroundColor, accountViewModel, nav) + } else { + ClickableTextPrimary( + text = "@${baseNote.idNote().toShortDisplay()}", + onClick = { routeFor(baseNote, accountViewModel.account)?.let { nav.nav(it) } }, + ) + } + + addedChars?.ifBlank { null }?.let { Text(text = it) } +} + +@Composable +private fun DisplayUserFromTag( + baseUser: User, + accountViewModel: AccountViewModel, + nav: INav, +) { + val meta by observeUserInfo(baseUser, accountViewModel) + val nickname by observeUserDisplayNickname(baseUser, accountViewModel) + val petName = nickname?.petName + + CrossfadeIfEnabled(targetState = meta, label = "DisplayUserFromTag") { + Row { + CreateClickableTextWithEmoji( + clickablePart = remember(meta, petName) { petName ?: it?.info?.bestName() ?: baseUser.pubkeyDisplayHex() }, + maxLines = 1, + route = remember(baseUser) { routeFor(baseUser) }, + nav = nav, + tags = if (petName != null) nickname?.tags else it?.tags, + ) + } + } +} diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt new file mode 100644 index 0000000000..2d29abddc9 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/richtext/RichTextPlatform.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.richtext + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import com.vitorpamplona.amethyst.commons.model.ImmutableListOfLists +import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav +import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel + +/** + * What a front end plugs into the shared rich-text viewer: the [RichTextSegmentRenderer] for its + * platform leaves (zoomable media, LaTeX, payments, link previews, Blossom links) and its markdown + * renderer. The shared viewer parses, lays out paragraphs and renders text, emoji, hashtags and + * mentions itself, and asks this for everything else. + * + * A front end installs its own through [LocalRichTextPlatform] at its composition root (Android + * does so in its theme). Without one, [Plain] renders every platform segment as text, which is + * what previews and a front end still wiring its leaves get. + */ +@Stable +interface RichTextPlatform { + /** The segment renderer for one viewer call; it may close over every argument. */ + fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer + + /** Renders [content] that the parser recognised as markdown. */ + @Composable + fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) + + /** Text for every platform segment, and markdown shown as its source. */ + object Plain : RichTextPlatform { + override fun segmentRenderer( + accountViewModel: AccountViewModel, + nav: INav, + backgroundColor: MutableState, + callbackUri: String?, + canPreview: Boolean, + ): RichTextSegmentRenderer = PlainTextSegmentRenderer + + @Composable + override fun Markdown( + content: String, + tags: ImmutableListOfLists, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + callbackUri: String?, + accountViewModel: AccountViewModel, + nav: INav, + ) = Text(content) + } +} + +/** The front end's [RichTextPlatform]. Static: it is set once at the root and never changes. */ +val LocalRichTextPlatform = staticCompositionLocalOf { RichTextPlatform.Plain }