feat: support webhooks
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
197c6db56a
commit
7e2eccf387
|
|
@ -20,6 +20,7 @@ data class Message(
|
|||
val mentions: List<String>? = null,
|
||||
val masquerade: Masquerade? = null,
|
||||
val system: SystemInfo? = null,
|
||||
val webhook: WebHook? = null,
|
||||
val type: String? = null, // this is _only_ used for websocket events!
|
||||
val tail: Boolean? = null // this is used to determine if the message is the last in a message group
|
||||
) {
|
||||
|
|
@ -110,3 +111,9 @@ data class SystemInfo(
|
|||
val to: String? = null,
|
||||
val content: String? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class WebHook(
|
||||
val avatar: String? = null,
|
||||
val name: String? = null,
|
||||
)
|
||||
|
|
@ -14,6 +14,7 @@ sealed class Action {
|
|||
data class ReportUser(val userId: String) : Action()
|
||||
data class ReportMessage(val messageId: String) : Action()
|
||||
data class OpenVoiceChannelOverlay(val channelId: String) : Action()
|
||||
data object OpenWebhookSheet : Action()
|
||||
}
|
||||
|
||||
val ActionChannel = Channel<Action>(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ enum class InlineBadge {
|
|||
Bot,
|
||||
Bridge,
|
||||
PlatformModeration,
|
||||
TeamMember
|
||||
TeamMember,
|
||||
Webhook
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -50,6 +51,13 @@ fun InlineBadge(
|
|||
tint = colour,
|
||||
modifier = modifier
|
||||
)
|
||||
|
||||
InlineBadge.Webhook -> Icon(
|
||||
painter = painterResource(id = R.drawable.ic_hook_24dp),
|
||||
contentDescription = stringResource(id = R.string.badge_webhook_alt),
|
||||
tint = colour,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +68,7 @@ fun InlineBadges(
|
|||
bridge: Boolean = false,
|
||||
platformModeration: Boolean = false,
|
||||
teamMember: Boolean = false,
|
||||
webhook: Boolean = false,
|
||||
colour: Color = Color.Unspecified,
|
||||
precedingIfAny: @Composable () -> Unit = {},
|
||||
followingIfAny: @Composable () -> Unit = {}
|
||||
|
|
@ -99,6 +108,13 @@ fun InlineBadges(
|
|||
colour = colour
|
||||
)
|
||||
}
|
||||
if (webhook) {
|
||||
InlineBadge(
|
||||
badge = InlineBadge.Webhook,
|
||||
modifier = modifier,
|
||||
colour = colour
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBadges) {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,8 @@ fun Message(
|
|||
canReply: Boolean = false,
|
||||
onReply: () -> Unit = {},
|
||||
onAddReaction: () -> Unit = {},
|
||||
fromWebhook: Boolean = false,
|
||||
webhookName: String? = null
|
||||
) {
|
||||
val author = RevoltAPI.userCache[message.author] ?: return CircularProgressIndicator()
|
||||
val context = LocalContext.current
|
||||
|
|
@ -304,7 +306,7 @@ fun Message(
|
|||
if (message.tail == false) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = authorName(message),
|
||||
text = webhookName ?: authorName(message),
|
||||
style = LocalTextStyle.current.copy(
|
||||
fontWeight = FontWeight.Bold,
|
||||
brush = authorColour(message)
|
||||
|
|
@ -328,6 +330,7 @@ fun Message(
|
|||
bridge = message.masquerade != null && author.bot != null,
|
||||
platformModeration = author.id == SpecialUsers.PLATFORM_MODERATION_USER,
|
||||
teamMember = author.id in SpecialUsers.TEAM_MEMBER_FLAIRS.keys,
|
||||
webhook = fromWebhook,
|
||||
colour = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f),
|
||||
modifier = Modifier.size(16.dp),
|
||||
precedingIfAny = {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import chat.revolt.sheets.ReactionInfoSheet
|
|||
import chat.revolt.sheets.ServerContextSheet
|
||||
import chat.revolt.sheets.StatusSheet
|
||||
import chat.revolt.sheets.UserInfoSheet
|
||||
import chat.revolt.sheets.WebHookUserSheet
|
||||
import com.airbnb.lottie.RenderMode
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
|
|
@ -229,6 +230,8 @@ fun ChatRouterScreen(
|
|||
var userContextSheetTarget by remember { mutableStateOf("") }
|
||||
var userContextSheetServer by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
var showWebhookInfoSheet by remember { mutableStateOf(false) }
|
||||
|
||||
var showChannelUnavailableAlert by remember { mutableStateOf(false) }
|
||||
|
||||
var showLinkInfoSheet by remember { mutableStateOf(false) }
|
||||
|
|
@ -389,6 +392,10 @@ fun ChatRouterScreen(
|
|||
voiceChannelOverlayChannelId = action.channelId
|
||||
voiceChannelOverlay = true
|
||||
}
|
||||
|
||||
is Action.OpenWebhookSheet -> {
|
||||
showWebhookInfoSheet = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -554,6 +561,19 @@ fun ChatRouterScreen(
|
|||
}
|
||||
}
|
||||
|
||||
if (showWebhookInfoSheet) {
|
||||
val webhookInfoSheetState = rememberModalBottomSheetState()
|
||||
|
||||
ModalBottomSheet(
|
||||
sheetState = webhookInfoSheetState,
|
||||
onDismissRequest = {
|
||||
showWebhookInfoSheet = false
|
||||
}
|
||||
) {
|
||||
WebHookUserSheet()
|
||||
}
|
||||
}
|
||||
|
||||
if (showReportUser) {
|
||||
ReportUserDialog(
|
||||
onDismiss = { showReportUser = false },
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.datetime.Instant
|
||||
import java.io.File
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
sealed class ChannelScreenItem {
|
||||
data class RegularMessage(val message: Message) : ChannelScreenItem()
|
||||
|
|
@ -603,14 +602,20 @@ fun ChannelScreen(
|
|||
}
|
||||
},
|
||||
onAvatarClick = {
|
||||
item.message.author?.let { author ->
|
||||
if (item.message.webhook != null) {
|
||||
scope.launch {
|
||||
ActionChannel.send(
|
||||
Action.OpenUserSheet(
|
||||
author,
|
||||
viewModel.channel?.server
|
||||
ActionChannel.send(Action.OpenWebhookSheet)
|
||||
}
|
||||
} else {
|
||||
item.message.author?.let { author ->
|
||||
scope.launch {
|
||||
ActionChannel.send(
|
||||
Action.OpenUserSheet(
|
||||
author,
|
||||
viewModel.channel?.server
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -631,7 +636,9 @@ fun ChannelScreen(
|
|||
reactSheetTarget = messageId
|
||||
reactSheetShown = true
|
||||
}
|
||||
}
|
||||
},
|
||||
fromWebhook = item.message.webhook != null,
|
||||
webhookName = item.message.webhook?.name
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
package chat.revolt.sheets
|
||||
|
||||
import android.widget.Toast
|
||||
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.layout.size
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.revolt.R
|
||||
import chat.revolt.components.generic.NonIdealState
|
||||
|
||||
@Composable
|
||||
fun WebHookUserSheet(modifier: Modifier = Modifier) {
|
||||
val context = LocalContext.current
|
||||
|
||||
NonIdealState(
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_hook_24dp),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.user_info_sheet_webhook)
|
||||
)
|
||||
},
|
||||
description = {
|
||||
Text(
|
||||
text = stringResource(R.string.user_info_sheet_webhook_description),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
)
|
||||
Column(Modifier.padding(horizontal = 16.dp)) {
|
||||
Text(
|
||||
text = stringResource(R.string.user_info_sheet_webhook_description_2),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(Modifier.height(32.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
Toast(context).apply {
|
||||
setText(context.getString(R.string.comingsoon_toast))
|
||||
duration = Toast.LENGTH_SHORT
|
||||
show()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.user_info_sheet_webhook_learn_more))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(48.dp))
|
||||
}
|
||||
|
|
@ -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="M18,6C18,7.82 16.76,9.41 15,9.86V17A5,5 0 0,1 10,22A5,5 0 0,1 5,17V12L10,17H7A3,3 0 0,0 10,20A3,3 0 0,0 13,17V9.86C11.23,9.4 10,7.8 10,5.97C10,3.76 11.8,2 14,2C16.22,2 18,3.79 18,6M14,8A2,2 0 0,0 16,6A2,2 0 0,0 14,4A2,2 0 0,0 12,6A2,2 0 0,0 14,8Z" />
|
||||
</vector>
|
||||
|
|
@ -125,6 +125,7 @@
|
|||
<string name="badge_masquerade_alt">From linked channel</string>
|
||||
<string name="badge_platform_moderation_alt">Platform moderation</string>
|
||||
<string name="badge_team_member_alt">Revolt team member</string>
|
||||
<string name="badge_webhook_alt">Webhook</string>
|
||||
|
||||
<string name="unknown">Unknown</string>
|
||||
|
||||
|
|
@ -352,6 +353,10 @@
|
|||
<string name="user_info_sheet_open">Open user info</string>
|
||||
<string name="user_info_sheet_user_not_found">Can\'t resolve this user</string>
|
||||
<string name="user_info_sheet_user_not_found_description">This user may have been deleted or you may not have permission to view them.</string>
|
||||
<string name="user_info_sheet_webhook">Is it a bird, is it a plane?</string>
|
||||
<string name="user_info_sheet_webhook_description">No, it\'s a webhook!</string>
|
||||
<string name="user_info_sheet_webhook_description_2">Webhooks are automated broadcasts from other services on the internet. They can\'t chat back, but you can still see what they have to say.</string>
|
||||
<string name="user_info_sheet_webhook_learn_more">Learn more</string>
|
||||
<string name="user_info_sheet_category_bio">Bio</string>
|
||||
<string name="user_info_sheet_bio_empty">This user hasn\'t set a bio yet.</string>
|
||||
<string name="user_info_sheet_bio_not_found">This user\'s bio could not be fetched. Please verify you share a server or are friends.</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue