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:
Claude
2026-06-26 13:39:05 +00:00
parent 7234324332
commit 3c041d2915
6 changed files with 387 additions and 120 deletions
@@ -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,
)
}
}
}
@@ -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) {
+6
View File
@@ -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>
@@ -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")