feat: tiny ux tweaks
This commit is contained in:
parent
74a1454f73
commit
96fb9f8983
|
|
@ -50,11 +50,7 @@ class Unreads {
|
||||||
suspend fun markAsRead(channelId: String, messageId: String, sync: Boolean = true) {
|
suspend fun markAsRead(channelId: String, messageId: String, sync: Boolean = true) {
|
||||||
if (!hasLoaded.value) return
|
if (!hasLoaded.value) return
|
||||||
channels[channelId]?.let {
|
channels[channelId]?.let {
|
||||||
if (it.last_id == messageId) {
|
channels[channelId] = it.copy(last_id = messageId)
|
||||||
channels.remove(channelId)
|
|
||||||
} else {
|
|
||||||
channels[channelId] = it.copy(last_id = messageId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sync) {
|
if (sync) {
|
||||||
ackChannel(channelId, messageId)
|
ackChannel(channelId, messageId)
|
||||||
|
|
@ -63,11 +59,7 @@ class Unreads {
|
||||||
|
|
||||||
fun processExternalAck(channelId: String, messageId: String) {
|
fun processExternalAck(channelId: String, messageId: String) {
|
||||||
channels[channelId]?.let {
|
channels[channelId]?.let {
|
||||||
if (it.last_id == messageId) {
|
channels[channelId] = it.copy(last_id = messageId)
|
||||||
channels.remove(channelId)
|
|
||||||
} else {
|
|
||||||
channels[channelId] = it.copy(last_id = messageId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ package chat.revolt.components.chat
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
|
@ -16,6 +17,7 @@ import androidx.compose.ui.unit.sp
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
import chat.revolt.api.asJanuaryProxyUrl
|
import chat.revolt.api.asJanuaryProxyUrl
|
||||||
|
import chat.revolt.api.internals.WebCompat
|
||||||
import chat.revolt.components.generic.UserAvatar
|
import chat.revolt.components.generic.UserAvatar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -30,67 +32,77 @@ fun InReplyTo(
|
||||||
|
|
||||||
val username = message?.masquerade?.name ?: author?.username ?: ""
|
val username = message?.masquerade?.name ?: author?.username ?: ""
|
||||||
|
|
||||||
Row(
|
val contentColor = LocalContentColor.current
|
||||||
|
val usernameColor = message?.masquerade?.colour?.let {
|
||||||
|
WebCompat.parseColour(it)
|
||||||
|
} ?: contentColor
|
||||||
|
|
||||||
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(4.dp)
|
.clickable { onMessageClick(messageId) }
|
||||||
.clickable { onMessageClick(messageId) },
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.width(48.dp))
|
Row(
|
||||||
|
modifier = Modifier.padding(4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.width(40.dp))
|
||||||
|
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
UserAvatar(
|
UserAvatar(
|
||||||
username = username,
|
username = username,
|
||||||
userId = author?.id ?: "",
|
userId = author?.id ?: "",
|
||||||
avatar = author?.avatar,
|
avatar = author?.avatar,
|
||||||
rawUrl = message.masquerade?.avatar?.let { asJanuaryProxyUrl(it) },
|
rawUrl = message.masquerade?.avatar?.let { asJanuaryProxyUrl(it) },
|
||||||
size = 16.dp
|
size = 16.dp
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = if (author != null) {
|
text = if (author != null) {
|
||||||
if (withMention) {
|
if (withMention) {
|
||||||
"@$username"
|
"@$username"
|
||||||
|
} else {
|
||||||
|
username
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
username
|
stringResource(id = R.string.unknown)
|
||||||
|
},
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = usernameColor,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.padding(horizontal = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
InlineBadges(
|
||||||
|
bot = message.masquerade == null && author?.bot != null,
|
||||||
|
masquerade = message.masquerade != null && author?.bot != null,
|
||||||
|
colour = contentColor.copy(alpha = 0.5f),
|
||||||
|
modifier = Modifier.size(8.dp),
|
||||||
|
followingIfAny = {
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
}
|
}
|
||||||
} else {
|
)
|
||||||
stringResource(id = R.string.unknown)
|
|
||||||
},
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.9f),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier.padding(horizontal = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
InlineBadges(
|
Text(
|
||||||
bot = message.masquerade == null && author?.bot != null,
|
text = message.content ?: "",
|
||||||
masquerade = message.masquerade != null && author?.bot != null,
|
fontSize = 12.sp,
|
||||||
colour = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f),
|
color = contentColor.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(8.dp),
|
maxLines = 1,
|
||||||
followingIfAny = {
|
overflow = TextOverflow.Ellipsis
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
)
|
||||||
}
|
} else {
|
||||||
)
|
Text(
|
||||||
|
text = stringResource(id = R.string.reply_message_not_cached),
|
||||||
Text(
|
fontStyle = FontStyle.Italic, // inter doesn't have italics...
|
||||||
text = message.content ?: "",
|
color = contentColor.copy(alpha = 0.7f),
|
||||||
fontSize = 12.sp,
|
fontFamily = FontFamily.Default, // ...so we use the defaul t font
|
||||||
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
|
fontSize = 12.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.reply_message_not_cached),
|
|
||||||
fontStyle = FontStyle.Italic,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package chat.revolt.components.chat
|
package chat.revolt.components.chat
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
|
@ -24,7 +25,7 @@ import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.components.generic.RemoteImage
|
import chat.revolt.components.generic.RemoteImage
|
||||||
import chat.revolt.components.generic.UserAvatar
|
import chat.revolt.components.generic.UserAvatar
|
||||||
import chat.revolt.components.generic.UserAvatarWidthPlaceholder
|
import chat.revolt.components.generic.UserAvatarWidthPlaceholder
|
||||||
import chat.revolt.markdown.Renderer
|
import chat.revolt.markdown.Markdown
|
||||||
import chat.revolt.api.schemas.Message as MessageSchema
|
import chat.revolt.api.schemas.Message as MessageSchema
|
||||||
|
|
||||||
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
|
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
|
||||||
|
|
@ -62,13 +63,17 @@ fun Message(
|
||||||
}
|
}
|
||||||
|
|
||||||
message.replies?.forEach { reply ->
|
message.replies?.forEach { reply ->
|
||||||
val replyMessage = RevoltAPI.messageCache[reply] ?: return@forEach
|
val replyMessage = RevoltAPI.messageCache[reply]
|
||||||
|
|
||||||
InReplyTo(
|
InReplyTo(
|
||||||
messageId = reply,
|
messageId = reply,
|
||||||
withMention = message.mentions?.contains(replyMessage.author) == true
|
withMention = replyMessage?.author?.let { message.mentions?.contains(replyMessage.author) }
|
||||||
|
?: false,
|
||||||
) {
|
) {
|
||||||
// TODO Add jump to message
|
// TODO Add jump to message
|
||||||
|
if (replyMessage == null) {
|
||||||
|
Toast.makeText(context, "lmao prankd", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +136,7 @@ fun Message(
|
||||||
|
|
||||||
message.content?.let {
|
message.content?.let {
|
||||||
Text(
|
Text(
|
||||||
text = Renderer.annotateMarkdown(it),
|
text = Markdown.annotate(it),
|
||||||
maxLines = if (truncate) 1 else Int.MAX_VALUE,
|
maxLines = if (truncate) 1 else Int.MAX_VALUE,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package chat.revolt.internals.markdown
|
||||||
|
|
||||||
|
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||||
|
import chat.revolt.api.schemas.User
|
||||||
|
|
||||||
|
data class MarkdownContext(
|
||||||
|
val memberMap: SnapshotStateMap<String, String>,
|
||||||
|
val userMap: SnapshotStateMap<String, User>,
|
||||||
|
val channelMap: SnapshotStateMap<String, String>,
|
||||||
|
val serverId: String,
|
||||||
|
)
|
||||||
|
|
@ -27,6 +27,7 @@ import chat.revolt.api.routes.user.blockUser
|
||||||
import chat.revolt.api.schemas.ContentReportReason
|
import chat.revolt.api.schemas.ContentReportReason
|
||||||
import chat.revolt.components.chat.Message
|
import chat.revolt.components.chat.Message
|
||||||
import chat.revolt.components.generic.FormTextField
|
import chat.revolt.components.generic.FormTextField
|
||||||
|
import chat.revolt.markdown.Markdown
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
enum class ReportingState {
|
enum class ReportingState {
|
||||||
|
|
@ -48,6 +49,9 @@ fun ReportMessageDialog(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val author = RevoltAPI.userCache[message.author]
|
||||||
|
val messageIsBridged = author?.let { author.bot != null && message.masquerade != null } ?: false
|
||||||
|
|
||||||
val state = remember { mutableStateOf(ReportingState.Reason) }
|
val state = remember { mutableStateOf(ReportingState.Reason) }
|
||||||
|
|
||||||
val selectedReason = remember { mutableStateOf("Illegal") }
|
val selectedReason = remember { mutableStateOf("Illegal") }
|
||||||
|
|
@ -104,6 +108,14 @@ fun ReportMessageDialog(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messageIsBridged) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = Markdown.annotate(stringResource(id = R.string.report_message_bridge_notice)),
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
Box {
|
Box {
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@
|
||||||
|
|
||||||
<string name="report_message">Thank you for taking the time to report this message. Please provide a reason for reporting this message.</string>
|
<string name="report_message">Thank you for taking the time to report this message. Please provide a reason for reporting this message.</string>
|
||||||
<string name="report_message_preview">Selected message:</string>
|
<string name="report_message_preview">Selected message:</string>
|
||||||
|
<string name="report_message_bridge_notice">**Note:** This message may have been sent from another platform. It is recommended to also report the message on the platform it was sent from.</string>
|
||||||
<string name="report_server">Thank you for taking the time to report this server. Please provide a reason for reporting this server.</string>
|
<string name="report_server">Thank you for taking the time to report this server. Please provide a reason for reporting this server.</string>
|
||||||
<string name="report_server_preview">Selected server:</string>
|
<string name="report_server_preview">Selected server:</string>
|
||||||
<string name="report_user">Thank you for taking the time to report this user. Please provide a reason for reporting this user.</string>
|
<string name="report_user">Thank you for taking the time to report this user. Please provide a reason for reporting this user.</string>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
|
||||||
object Renderer {
|
object Markdown {
|
||||||
fun annotateMarkdown(text: String): AnnotatedString {
|
fun <Ctx> annotateInContext(text: String, context: Ctx): AnnotatedString {
|
||||||
// TODO this is all placeholder code
|
// TODO this is all placeholder code
|
||||||
val boldRegex = Regex("\\*\\*(.*?)\\*\\*")
|
val boldRegex = Regex("\\*\\*(.*?)\\*\\*")
|
||||||
return buildAnnotatedString {
|
return buildAnnotatedString {
|
||||||
|
|
@ -23,4 +23,6 @@ object Renderer {
|
||||||
toAnnotatedString()
|
toAnnotatedString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun annotate(text: String): AnnotatedString = annotateInContext(text, Unit)
|
||||||
}
|
}
|
||||||
|
|
@ -58,10 +58,3 @@ open class Node(
|
||||||
*/
|
*/
|
||||||
val position: Position = Position()
|
val position: Position = Position()
|
||||||
)
|
)
|
||||||
|
|
||||||
open class UnistParent(
|
|
||||||
/**
|
|
||||||
* List representing the children of a node.
|
|
||||||
*/
|
|
||||||
val children: List<Node> = emptyList()
|
|
||||||
) : Node()
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue