From d639048b5c5c821106a8a0a9b1ee450517286124 Mon Sep 17 00:00:00 2001 From: AbronStudio Date: Tue, 19 Aug 2025 16:01:40 +0330 Subject: [PATCH] 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. --- .../peptide/activities/ShareTargetActivity.kt | 2 +- .../screens/chat/drawer/ChannelSideDrawer.kt | 8 +- .../screens/settings/UserButtons.kt | 90 --- .../peptide/sheets/ChannelContextSheet.kt | 2 +- .../java/chat/peptide/sheets/UserInfoSheet.kt | 661 ++++++++++-------- 5 files changed, 374 insertions(+), 389 deletions(-) diff --git a/app/src/main/java/chat/peptide/activities/ShareTargetActivity.kt b/app/src/main/java/chat/peptide/activities/ShareTargetActivity.kt index 1e921063..7fed102d 100644 --- a/app/src/main/java/chat/peptide/activities/ShareTargetActivity.kt +++ b/app/src/main/java/chat/peptide/activities/ShareTargetActivity.kt @@ -352,7 +352,7 @@ fun ShareTargetScreen( hasUnread = false, onDestinationChanged = { selectedChannel = channel.id }, onOpenChannelContextSheet = {}, - onOpenUserInfoSheet = {} + onOpenUserInfoSheet = {_ ->} ) else -> ChannelItem( diff --git a/app/src/main/java/chat/peptide/composables/screens/chat/drawer/ChannelSideDrawer.kt b/app/src/main/java/chat/peptide/composables/screens/chat/drawer/ChannelSideDrawer.kt index 3b26eff3..905151aa 100644 --- a/app/src/main/java/chat/peptide/composables/screens/chat/drawer/ChannelSideDrawer.kt +++ b/app/src/main/java/chat/peptide/composables/screens/chat/drawer/ChannelSideDrawer.kt @@ -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)} ) } } diff --git a/app/src/main/java/chat/peptide/composables/screens/settings/UserButtons.kt b/app/src/main/java/chat/peptide/composables/screens/settings/UserButtons.kt index 23a82b63..41394410 100644 --- a/app/src/main/java/chat/peptide/composables/screens/settings/UserButtons.kt +++ b/app/src/main/java/chat/peptide/composables/screens/settings/UserButtons.kt @@ -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) - ) - } - } - } } } \ No newline at end of file diff --git a/app/src/main/java/chat/peptide/sheets/ChannelContextSheet.kt b/app/src/main/java/chat/peptide/sheets/ChannelContextSheet.kt index 7b2f882f..f707c31f 100644 --- a/app/src/main/java/chat/peptide/sheets/ChannelContextSheet.kt +++ b/app/src/main/java/chat/peptide/sheets/ChannelContextSheet.kt @@ -369,7 +369,7 @@ private fun NotificationOptionButton( } @Composable -private fun NotificationRadioRow( +fun NotificationRadioRow( title: String, type: NotificationType, channelId: String, diff --git a/app/src/main/java/chat/peptide/sheets/UserInfoSheet.kt b/app/src/main/java/chat/peptide/sheets/UserInfoSheet.kt index 9108eb40..4bca62d3 100644 --- a/app/src/main/java/chat/peptide/sheets/UserInfoSheet.kt +++ b/app/src/main/java/chat/peptide/sheets/UserInfoSheet.kt @@ -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(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) - } } - } \ No newline at end of file