mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
Merge pull request #3544 from vitorpamplona/claude/pr-note-button-sizing-732r64
Clean up Git card styling and fix duplicated subject in content
This commit is contained in:
@@ -21,12 +21,10 @@
|
||||
package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -85,7 +83,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.repoHasFetchableClo
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.Font12SP
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size10dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size16dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.Size5dp
|
||||
@@ -93,7 +90,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size8dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
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.nip34Git.issue.GitIssueEvent
|
||||
import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent
|
||||
@@ -102,9 +98,7 @@ 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
|
||||
private val ChipShape = RoundedCornerShape(8.dp)
|
||||
private val CardPadding = PaddingValues(start = Size10dp, top = Size10dp, end = Size10dp, bottom = Size5dp)
|
||||
private val HeaderSpacing = Arrangement.spacedBy(Size8dp)
|
||||
private val LinkRowSpacing = Arrangement.spacedBy(Size8dp)
|
||||
|
||||
@@ -113,15 +107,7 @@ private fun GitCardContainer(
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val border = MaterialTheme.colorScheme.subtleBorder
|
||||
Column(
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.clip(CardShape)
|
||||
.border(1.dp, border, CardShape)
|
||||
.padding(CardPadding),
|
||||
) {
|
||||
Column(modifier = modifier.fillMaxWidth()) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -261,12 +247,31 @@ private fun GitMetaRow(
|
||||
/** 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
|
||||
|
||||
/**
|
||||
* Some NIP-34 clients duplicate the subject tag as a leading markdown heading of the
|
||||
* content ("# Title\n\n…"). The card already renders the subject as its own title, so
|
||||
* when the first line is a heading matching [subject], drop it from the body.
|
||||
*/
|
||||
private fun stripDuplicatedSubject(
|
||||
content: String,
|
||||
subject: String?,
|
||||
): String {
|
||||
if (subject.isNullOrBlank()) return content
|
||||
val trimmed = content.trimStart()
|
||||
if (!trimmed.startsWith("#")) return content
|
||||
val firstLineEnd = trimmed.indexOf('\n').let { if (it < 0) trimmed.length else it }
|
||||
val heading = trimmed.substring(0, firstLineEnd).trimStart('#').trim()
|
||||
if (!heading.equals(subject.trim(), ignoreCase = true)) return content
|
||||
return trimmed.substring(firstLineEnd).trimStart()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* caller, so it is not inlined here — pass it as [renderedSubject] so a copy
|
||||
* duplicated into the content as a leading heading is stripped.
|
||||
*/
|
||||
@Composable
|
||||
private fun GitMarkdownBody(
|
||||
@@ -277,8 +282,10 @@ private fun GitMarkdownBody(
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
renderedSubject: String? = null,
|
||||
) {
|
||||
LoadDecryptedContent(note, accountViewModel) { body ->
|
||||
LoadDecryptedContent(note, accountViewModel) { rawBody ->
|
||||
val body = remember(rawBody, renderedSubject) { stripDuplicatedSubject(rawBody, renderedSubject) }
|
||||
val isAuthorTheLoggedUser =
|
||||
remember(note.event) { accountViewModel.isLoggedUser(note.author) }
|
||||
|
||||
@@ -537,7 +544,7 @@ private fun RenderGitIssueEvent(
|
||||
|
||||
Spacer(modifier = HalfDoubleVertSpacer)
|
||||
|
||||
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav, renderedSubject = subject)
|
||||
|
||||
if (!makeItShort) {
|
||||
GitStatusActions(note, accountViewModel)
|
||||
@@ -669,7 +676,7 @@ private fun RenderGitPullRequestEvent(
|
||||
|
||||
Spacer(modifier = HalfDoubleVertSpacer)
|
||||
|
||||
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav, renderedSubject = subject)
|
||||
|
||||
if (!makeItShort) {
|
||||
GitPullRequestChanges(cloneUrls, currentCommit, mergeBase, accountViewModel)
|
||||
|
||||
+14
-6
@@ -99,9 +99,13 @@ fun GitPullRequestChanges(
|
||||
|
||||
when (val s = state) {
|
||||
ChangesState.Idle ->
|
||||
FilledTonalButton(onClick = { load() }, modifier = Modifier.padding(top = 8.dp)) {
|
||||
Icon(MaterialSymbols.Code, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Text(stringRes(R.string.git_pr_view_changes), modifier = Modifier.padding(start = 6.dp))
|
||||
FilledTonalButton(
|
||||
onClick = { load() },
|
||||
modifier = Modifier.padding(top = 8.dp).then(CompactButtonHeight),
|
||||
contentPadding = CompactButtonPadding,
|
||||
) {
|
||||
Icon(MaterialSymbols.Code, contentDescription = null, modifier = Modifier.size(16.dp))
|
||||
Text(stringRes(R.string.git_pr_view_changes), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
|
||||
ChangesState.Loading ->
|
||||
@@ -129,9 +133,13 @@ fun GitPullRequestChanges(
|
||||
}
|
||||
|
||||
ChangesState.Failed ->
|
||||
FilledTonalButton(onClick = { load() }, modifier = Modifier.padding(top = 8.dp)) {
|
||||
Icon(MaterialSymbols.Refresh, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Text(stringRes(R.string.git_pr_changes_retry), modifier = Modifier.padding(start = 6.dp))
|
||||
FilledTonalButton(
|
||||
onClick = { load() },
|
||||
modifier = Modifier.padding(top = 8.dp).then(CompactButtonHeight),
|
||||
contentPadding = CompactButtonPadding,
|
||||
) {
|
||||
Icon(MaterialSymbols.Refresh, contentDescription = null, modifier = Modifier.size(16.dp))
|
||||
Text(stringRes(R.string.git_pr_changes_retry), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-8
@@ -22,6 +22,8 @@ package com.vitorpamplona.amethyst.ui.note.types
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@@ -55,6 +57,10 @@ import com.vitorpamplona.quartz.nip34Git.status.GitStatusOpenEvent
|
||||
|
||||
private enum class StatusTarget { OPEN, CLOSED, APPLIED }
|
||||
|
||||
/** Compact sizing shared by the small action buttons on git cards. */
|
||||
internal val CompactButtonHeight = Modifier.height(32.dp)
|
||||
internal val CompactButtonPadding = PaddingValues(horizontal = 14.dp, vertical = 4.dp)
|
||||
|
||||
/**
|
||||
* NIP-34 status controls for an issue, patch or pull request. Visible only to the
|
||||
* people allowed to moderate the thread — the item's author and the repository
|
||||
@@ -85,23 +91,33 @@ fun GitStatusActions(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
if (closedOrApplied) {
|
||||
FilledTonalButton(onClick = { sendStatus(accountViewModel, note, StatusTarget.OPEN) }) {
|
||||
Icon(MaterialSymbols.RadioButtonChecked, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Text(stringRes(R.string.git_status_reopen), modifier = Modifier.padding(start = 6.dp))
|
||||
FilledTonalButton(
|
||||
onClick = { sendStatus(accountViewModel, note, StatusTarget.OPEN) },
|
||||
modifier = CompactButtonHeight,
|
||||
contentPadding = CompactButtonPadding,
|
||||
) {
|
||||
Icon(MaterialSymbols.RadioButtonChecked, contentDescription = null, modifier = Modifier.size(16.dp))
|
||||
Text(stringRes(R.string.git_status_reopen), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
} else {
|
||||
if (isPatchOrPr) {
|
||||
FilledTonalButton(onClick = { sendStatus(accountViewModel, note, StatusTarget.APPLIED) }) {
|
||||
Icon(MaterialSymbols.Check, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Text(stringRes(R.string.git_status_mark_merged), modifier = Modifier.padding(start = 6.dp))
|
||||
FilledTonalButton(
|
||||
onClick = { sendStatus(accountViewModel, note, StatusTarget.APPLIED) },
|
||||
modifier = CompactButtonHeight,
|
||||
contentPadding = CompactButtonPadding,
|
||||
) {
|
||||
Icon(MaterialSymbols.Check, contentDescription = null, modifier = Modifier.size(16.dp))
|
||||
Text(stringRes(R.string.git_status_mark_merged), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
}
|
||||
OutlinedButton(
|
||||
onClick = { sendStatus(accountViewModel, note, StatusTarget.CLOSED) },
|
||||
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error),
|
||||
modifier = CompactButtonHeight,
|
||||
contentPadding = CompactButtonPadding,
|
||||
) {
|
||||
Icon(MaterialSymbols.Cancel, contentDescription = null, modifier = Modifier.size(18.dp))
|
||||
Text(stringRes(R.string.git_status_close), modifier = Modifier.padding(start = 6.dp))
|
||||
Icon(MaterialSymbols.Cancel, contentDescription = null, modifier = Modifier.size(16.dp))
|
||||
Text(stringRes(R.string.git_status_close), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user