diff --git a/app/src/main/java/chat/peptide/sheets/ServerContextSheet.kt b/app/src/main/java/chat/peptide/sheets/ServerContextSheet.kt index 22cdf459..3704e291 100644 --- a/app/src/main/java/chat/peptide/sheets/ServerContextSheet.kt +++ b/app/src/main/java/chat/peptide/sheets/ServerContextSheet.kt @@ -3,6 +3,12 @@ package chat.peptide.sheets import android.content.Intent import android.widget.Toast import androidx.compose.foundation.background +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.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -11,6 +17,7 @@ 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.rememberScrollState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll @@ -22,8 +29,10 @@ import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.RadioButton import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -44,6 +53,9 @@ import androidx.core.net.toUri import chat.peptide.R import chat.peptide.api.PeptideAPI import chat.peptide.api.routes.server.leaveOrDeleteServer +import chat.peptide.api.schemas.NotificationSettings +import chat.peptide.api.settings.NotificationType +import chat.peptide.api.settings.SyncedSettings import chat.peptide.composables.generic.PepTextButton import chat.peptide.composables.generic.SheetButton import chat.peptide.composables.generic.SquareButton @@ -54,6 +66,7 @@ import chat.peptide.callbacks.Action import chat.peptide.callbacks.ActionChannel import chat.peptide.internals.Platform import chat.peptide.screens.chat.ChatRouterDestination +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @Composable @@ -81,6 +94,7 @@ fun ServerContextSheet( return } + var page by remember { mutableIntStateOf(0) } if (showLeaveConfirmation) { AlertDialog( @@ -160,167 +174,305 @@ fun ServerContextSheet( ) } - Column(Modifier.verticalScroll(rememberScrollState())) { - Column( - verticalArrangement = Arrangement.spacedBy(16.dp), - modifier = Modifier - .padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), - ) { - ServerOverview(server) + 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 } + } + }, label = "Server context pager" + ) { current -> + if (current == 0) { + Column(Modifier.verticalScroll(rememberScrollState())) { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier + .padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), + ) { + ServerOverview(server) - SelectionContainer { - RichMarkdown( - input = if (server.description?.isBlank() == false) { - server.description - } else { - stringResource( - R.string.server_context_sheet_description_empty + SelectionContainer { + RichMarkdown( + input = if (server.description?.isBlank() == false) { + server.description + } else { + stringResource( + R.string.server_context_sheet_description_empty + ) + } ) } - ) - } - if (server.owner == PeptideAPI.selfId) { + if (server.owner == PeptideAPI.selfId) { + Box( + modifier = Modifier + .clip(MaterialTheme.shapes.medium) + .background(MaterialTheme.colorScheme.primary) + ) { + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimary) { + SheetSelection( + icon = {}, + title = { + Text( + text = stringResource(id = R.string.server_context_sheet_moderators_early_disclaimer_title) + ) + }, + description = { + Text( + text = stringResource(id = R.string.server_context_sheet_moderators_early_disclaimer_body) + ) + }, + arrowTint = LocalContentColor.current.copy(alpha = 0.5f), + ) { + context.startActivity( + Intent( + Intent.ACTION_VIEW, + "${PeptideAPI.getCurrentAppUrl()}/server/${server.id}/settings".toUri() + ) + ) + } + } + } + } + Spacer(modifier = Modifier.height(12.dp)) + } + + // Primary actions group + Column( + modifier = Modifier + .padding(horizontal = 12.dp) + .clip(RoundedCornerShape(16.dp)) + .background(MaterialTheme.colorScheme.surfaceBright) + ) { + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.icn_identifier_copy_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.server_context_sheet_actions_copy_id) + ) + }, + onClick = { + if (server.id == null) return@SheetButton + + clipboardManager.setText(AnnotatedString(server.id)) + + if (Platform.needsShowClipboardNotification()) { + Toast.makeText( + context, + context.getString(R.string.server_context_sheet_actions_copy_id_copied), + Toast.LENGTH_SHORT + ).show() + } + + coroutineScope.launch { + onHideSheet() + } + } + ) + HorizontalDivider() + SheetButton( + leadingContent = { + Icon( + painter = painterResource(R.drawable.icn_notification_settings_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.channel_info_sheet_options_notifications_manage) + ) + }, + onClick = { page = 1 } + ) + HorizontalDivider() + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.icn_mark_chat_read_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.server_context_sheet_actions_mark_read) + ) + }, + onClick = { + coroutineScope.launch { + server.id?.let { + PeptideAPI.unreads.markServerAsRead(it, sync = true) + } + onHideSheet() + } + } + ) + } + + // Danger actions group + if (server.owner != PeptideAPI.selfId) { + Column( + modifier = Modifier + .padding(start = 12.dp, end = 12.dp, top = 16.dp) + .clip(RoundedCornerShape(16.dp)) + .background(MaterialTheme.colorScheme.surfaceBright) + ) { + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.icn_report_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.server_context_sheet_actions_report), + ) + }, + dangerous = true, + onClick = { + onReportServer() + } + ) + + HorizontalDivider() + + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.icn_door_open_24dp), + contentDescription = null, + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.server_context_sheet_actions_leave) + ) + }, + dangerous = true, + onClick = { + showLeaveConfirmation = true + } + ) + } + } + } + } else { + Column(Modifier.verticalScroll(rememberScrollState())) { Box( modifier = Modifier - .clip(MaterialTheme.shapes.medium) - .background(MaterialTheme.colorScheme.primary) + .fillMaxWidth() + .padding(12.dp), ) { - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimary) { - SheetSelection( - icon = {}, - title = { - Text( - text = stringResource(id = R.string.server_context_sheet_moderators_early_disclaimer_title) - ) + 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, start = 12.dp, end = 12.dp) + .clip(RoundedCornerShape(16.dp)) + .background(MaterialTheme.colorScheme.surfaceBright) + ) { + var selected by remember { + mutableStateOf( + NotificationType.fromStorage( + SyncedSettings.notifications.server[server.id ?: ""] + ).storageValue + ) + } + + fun updateSelection(newValue: NotificationType) { + selected = newValue.storageValue + val currentSettings = SyncedSettings.notifications + val updated = NotificationSettings( + server = currentSettings.server.toMutableMap().apply { + if (server.id.isNullOrBlank() || newValue == NotificationType.DEFAULT) { + if (!server.id.isNullOrBlank()) remove(server.id) + } else { + put(server.id!!, newValue.storageValue) + } }, - description = { - Text( - text = stringResource(id = R.string.server_context_sheet_moderators_early_disclaimer_body) - ) - }, - arrowTint = LocalContentColor.current.copy(alpha = 0.5f), - ) { - context.startActivity( - Intent( - Intent.ACTION_VIEW, - "${PeptideAPI.getCurrentAppUrl()}/server/${server.id}/settings".toUri() - ) - ) + channel = currentSettings.channel + ) + GlobalScope.launch { + SyncedSettings.updateNotifications(updated) } } + + @Composable + fun ServerNotificationRow(title: String, type: NotificationType) { + val isSelected = selected == type.storageValue + SheetButton( + headlineContent = { Text(text = title) }, + leadingContent = { + Icon( + painter = painterResource( + id = when (type) { + NotificationType.DEFAULT -> R.drawable.icn_notif_use_default + NotificationType.MUTED -> R.drawable.icn_notif_mute + NotificationType.ALL -> R.drawable.icn_notif_all_messages + NotificationType.MENTIONS_ONLY -> R.drawable.icn_notif_mention_only + NotificationType.NONE -> R.drawable.icn_notif_none + } + ), + contentDescription = null + ) + }, + trailingContent = { + RadioButton( + selected = isSelected, + onClick = { updateSelection(type) } + ) + }, + onClick = { updateSelection(type) } + ) + } + + ServerNotificationRow( + title = stringResource(id = R.string.notification_option_use_default), + type = NotificationType.DEFAULT + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp)) + ServerNotificationRow( + title = stringResource(id = R.string.notification_option_muted), + type = NotificationType.MUTED + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp)) + ServerNotificationRow( + title = stringResource(id = R.string.notification_option_all_messages), + type = NotificationType.ALL + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp)) + ServerNotificationRow( + title = stringResource(id = R.string.notification_option_mentions_only), + type = NotificationType.MENTIONS_ONLY + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 12.dp)) + ServerNotificationRow( + title = stringResource(id = R.string.notification_option_none), + type = NotificationType.NONE + ) } } - Spacer(modifier = Modifier.height(12.dp)) - } - - // Primary actions group - Column( - modifier = Modifier - .padding(horizontal = 12.dp) - .clip(RoundedCornerShape(16.dp)) - .background(MaterialTheme.colorScheme.surfaceBright) - ) { - SheetButton( - leadingContent = { - Icon( - painter = painterResource(id = R.drawable.icn_identifier_copy_24dp), - contentDescription = null - ) - }, - headlineContent = { - Text( - text = stringResource(id = R.string.server_context_sheet_actions_copy_id) - ) - }, - onClick = { - if (server.id == null) return@SheetButton - - clipboardManager.setText(AnnotatedString(server.id)) - - if (Platform.needsShowClipboardNotification()) { - Toast.makeText( - context, - context.getString(R.string.server_context_sheet_actions_copy_id_copied), - Toast.LENGTH_SHORT - ).show() - } - - coroutineScope.launch { - onHideSheet() - } - } - ) - HorizontalDivider() - SheetButton( - leadingContent = { - Icon( - painter = painterResource(id = R.drawable.icn_mark_chat_read_24dp), - contentDescription = null - ) - }, - headlineContent = { - Text( - text = stringResource(id = R.string.server_context_sheet_actions_mark_read) - ) - }, - onClick = { - coroutineScope.launch { - server.id?.let { - PeptideAPI.unreads.markServerAsRead(it, sync = true) - } - onHideSheet() - } - } - ) - } - - // Danger actions group - if (server.owner != PeptideAPI.selfId) { - Column( - modifier = Modifier - .padding(start = 12.dp, end = 12.dp, top = 16.dp) - .clip(RoundedCornerShape(16.dp)) - .background(MaterialTheme.colorScheme.surfaceBright) - ) { - SheetButton( - leadingContent = { - Icon( - painter = painterResource(id = R.drawable.icn_report_24dp), - contentDescription = null - ) - }, - headlineContent = { - Text( - text = stringResource(id = R.string.server_context_sheet_actions_report), - ) - }, - dangerous = true, - onClick = { - onReportServer() - } - ) - - HorizontalDivider() - - SheetButton( - leadingContent = { - Icon( - painter = painterResource(id = R.drawable.icn_door_open_24dp), - contentDescription = null, - ) - }, - headlineContent = { - Text( - text = stringResource(id = R.string.server_context_sheet_actions_leave) - ) - }, - dangerous = true, - onClick = { - showLeaveConfirmation = true - } - ) - } } } }