refactor: Update ShareTargetActivity and ChannelSideDrawer for improved user context handling

This commit refines the user context handling in ShareTargetActivity and ChannelSideDrawer components.

- Modified the onOpenUserInfoSheet callback in ShareTargetActivity to accept a user ID parameter.
- Enhanced ChannelSideDrawer to utilize the updated onOpenUserInfoSheet callback for better user context interactions.
- Adjusted the ModalBottomSheet state in ChannelSideDrawer to skip partially expanded states for improved user experience.
- Cleaned up unused code and improved overall readability in the affected files.
This commit is contained in:
AbronStudio 2025-08-19 16:01:40 +03:30
parent 48513b761b
commit d639048b5c
5 changed files with 374 additions and 389 deletions

View File

@ -352,7 +352,7 @@ fun ShareTargetScreen(
hasUnread = false,
onDestinationChanged = { selectedChannel = channel.id },
onOpenChannelContextSheet = {},
onOpenUserInfoSheet = {}
onOpenUserInfoSheet = {_ ->}
)
else -> ChannelItem(

View File

@ -192,7 +192,9 @@ fun ChannelSideDrawer(
}
if (userContextSheetTarget != null) {
val userContextSheetState = rememberModalBottomSheetState()
val userContextSheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true,
)
ModalBottomSheet(
sheetState = userContextSheetState,
onDismissRequest = {
@ -826,8 +828,8 @@ private fun ColumnScope.DirectMessagesChannelListRenderer(
onDestinationChanged = { dest ->
onDestinationChanged(dest)
},
onOpenChannelContextSheet = onOpenUserInfoSheet,
onOpenUserInfoSheet = onOpenUserInfoSheet
onOpenChannelContextSheet = {},
onOpenUserInfoSheet = {userId -> onOpenUserInfoSheet(userId)}
)
}
}

View File

@ -250,95 +250,5 @@ fun UserButtons(
"BlockedOther" -> Box(Modifier.weight(1f))
}
if (user.relationship != "User") {
Row { // Prevent the dropdown menu from counting towards arrangement spacing
DropdownMenu(
expanded = menuOpen,
onDismissRequest = { menuOpen = false }
) {
when (user.relationship) {
"Friend" -> {
DropdownMenuItem(
text = {
Text(stringResource(R.string.user_info_sheet_remove_friend))
},
onClick = {
scope.launch {
try {
unfriendUser(user.id)
} catch (e: Exception) {
if (e.message == "NoEffect") return@launch
logcat(LogPriority.ERROR) { e.asLog() }
}
}
}
)
}
}
when (user.relationship) {
"Blocked" -> {}
else -> DropdownMenuItem(
text = {
Text(stringResource(R.string.user_info_sheet_block))
},
onClick = {
scope.launch {
try {
blockUser(user.id)
} catch (e: Exception) {
if (e.message == "NoEffect") return@launch
logcat(LogPriority.ERROR) { e.asLog() }
}
}
}
)
}
DropdownMenuItem(
text = {
Text(stringResource(R.string.user_info_sheet_copy_id))
},
onClick = {
scope.launch {
clipboard.setText(AnnotatedString(user.id))
}
}
)
DropdownMenuItem(
text = {
Text(stringResource(R.string.user_info_sheet_report))
},
onClick = {
scope.launch {
ActionChannel.send(Action.ReportUser(user.id))
if (Platform.needsShowClipboardNotification()) {
Toast.makeText(
context,
context.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
}
}
}
)
}
IconButton(
onClick = {
menuOpen = true
}
) {
Icon(
painter = painterResource(R.drawable.icn_more_vert_24dp),
contentDescription = stringResource(R.string.menu)
)
}
}
}
}
}

View File

@ -369,7 +369,7 @@ private fun NotificationOptionButton(
}
@Composable
private fun NotificationRadioRow(
fun NotificationRadioRow(
title: String,
type: NotificationType,
channelId: String,

View File

@ -1,24 +1,29 @@
package chat.peptide.sheets
import android.text.format.DateUtils
import android.widget.Toast
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SmallFloatingActionButton
@ -29,35 +34,42 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.peptide.R
import chat.peptide.api.PeptideAPI
import chat.peptide.api.internals.BrushCompat
import chat.peptide.api.internals.ULID
import chat.peptide.api.internals.solidColor
import chat.peptide.api.routes.user.fetchUserProfile
import chat.peptide.api.routes.user.blockUser
import chat.peptide.api.routes.user.getOrFetchUser
import chat.peptide.api.schemas.Profile
import chat.peptide.api.routes.user.unfriendUser
import chat.peptide.api.schemas.ChannelType
import chat.peptide.api.schemas.NotificationSettings
import chat.peptide.api.settings.Experiments
import chat.peptide.api.settings.FeatureFlags
import chat.peptide.composables.chat.RoleListEntry
import chat.peptide.composables.chat.UserBadgeList
import chat.peptide.composables.chat.UserBadgeRow
import chat.peptide.api.settings.NotificationType
import chat.peptide.api.settings.SyncedSettings
import chat.peptide.callbacks.Action
import chat.peptide.callbacks.ActionChannel
import chat.peptide.composables.generic.NonIdealState
import chat.peptide.composables.generic.SheetButton
import chat.peptide.composables.generic.UserAvatar
import chat.peptide.composables.markdown.RichMarkdown
import chat.peptide.composables.screens.settings.RawUserOverview
import chat.peptide.composables.screens.settings.UserButtons
import chat.peptide.composables.sheets.SheetTile
import kotlinx.datetime.Instant
import chat.peptide.internals.Platform
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import logcat.LogPriority
import logcat.asLog
import logcat.logcat
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -82,20 +94,6 @@ fun UserInfoSheet(
val server = PeptideAPI.serverCache[serverId]
var profile by remember { mutableStateOf<Profile?>(null) }
var profileNotFound by remember { mutableStateOf(false) }
LaunchedEffect(resolvedUser) {
try {
resolvedUser?.id?.let { fetchUserProfile(it) }?.let { profile = it }
} catch (e: Exception) {
if (e.message == "NotFound") {
profileNotFound = true
}
e.printStackTrace()
}
}
if (resolvedUser == null) {
NonIdealState(
icon = {
@ -144,288 +142,363 @@ fun UserInfoSheet(
}
}
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalItemSpacing = 16.dp,
modifier = Modifier.padding(16.dp)
) {
item(key = "overview", span = StaggeredGridItemSpan.FullLine) {
Box {
RawUserOverview(resolvedUser!!, profile, internalPadding = false)
Row(
modifier = Modifier
.align(Alignment.TopEnd)
.padding(top = 8.dp, end = 8.dp)
) {
if (Experiments.enableServerIdentityOptions.isEnabled) {
SmallFloatingActionButton(
onClick = { showServerIdentityOptions = true },
) {
Icon(
painter = painterResource(R.drawable.icn_psychology_alt_24dp),
contentDescription = null
)
}
}
// Page state: 0 = main, 1 = notifications
var page by remember { mutableStateOf(0) }
if (FeatureFlags.userCardsGranted) {
SmallFloatingActionButton(
onClick = { showUserCard = true },
) {
Icon(
painter = painterResource(R.drawable.icn_badge_24dp),
contentDescription = null
)
}
}
}
AnimatedContent(
targetState = page,
transitionSpec = {
if (targetState > initialState) {
slideInHorizontally(animationSpec = tween(200)) { it } togetherWith
slideOutHorizontally(animationSpec = tween(200)) { -it }
} else {
slideInHorizontally(animationSpec = tween(200)) { -it } togetherWith
slideOutHorizontally(animationSpec = tween(200)) { it }
}
}
member?.roles?.let {
item(key = "roles") {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_roles))
},
contentPreview = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
it
.map { roleId -> server?.roles?.get(roleId) }
.sortedBy { it?.rank ?: 0.0 }
.take(3)
.forEach { role ->
role?.let {
RoleListEntry(
label = role.name ?: "null",
brush = role.colour?.let { BrushCompat.parseColour(it) }
?: Brush.solidColor(LocalContentColor.current)
)
}
}
}
}
) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
it
.map { roleId -> server?.roles?.get(roleId) }
.sortedBy { it?.rank ?: 0.0 }
.forEach { role ->
role?.let {
RoleListEntry(
label = role.name ?: "null",
brush = role.colour?.let { BrushCompat.parseColour(it) }
?: Brush.solidColor(LocalContentColor.current)
}, label = "User info actions pager"
) { current ->
val scope = rememberCoroutineScope()
val clipboardManager = LocalClipboardManager.current
val context = LocalContext.current
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalItemSpacing = 16.dp,
modifier = Modifier.padding(16.dp)
) {
if (current == 0) {
item(key = "overview", span = StaggeredGridItemSpan.FullLine) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceBright)
.padding(16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
UserAvatar(
username = resolvedUser!!.displayName ?: resolvedUser!!.username
?: stringResource(R.string.unknown),
avatar = resolvedUser!!.avatar,
userId = resolvedUser!!.id!!,
size = 64.dp
)
Column(modifier = Modifier.weight(1f)) {
Text(
text = resolvedUser!!.displayName ?: resolvedUser!!.username
?: stringResource(R.string.unknown),
style = MaterialTheme.typography.titleMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
resolvedUser!!.username?.let { uname ->
Text(
text = "@" + uname,
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
}
}
}
val accountAt = resolvedUser!!.id?.let {
DateUtils.getRelativeTimeSpanString(
ULID.asTimestamp(resolvedUser!!.id!!),
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS
).toString()
}
val joinedAt = member?.joinedAt?.let {
DateUtils.getRelativeTimeSpanString(
Instant.parse(member.joinedAt).toEpochMilliseconds(),
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS
).toString()
}
item(key = "joined") {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_joined))
},
contentPreview = {
if (joinedAt != null && server?.name != null) {
Text(
text = joinedAt,
fontSize = 14.sp
)
Text(
text = server.name,
style = MaterialTheme.typography.labelMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(Modifier.height(4.dp))
}
accountAt?.let { _ ->
Text(
text = accountAt,
fontSize = 14.sp
)
Text(
text = stringResource(id = R.string.user_info_sheet_category_joined_peptide),
style = MaterialTheme.typography.labelMedium
)
}
}
) {
if (joinedAt != null && server?.name != null) {
Text(
text = joinedAt,
style = MaterialTheme.typography.displaySmall
)
Text(
text = server.name,
style = MaterialTheme.typography.labelMedium
)
Spacer(Modifier.height(8.dp))
}
accountAt?.let { _ ->
Text(
text = accountAt,
style = MaterialTheme.typography.displaySmall
)
Text(
text = stringResource(id = R.string.user_info_sheet_category_joined_peptide),
style = MaterialTheme.typography.labelMedium
)
}
}
}
if ((resolvedUser?.badges ?: 0) > 0) {
item(key = "info") {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_badges))
},
contentPreview = {
resolvedUser?.badges?.let { UserBadgeRow(badges = it) }
}
) {
resolvedUser?.badges?.let { UserBadgeList(badges = it) }
}
}
}
if (resolvedUser?.status?.text != null) {
item(key = "status") {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_status))
},
contentPreview = {
Text(
text = resolvedUser!!.status!!.text ?: "",
fontSize = 14.sp,
maxLines = 5,
overflow = TextOverflow.Ellipsis
)
}
) {
Text(
text = resolvedUser!!.status!!.text ?: "",
style = MaterialTheme.typography.bodyMedium
)
}
}
}
if (resolvedUser?.bot != null) {
val resolvedOwner = resolvedUser!!.bot!!.owner?.let { PeptideAPI.userCache[it] }
item(key = "bot-owner") {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_owner))
},
contentPreview = {
Row(
verticalAlignment = Alignment.CenterVertically
) {
resolvedOwner?.let {
UserAvatar(
username = it.displayName ?: it.username
?: stringResource(R.string.unknown),
avatar = it.avatar,
userId = it.id!!,
size = 32.dp
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = it.displayName ?: it.username
?: stringResource(R.string.unknown),
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
} ?: run {
Icon(
painter = painterResource(id = R.drawable.icn_error_24dp),
contentDescription = null
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.unknown),
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
if (Experiments.enableServerIdentityOptions.isEnabled || FeatureFlags.userCardsGranted) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
if (Experiments.enableServerIdentityOptions.isEnabled) {
SmallFloatingActionButton(onClick = {
showServerIdentityOptions = true
}) {
Icon(
painter = painterResource(R.drawable.icn_psychology_alt_24dp),
contentDescription = null
)
}
}
if (FeatureFlags.userCardsGranted) {
SmallFloatingActionButton(onClick = {
showUserCard = true
}) {
Icon(
painter = painterResource(R.drawable.icn_badge_24dp),
contentDescription = null
)
}
}
}
}
}
resolvedUser!!.status?.text?.takeIf { it.isNotBlank() }?.let { st ->
Spacer(Modifier.height(12.dp))
Text(
text = st,
style = MaterialTheme.typography.bodyMedium
)
}
}
) {
resolvedOwner?.let {
RawUserOverview(it, null, internalPadding = false)
} ?: run {
NonIdealState(
icon = {
}
// Primary actions block (View Profile, Message, Notification Options, Copy DM ID)
item(key = "primary-actions", span = StaggeredGridItemSpan.FullLine) {
if (current == 0) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceBright)
) {
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.overview_screen_settings)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.icn_settings_24dp),
contentDescription = null
)
},
onClick = { /* open profile */ }
)
HorizontalDivider()
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.message_friends)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.ic_new_message),
contentDescription = null
)
},
onClick = { /* open DM screen */ }
)
HorizontalDivider()
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.channel_info_sheet_options_notifications_manage)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.icn_notification_settings_24dp),
contentDescription = null
)
},
onClick = { page = 1 }
)
HorizontalDivider()
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.channel_context_sheet_actions_copy_id)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.icn_identifier_copy_24dp),
contentDescription = null
)
},
onClick = {
resolvedUser?.id?.let { userId ->
scope.launch {
clipboardManager.setText(AnnotatedString(userId))
Toast.makeText(
context,
context.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
}
}
}
)
}
}
}
// Danger block (Close DM, Report User)
item(key = "danger-actions", span = StaggeredGridItemSpan.FullLine) {
Column(
modifier = Modifier
.padding(top = 16.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceBright)
) {
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.user_info_sheet_block)) },
leadingContent = {
Icon(
painter = painterResource(id = R.drawable.icn_error_24dp),
painter = painterResource(R.drawable.icn_block_24dp),
contentDescription = null,
modifier = Modifier.size(24.dp)
)
},
title = {
Text(
text = stringResource(R.string.user_info_sheet_owner_not_found)
onClick = {
scope.launch {
try {
resolvedUser?.id?.let { userId ->
blockUser(userId)
}
} catch (e: Exception) {
if (e.message == "NoEffect") return@launch
logcat(LogPriority.ERROR) { e.asLog() }
}
}
},
modifier = Modifier,
dangerous = true
)
if(resolvedUser?.relationship == "Friend"){
HorizontalDivider()
SheetButton(
headlineContent = { Text(stringResource(R.string.user_info_sheet_remove_friend)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.icn_group_remove_24dp),
contentDescription = null
)
},
onClick = {
resolvedUser?.id?.let {userId ->
scope.launch {
try {
unfriendUser(userId)
} catch (e: Exception) {
if (e.message == "NoEffect") return@launch
logcat(LogPriority.ERROR) { e.asLog() }
}
}
}
},
dangerous = true
)
}
HorizontalDivider()
SheetButton(
headlineContent = { Text(text = stringResource(id = R.string.report)) },
leadingContent = {
Icon(
painter = painterResource(R.drawable.icn_psychology_alt_24dp),
contentDescription = null
)
}
},
onClick = {
resolvedUser?.id?.let { userId ->
scope.launch {
ActionChannel.send(Action.ReportUser(userId))
if (Platform.needsShowClipboardNotification()) {
Toast.makeText(
context,
context.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
}
}
}
},
dangerous = true
)
}
}
}
}
if (profile?.content.isNullOrBlank().not()) {
item(key = "bio", span = StaggeredGridItemSpan.FullLine) {
SheetTile(
header = {
Text(stringResource(R.string.user_info_sheet_category_bio))
},
contentPreview = {
RichMarkdown(input = profile?.content!!)
}
) {
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) {
RichMarkdown(input = profile?.content!!)
// Removed joined, badges, and bio sections per request
item(key = "actions", span = StaggeredGridItemSpan.FullLine) {
UserButtons(resolvedUser!!, dismissSheet)
}
} else {
item(key = "notifications", span = StaggeredGridItemSpan.FullLine) {
// Notifications page
Column {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_left_24dp),
contentDescription = null,
modifier = Modifier
.size(24.dp)
.clickable { page = 0 }
.align(Alignment.CenterStart)
)
Text(
modifier = Modifier.align(Alignment.Center),
text = stringResource(id = R.string.channel_info_sheet_options_notifications_manage),
style = MaterialTheme.typography.titleMedium
)
}
Column(
modifier = Modifier
.padding(top = 24.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceBright)
) {
// Radio options
val dmChannelId = PeptideAPI.channelCache.values.firstOrNull { ch ->
ch.channelType == ChannelType.DirectMessage && ch.user == resolvedUser!!.id
}?.id
var selected by remember {
mutableStateOf(
NotificationType.fromStorage(
SyncedSettings.notifications.channel[dmChannelId ?: ""]
).storageValue
)
}
fun updateSelection(newValue: NotificationType) {
selected = newValue.storageValue
val currentSettings = SyncedSettings.notifications
val updated = NotificationSettings(
server = currentSettings.server,
channel = currentSettings.channel.toMutableMap().apply {
if (dmChannelId.isNullOrBlank() || newValue == NotificationType.DEFAULT) {
if (!dmChannelId.isNullOrBlank()) remove(dmChannelId)
} else {
put(dmChannelId, newValue.storageValue)
}
}
)
GlobalScope.launch {
SyncedSettings.updateNotifications(updated)
}
}
NotificationRadioRow(
title = stringResource(id = R.string.notification_option_use_default),
type = NotificationType.DEFAULT,
channelId = dmChannelId ?: "",
current = selected,
onChange = { updateSelection(NotificationType.DEFAULT) }
)
HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp))
NotificationRadioRow(
title = stringResource(id = R.string.notification_option_muted),
type = NotificationType.MUTED,
channelId = dmChannelId ?: "",
current = selected,
onChange = { updateSelection(NotificationType.MUTED) }
)
HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp))
NotificationRadioRow(
title = stringResource(id = R.string.notification_option_all_messages),
type = NotificationType.ALL,
channelId = dmChannelId ?: "",
current = selected,
onChange = { updateSelection(NotificationType.ALL) }
)
HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp))
NotificationRadioRow(
title = stringResource(id = R.string.notification_option_mentions_only),
type = NotificationType.MENTIONS_ONLY,
channelId = dmChannelId ?: "",
current = selected,
onChange = { updateSelection(NotificationType.MENTIONS_ONLY) }
)
HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp))
NotificationRadioRow(
title = stringResource(id = R.string.notification_option_none),
type = NotificationType.NONE,
channelId = dmChannelId ?: "",
current = selected,
onChange = { updateSelection(NotificationType.NONE) }
)
}
}
}
}
}
item(key = "actions", span = StaggeredGridItemSpan.FullLine) {
UserButtons(resolvedUser!!, dismissSheet)
}
}
}