mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCXL6btUeZZmSP1TCYkKh
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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<Color>,
|
||||
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<Color>,
|
||||
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<Color>,
|
||||
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<Color>,
|
||||
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<Color>,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -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) {
|
||||
|
||||
@@ -2534,6 +2534,10 @@
|
||||
<string name="forked_from">Forked from</string>
|
||||
<string name="git_web_address">Web:</string>
|
||||
<string name="git_clone_address">Clone:</string>
|
||||
<string name="git_branch">Branch</string>
|
||||
<string name="git_commit">Commit</string>
|
||||
<string name="git_merge_base">Merge base</string>
|
||||
<string name="git_pr_update_description">Updated the pull request to a new commit.</string>
|
||||
<string name="git_status_open">Open</string>
|
||||
<string name="git_status_merged">Merged</string>
|
||||
<string name="git_status_closed">Closed</string>
|
||||
@@ -2868,6 +2872,8 @@
|
||||
<string name="kind_git_patch">Git Patch</string>
|
||||
<string name="kind_git_repo">Git Repo</string>
|
||||
<string name="kind_git_reply">Git Reply</string>
|
||||
<string name="kind_git_pr">Pull Request</string>
|
||||
<string name="kind_git_pr_update">PR Update</string>
|
||||
<string name="kind_zap_goals">Zap Goals</string>
|
||||
<string name="kind_hashtag_follows">Hashtag Follows</string>
|
||||
<string name="kind_highlights">Highlights</string>
|
||||
|
||||
Binary file not shown.
+3
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user