feat: modernize notify-tag chips in new post screens

Replace the plain solid-color buttons used for Notify: mentions with
Material3 InputChips that show each user's avatar and display name plus a
remove (X) trailing icon, matching the modern contact-chip pattern. The
add-user action now uses an AssistChip with a PersonAdd icon.

Since the Notifying composable is shared, this updates the look across all
new post screens (short notes, comments/replies, and polls).
This commit is contained in:
Claude
2026-06-13 03:38:32 +00:00
parent eff826f3d5
commit d7a552770f
2 changed files with 59 additions and 56 deletions
@@ -23,27 +23,28 @@ package com.vitorpamplona.amethyst.ui.note.creators.notify
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material3.AssistChip
import androidx.compose.material3.AssistChipDefaults
import androidx.compose.material3.InputChip
import androidx.compose.material3.InputChipDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
import com.vitorpamplona.amethyst.ui.theme.Size24dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.collections.immutable.ImmutableList
@@ -59,7 +60,10 @@ fun Notifying(
) {
val mentions = baseMentions?.toSet()
FlowRow(horizontalArrangement = Arrangement.spacedBy(5.dp)) {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
if (!mentions.isNullOrEmpty() || showWhenEmpty) {
Text(
label ?: stringRes(R.string.reply_notify),
@@ -68,60 +72,58 @@ fun Notifying(
modifier = Modifier.align(CenterVertically),
)
mentions?.forEachIndexed { _, user ->
Button(
shape = ButtonBorder,
colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.mediumImportanceLink,
),
onClick = { onClick(user) },
) {
DisplayUserNameWithDeleteMark(user, accountViewModel)
}
mentions?.forEach { user ->
NotifyUserChip(user, accountViewModel) { onClick(user) }
}
if (onAddUser != null) {
Button(
shape = ButtonBorder,
colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.mediumImportanceLink,
),
onClick = onAddUser,
) {
Text(
text = stringRes(R.string.notify_add_user),
color = Color.White,
textAlign = TextAlign.Center,
)
}
AddUserChip(onAddUser)
}
}
}
}
@Composable
private fun DisplayUserNameWithDeleteMark(
private fun NotifyUserChip(
user: User,
accountViewModel: AccountViewModel,
onRemove: () -> Unit,
) {
val innerUserState by observeUserInfo(user, accountViewModel)
val meta = innerUserState
if (meta != null) {
CreateTextWithEmoji(
text = remember(meta) { "${meta.info.bestName() ?: user.pubkeyDisplayHex()}" },
tags = meta.tags,
color = Color.White,
textAlign = TextAlign.Center,
)
} else {
Text(
text = remember(meta) { "${user.pubkeyDisplayHex()}" },
color = Color.White,
textAlign = TextAlign.Center,
)
}
InputChip(
selected = false,
onClick = onRemove,
label = {
UsernameDisplay(
user,
weight = Modifier.widthIn(max = 180.dp),
fontWeight = FontWeight.SemiBold,
accountViewModel = accountViewModel,
)
},
avatar = {
BaseUserPicture(user, Size24dp, accountViewModel)
},
trailingIcon = {
Icon(
symbol = MaterialSymbols.Close,
contentDescription = stringRes(R.string.notify_remove_user),
modifier = Modifier.size(InputChipDefaults.IconSize),
)
},
)
}
@Composable
private fun AddUserChip(onAddUser: () -> Unit) {
AssistChip(
onClick = onAddUser,
label = { Text(text = stringRes(R.string.notify_add_user)) },
leadingIcon = {
Icon(
symbol = MaterialSymbols.PersonAdd,
contentDescription = null,
modifier = Modifier.size(AssistChipDefaults.IconSize),
)
},
)
}
+2 -1
View File
@@ -990,7 +990,8 @@
<string name="private_note_locked">Replies to a private note always stay private</string>
<string name="private_note_visible_to">Visible to</string>
<string name="private_note_no_receivers">No receivers yet: only you will be able to see this note. Add people to share it with.</string>
<string name="notify_add_user">+ Add</string>
<string name="notify_add_user">Add</string>
<string name="notify_remove_user">Remove user from notifications</string>
<string name="notify_search_and_add_user">Search and add a user to notify</string>
<string name="bookmark_absence_indicator">is not a bookmark here</string>
<string name="bookmark_remove_action_desc">Remove bookmark from list</string>