feat: channel menu and mark as read
This commit is contained in:
parent
b0579d1436
commit
dd78679901
|
|
@ -0,0 +1,127 @@
|
||||||
|
package chat.revolt.components.screens.chat.drawer.channel
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
import chat.revolt.R
|
||||||
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.api.schemas.ChannelType
|
||||||
|
import chat.revolt.components.screens.chat.DoubleDrawerState
|
||||||
|
import chat.revolt.components.screens.chat.drawer.server.DrawerChannel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RowScope.ChannelList(
|
||||||
|
serverId: String,
|
||||||
|
navController: NavController,
|
||||||
|
drawerState: DoubleDrawerState
|
||||||
|
) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||||
|
|
||||||
|
Surface(
|
||||||
|
tonalElevation = 1.dp,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 4.dp, top = 8.dp, bottom = 8.dp)
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
if (serverId == "home") {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
RevoltAPI.channelCache.values.filter { it.channelType == ChannelType.Group }
|
||||||
|
.forEach { channel ->
|
||||||
|
DrawerChannel(
|
||||||
|
name = channel.name
|
||||||
|
?: "GDM #${channel.id}",
|
||||||
|
channelType = ChannelType.Group,
|
||||||
|
selected = (channel.id == navBackStackEntry?.arguments?.getString(
|
||||||
|
"channelId"
|
||||||
|
)),
|
||||||
|
hasUnread = channel.lastMessageID?.let { lastMessageID ->
|
||||||
|
RevoltAPI.unreads.hasUnread(
|
||||||
|
channel.id!!,
|
||||||
|
lastMessageID
|
||||||
|
)
|
||||||
|
} ?: false,
|
||||||
|
onClick = {
|
||||||
|
navController.navigate("channel/${channel.id}")
|
||||||
|
coroutineScope.launch { drawerState.focusCenter() }
|
||||||
|
},
|
||||||
|
onLongClick = {
|
||||||
|
navController.navigate("channel/${channel.id}/info")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val server = RevoltAPI.serverCache[serverId]
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = server?.name
|
||||||
|
?: stringResource(R.string.unknown),
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
server?.channels?.forEach { channelId ->
|
||||||
|
RevoltAPI.channelCache[channelId]?.let { ch ->
|
||||||
|
DrawerChannel(
|
||||||
|
name = ch.name!!,
|
||||||
|
channelType = ch.channelType!!,
|
||||||
|
selected = navBackStackEntry?.arguments?.getString(
|
||||||
|
"channelId"
|
||||||
|
) == ch.id,
|
||||||
|
hasUnread = ch.lastMessageID?.let { lastMessageID ->
|
||||||
|
RevoltAPI.unreads.hasUnread(
|
||||||
|
ch.id!!,
|
||||||
|
lastMessageID
|
||||||
|
)
|
||||||
|
} ?: true,
|
||||||
|
onClick = {
|
||||||
|
coroutineScope.launch { drawerState.focusCenter() }
|
||||||
|
navController.navigate("channel/${ch.id}") {
|
||||||
|
popUpTo("home") {
|
||||||
|
inclusive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongClick = {
|
||||||
|
navController.navigate("channel/${ch.id}/menu")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,9 @@ package chat.revolt.components.screens.chat.drawer.server
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.core.spring
|
import androidx.compose.animation.core.spring
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
|
@ -22,13 +23,15 @@ import androidx.compose.ui.unit.dp
|
||||||
import chat.revolt.api.schemas.ChannelType
|
import chat.revolt.api.schemas.ChannelType
|
||||||
import chat.revolt.components.screens.chat.ChannelIcon
|
import chat.revolt.components.screens.chat.ChannelIcon
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun DrawerChannel(
|
fun DrawerChannel(
|
||||||
channelType: ChannelType,
|
channelType: ChannelType,
|
||||||
name: String,
|
name: String,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
hasUnread: Boolean,
|
hasUnread: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit,
|
||||||
|
onLongClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val backgroundColor = animateColorAsState(
|
val backgroundColor = animateColorAsState(
|
||||||
if (selected) MaterialTheme.colorScheme.background
|
if (selected) MaterialTheme.colorScheme.background
|
||||||
|
|
@ -52,7 +55,10 @@ fun DrawerChannel(
|
||||||
.clip(MaterialTheme.shapes.medium)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
.background(backgroundColor.value)
|
.background(backgroundColor.value)
|
||||||
.alpha(channelAlpha.value)
|
.alpha(channelAlpha.value)
|
||||||
.clickable(onClick = onClick)
|
.combinedClickable(
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onLongClick
|
||||||
|
)
|
||||||
.padding(vertical = 8.dp, horizontal = 16.dp),
|
.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,10 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -30,17 +28,17 @@ import chat.revolt.R
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
import chat.revolt.api.realtime.DisconnectionState
|
import chat.revolt.api.realtime.DisconnectionState
|
||||||
import chat.revolt.api.realtime.RealtimeSocket
|
import chat.revolt.api.realtime.RealtimeSocket
|
||||||
import chat.revolt.api.schemas.ChannelType
|
|
||||||
import chat.revolt.components.chat.DisconnectedNotice
|
import chat.revolt.components.chat.DisconnectedNotice
|
||||||
import chat.revolt.components.generic.UserAvatar
|
import chat.revolt.components.generic.UserAvatar
|
||||||
import chat.revolt.components.generic.presenceFromStatus
|
import chat.revolt.components.generic.presenceFromStatus
|
||||||
import chat.revolt.components.screens.chat.DoubleDrawer
|
import chat.revolt.components.screens.chat.DoubleDrawer
|
||||||
import chat.revolt.components.screens.chat.drawer.server.DrawerChannel
|
import chat.revolt.components.screens.chat.drawer.channel.ChannelList
|
||||||
import chat.revolt.components.screens.chat.drawer.server.DrawerServer
|
import chat.revolt.components.screens.chat.drawer.server.DrawerServer
|
||||||
import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon
|
import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon
|
||||||
import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator
|
import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator
|
||||||
import chat.revolt.components.screens.chat.rememberDoubleDrawerState
|
import chat.revolt.components.screens.chat.rememberDoubleDrawerState
|
||||||
import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog
|
import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog
|
||||||
|
import chat.revolt.screens.chat.sheets.ChannelContextSheet
|
||||||
import chat.revolt.screens.chat.sheets.ChannelInfoSheet
|
import chat.revolt.screens.chat.sheets.ChannelInfoSheet
|
||||||
import chat.revolt.screens.chat.sheets.MessageContextSheet
|
import chat.revolt.screens.chat.sheets.MessageContextSheet
|
||||||
import chat.revolt.screens.chat.sheets.StatusSheet
|
import chat.revolt.screens.chat.sheets.StatusSheet
|
||||||
|
|
@ -91,7 +89,6 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
|
||||||
|
|
||||||
val bottomSheetNavigator = rememberBottomSheetNavigator()
|
val bottomSheetNavigator = rememberBottomSheetNavigator()
|
||||||
val navController = rememberNavController(bottomSheetNavigator)
|
val navController = rememberNavController(bottomSheetNavigator)
|
||||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
|
||||||
|
|
||||||
ModalBottomSheetLayout(
|
ModalBottomSheetLayout(
|
||||||
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||||
|
|
@ -176,91 +173,11 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
|
||||||
}
|
}
|
||||||
|
|
||||||
Crossfade(targetState = viewModel.currentServer) {
|
Crossfade(targetState = viewModel.currentServer) {
|
||||||
Surface(
|
ChannelList(
|
||||||
tonalElevation = 1.dp,
|
serverId = it,
|
||||||
modifier = Modifier
|
navController = navController,
|
||||||
.padding(start = 4.dp, top = 8.dp, bottom = 8.dp)
|
drawerState = drawerState
|
||||||
.clip(RoundedCornerShape(16.dp))
|
)
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.weight(1f)
|
|
||||||
) {
|
|
||||||
if (it == "home") {
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
RevoltAPI.channelCache.values.filter { it.channelType == ChannelType.Group }
|
|
||||||
.forEach { channel ->
|
|
||||||
DrawerChannel(
|
|
||||||
name = channel.name
|
|
||||||
?: "GDM #${channel.id}",
|
|
||||||
channelType = ChannelType.Group,
|
|
||||||
selected = channel.id == (navBackStackEntry?.arguments?.getString(
|
|
||||||
"channelId"
|
|
||||||
) ?: false),
|
|
||||||
hasUnread = channel.lastMessageID?.let { lastMessageID ->
|
|
||||||
RevoltAPI.unreads.hasUnread(
|
|
||||||
channel.id!!,
|
|
||||||
lastMessageID
|
|
||||||
)
|
|
||||||
} ?: false,
|
|
||||||
onClick = {
|
|
||||||
navController.navigate("channel/${channel.id}")
|
|
||||||
scope.launch {
|
|
||||||
drawerState.focusCenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val server = RevoltAPI.serverCache[it]
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = server?.name
|
|
||||||
?: stringResource(R.string.unknown),
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
fontSize = 24.sp,
|
|
||||||
modifier = Modifier.padding(16.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
server?.channels?.forEach { channelId ->
|
|
||||||
RevoltAPI.channelCache[channelId]?.let { ch ->
|
|
||||||
DrawerChannel(
|
|
||||||
name = ch.name!!,
|
|
||||||
channelType = ch.channelType!!,
|
|
||||||
selected = navBackStackEntry?.arguments?.getString(
|
|
||||||
"channelId"
|
|
||||||
) == ch.id,
|
|
||||||
hasUnread = ch.lastMessageID?.let { lastMessageID ->
|
|
||||||
RevoltAPI.unreads.hasUnread(
|
|
||||||
ch.id!!,
|
|
||||||
lastMessageID
|
|
||||||
)
|
|
||||||
} ?: true,
|
|
||||||
onClick = {
|
|
||||||
scope.launch { drawerState.focusCenter() }
|
|
||||||
navController.navigate("channel/${ch.id}") {
|
|
||||||
popUpTo("home") {
|
|
||||||
inclusive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +217,15 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bottomSheet("channel/{channelId}/menu") { backStackEntry ->
|
||||||
|
val channelId = backStackEntry.arguments?.getString("channelId")
|
||||||
|
if (channelId != null) {
|
||||||
|
ChannelContextSheet(
|
||||||
|
navController = navController,
|
||||||
|
channelId = channelId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
bottomSheet("message/{messageId}/menu") { backStackEntry ->
|
bottomSheet("message/{messageId}/menu") { backStackEntry ->
|
||||||
val messageId = backStackEntry.arguments?.getString("messageId")
|
val messageId = backStackEntry.arguments?.getString("messageId")
|
||||||
if (messageId != null) {
|
if (messageId != null) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
package chat.revolt.screens.chat.sheets
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
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.navigation.NavController
|
||||||
|
import chat.revolt.R
|
||||||
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.components.generic.SheetClickable
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChannelContextSheet(
|
||||||
|
navController: NavController,
|
||||||
|
channelId: String,
|
||||||
|
) {
|
||||||
|
val channel = RevoltAPI.channelCache[channelId]
|
||||||
|
if (channel == null) {
|
||||||
|
navController.popBackStack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val clipboardManager = LocalClipboardManager.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
clipboardManager.setText(AnnotatedString(channel.id))
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.channel_context_sheet_actions_copy_id_copied),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
channel.lastMessageID?.let {
|
||||||
|
RevoltAPI.unreads.markAsRead(channelId, it, sync = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,10 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Edit
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.*
|
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.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
|
@ -40,234 +43,256 @@ fun MessageContextSheet(
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
|
|
||||||
Surface {
|
Column(
|
||||||
Column(
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.clip(MaterialTheme.shapes.medium)
|
||||||
.verticalScroll(rememberScrollState()),
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
||||||
|
.padding(bottom = 8.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Message(
|
||||||
modifier = Modifier
|
message = message.copy(
|
||||||
.clip(MaterialTheme.shapes.medium)
|
tail = false,
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
masquerade = null
|
||||||
.padding(bottom = 8.dp)
|
),
|
||||||
) {
|
truncate = true
|
||||||
Message(
|
)
|
||||||
message = message.copy(
|
}
|
||||||
tail = false,
|
|
||||||
masquerade = null
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
),
|
|
||||||
truncate = true
|
SheetClickable(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_reply_24dp),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.message_context_sheet_actions_reply),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
UiCallbacks.emitQueueMessageForReply(messageId)
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
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
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.comingsoon_toast),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
SheetClickable(
|
SheetClickable(
|
||||||
icon = { modifier ->
|
icon = { modifier ->
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_reply_24dp),
|
painter = painterResource(id = R.drawable.ic_content_copy_24dp),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
label = { style ->
|
label = { style ->
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_reply),
|
text = stringResource(id = R.string.message_context_sheet_actions_copy),
|
||||||
style = style
|
style = style
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
UiCallbacks.emitQueueMessageForReply(messageId)
|
if (message.content == null || message.content.isEmpty()) {
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
context,
|
context,
|
||||||
context.getString(R.string.comingsoon_toast),
|
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
|
return@SheetClickable
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetClickable(
|
clipboardManager.setText(AnnotatedString(message.content))
|
||||||
icon = { modifier ->
|
Toast.makeText(
|
||||||
Icon(
|
context,
|
||||||
painter = painterResource(id = R.drawable.ic_content_copy_24dp),
|
context.getString(R.string.copied),
|
||||||
contentDescription = null,
|
Toast.LENGTH_SHORT
|
||||||
modifier = modifier
|
).show()
|
||||||
)
|
navController.popBackStack()
|
||||||
},
|
}
|
||||||
label = { style ->
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_copy),
|
|
||||||
style = style
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
if (message.content == null || message.content.isEmpty()) {
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
navController.popBackStack()
|
|
||||||
return@SheetClickable
|
|
||||||
}
|
|
||||||
|
|
||||||
clipboardManager.setText(AnnotatedString(message.content))
|
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 == null || message.content.isEmpty()) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
context,
|
context,
|
||||||
context.getString(R.string.copied),
|
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
|
return@SheetClickable
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetClickable(
|
val server = RevoltAPI.serverCache.values.find { server ->
|
||||||
icon = { modifier ->
|
server.channels?.contains(message.channel) ?: false
|
||||||
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 == null || message.content.isEmpty()) {
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
navController.popBackStack()
|
|
||||||
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))
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.message_context_sheet_actions_copy_link_copied),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
}
|
||||||
|
val messageLink =
|
||||||
|
"$REVOLT_APP/server/${server?.id}/channel/${message.channel}/${message.id}"
|
||||||
|
|
||||||
SheetClickable(
|
clipboardManager.setText(AnnotatedString(messageLink))
|
||||||
icon = { modifier ->
|
Toast.makeText(
|
||||||
Icon(
|
context,
|
||||||
painter = painterResource(id = R.drawable.ic_content_copy_id_24dp),
|
context.getString(R.string.message_context_sheet_actions_copy_link_copied),
|
||||||
contentDescription = null,
|
Toast.LENGTH_SHORT
|
||||||
modifier = modifier
|
).show()
|
||||||
)
|
navController.popBackStack()
|
||||||
},
|
}
|
||||||
label = { style ->
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_copy_id),
|
|
||||||
style = style
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
if (message.id == null) return@SheetClickable
|
|
||||||
|
|
||||||
clipboardManager.setText(AnnotatedString(message.id))
|
SheetClickable(
|
||||||
Toast.makeText(
|
icon = { modifier ->
|
||||||
context,
|
Icon(
|
||||||
context.getString(R.string.message_context_sheet_actions_copy_id_copied),
|
painter = painterResource(id = R.drawable.ic_content_copy_id_24dp),
|
||||||
Toast.LENGTH_SHORT
|
contentDescription = null,
|
||||||
).show()
|
modifier = modifier
|
||||||
navController.popBackStack()
|
)
|
||||||
}
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.message_context_sheet_actions_copy_id),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
if (message.id == null) return@SheetClickable
|
||||||
|
|
||||||
SheetClickable(
|
clipboardManager.setText(AnnotatedString(message.id))
|
||||||
icon = { modifier ->
|
Toast.makeText(
|
||||||
Icon(
|
context,
|
||||||
imageVector = Icons.Default.Edit,
|
context.getString(R.string.message_context_sheet_actions_copy_id_copied),
|
||||||
contentDescription = null,
|
Toast.LENGTH_SHORT
|
||||||
modifier = modifier
|
).show()
|
||||||
)
|
navController.popBackStack()
|
||||||
},
|
}
|
||||||
label = { style ->
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_edit),
|
|
||||||
style = style
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.comingsoon_toast),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
|
|
||||||
SheetClickable(
|
|
||||||
icon = { modifier ->
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Delete,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = { style ->
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_delete),
|
|
||||||
style = style
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
context.getString(R.string.comingsoon_toast),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
|
|
||||||
SheetClickable(
|
SheetClickable(
|
||||||
icon = { modifier ->
|
icon = { modifier ->
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = R.drawable.ic_flag_24dp),
|
painter = painterResource(id = R.drawable.ic_eye_off_24dp),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
label = { style ->
|
label = { style ->
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.message_context_sheet_actions_report),
|
text = stringResource(id = R.string.message_context_sheet_actions_mark_unread),
|
||||||
style = style
|
style = style
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
navController.navigate("report/message/${message.id}")
|
Toast.makeText(
|
||||||
}
|
context,
|
||||||
|
context.getString(R.string.comingsoon_toast),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.comingsoon_toast),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
SheetClickable(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Delete,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.message_context_sheet_actions_delete),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.comingsoon_toast),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
SheetClickable(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_flag_24dp),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = { style ->
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.message_context_sheet_actions_report),
|
||||||
|
style = style
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
navController.navigate("report/message/${message.id}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M23.5,17L18.5,22L15,18.5L16.5,17L18.5,19L22,15.5L23.5,17M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9M12,17C12.5,17 12.97,16.93 13.42,16.79C13.15,17.5 13,18.22 13,19V19.45L12,19.5C7,19.5 2.73,16.39 1,12C2.73,7.61 7,4.5 12,4.5C17,4.5 21.27,7.61 23,12C22.75,12.64 22.44,13.26 22.08,13.85C21.18,13.31 20.12,13 19,13C18.22,13 17.5,13.15 16.79,13.42C16.93,12.97 17,12.5 17,12A5,5 0 0,0 12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17Z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -140,6 +140,15 @@
|
||||||
<string name="message_context_sheet_actions_copy_link_copied">Copied message link to clipboard</string>
|
<string name="message_context_sheet_actions_copy_link_copied">Copied message link to clipboard</string>
|
||||||
<string name="message_context_sheet_actions_react">React</string>
|
<string name="message_context_sheet_actions_react">React</string>
|
||||||
<string name="message_context_sheet_actions_report">Report</string>
|
<string name="message_context_sheet_actions_report">Report</string>
|
||||||
|
<string name="message_context_sheet_actions_mark_unread">Mark as unread</string>
|
||||||
|
|
||||||
|
<string name="channel_context_sheet_actions_copy_id">Copy ID</string>
|
||||||
|
<string name="channel_context_sheet_actions_copy_id_copied">Copied channel ID to clipboard</string>
|
||||||
|
<string name="channel_context_sheet_actions_mark_read">Mark as read</string>
|
||||||
|
|
||||||
|
<string name="server_context_sheet_actions_copy_id">Copy ID</string>
|
||||||
|
<string name="server_context_sheet_actions_copy_id_copied">Copied server ID to clipboard</string>
|
||||||
|
<string name="server_context_sheet_actions_mark_read">Mark as read</string>
|
||||||
|
|
||||||
<string name="report">Report</string>
|
<string name="report">Report</string>
|
||||||
<string name="report_cancel">Cancel</string>
|
<string name="report_cancel">Cancel</string>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue