diff --git a/app/src/main/java/chat/revolt/components/generic/SheetButton.kt b/app/src/main/java/chat/revolt/components/generic/SheetButton.kt new file mode 100644 index 00000000..1809f1b9 --- /dev/null +++ b/app/src/main/java/chat/revolt/components/generic/SheetButton.kt @@ -0,0 +1,66 @@ +package chat.revolt.components.generic + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ListItem +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SheetButton( + headlineContent: @Composable () -> Unit, + leadingContent: @Composable () -> Unit, + onClick: () -> Unit, + modifier: Modifier = Modifier, + supportingContent: @Composable (() -> Unit)? = null, + dangerous: Boolean = false +) { + Box( + modifier = modifier + .clickable { onClick() } + .padding(horizontal = 16.dp) + ) { + ListItem( + headlineContent = { + CompositionLocalProvider( + value = if (dangerous) { + LocalContentColor provides MaterialTheme.colorScheme.error + } else { + LocalContentColor provides MaterialTheme.colorScheme.onSurface + } + ) { + headlineContent() + } + }, + leadingContent = { + CompositionLocalProvider( + value = if (dangerous) { + LocalContentColor provides MaterialTheme.colorScheme.error + } else { + LocalContentColor provides MaterialTheme.colorScheme.onSurface + } + ) { + leadingContent() + } + }, + supportingContent = { + supportingContent?.run { + CompositionLocalProvider( + value = if (dangerous) { + LocalContentColor provides MaterialTheme.colorScheme.error + } else { + LocalContentColor provides MaterialTheme.colorScheme.onSurface + } + ) { + this() + } + } + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/generic/SheetClickable.kt b/app/src/main/java/chat/revolt/components/generic/SheetClickable.kt deleted file mode 100644 index ca724a90..00000000 --- a/app/src/main/java/chat/revolt/components/generic/SheetClickable.kt +++ /dev/null @@ -1,73 +0,0 @@ -package chat.revolt.components.generic - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Person -import androidx.compose.material3.Icon -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp - -@Composable -fun SheetClickable( - icon: @Composable (Modifier) -> Unit, - label: @Composable (TextStyle) -> Unit, - modifier: Modifier = Modifier, - dangerous: Boolean = false, - onClick: () -> Unit -) { - CompositionLocalProvider( - LocalContentColor provides if (dangerous) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onBackground - ) { - Box(modifier = modifier.padding(vertical = 4.dp)) { - Row( - modifier = Modifier - .clip(MaterialTheme.shapes.medium) - .clickable(onClick = onClick) - .padding(all = 4.dp) - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - icon(Modifier.padding(end = 16.dp)) - label( - MaterialTheme.typography.bodyMedium.copy( - color = LocalContentColor.current, - fontWeight = FontWeight.SemiBold - ) - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -fun SettingsCategoryPreview() { - SheetClickable( - icon = { modifier -> - Icon( - modifier = modifier, - imageVector = Icons.Default.Person, - contentDescription = "Account" - ) - }, - label = { textStyle -> - Text(text = "Account", style = textStyle) - }, - onClick = {} - ) -} diff --git a/app/src/main/java/chat/revolt/components/generic/SheetEnd.kt b/app/src/main/java/chat/revolt/components/generic/SheetEnd.kt new file mode 100644 index 00000000..32f0e97c --- /dev/null +++ b/app/src/main/java/chat/revolt/components/generic/SheetEnd.kt @@ -0,0 +1,12 @@ +package chat.revolt.components.generic + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SheetEnd(modifier: Modifier = Modifier) { + Spacer(modifier.height(8.dp)) +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/generic/SheetHeaderPadding.kt b/app/src/main/java/chat/revolt/components/generic/SheetHeaderPadding.kt index a8e29964..7bbb83b8 100644 --- a/app/src/main/java/chat/revolt/components/generic/SheetHeaderPadding.kt +++ b/app/src/main/java/chat/revolt/components/generic/SheetHeaderPadding.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.unit.dp fun SheetHeaderPadding(content: @Composable BoxScope.() -> Unit) { Box( Modifier - .padding(start = 16.dp, end = 16.dp, top = 16.dp) - .fillMaxWidth(), content = content) + .padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp) + .fillMaxWidth(), content = content + ) } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/screens/chat/ChannelSheetHeader.kt b/app/src/main/java/chat/revolt/components/screens/chat/ChannelSheetHeader.kt index 95caf1a7..0021a73e 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/ChannelSheetHeader.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/ChannelSheetHeader.kt @@ -2,15 +2,23 @@ package chat.revolt.components.screens.chat import androidx.compose.foundation.background 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.padding +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -24,24 +32,35 @@ import chat.revolt.api.schemas.ChannelType import chat.revolt.api.schemas.User import chat.revolt.components.generic.RemoteImage import chat.revolt.components.generic.UserAvatar +import chat.revolt.components.markdown.MarkdownTree +import chat.revolt.ndk.AstNode +import chat.revolt.ndk.Stendal @Composable fun ChannelSheetHeader( channelName: String, channelIcon: AutumnResource? = null, channelType: ChannelType, + channelDescription: String? = null, dmPartner: User? = null ) { + var renderedChannelDescription by remember { mutableStateOf(null) } + + LaunchedEffect(channelDescription) { + if (channelDescription != null) { + renderedChannelDescription = Stendal.render(channelDescription) + } + } + Row( - modifier = Modifier.padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .size(48.dp) - .clip(CircleShape) + .clip(if (channelType == ChannelType.DirectMessage) CircleShape else MaterialTheme.shapes.medium) .background( - MaterialTheme.colorScheme.primary.copy(alpha = 0.2f) + MaterialTheme.colorScheme.primaryContainer ), contentAlignment = Alignment.Center ) { @@ -49,11 +68,11 @@ fun ChannelSheetHeader( RemoteImage( url = "$REVOLT_FILES/icons/${channelIcon.id ?: ""}?max_side=48", description = null, // decorative - contentScale = ContentScale.Fit, + contentScale = ContentScale.Crop, height = 48, width = 48, modifier = Modifier - .size(24.dp) + .size(48.dp) ) } else if (dmPartner != null) { UserAvatar( @@ -66,17 +85,26 @@ fun ChannelSheetHeader( .size(48.dp) ) } else { - ChannelIcon(channelType = channelType) + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) { + ChannelIcon(channelType = channelType) + } } } Spacer(modifier = Modifier.width(12.dp)) - Text( - text = channelName, - fontWeight = FontWeight.SemiBold, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) + Column { + Text( + text = channelName, + fontWeight = FontWeight.SemiBold, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + if (renderedChannelDescription != null && channelDescription?.isNotBlank() == true) { + Spacer(modifier = Modifier.height(8.dp)) + MarkdownTree(node = renderedChannelDescription!!) + } + } } } diff --git a/app/src/main/java/chat/revolt/sheets/AddServerSheet.kt b/app/src/main/java/chat/revolt/sheets/AddServerSheet.kt index 42771b79..c20e12b8 100644 --- a/app/src/main/java/chat/revolt/sheets/AddServerSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/AddServerSheet.kt @@ -5,7 +5,6 @@ import android.util.Log import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -16,7 +15,6 @@ import androidx.compose.material.icons.automirrored.filled.ExitToApp import androidx.compose.material.icons.filled.Build import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon -import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -32,6 +30,8 @@ import chat.revolt.R import chat.revolt.activities.InviteActivity import chat.revolt.api.REVOLT_APP import chat.revolt.components.generic.FormTextField +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.components.generic.SheetHeaderPadding @Composable @@ -61,7 +61,7 @@ fun AddServerSheet() { Spacer(modifier = Modifier.height(16.dp)) - ListItem( + SheetButton( headlineContent = { Text(stringResource(id = R.string.add_server_sheet_join_by_invite)) }, @@ -71,12 +71,12 @@ fun AddServerSheet() { contentDescription = null ) }, - modifier = Modifier.clickable { + onClick = { joinFromInviteModalOpen.value = true } ) - ListItem( + SheetButton( headlineContent = { Text(stringResource(id = R.string.add_server_sheet_create_new)) }, @@ -86,7 +86,7 @@ fun AddServerSheet() { contentDescription = null ) }, - modifier = Modifier.clickable { + onClick = { Toast.makeText( context, context.getString( @@ -97,7 +97,7 @@ fun AddServerSheet() { } ) - Spacer(modifier = Modifier.height(16.dp)) + SheetEnd() } } diff --git a/app/src/main/java/chat/revolt/sheets/ChannelContextSheet.kt b/app/src/main/java/chat/revolt/sheets/ChannelContextSheet.kt index 5a8952d8..18aa589d 100644 --- a/app/src/main/java/chat/revolt/sheets/ChannelContextSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/ChannelContextSheet.kt @@ -2,7 +2,6 @@ package chat.revolt.sheets import android.widget.Toast import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.CircularProgressIndicator @@ -20,7 +19,8 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp import chat.revolt.R import chat.revolt.api.RevoltAPI -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.internals.Platform import kotlinx.coroutines.launch @@ -43,23 +43,20 @@ fun ChannelContextSheet(channelId: String, onHideSheet: suspend () -> Unit) { val coroutineScope = rememberCoroutineScope() - Column { - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_content_copy_id_24dp), - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.channel_context_sheet_actions_copy_id), - style = style - ) - } - ) { - if (channel.id == null) return@SheetClickable + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_context_sheet_actions_copy_id), + ) + }, + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_content_copy_id_24dp), + contentDescription = null + ) + }, + onClick = { + if (channel.id == null) return@SheetButton clipboardManager.setText(AnnotatedString(channel.id)) @@ -75,22 +72,21 @@ fun ChannelContextSheet(channelId: String, onHideSheet: suspend () -> Unit) { onHideSheet() } } + ) - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_eye_check_24dp), - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.channel_context_sheet_actions_mark_read), - style = style - ) - } - ) { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_context_sheet_actions_mark_read), + ) + }, + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_eye_check_24dp), + contentDescription = null + ) + }, + onClick = { coroutineScope.launch { channel.lastMessageID?.let { RevoltAPI.unreads.markAsRead(channelId, it, sync = true) @@ -98,5 +94,7 @@ fun ChannelContextSheet(channelId: String, onHideSheet: suspend () -> Unit) { onHideSheet() } } - } + ) + + SheetEnd() } diff --git a/app/src/main/java/chat/revolt/sheets/ChannelInfoSheet.kt b/app/src/main/java/chat/revolt/sheets/ChannelInfoSheet.kt index 034fdad1..4f44c9bf 100644 --- a/app/src/main/java/chat/revolt/sheets/ChannelInfoSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/ChannelInfoSheet.kt @@ -1,13 +1,11 @@ package chat.revolt.sheets +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -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.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.List import androidx.compose.material.icons.filled.Add @@ -15,8 +13,8 @@ import androidx.compose.material.icons.filled.Notifications import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState @@ -40,7 +38,8 @@ import chat.revolt.api.internals.has import chat.revolt.api.schemas.ChannelType import chat.revolt.callbacks.Action import chat.revolt.callbacks.ActionChannel -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.components.screens.chat.ChannelSheetHeader import chat.revolt.internals.extensions.rememberChannelPermissions import chat.revolt.screens.chat.dialogs.InviteDialog @@ -98,169 +97,130 @@ fun ChannelInfoSheet(channelId: String, onHideSheet: suspend () -> Unit) { return } - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .verticalScroll(rememberScrollState()) - ) { - val isDM = ChannelUtils.resolveDMPartner(channel) != null - val partner = ChannelUtils - .resolveDMPartner(channel) - ?.let { - RevoltAPI.userCache[it] - } + val partner = ChannelUtils + .resolveDMPartner(channel) + ?.let { + RevoltAPI.userCache[it] + } + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), + ) { ChannelSheetHeader( channelName = channel.name ?: ChannelUtils.resolveDMName(channel) ?: stringResource(id = R.string.unknown), channelIcon = channel.icon, channelType = channel.channelType ?: ChannelType.TextChannel, + channelDescription = channel.description, dmPartner = partner ) + HorizontalDivider() + } - if (!isDM) { - Spacer(modifier = Modifier.height(12.dp)) - - Text( - text = stringResource(id = R.string.channel_info_sheet_description), - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(bottom = 10.dp) - ) - Text( - text = if (channel.description.isNullOrBlank()) { - stringResource( - id = R.string.channel_info_sheet_description_empty + when (channel.channelType) { + ChannelType.TextChannel, ChannelType.VoiceChannel, ChannelType.Group -> { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_info_sheet_options_members), ) - } else { - channel.description }, - modifier = Modifier.padding(bottom = 10.dp) + leadingContent = { + Icon( + imageVector = Icons.AutoMirrored.Default.List, + contentDescription = null + ) + }, + onClick = { + memberListSheetShown = true + } ) } - Spacer(modifier = Modifier.height(12.dp)) - - Text( - text = stringResource(id = R.string.channel_info_sheet_options), - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(bottom = 4.dp) - ) + else -> {} + } + if ( + Roles.permissionFor( + channel, + RevoltAPI.userCache[RevoltAPI.selfId] + ) has PermissionBit.InviteOthers + ) { when (channel.channelType) { - ChannelType.TextChannel, ChannelType.VoiceChannel, ChannelType.Group -> { - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.AutoMirrored.Default.List, - contentDescription = null, - modifier = modifier + ChannelType.TextChannel, ChannelType.VoiceChannel -> { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_info_sheet_options_invite), ) }, - label = { style -> - Text( - text = stringResource(id = R.string.channel_info_sheet_options_members), - style = style + leadingContent = { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null ) + }, + onClick = { + inviteDialogShown = true } - ) { - memberListSheetShown = true - } + ) + } + + ChannelType.Group -> { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_info_sheet_options_add), + ) + }, + leadingContent = { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null + ) + }, + onClick = {} + ) } else -> {} } + } - if ( - Roles.permissionFor( - channel, - RevoltAPI.userCache[RevoltAPI.selfId] - ) has PermissionBit.InviteOthers - ) { - when (channel.channelType) { - ChannelType.TextChannel, ChannelType.VoiceChannel -> { - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Add, - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.channel_info_sheet_options_invite), - style = style - ) - } - ) { - inviteDialogShown = true - } - } + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.channel_info_sheet_options_notifications_manage), + ) + }, + leadingContent = { + Icon( + imageVector = Icons.Default.Notifications, + contentDescription = null + ) + }, + onClick = {} + ) - ChannelType.Group -> { - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Add, - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.channel_info_sheet_options_add), - style = style - ) - } - ) { - } - } - - else -> {} - } - } - - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Notifications, - contentDescription = null, - modifier = modifier + if ( + (permissions has PermissionBit.ManageChannel || permissions has PermissionBit.ManageRole) + && (channel.channelType != ChannelType.SavedMessages && channel.channelType != ChannelType.DirectMessage) + ) { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.settings), ) }, - label = { style -> - Text( - text = stringResource( - id = R.string.channel_info_sheet_options_notifications_manage - ), - style = style + leadingContent = { + Icon( + imageVector = Icons.Default.Settings, + contentDescription = null ) - } - ) { - } - - if ( - (permissions has PermissionBit.ManageChannel || permissions has PermissionBit.ManageRole) - && (channel.channelType != ChannelType.SavedMessages && channel.channelType != ChannelType.DirectMessage) - ) { - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Settings, - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource( - id = R.string.settings - ), - style = style - ) - } - ) { + }, + onClick = { scope.launch { onHideSheet() } @@ -269,8 +229,8 @@ fun ChannelInfoSheet(channelId: String, onHideSheet: suspend () -> Unit) { ActionChannel.send(Action.TopNavigate("settings/channel/${channel.id}")) } } - } - - Spacer(modifier = Modifier.height(8.dp)) + ) } + + SheetEnd() } diff --git a/app/src/main/java/chat/revolt/sheets/EmoteInfoSheet.kt b/app/src/main/java/chat/revolt/sheets/EmoteInfoSheet.kt index bcff289d..f60816e9 100644 --- a/app/src/main/java/chat/revolt/sheets/EmoteInfoSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/EmoteInfoSheet.kt @@ -1,20 +1,17 @@ package chat.revolt.sheets import android.widget.Toast -import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement 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.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.layout.width +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -24,7 +21,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext @@ -41,7 +37,8 @@ import chat.revolt.api.routes.custom.fetchEmoji import chat.revolt.api.schemas.Emoji import chat.revolt.api.schemas.Server import chat.revolt.components.generic.RemoteImage -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.internals.Platform import kotlinx.coroutines.launch @@ -62,40 +59,31 @@ fun EmoteInfoSheet(id: String, onDismiss: () -> Unit) { } Column( - modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) - .verticalScroll(rememberScrollState()) + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), ) { Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clip(MaterialTheme.shapes.medium) - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(0.dp)) + verticalAlignment = Alignment.CenterVertically ) { RemoteImage( url = "$REVOLT_FILES/emojis/$id", description = emoteInfo?.name, contentScale = ContentScale.Fit, modifier = Modifier - .padding(16.dp) .size(32.dp) ) - Column( - modifier = Modifier.padding( - top = 16.dp, - start = 0.dp, - end = 16.dp, - bottom = 16.dp - ) - ) { + Spacer(modifier = Modifier.width(16.dp)) + + Column { Text( - text = emoteInfo?.name ?: id, - fontWeight = FontWeight.Bold, + text = ":${emoteInfo?.name ?: id}:", + fontWeight = FontWeight.SemiBold, letterSpacing = 1.15.sp ) + Spacer(modifier = Modifier.height(4.dp)) + Text( text = if (parentServer != null) { stringResource( @@ -109,23 +97,22 @@ fun EmoteInfoSheet(id: String, onDismiss: () -> Unit) { } } - Spacer(modifier = Modifier.height(8.dp)) + HorizontalDivider() + } - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_content_copy_24dp), - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.copy), - style = style - ) - } - ) { + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.copy) + ) + }, + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_content_copy_24dp), + contentDescription = null + ) + }, + onClick = { coroutineScope.launch { clipboardManager.setText(AnnotatedString(":$id:")) if (Platform.needsShowClipboardNotification()) { @@ -138,5 +125,7 @@ fun EmoteInfoSheet(id: String, onDismiss: () -> Unit) { } onDismiss() } - } + ) + + SheetEnd() } diff --git a/app/src/main/java/chat/revolt/sheets/LinkInfoSheet.kt b/app/src/main/java/chat/revolt/sheets/LinkInfoSheet.kt index 6b511f7d..0e9afa44 100644 --- a/app/src/main/java/chat/revolt/sheets/LinkInfoSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/LinkInfoSheet.kt @@ -3,24 +3,23 @@ package chat.revolt.sheets import android.net.Uri import android.widget.Toast import androidx.browser.customtabs.CustomTabsIntent -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.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ExitToApp +import androidx.compose.material.ripple.LocalRippleTheme +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -28,8 +27,10 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp import chat.revolt.R -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.internals.Platform +import chat.revolt.ui.theme.ClearRippleTheme import kotlinx.coroutines.launch @Composable @@ -39,50 +40,86 @@ fun LinkInfoSheet(url: String, onDismiss: () -> Unit) { val coroutineScope = rememberCoroutineScope() Column( - modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) - .verticalScroll(rememberScrollState()) + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), ) { - Box( - modifier = Modifier - .clip(MaterialTheme.shapes.medium) - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(0.dp)) - .clickable(onClick = { - if (url.startsWith("revolt-android://")) return@clickable + CompositionLocalProvider(value = LocalRippleTheme provides ClearRippleTheme) { + Box( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = { + val customTab = CustomTabsIntent + .Builder() + .setShowTitle(true) + .build() - val customTab = CustomTabsIntent - .Builder() - .setShowTitle(true) - .build() - - customTab.launchUrl(context, Uri.parse(url)) - }) - ) { - Text( - text = url, - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.padding(16.dp) - ) - } - - Spacer(modifier = Modifier.height(8.dp)) - - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_content_copy_24dp), - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> + try { + customTab.launchUrl(context, Uri.parse(url)) + } catch (e: Exception) { + Toast + .makeText( + context, + context.getString(R.string.link_type_no_intent), + Toast.LENGTH_SHORT + ) + .show() + } + }) + ) { Text( - text = stringResource(id = R.string.copy), - style = style + text = url, + color = MaterialTheme.colorScheme.primary ) } - ) { + } + + HorizontalDivider() + } + + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.link_open) + ) + }, + leadingContent = { + Icon( + imageVector = Icons.AutoMirrored.Default.ExitToApp, + contentDescription = null + ) + }, + onClick = { + val customTab = CustomTabsIntent + .Builder() + .setShowTitle(true) + .build() + + try { + customTab.launchUrl(context, Uri.parse(url)) + } catch (e: Exception) { + Toast + .makeText( + context, + context.getString(R.string.link_type_no_intent), + Toast.LENGTH_SHORT + ) + .show() + } + } + ) + SheetButton( + headlineContent = { + Text( + text = stringResource(id = R.string.copy) + ) + }, + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_content_copy_24dp), + contentDescription = null + ) + }, + onClick = { coroutineScope.launch { clipboardManager.setText(AnnotatedString(url)) if (Platform.needsShowClipboardNotification()) { @@ -95,5 +132,7 @@ fun LinkInfoSheet(url: String, onDismiss: () -> Unit) { } onDismiss() } - } + ) + + SheetEnd() } diff --git a/app/src/main/java/chat/revolt/sheets/MemberContextSheet.kt b/app/src/main/java/chat/revolt/sheets/MemberContextSheet.kt index 188ba351..6c153b6e 100644 --- a/app/src/main/java/chat/revolt/sheets/MemberContextSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/MemberContextSheet.kt @@ -1,10 +1,8 @@ package chat.revolt.sheets import android.widget.Toast -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.ColumnScope import androidx.compose.material3.Icon -import androidx.compose.material3.ListItem import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -12,7 +10,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -22,6 +19,8 @@ import androidx.compose.ui.text.style.TextOverflow import chat.revolt.R import chat.revolt.api.RevoltAPI import chat.revolt.api.routes.channel.removeMember +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.internals.Platform import kotlinx.coroutines.launch @@ -46,7 +45,7 @@ fun ColumnScope.GroupDMMemberContextSheet( if (channel == null) return if (channel.owner == RevoltAPI.selfId && userId != RevoltAPI.selfId) { - ListItem( + SheetButton( headlineContent = { CompositionLocalProvider(value = LocalContentColor provides MaterialTheme.colorScheme.error) { Text( @@ -67,7 +66,7 @@ fun ColumnScope.GroupDMMemberContextSheet( ) } }, - modifier = Modifier.clickable { + onClick = { scope.launch { removeMember(channelId, userId) onRequestUpdateMembers() @@ -78,7 +77,7 @@ fun ColumnScope.GroupDMMemberContextSheet( } // TODO replace with something useful (currently so that your sheet is not empty if you don't have permissions) - ListItem( + SheetButton( headlineContent = { Text(stringResource(R.string.user_info_sheet_copy_id)) }, @@ -88,7 +87,7 @@ fun ColumnScope.GroupDMMemberContextSheet( contentDescription = null ) }, - modifier = Modifier.clickable { + onClick = { clipboardManager.setText(AnnotatedString(userId)) if (Platform.needsShowClipboardNotification()) { @@ -100,6 +99,8 @@ fun ColumnScope.GroupDMMemberContextSheet( } } ) + + SheetEnd() } @Composable @@ -126,7 +127,7 @@ fun ColumnScope.ServerMemberContextSheet( // TODO add something useful (moderation actions) // TODO replace with something useful (currently so that your sheet is not empty if you don't have permissions) - ListItem( + SheetButton( headlineContent = { Text(stringResource(R.string.user_info_sheet_copy_id)) }, @@ -136,7 +137,7 @@ fun ColumnScope.ServerMemberContextSheet( contentDescription = null ) }, - modifier = Modifier.clickable { + onClick = { clipboardManager.setText(AnnotatedString(userId)) if (Platform.needsShowClipboardNotification()) { @@ -148,4 +149,6 @@ fun ColumnScope.ServerMemberContextSheet( } } ) + + SheetEnd() } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt b/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt index a5c6dc70..6ae7e91c 100644 --- a/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/MessageContextSheet.kt @@ -1,10 +1,9 @@ package chat.revolt.sheets import android.widget.Toast -import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -13,18 +12,19 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.ripple.LocalRippleTheme import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -32,7 +32,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource @@ -49,8 +48,10 @@ import chat.revolt.api.routes.channel.deleteMessage import chat.revolt.api.routes.channel.react import chat.revolt.callbacks.UiCallbacks import chat.revolt.components.chat.Message -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.internals.Platform +import chat.revolt.ui.theme.ClearRippleTheme import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @@ -91,28 +92,70 @@ fun MessageContextSheet( ) { Column( modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) .verticalScroll(rememberScrollState()) ) { - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_content_copy_24dp), - contentDescription = null, - modifier = modifier + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( - text = stringResource(id = R.string.message_context_sheet_actions_copy), - style = style + text = stringResource(id = R.string.message_context_sheet_actions_copy) ) - } - ) { - if (message.content.isNullOrEmpty()) { + }, + onClick = { + if (message.content.isNullOrEmpty()) { + coroutineScope.launch { + shareSheetState.hide() + onHideSheet() + Toast.makeText( + context, + context.getString( + R.string.message_context_sheet_actions_copy_failed_empty + ), + Toast.LENGTH_SHORT + ).show() + } + return@SheetButton + } + + if (Platform.needsShowClipboardNotification()) { + Toast.makeText( + context, + context.getString(R.string.copied), + Toast.LENGTH_SHORT + ).show() + } + coroutineScope.launch { shareSheetState.hide() + } + coroutineScope.launch { + clipboardManager.setText(AnnotatedString(message.content)) onHideSheet() + } + } + ) + + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_link_variant_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource( + id = R.string.message_context_sheet_actions_copy_link + ) + ) + }, + onClick = { + if (message.content.isNullOrEmpty()) { Toast.makeText( context, context.getString( @@ -120,52 +163,33 @@ fun MessageContextSheet( ), Toast.LENGTH_SHORT ).show() + + coroutineScope.launch { + shareSheetState.hide() + } + coroutineScope.launch { + onHideSheet() + } + + return@SheetButton } - return@SheetClickable - } - if (Platform.needsShowClipboardNotification()) { - Toast.makeText( - context, - context.getString(R.string.copied), - Toast.LENGTH_SHORT - ).show() - } + val server = RevoltAPI.serverCache.values.find { server -> + server.channels?.contains(message.channel) ?: false + } + val messageLink = + "$REVOLT_APP/server/${server?.id}/channel/${message.channel}/${message.id}" - coroutineScope.launch { - shareSheetState.hide() - } - coroutineScope.launch { - clipboardManager.setText(AnnotatedString(message.content)) - onHideSheet() - } - } - - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_link_variant_24dp), - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource( - id = R.string.message_context_sheet_actions_copy_link - ), - style = style - ) - } - ) { - if (message.content.isNullOrEmpty()) { - Toast.makeText( - context, - context.getString( - R.string.message_context_sheet_actions_copy_failed_empty - ), - Toast.LENGTH_SHORT - ).show() + clipboardManager.setText(AnnotatedString(messageLink)) + if (Platform.needsShowClipboardNotification()) { + Toast.makeText( + context, + context.getString( + R.string.message_context_sheet_actions_copy_link_copied + ), + Toast.LENGTH_SHORT + ).show() + } coroutineScope.launch { shareSheetState.hide() @@ -173,74 +197,49 @@ fun MessageContextSheet( coroutineScope.launch { onHideSheet() } - - return@SheetClickable } + ) - val server = RevoltAPI.serverCache.values.find { server -> - server.channels?.contains(message.channel) ?: false - } - val messageLink = - "$REVOLT_APP/server/${server?.id}/channel/${message.channel}/${message.id}" - - clipboardManager.setText(AnnotatedString(messageLink)) - if (Platform.needsShowClipboardNotification()) { - Toast.makeText( - context, - context.getString( - R.string.message_context_sheet_actions_copy_link_copied - ), - Toast.LENGTH_SHORT - ).show() - } - - coroutineScope.launch { - shareSheetState.hide() - } - coroutineScope.launch { - onHideSheet() - } - } - - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_content_copy_id_24dp), - contentDescription = null, - modifier = modifier + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( text = stringResource( id = R.string.message_context_sheet_actions_copy_id - ), - style = style + ) ) - } - ) { - if (message.id == null) return@SheetClickable + }, + onClick = { + if (message.id == null) return@SheetButton - clipboardManager.setText(AnnotatedString(message.id)) + clipboardManager.setText(AnnotatedString(message.id)) - if (Platform.needsShowClipboardNotification()) { - Toast.makeText( - context, - context.getString( - R.string.message_context_sheet_actions_copy_id_copied - ), - Toast.LENGTH_SHORT - ).show() - } + if (Platform.needsShowClipboardNotification()) { + Toast.makeText( + context, + context.getString( + R.string.message_context_sheet_actions_copy_id_copied + ), + Toast.LENGTH_SHORT + ).show() + } - coroutineScope.launch { - shareSheetState.hide() + coroutineScope.launch { + shareSheetState.hide() + } + coroutineScope.launch { + onHideSheet() + } } - coroutineScope.launch { - onHideSheet() - } - } + ) } + + SheetEnd() } } @@ -312,130 +311,124 @@ fun MessageContextSheet( Column( modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) .verticalScroll(rememberScrollState()) ) { - Box( - modifier = Modifier - .clip(MaterialTheme.shapes.medium) - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(0.dp)) - .padding(bottom = 8.dp) - ) { - Message( - message = message.copy( - tail = false, - masquerade = null + CompositionLocalProvider(value = LocalRippleTheme provides ClearRippleTheme) { + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), + ) { + Message( + message = message.copy( + tail = false, + masquerade = null + ) ) - ) + + HorizontalDivider() + } } - Spacer(modifier = Modifier.height(8.dp)) - - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_reply_24dp), - contentDescription = null, - modifier = modifier + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( text = stringResource(id = R.string.message_context_sheet_actions_reply), - style = style - ) - } - ) { - coroutineScope.launch { - UiCallbacks.replyToMessage(messageId) - onHideSheet() - } - } - - SheetClickable( - icon = { modifier -> - Icon( - painter = painterResource(id = R.drawable.ic_hamburger_plus_24dp), - contentDescription = null, - modifier = modifier ) }, - label = { style -> - Text( - text = stringResource(id = R.string.message_context_sheet_actions_react), - style = style - ) - } - ) { - showReactSheet = true - } - - if (message.author == RevoltAPI.selfId) { - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Edit, - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.message_context_sheet_actions_edit), - style = style - ) - } - ) { + onClick = { coroutineScope.launch { - UiCallbacks.editMessage(messageId) + UiCallbacks.replyToMessage(messageId) onHideSheet() } } - } + ) - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( - painter = painterResource(id = R.drawable.ic_eye_off_24dp), - contentDescription = null, - modifier = modifier + painter = painterResource(id = R.drawable.ic_hamburger_plus_24dp), + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( - text = stringResource(id = R.string.message_context_sheet_actions_mark_unread), - style = style + text = stringResource(id = R.string.message_context_sheet_actions_react), ) + }, + onClick = { + showReactSheet = true } - ) { - Toast.makeText( - context, - context.getString(R.string.comingsoon_toast), - Toast.LENGTH_SHORT - ).show() + ) - coroutineScope.launch { - onHideSheet() - } + if (message.author == RevoltAPI.selfId) { + SheetButton( + leadingContent = { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.message_context_sheet_actions_edit), + ) + }, + onClick = { + coroutineScope.launch { + UiCallbacks.editMessage(messageId) + onHideSheet() + } + } + ) } - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { + Icon( + painter = painterResource(id = R.drawable.ic_eye_off_24dp), + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.message_context_sheet_actions_mark_unread), + ) + }, + onClick = { + Toast.makeText( + context, + context.getString(R.string.comingsoon_toast), + Toast.LENGTH_SHORT + ).show() + + coroutineScope.launch { + onHideSheet() + } + } + ) + + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_share_24dp), contentDescription = null, - modifier = modifier ) }, - label = { style -> + headlineContent = { Text( text = stringResource(id = R.string.share), - style = style ) + }, + onClick = { + showShareSheet = true } - ) { - showShareSheet = true - } + ) if ( (message.channel?.let { @@ -446,47 +439,47 @@ fun MessageContextSheet( ) } ?: 0) has PermissionBit.ManageMessages || message.author == RevoltAPI.selfId ) { - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( imageVector = Icons.Default.Delete, - contentDescription = null, - modifier = modifier + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( text = stringResource(id = R.string.message_context_sheet_actions_delete), - style = style ) }, - dangerous = true - ) { - showDeleteMessageConfirmation = true - } + dangerous = true, + onClick = { + showDeleteMessageConfirmation = true + } + ) } if (message.author != RevoltAPI.selfId) { - SheetClickable( - icon = { modifier -> + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_flag_24dp), - contentDescription = null, - modifier = modifier + contentDescription = null ) }, - label = { style -> + headlineContent = { Text( text = stringResource(id = R.string.message_context_sheet_actions_report), - style = style ) }, - dangerous = true - ) { - coroutineScope.launch { - onReportMessage() - } - } + dangerous = true, + onClick = { + coroutineScope.launch { + onReportMessage() + } + }, + ) } + + SheetEnd() } } diff --git a/app/src/main/java/chat/revolt/sheets/ReactionInfoSheet.kt b/app/src/main/java/chat/revolt/sheets/ReactionInfoSheet.kt index b157f950..2222c0f8 100644 --- a/app/src/main/java/chat/revolt/sheets/ReactionInfoSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/ReactionInfoSheet.kt @@ -1,14 +1,16 @@ package chat.revolt.sheets import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background +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.LazyColumn import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.LocalTextStyle @@ -16,7 +18,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ScrollableTabRow import androidx.compose.material3.Tab import androidx.compose.material3.Text -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -26,7 +27,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.PlatformTextStyle @@ -45,6 +45,7 @@ import chat.revolt.api.schemas.Emoji import chat.revolt.api.schemas.User import chat.revolt.components.chat.MemberListItem import chat.revolt.components.generic.RemoteImage +import chat.revolt.components.generic.SheetEnd @OptIn(ExperimentalFoundationApi::class) @Composable @@ -118,94 +119,97 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) { if (reactionEmoji?.isNotEmpty() == true) { item("info") { val current = reactionEmoji[selectedReactionIndex] - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(16.dp) - .clip(MaterialTheme.shapes.medium) - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(0.dp)) - ) { - if (current.isUlid()) { - val cached = extendedEmojiInfo.find { it.id == current } - RemoteImage( - url = "$REVOLT_FILES/emojis/$current/emoji.gif", - description = cached?.name, - contentScale = ContentScale.Fit, - modifier = Modifier - .padding(16.dp) - .size(32.dp) - ) - } else { - Box( - modifier = Modifier - .padding(16.dp) - .size(32.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = current, - style = MaterialTheme.typography.bodyLarge.copy( - fontSize = 28.sp, - fontWeight = FontWeight.Bold, - textAlign = TextAlign.Center, - platformStyle = PlatformTextStyle( - includeFontPadding = false - ) - ), - modifier = Modifier - .size(64.dp) - ) - } - } - Column( - modifier = Modifier.padding( - top = 16.dp, - start = 0.dp, - end = 16.dp, - bottom = 16.dp - ) + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding( + top = 16.dp, + start = 16.dp, + end = 16.dp, + bottom = 4.dp + ), + ) { + Row( + verticalAlignment = Alignment.CenterVertically ) { if (current.isUlid()) { val cached = extendedEmojiInfo.find { it.id == current } - Text( - text = ":${cached?.name ?: current}:", - fontWeight = FontWeight.Bold, - letterSpacing = 1.15.sp + RemoteImage( + url = "$REVOLT_FILES/emojis/$current/emoji.gif", + description = cached?.name, + contentScale = ContentScale.Fit, + modifier = Modifier + .size(32.dp) ) } else { - Text( - text = MessageProcessor.emoji.unicodeAsShortcode(current) - ?: current, - fontWeight = FontWeight.Bold, - letterSpacing = 1.15.sp - ) + Box( + modifier = Modifier + .size(32.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = current, + style = MaterialTheme.typography.bodyLarge.copy( + fontSize = 28.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + platformStyle = PlatformTextStyle( + includeFontPadding = false + ) + ), + modifier = Modifier + .size(64.dp) + ) + } } - Text( - text = if (current.isUlid()) { - val cached = extendedEmojiInfo.find { it.id == current } - if (cached?.parent != null) { - when (cached.parent.type) { - "Server" -> RevoltAPI.serverCache[cached.parent.id]?.name?.let { - stringResource( - id = R.string.emote_info_from_server, - it - ) - } - ?: stringResource(id = R.string.emote_info_from_server_unknown) + Spacer(modifier = Modifier.width(16.dp)) - else -> stringResource(id = R.string.emote_info_from_server_unknown) + Column { + if (current.isUlid()) { + val cached = extendedEmojiInfo.find { it.id == current } + Text( + text = ":${cached?.name ?: current}:", + fontWeight = FontWeight.SemiBold, + letterSpacing = 1.15.sp + ) + } else { + Text( + text = MessageProcessor.emoji.unicodeAsShortcode(current) + ?: current, + fontWeight = FontWeight.SemiBold, + letterSpacing = 1.15.sp + ) + } + + Spacer(modifier = Modifier.height(4.dp)) + + Text( + text = if (current.isUlid()) { + val cached = extendedEmojiInfo.find { it.id == current } + if (cached?.parent != null) { + when (cached.parent.type) { + "Server" -> RevoltAPI.serverCache[cached.parent.id]?.name?.let { + stringResource( + id = R.string.emote_info_from_server, + it + ) + } + ?: stringResource(id = R.string.emote_info_from_server_unknown) + + else -> stringResource(id = R.string.emote_info_from_server_unknown) + } + } else { + stringResource(id = R.string.emote_info_from_server_unknown) } } else { - stringResource(id = R.string.emote_info_from_server_unknown) + stringResource(id = R.string.emote_info_from_unicode) } - } else { - stringResource(id = R.string.emote_info_from_unicode) - } - ) + ) + } } + + HorizontalDivider() } } @@ -236,7 +240,7 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) { } item("bottom") { - Spacer(Modifier.size(16.dp)) + SheetEnd() } } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/sheets/ServerContextSheet.kt b/app/src/main/java/chat/revolt/sheets/ServerContextSheet.kt index 3cbb2896..0ad43826 100644 --- a/app/src/main/java/chat/revolt/sheets/ServerContextSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/ServerContextSheet.kt @@ -1,18 +1,20 @@ package chat.revolt.sheets import android.widget.Toast +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.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -32,7 +34,8 @@ import androidx.compose.ui.unit.dp import chat.revolt.R import chat.revolt.api.RevoltAPI import chat.revolt.api.routes.server.leaveOrDeleteServer -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.components.markdown.RichMarkdown import chat.revolt.components.screens.settings.ServerOverview import chat.revolt.internals.Platform @@ -138,19 +141,12 @@ fun ServerContextSheet( } Column( - modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 0.dp, bottom = 16.dp) + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 4.dp), ) { ServerOverview(server) - Column( - modifier = Modifier.padding(horizontal = 4.dp) - ) { - Text( - text = stringResource(id = R.string.server_context_sheet_category_description), - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(vertical = 14.dp) - ) - + SelectionContainer { RichMarkdown( input = if (server.description?.isBlank() == false) { server.description @@ -160,27 +156,25 @@ fun ServerContextSheet( ) } ) - - Text( - text = stringResource(id = R.string.server_context_sheet_category_actions), - style = MaterialTheme.typography.bodySmall, - modifier = Modifier.padding(top = 14.dp, bottom = 10.dp) - ) } - SheetClickable(icon = { + HorizontalDivider() + } + + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_content_copy_id_24dp), - contentDescription = null, - modifier = it + contentDescription = null ) - }, label = { + }, + headlineContent = { Text( - text = stringResource(id = R.string.server_context_sheet_actions_copy_id), - style = it + text = stringResource(id = R.string.server_context_sheet_actions_copy_id) ) - }) { - if (server.id == null) return@SheetClickable + }, + onClick = { + if (server.id == null) return@SheetButton clipboardManager.setText(AnnotatedString(server.id)) @@ -196,19 +190,21 @@ fun ServerContextSheet( onHideSheet() } } + ) - SheetClickable(icon = { + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_eye_check_24dp), - contentDescription = null, - modifier = it + contentDescription = null ) - }, label = { + }, + headlineContent = { Text( - text = stringResource(id = R.string.server_context_sheet_actions_mark_read), - style = it + text = stringResource(id = R.string.server_context_sheet_actions_mark_read) ) - }) { + }, + onClick = { coroutineScope.launch { server.id?.let { RevoltAPI.unreads.markServerAsRead(it, sync = true) @@ -216,37 +212,45 @@ fun ServerContextSheet( onHideSheet() } } + ) - if (server.owner != RevoltAPI.selfId) { - SheetClickable(icon = { + if (server.owner != RevoltAPI.selfId) { + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_flag_24dp), - contentDescription = null, - modifier = it + contentDescription = null ) - }, label = { + }, + headlineContent = { Text( text = stringResource(id = R.string.server_context_sheet_actions_report), - style = it ) - }, dangerous = true) { + }, + dangerous = true, + onClick = { onReportServer() } + ) - SheetClickable(icon = { + SheetButton( + leadingContent = { Icon( painter = painterResource(id = R.drawable.ic_arrow_left_bold_box_24dp), contentDescription = null, - modifier = it ) - }, label = { + }, + headlineContent = { Text( - text = stringResource(id = R.string.server_context_sheet_actions_leave), - style = it + text = stringResource(id = R.string.server_context_sheet_actions_leave) ) - }, dangerous = true) { + }, + dangerous = true, + onClick = { showLeaveConfirmation = true } - } + ) } + + SheetEnd() } diff --git a/app/src/main/java/chat/revolt/sheets/StatusSheet.kt b/app/src/main/java/chat/revolt/sheets/StatusSheet.kt index 86859917..c6a4d35a 100644 --- a/app/src/main/java/chat/revolt/sheets/StatusSheet.kt +++ b/app/src/main/java/chat/revolt/sheets/StatusSheet.kt @@ -19,7 +19,8 @@ import androidx.compose.ui.unit.dp import chat.revolt.R import chat.revolt.api.RevoltAPI import chat.revolt.api.routes.user.patchSelf -import chat.revolt.components.generic.SheetClickable +import chat.revolt.components.generic.SheetButton +import chat.revolt.components.generic.SheetEnd import chat.revolt.components.generic.asApiName import chat.revolt.components.generic.presenceFromStatus import chat.revolt.components.screens.settings.UserOverview @@ -52,24 +53,25 @@ fun StatusSheet(onBeforeNavigation: () -> Unit, onGoSettings: () -> Unit) { ) Spacer(modifier = Modifier.height(8.dp)) + } - SheetClickable( - icon = { modifier -> - Icon( - imageVector = Icons.Default.Settings, - contentDescription = null, - modifier = modifier - ) - }, - label = { style -> - Text( - text = stringResource(id = R.string.settings), - style = style - ) - } - ) { + SheetButton( + leadingContent = { + Icon( + imageVector = Icons.Default.Settings, + contentDescription = null + ) + }, + headlineContent = { + Text( + text = stringResource(id = R.string.settings) + ) + }, + onClick = { onBeforeNavigation() onGoSettings() } - } + ) + + SheetEnd() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4d305ede..dffd60eb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -289,9 +289,7 @@ Copied channel ID to clipboard Mark as read - Description There hasn\'t been a description set for this server yet. - Actions Copy ID Copied server ID to clipboard @@ -416,6 +414,7 @@ Don\'t block No app found to handle this link + Open You\'ve been invited to join this server. Would you like to join? Join