From 173a422d8642b611db9846c47ef8fc0d70170ea2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 13:00:39 +0000 Subject: [PATCH 1/3] fix: notify on NIP-34 pull requests (kind 1618/1619) New pull request events (GitPullRequestEvent, kind 1618) and pull request updates (GitPullRequestUpdateEvent, kind 1619) were never wired into the notification pipeline, which only handled patches (1617) and issues (1621). As a result repo maintainers received no notification when a PR was opened against their repository, even though the PR event p-tags the repo owner. Add both kinds in all four places that gate notifications: - FilterNotificationsToPubkey: request the kinds from relays so the notification subscription actually pulls PR events. - NotificationFeedFilter.NOTIFICATION_KINDS: let cached PR events through to the in-app Notifications tab. - NotificationFeedFilter.tagsAnEventByUser: treat PR/PR-update as notifiable (mirrors the existing patch/issue handling). - EventNotificationConsumer: dispatch PR/PR-update via notifyMention so push notifications fire. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_018wCXL6btUeZZmSP1TCYkKh --- .../service/notifications/EventNotificationConsumer.kt | 4 ++++ .../nip01Notifications/FilterNotificationsToPubkey.kt | 4 ++++ .../loggedIn/notifications/dal/NotificationFeedFilter.kt | 8 +++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index 2a1ea4887c..8b048326b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -72,6 +72,8 @@ import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent @@ -268,6 +270,8 @@ class EventNotificationConsumer( is PollEvent, is GitPatchEvent, is GitIssueEvent, + is GitPullRequestEvent, + is GitPullRequestUpdateEvent, is HighlightEvent, is LongTextNoteEvent, is WikiNoteEvent, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt index 10cca27dc1..aeef3e5da1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt @@ -40,6 +40,8 @@ import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip34Git.reply.GitReplyEvent import com.vitorpamplona.quartz.nip47WalletConnect.events.LnZapPaymentResponseEvent import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent @@ -84,6 +86,8 @@ val NotificationsPerKeyKinds2 = GitReplyEvent.KIND, GitIssueEvent.KIND, GitPatchEvent.KIND, + GitPullRequestEvent.KIND, + GitPullRequestUpdateEvent.KIND, HighlightEvent.KIND, CommentEvent.KIND, CalendarDateSlotEvent.KIND, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt index 5e2d20ddd8..9840680ee9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt @@ -54,6 +54,8 @@ import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip52Calendar.appt.day.CalendarDateSlotEvent import com.vitorpamplona.quartz.nip52Calendar.appt.time.CalendarTimeSlotEvent import com.vitorpamplona.quartz.nip52Calendar.rsvp.CalendarRSVPEvent @@ -128,6 +130,8 @@ class NotificationFeedFilter( GenericRepostEvent.KIND, GitIssueEvent.KIND, GitPatchEvent.KIND, + GitPullRequestEvent.KIND, + GitPullRequestUpdateEvent.KIND, HighlightEvent.KIND, TextNoteEvent.KIND, ReactionEvent.KIND, @@ -205,7 +209,9 @@ class NotificationFeedFilter( return true } - if (event is GitIssueEvent || event is GitPatchEvent) { + if (event is GitIssueEvent || event is GitPatchEvent || + event is GitPullRequestEvent || event is GitPullRequestUpdateEvent + ) { return true } From 723432433205d9fe96b2a8acd2a68fb15d2b1fae Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 13:09:47 +0000 Subject: [PATCH 2/3] fix: escape apostrophes in fr-rCA CDATA strings Two French-Canadian CDATA string resources carried a raw apostrophe (`l'utilisateur`), which aapt2 rejects with "Invalid unicode escape sequence", breaking every Android resource merge (merge*Resources) and therefore the whole Android build. Escape them as `\'` like the other apostrophes in the file. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_018wCXL6btUeZZmSP1TCYkKh --- amethyst/src/main/res/values-fr-rCA/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/res/values-fr-rCA/strings.xml b/amethyst/src/main/res/values-fr-rCA/strings.xml index 5eefcf644f..d456a47d35 100644 --- a/amethyst/src/main/res/values-fr-rCA/strings.xml +++ b/amethyst/src/main/res/values-fr-rCA/strings.xml @@ -44,7 +44,7 @@ OTS : En attente Demande de suppression Bloquer / Signaler - + Signaler Spam / Arnaque Signaler une falsification d\'identité Signaler un comportement illégal @@ -401,7 +401,7 @@ Nudité ou contenu graphique Comportement illégal Bloquer un utilisateur cachera son contenu dans votre application. Vos notes sont toujours visibles publiquement, y compris pour les personnes que vous bloquez. Les utilisateurs bloqués sont listés sur l\'écran Filtres de Sécurité. - + Signaler un Abus Tous les rapports publiés seront visibles publiquement. Fournir un contexte optionnel supplémentaire sur votre signalement… From 3c041d2915e37c99fc4f8fc38b33be182eccf468 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 13:39:05 +0000 Subject: [PATCH 3/3] feat: modern git cards for pull requests, plus issue/patch polish NIP-34 pull requests (kind 1618) and pull-request updates (kind 1619) previously had no renderer and fell through to the plain text-note branch, so a PR notification opened onto an unstyled markdown blob with none of its structured data shown. Add dedicated cards that reuse the existing patch/issue card vocabulary (bordered container, type chip, status pill, embedded repository header) and surface the PR-specific metadata the event carries: - Pull Request card: "Pull Request" chip with a merge glyph, status pill, subject title, branch name, current commit, merge base, and clone-URL download rows. - PR Update card: "PR Update" chip, repository header, new commit / merge base, clone URLs, and an explanatory line (updates carry no body content). While here, modernize the existing cards consistently: - Factor the shared markdown body, metadata row, and subject title into reusable composables (GitMarkdownBody / GitMetaRow / GitSubjectTitle). - Show the issue subject as a proper title. The old code cast the event to TextNoteEvent to read the subject, which always returned null (GitIssueEvent is not a TextNoteEvent), so issue subjects were never displayed; read it from GitIssueEvent.subject() instead. - Render the patch commit as an iconed metadata row. Wire the two new kinds into NoteCompose and the thread detail view, add the CallMerge / Commit / AltRoute Material symbols (font subset regenerated), and add the new string resources. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_018wCXL6btUeZZmSP1TCYkKh --- .../amethyst/ui/note/NoteCompose.kt | 28 ++ .../amethyst/ui/note/types/Git.kt | 462 +++++++++++++----- .../loggedIn/threadview/ThreadFeedView.kt | 8 + amethyst/src/main/res/values/strings.xml | 6 + .../font/material_symbols_outlined.ttf | Bin 455704 -> 458856 bytes .../commons/icons/symbols/MaterialSymbols.kt | 3 + 6 files changed, 387 insertions(+), 120 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index b618a75605..6b5954a8a0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -138,6 +138,8 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource import com.vitorpamplona.amethyst.ui.note.types.RenderFundraiser import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestUpdateEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGoal import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight @@ -264,6 +266,8 @@ import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent @@ -1203,6 +1207,30 @@ private fun RenderNoteRow( ) } + is GitPullRequestEvent -> { + RenderGitPullRequestEvent( + baseNote, + makeItShort, + canPreview, + quotesLeft, + backgroundColor, + accountViewModel, + nav, + ) + } + + is GitPullRequestUpdateEvent -> { + RenderGitPullRequestUpdateEvent( + baseNote, + makeItShort, + canPreview, + quotesLeft, + backgroundColor, + accountViewModel, + nav, + ) + } + is PrivateDmEvent -> { RenderPrivateMessage( baseNote, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index 43b310e905..e54e800ccf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -37,7 +37,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -79,10 +78,10 @@ import com.vitorpamplona.amethyst.ui.theme.grayText import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.subtleBorder import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent -import com.vitorpamplona.quartz.nip14Subject.subject import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent private val CardShape = QuoteBorder @@ -141,19 +140,33 @@ private fun TypeChip( text: String, background: Color, contentColor: Color, + symbol: MaterialSymbol? = null, ) { - Text( - text = text, - style = MaterialTheme.typography.labelMedium, - fontWeight = FontWeight.SemiBold, - color = contentColor, - maxLines = 1, + Row( modifier = Modifier .clip(ChipShape) .background(background) .padding(horizontal = Size8dp, vertical = 2.dp), - ) + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(Size5dp), + ) { + symbol?.let { + Icon( + symbol = it, + contentDescription = null, + modifier = Modifier.size(14.dp), + tint = contentColor, + ) + } + Text( + text = text, + style = MaterialTheme.typography.labelMedium, + fontWeight = FontWeight.SemiBold, + color = contentColor, + maxLines = 1, + ) + } } @Composable @@ -180,6 +193,119 @@ private fun LinkRow( } } +@Composable +private fun GitSubjectTitle(text: String) { + Spacer(modifier = StdVertSpacer) + Text( + text = text, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSurface, + overflow = TextOverflow.Ellipsis, + maxLines = 3, + ) +} + +/** + * A small icon + value line for a piece of git metadata such as a branch name, + * commit hash or merge base. [value] is shown verbatim; commit-like hashes are + * expected to be shortened by the caller via [shortCommit]. + */ +@Composable +private fun GitMetaRow( + symbol: MaterialSymbol, + contentDescription: String?, + value: String, +) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = LinkRowSpacing, + ) { + Icon( + symbol = symbol, + contentDescription = contentDescription, + modifier = Modifier.size(Size16dp), + tint = MaterialTheme.colorScheme.grayText, + ) + Text( + text = value, + style = MaterialTheme.typography.labelMedium.copy(fontSize = Font12SP), + color = MaterialTheme.colorScheme.grayText, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } +} + +/** Shortens a 40-char git object id to its 7-char prefix for display. */ +private fun String.shortCommit(): String = if (length > 7) take(7) else this + +/** + * The shared markdown body used by patches, issues and pull requests: honors + * the collapsed [makeItShort] preview for the logged-in user's own posts and + * otherwise renders the full content with sensitivity warnings and uncited + * hashtags. The subject, when present, is rendered separately as a title by the + * caller, so it is not inlined here. + */ +@Composable +private fun GitMarkdownBody( + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + LoadDecryptedContent(note, accountViewModel) { body -> + val isAuthorTheLoggedUser = + remember(note.event) { accountViewModel.isLoggedUser(note.author) } + + if (makeItShort && isAuthorTheLoggedUser) { + Text( + text = body, + color = MaterialTheme.colorScheme.placeholderText, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + } else { + val callbackUri = remember(note) { note.toNostrUri() } + + SensitivityWarning( + note = note, + accountViewModel = accountViewModel, + ) { + val tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList } + + TranslatableRichTextViewer( + content = body, + canPreview = canPreview && !makeItShort, + quotesLeft = quotesLeft, + modifier = Modifier.fillMaxWidth(), + tags = tags, + backgroundColor = backgroundColor, + id = note.idHex, + callbackUri = callbackUri, + accountViewModel = accountViewModel, + nav = nav, + ) + } + + val event = note.event + if (event?.hasHashtags() == true) { + DisplayUncitedHashtags( + event = event, + content = body, + callbackUri = callbackUri, + accountViewModel = accountViewModel, + nav = nav, + ) + } + } + } +} + @Composable fun RenderGitPatchEvent( baseNote: Note, @@ -278,16 +404,6 @@ private fun RenderGitPatchEvent( ) GitStatusPill(targetIdHex = note.idHex, defaultIfMissing = StatusKind.OPEN) - - val commit = remember(noteEvent) { noteEvent.commit() } - commit?.takeIf { it.isNotBlank() }?.let { hash -> - Text( - text = hash.take(7), - style = MaterialTheme.typography.labelMedium.copy(fontSize = Font12SP), - color = MaterialTheme.colorScheme.grayText, - maxLines = 1, - ) - } } val repository = remember(noteEvent) { noteEvent.repositoryAddress() } @@ -300,66 +416,19 @@ private fun RenderGitPatchEvent( } } + val commit = remember(noteEvent) { noteEvent.commit()?.takeIf { it.isNotBlank() } } + if (commit != null) { + Spacer(modifier = StdVertSpacer) + GitMetaRow( + symbol = MaterialSymbols.Commit, + contentDescription = stringRes(id = R.string.git_commit), + value = commit.shortCommit(), + ) + } + Spacer(modifier = HalfDoubleVertSpacer) - LoadDecryptedContent(note, accountViewModel) { body -> - val eventContent by - remember(note.event) { - derivedStateOf { - val subject = (note.event as? TextNoteEvent)?.subject()?.ifEmpty { null } - - if (!subject.isNullOrBlank() && !body.split("\n")[0].contains(subject)) { - "### $subject\n$body" - } else { - body - } - } - } - - val isAuthorTheLoggedUser = - remember(note.event) { accountViewModel.isLoggedUser(note.author) } - - if (makeItShort && isAuthorTheLoggedUser) { - Text( - text = eventContent, - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) - } else { - val callbackUri = remember(note) { note.toNostrUri() } - - SensitivityWarning( - note = note, - accountViewModel = accountViewModel, - ) { - val tags = remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList } - - TranslatableRichTextViewer( - content = eventContent, - canPreview = canPreview && !makeItShort, - quotesLeft = quotesLeft, - modifier = Modifier.fillMaxWidth(), - tags = tags, - backgroundColor = backgroundColor, - id = note.idHex, - callbackUri = callbackUri, - accountViewModel = accountViewModel, - nav = nav, - ) - } - - if (note.event?.hasHashtags() == true) { - DisplayUncitedHashtags( - event = noteEvent, - content = eventContent, - callbackUri = callbackUri, - accountViewModel = accountViewModel, - nav = nav, - ) - } - } - } + GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav) } } @@ -412,6 +481,11 @@ private fun RenderGitIssueEvent( GitStatusPill(targetIdHex = note.idHex, defaultIfMissing = StatusKind.OPEN) } + val subject = remember(noteEvent) { noteEvent.subject()?.takeIf { it.isNotBlank() } } + if (subject != null) { + GitSubjectTitle(subject) + } + val repository = remember(noteEvent) { noteEvent.repositoryAddress() } if (repository != null) { Spacer(modifier = StdVertSpacer) @@ -424,56 +498,204 @@ private fun RenderGitIssueEvent( Spacer(modifier = HalfDoubleVertSpacer) - LoadDecryptedContent(note, accountViewModel) { body -> - val eventContent by - remember(note.event) { - derivedStateOf { - val subject = (note.event as? TextNoteEvent)?.subject()?.ifEmpty { null } + GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav) + } +} - if (!subject.isNullOrBlank() && !body.split("\n")[0].contains(subject)) { - "### $subject\n$body" - } else { - body - } - } +@Composable +fun RenderGitPullRequestEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + val event = baseNote.event as? GitPullRequestEvent ?: return + + RenderGitPullRequestEvent( + event, + baseNote, + makeItShort, + canPreview, + quotesLeft, + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +private fun RenderGitPullRequestEvent( + noteEvent: GitPullRequestEvent, + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + GitCardContainer { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = HeaderSpacing, + ) { + TypeChip( + text = stringRes(id = R.string.kind_git_pr), + background = MaterialTheme.colorScheme.secondary.copy(alpha = 0.15f), + contentColor = MaterialTheme.colorScheme.secondary, + symbol = MaterialSymbols.CallMerge, + ) + + GitStatusPill(targetIdHex = note.idHex, defaultIfMissing = StatusKind.OPEN) + } + + val subject = remember(noteEvent) { noteEvent.subject()?.takeIf { it.isNotBlank() } } + if (subject != null) { + GitSubjectTitle(subject) + } + + val repository = remember(noteEvent) { noteEvent.repositoryAddress() } + if (repository != null) { + Spacer(modifier = StdVertSpacer) + LoadAddressableNote(repository, accountViewModel) { + if (it != null) { + RenderShortRepositoryHeader(it, accountViewModel, nav) } + } + } - val isAuthorTheLoggedUser = - remember(note.event) { accountViewModel.isLoggedUser(note.author) } + val branch = remember(noteEvent) { noteEvent.branchName()?.takeIf { it.isNotBlank() } } + val currentCommit = remember(noteEvent) { noteEvent.currentCommit()?.takeIf { it.isNotBlank() } } + val mergeBase = remember(noteEvent) { noteEvent.mergeBase()?.takeIf { it.isNotBlank() } } + val cloneUrls = remember(noteEvent) { noteEvent.cloneUrls().filter { it.isNotBlank() } } - if (makeItShort && isAuthorTheLoggedUser) { - Text( - text = eventContent, - color = MaterialTheme.colorScheme.placeholderText, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) - } else { - val callbackUri = remember(note) { note.toNostrUri() } + if (branch != null || currentCommit != null || mergeBase != null) { + Spacer(modifier = StdVertSpacer) + Column(verticalArrangement = Arrangement.spacedBy(Size5dp)) { + branch?.let { + GitMetaRow(MaterialSymbols.AltRoute, stringRes(id = R.string.git_branch), it) + } + currentCommit?.let { + GitMetaRow(MaterialSymbols.Commit, stringRes(id = R.string.git_commit), it.shortCommit()) + } + mergeBase?.let { + GitMetaRow(MaterialSymbols.CallMerge, stringRes(id = R.string.git_merge_base), it.shortCommit()) + } + } + } - SensitivityWarning( - note = note, - accountViewModel = accountViewModel, - ) { - val tags = - remember(note) { note.event?.tags?.toImmutableListOfLists() ?: EmptyTagList } - - TranslatableRichTextViewer( - content = eventContent, - canPreview = canPreview && !makeItShort, - quotesLeft = quotesLeft, - modifier = Modifier.fillMaxWidth(), - tags = tags, - backgroundColor = backgroundColor, - id = note.idHex, - callbackUri = callbackUri, - accountViewModel = accountViewModel, - nav = nav, + if (cloneUrls.isNotEmpty()) { + Spacer(modifier = StdVertSpacer) + Column(verticalArrangement = Arrangement.spacedBy(Size5dp)) { + cloneUrls.forEach { url -> + LinkRow( + symbol = MaterialSymbols.CloudDownload, + contentDescription = stringRes(id = R.string.git_clone_address), + url = url, ) } + } + } - if (note.event?.hasHashtags() == true) { - DisplayUncitedHashtags(noteEvent, eventContent, callbackUri, accountViewModel, nav) + Spacer(modifier = HalfDoubleVertSpacer) + + GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav) + } +} + +@Composable +fun RenderGitPullRequestUpdateEvent( + baseNote: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + val event = baseNote.event as? GitPullRequestUpdateEvent ?: return + + RenderGitPullRequestUpdateEvent( + event, + baseNote, + makeItShort, + canPreview, + quotesLeft, + backgroundColor, + accountViewModel, + nav, + ) +} + +@Composable +private fun RenderGitPullRequestUpdateEvent( + noteEvent: GitPullRequestUpdateEvent, + note: Note, + makeItShort: Boolean, + canPreview: Boolean, + quotesLeft: Int, + backgroundColor: MutableState, + accountViewModel: AccountViewModel, + nav: INav, +) { + GitCardContainer { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = HeaderSpacing, + ) { + TypeChip( + text = stringRes(id = R.string.kind_git_pr_update), + background = MaterialTheme.colorScheme.surfaceVariant, + contentColor = MaterialTheme.colorScheme.onSurfaceVariant, + symbol = MaterialSymbols.Sync, + ) + } + + val repository = remember(noteEvent) { noteEvent.repositoryAddress() } + if (repository != null) { + Spacer(modifier = StdVertSpacer) + LoadAddressableNote(repository, accountViewModel) { + if (it != null) { + RenderShortRepositoryHeader(it, accountViewModel, nav) + } + } + } + + Spacer(modifier = HalfDoubleVertSpacer) + Text( + text = stringRes(id = R.string.git_pr_update_description), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.grayText, + ) + + val currentCommit = remember(noteEvent) { noteEvent.currentCommit()?.takeIf { it.isNotBlank() } } + val mergeBase = remember(noteEvent) { noteEvent.mergeBase()?.takeIf { it.isNotBlank() } } + val cloneUrls = remember(noteEvent) { noteEvent.cloneUrls().filter { it.isNotBlank() } } + + if (currentCommit != null || mergeBase != null) { + Spacer(modifier = StdVertSpacer) + Column(verticalArrangement = Arrangement.spacedBy(Size5dp)) { + currentCommit?.let { + GitMetaRow(MaterialSymbols.Commit, stringRes(id = R.string.git_commit), it.shortCommit()) + } + mergeBase?.let { + GitMetaRow(MaterialSymbols.CallMerge, stringRes(id = R.string.git_merge_base), it.shortCommit()) + } + } + } + + if (cloneUrls.isNotEmpty()) { + Spacer(modifier = StdVertSpacer) + Column(verticalArrangement = Arrangement.spacedBy(Size5dp)) { + cloneUrls.forEach { url -> + LinkRow( + symbol = MaterialSymbols.CloudDownload, + contentDescription = stringRes(id = R.string.git_clone_address), + url = url, + ) } } } 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 dd8ce05494..048a41c119 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 @@ -169,6 +169,8 @@ import com.vitorpamplona.amethyst.ui.note.types.RenderFhirResource import com.vitorpamplona.amethyst.ui.note.types.RenderFundraiser import com.vitorpamplona.amethyst.ui.note.types.RenderGitIssueEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitPatchEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestEvent +import com.vitorpamplona.amethyst.ui.note.types.RenderGitPullRequestUpdateEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGitRepositoryEvent import com.vitorpamplona.amethyst.ui.note.types.RenderGoal import com.vitorpamplona.amethyst.ui.note.types.RenderHighlight @@ -279,6 +281,8 @@ import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent +import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent @@ -926,6 +930,10 @@ private fun FullBleedNoteCompose( RenderGitPatchEvent(baseNote, makeItShort = false, canPreview = true, quotesLeft = 3, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav) } else if (noteEvent is GitIssueEvent) { RenderGitIssueEvent(baseNote, makeItShort = false, canPreview = true, quotesLeft = 3, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav) + } else if (noteEvent is GitPullRequestEvent) { + RenderGitPullRequestEvent(baseNote, makeItShort = false, canPreview = true, quotesLeft = 3, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav) + } else if (noteEvent is GitPullRequestUpdateEvent) { + RenderGitPullRequestUpdateEvent(baseNote, makeItShort = false, canPreview = true, quotesLeft = 3, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav) } else if (noteEvent is AppDefinitionEvent) { RenderAppDefinition(baseNote, accountViewModel, nav) } else if (noteEvent is AppRecommendationEvent) { diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 8a2c8cfe7f..1aecc9857d 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -2534,6 +2534,10 @@ Forked from Web: Clone: + Branch + Commit + Merge base + Updated the pull request to a new commit. Open Merged Closed @@ -2868,6 +2872,8 @@ Git Patch Git Repo Git Reply + Pull Request + PR Update Zap Goals Hashtag Follows Highlights diff --git a/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf b/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf index 89a43d0a2afc3d509e8d6ac78e14ac66fdb31e08..79ccdd87138597ca80a58d397d675f2ebc63f48c 100644 GIT binary patch delta 10009 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 OIC$*=X~Uxe!2bhED${fT diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt index 18f9818e3b..d5e253298d 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt @@ -31,6 +31,7 @@ object MaterialSymbols { val AddPhotoAlternate = MaterialSymbol("\uE43E") val AddReaction = MaterialSymbol("\uE1D3") val AlternateEmail = MaterialSymbol("\uE0E6") + val AltRoute = MaterialSymbol("\uF184") val Apps = MaterialSymbol("\uE5C3") val ArrowDownward = MaterialSymbol("\uE5DB") val ArrowUpward = MaterialSymbol("\uE5D8") @@ -52,6 +53,7 @@ object MaterialSymbols { val CalendarMonth = MaterialSymbol("\uEBCC") val Call = MaterialSymbol("\uF0D4") val CallEnd = MaterialSymbol("\uF0BC") + val CallMerge = MaterialSymbol("\uE0B3") val CameraAlt = MaterialSymbol("\uE412") val CameraFront = MaterialSymbol("\uF2C9") val CameraRear = MaterialSymbol("\uF2C8") @@ -74,6 +76,7 @@ object MaterialSymbols { val Code = MaterialSymbol("\uE86F") val Collections = MaterialSymbol("\uE3D3") val CollectionsBookmark = MaterialSymbol("\uE431") + val Commit = MaterialSymbol("\uEAF5") val ContentCopy = MaterialSymbol("\uE14D") val ContentPaste = MaterialSymbol("\uE14F") val CurrencyBitcoin = MaterialSymbol("\uEBC5")