feat: message reporting and block route
This commit is contained in:
parent
5cf0943e26
commit
c38fc51e23
|
|
@ -0,0 +1 @@
|
|||
Revolt
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package chat.revolt.api.routes.safety
|
||||
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.RevoltError
|
||||
import chat.revolt.api.RevoltHttp
|
||||
import chat.revolt.api.RevoltJson
|
||||
import chat.revolt.api.schemas.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import kotlinx.serialization.SerializationException
|
||||
|
||||
suspend fun putMessageReport(
|
||||
messageId: String,
|
||||
reason: ContentReportReason,
|
||||
additionalContext: String? = null
|
||||
) {
|
||||
val fullMessageReport = FullMessageReport(
|
||||
content = MessageReport(
|
||||
report_reason = reason,
|
||||
id = messageId,
|
||||
),
|
||||
additional_context = additionalContext,
|
||||
)
|
||||
|
||||
val response = RevoltHttp.post("/safety/report") {
|
||||
headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||
setBody(
|
||||
RevoltJson.encodeToString(
|
||||
FullMessageReport.serializer(),
|
||||
fullMessageReport
|
||||
)
|
||||
)
|
||||
}
|
||||
.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||
throw Error(error.type)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun putServerReport(
|
||||
serverId: String,
|
||||
reason: ContentReportReason,
|
||||
additionalContext: String? = null
|
||||
) {
|
||||
val fullServerReport = FullServerReport(
|
||||
content = ServerReport(
|
||||
report_reason = reason,
|
||||
id = serverId,
|
||||
),
|
||||
additional_context = additionalContext,
|
||||
)
|
||||
|
||||
val response = RevoltHttp.post("/safety/report") {
|
||||
headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||
setBody(
|
||||
RevoltJson.encodeToString(
|
||||
FullServerReport.serializer(),
|
||||
fullServerReport
|
||||
)
|
||||
)
|
||||
}
|
||||
.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||
throw Error(error.type)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun putUserReport(
|
||||
userId: String,
|
||||
reason: UserReportReason,
|
||||
additionalContext: String? = null
|
||||
) {
|
||||
val fullUserReport = FullUserReport(
|
||||
content = UserReport(
|
||||
report_reason = reason,
|
||||
id = userId,
|
||||
),
|
||||
additional_context = additionalContext,
|
||||
)
|
||||
|
||||
val response = RevoltHttp.post("/safety/report") {
|
||||
headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||
setBody(
|
||||
RevoltJson.encodeToString(
|
||||
FullUserReport.serializer(),
|
||||
fullUserReport
|
||||
)
|
||||
)
|
||||
}
|
||||
.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||
throw Error(error.type)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package chat.revolt.api.routes.user
|
||||
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.RevoltError
|
||||
import chat.revolt.api.RevoltHttp
|
||||
import chat.revolt.api.RevoltJson
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import kotlinx.serialization.SerializationException
|
||||
|
||||
suspend fun blockUser(userId: String) {
|
||||
val response = RevoltHttp.put("/users/$userId/block") {
|
||||
headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||
}
|
||||
.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||
throw Error(error.type)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
|
||||
val user = RevoltAPI.userCache[userId] ?: return
|
||||
RevoltAPI.userCache[userId] = user.copy(relationship = "Blocked")
|
||||
}
|
||||
|
||||
suspend fun unblockUser(userId: String) {
|
||||
val response = RevoltHttp.delete("/users/$userId/block") {
|
||||
headers.append(RevoltAPI.TOKEN_HEADER_NAME, RevoltAPI.sessionToken)
|
||||
}
|
||||
.bodyAsText()
|
||||
|
||||
try {
|
||||
val error = RevoltJson.decodeFromString(RevoltError.serializer(), response)
|
||||
throw Error(error.type)
|
||||
} catch (e: SerializationException) {
|
||||
// Not an error
|
||||
}
|
||||
|
||||
val user = RevoltAPI.userCache[userId] ?: return
|
||||
RevoltAPI.userCache[userId] = user.copy(relationship = "None")
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ data class Message(
|
|||
edited = partial.edited ?: edited,
|
||||
embeds = partial.embeds ?: embeds,
|
||||
mentions = partial.mentions ?: mentions,
|
||||
masquerade = partial.masquerade ?: masquerade,
|
||||
type = partial.type ?: type,
|
||||
tail = partial.tail ?: tail,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
package chat.revolt.api.schemas
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
@Serializable
|
||||
enum class ContentReportReason(val value: String) {
|
||||
NoneSpecified("NoneSpecified"),
|
||||
Illegal("Illegal"),
|
||||
PromotesHarm("PromotesHarm"),
|
||||
SpamAbuse("SpamAbuse"),
|
||||
Malware("Malware"),
|
||||
Harassment("Harassment");
|
||||
|
||||
companion object : KSerializer<ContentReportReason> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() {
|
||||
return PrimitiveSerialDescriptor(
|
||||
"chat.revolt.api.schemas.ContentReportReason",
|
||||
PrimitiveKind.STRING
|
||||
)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): ContentReportReason =
|
||||
when (val value = decoder.decodeString()) {
|
||||
"NoneSpecified" -> NoneSpecified
|
||||
"Illegal" -> Illegal
|
||||
"PromotesHarm" -> PromotesHarm
|
||||
"SpamAbuse" -> SpamAbuse
|
||||
"Malware" -> Malware
|
||||
"Harassment" -> Harassment
|
||||
else -> throw IllegalArgumentException("Unknown ContentReportReason: $value")
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: ContentReportReason) {
|
||||
return encoder.encodeString(value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class UserReportReason(val value: String) {
|
||||
NoneSpecified("NoneSpecified"),
|
||||
SpamAbuse("SpamAbuse"),
|
||||
InappropriateProfile("InappropriateProfile"),
|
||||
Impersonation("Impersonation"),
|
||||
BanEvasion("BanEvasion"),
|
||||
Underage("Underage");
|
||||
|
||||
companion object : KSerializer<UserReportReason> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() {
|
||||
return PrimitiveSerialDescriptor(
|
||||
"chat.revolt.api.schemas.UserReportReason",
|
||||
PrimitiveKind.STRING
|
||||
)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): UserReportReason =
|
||||
when (val value = decoder.decodeString()) {
|
||||
"NoneSpecified" -> NoneSpecified
|
||||
"SpamAbuse" -> SpamAbuse
|
||||
"InappropriateProfile" -> InappropriateProfile
|
||||
"Impersonation" -> Impersonation
|
||||
"BanEvasion" -> BanEvasion
|
||||
"Underage" -> Underage
|
||||
else -> throw IllegalArgumentException("Unknown UserReportReason: $value")
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: UserReportReason) {
|
||||
return encoder.encodeString(value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class MessageReport(
|
||||
val type: String = "Message",
|
||||
val id: String,
|
||||
val report_reason: ContentReportReason,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FullMessageReport(
|
||||
val content: MessageReport,
|
||||
val additional_context: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ServerReport(
|
||||
val type: String = "Server",
|
||||
val id: String,
|
||||
val report_reason: ContentReportReason,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FullServerReport(
|
||||
val content: ServerReport,
|
||||
val additional_context: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class UserReport(
|
||||
val type: String = "User",
|
||||
val id: String,
|
||||
val report_reason: UserReportReason,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class FullUserReport(
|
||||
val content: UserReport,
|
||||
val additional_context: String? = null,
|
||||
)
|
||||
|
|
@ -25,10 +25,7 @@ import androidx.compose.ui.unit.sp
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.compose.*
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.realtime.DisconnectionState
|
||||
|
|
@ -43,6 +40,7 @@ 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.ServerDrawerSeparator
|
||||
import chat.revolt.components.screens.chat.rememberDoubleDrawerState
|
||||
import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog
|
||||
import chat.revolt.screens.chat.sheets.ChannelInfoSheet
|
||||
import chat.revolt.screens.chat.sheets.MessageContextSheet
|
||||
import chat.revolt.screens.chat.sheets.StatusSheet
|
||||
|
|
@ -302,6 +300,16 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
|
|||
bottomSheet("status") {
|
||||
StatusSheet(navController = navController, topNav = topNav)
|
||||
}
|
||||
|
||||
dialog("report/message/{messageId}") { backStackEntry ->
|
||||
val messageId = backStackEntry.arguments?.getString("messageId")
|
||||
if (messageId != null) {
|
||||
ReportMessageDialog(
|
||||
navController = navController,
|
||||
messageId = messageId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,332 @@
|
|||
package chat.revolt.screens.chat.dialogs.safety
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.routes.safety.putMessageReport
|
||||
import chat.revolt.api.routes.user.blockUser
|
||||
import chat.revolt.api.schemas.ContentReportReason
|
||||
import chat.revolt.components.chat.Message
|
||||
import chat.revolt.components.generic.FormTextField
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
enum class ReportingState {
|
||||
Reason,
|
||||
Sending,
|
||||
Done,
|
||||
Error
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReportMessageDialog(
|
||||
navController: NavController,
|
||||
messageId: String,
|
||||
) {
|
||||
val message = RevoltAPI.messageCache[messageId]
|
||||
if (message == null) {
|
||||
navController.popBackStack()
|
||||
return
|
||||
}
|
||||
|
||||
val state = remember { mutableStateOf(ReportingState.Reason) }
|
||||
|
||||
val selectedReason = remember { mutableStateOf("Illegal") }
|
||||
val userAddedContext = remember { mutableStateOf("") }
|
||||
|
||||
when (state.value) {
|
||||
ReportingState.Reason -> {
|
||||
val reasons = mapOf(
|
||||
"Illegal" to stringResource(id = R.string.report_reason_content_illegal),
|
||||
"PromotesHarm" to stringResource(id = R.string.report_reason_content_promotes_harm),
|
||||
"SpamAbuse" to stringResource(id = R.string.report_reason_content_spam_abuse),
|
||||
"Malware" to stringResource(id = R.string.report_reason_content_malware),
|
||||
"Harassment" to stringResource(id = R.string.report_reason_content_harassment),
|
||||
"Other" to stringResource(id = R.string.report_reason_content_other),
|
||||
)
|
||||
val reasonDropdownExpanded = remember { mutableStateOf(false) }
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
// nothing - prevent mistaps from closing the dialog
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
Text(text = stringResource(id = R.string.report_message))
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_message_preview),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(MaterialTheme.shapes.medium)
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
||||
.verticalScroll(rememberScrollState())
|
||||
.heightIn(max = 200.dp)
|
||||
.padding(bottom = 8.dp)
|
||||
) {
|
||||
Message(
|
||||
message = message.copy(
|
||||
tail = false,
|
||||
masquerade = null
|
||||
),
|
||||
truncate = false
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Box {
|
||||
TextField(
|
||||
value = reasons[selectedReason.value]
|
||||
?: stringResource(id = R.string.unknown),
|
||||
onValueChange = {
|
||||
selectedReason.value = it
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_reason),
|
||||
)
|
||||
},
|
||||
readOnly = true,
|
||||
trailingIcon = {
|
||||
IconToggleButton(
|
||||
checked = reasonDropdownExpanded.value,
|
||||
onCheckedChange = {
|
||||
reasonDropdownExpanded.value = it
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowDropDown,
|
||||
contentDescription = stringResource(id = R.string.report_reason)
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
expanded = reasonDropdownExpanded.value,
|
||||
onDismissRequest = {
|
||||
reasonDropdownExpanded.value = false
|
||||
},
|
||||
) {
|
||||
reasons.forEach { (key, value) ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = value)
|
||||
},
|
||||
onClick = {
|
||||
selectedReason.value = key
|
||||
reasonDropdownExpanded.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_reason_additional_hint),
|
||||
fontSize = 12.sp,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
FormTextField(
|
||||
value = userAddedContext.value,
|
||||
label = stringResource(id = R.string.report_reason_additional),
|
||||
onChange = {
|
||||
userAddedContext.value = it
|
||||
})
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.report_cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
state.value = ReportingState.Sending
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.report_submit))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ReportingState.Sending -> {
|
||||
AlertDialog(
|
||||
onDismissRequest = {},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_submitting),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
LaunchedEffect(true) {
|
||||
launch {
|
||||
try {
|
||||
Log.d("ReportMessageDialog", "Reporting message $messageId")
|
||||
putMessageReport(
|
||||
messageId,
|
||||
ContentReportReason.valueOf(selectedReason.value),
|
||||
userAddedContext.value
|
||||
)
|
||||
state.value = ReportingState.Done
|
||||
} catch (e: Exception) {
|
||||
state.value = ReportingState.Error
|
||||
Log.e("ReportMessageDialog", "Failed to report message", e)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissButton = {},
|
||||
confirmButton = {}
|
||||
)
|
||||
}
|
||||
|
||||
ReportingState.Done -> {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
navController.popBackStack()
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = null, // decorative
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_submit_success),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column() {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_submit_thanks),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_block_question),
|
||||
textAlign = TextAlign.Center,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.report_block_no))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
scope.launch {
|
||||
blockUser(message.author ?: return@launch)
|
||||
}
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.report_block_yes))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ReportingState.Error -> {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
navController.popBackStack()
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
contentDescription = null, // decorative
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_submit_error_header),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column() {
|
||||
Text(
|
||||
text = stringResource(id = R.string.report_submit_error),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.ok))
|
||||
}
|
||||
},
|
||||
confirmButton = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ import chat.revolt.api.RevoltAPI
|
|||
import chat.revolt.callbacks.UiCallbacks
|
||||
import chat.revolt.components.chat.Message
|
||||
import chat.revolt.components.generic.SheetClickable
|
||||
import chat.revolt.api.schemas.Message as MessageSchema
|
||||
|
||||
@Composable
|
||||
fun MessageContextSheet(
|
||||
|
|
@ -54,7 +53,10 @@ fun MessageContextSheet(
|
|||
.padding(bottom = 8.dp)
|
||||
) {
|
||||
Message(
|
||||
message = message.mergeWithPartial(MessageSchema(tail = false)),
|
||||
message = message.copy(
|
||||
tail = false,
|
||||
masquerade = null
|
||||
),
|
||||
truncate = true
|
||||
)
|
||||
}
|
||||
|
|
@ -264,12 +266,7 @@ fun MessageContextSheet(
|
|||
)
|
||||
},
|
||||
) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.comingsoon_toast),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
navController.popBackStack()
|
||||
navController.navigate("report/message/${message.id}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<string name="back">← Back</string>
|
||||
<string name="next">Next →</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="lets_go">Let\'s go</string>
|
||||
<string name="loading">Fetching some info, hang in there…</string>
|
||||
|
|
@ -138,6 +139,50 @@
|
|||
<string name="message_context_sheet_actions_react">React</string>
|
||||
<string name="message_context_sheet_actions_report">Report</string>
|
||||
|
||||
<string name="report">Report</string>
|
||||
<string name="report_cancel">Cancel</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_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_user">Thank you for taking the time to report this user. Please provide a reason for reporting this user.</string>
|
||||
<string name="report_user_preview">Selected user:</string>
|
||||
|
||||
<string name="report_reason">Reason</string>
|
||||
|
||||
<string name="report_reason_content_illegal">Illegal content</string>
|
||||
<string name="report_reason_content_promotes_harm">Promotes harm</string>
|
||||
<string name="report_reason_content_spam_abuse">Spam or similar platform abuse</string>
|
||||
<string name="report_reason_content_malware">Malware or phishing</string>
|
||||
<string name="report_reason_content_harassment">Harassment or cyberbullying</string>
|
||||
<string name="report_reason_content_other">Other</string>
|
||||
|
||||
<string name="report_reason_user_spam_abuse">Spam or similar platform abuse</string>
|
||||
<string name="report_reason_user_inappropriate_content">Inappropriate content (like NSFW)</string>
|
||||
<string name="report_reason_user_impersonation">Impersonation</string>
|
||||
<string name="report_reason_user_ban_evasion">Ban evasion</string>
|
||||
<string name="report_reason_user_underage">Not of minimum age to use the platform</string>
|
||||
<string name="report_reason_user_other">Other</string>
|
||||
|
||||
<string name="report_reason_additional">Additional information</string>
|
||||
<string name="report_reason_additional_hint">Any additional information that may help us in our investigation. Optional.</string>
|
||||
|
||||
<string name="report_submit">Submit</string>
|
||||
<string name="report_submitting">Reporting…</string>
|
||||
<string name="report_submit_success">Reported</string>
|
||||
|
||||
<string name="report_submit_thanks">Thank you for helping to keep Revolt safe. We will review your report as soon as possible.</string>
|
||||
|
||||
<string name="report_submit_error_header">Error</string>
|
||||
<string name="report_submit_error">An error occurred while submitting your report. Please try again later.</string>
|
||||
|
||||
<string name="report_submit_close">Close</string>
|
||||
|
||||
<string name="report_block_question">Would you like to block this user?</string>
|
||||
<string name="report_block_yes">Block</string>
|
||||
<string name="report_block_no">Don\'t block</string>
|
||||
|
||||
<string name="settings_appearance">Appearance</string>
|
||||
<string name="settings_appearance_theme">Theme</string>
|
||||
<string name="settings_appearance_theme_none">System</string>
|
||||
|
|
@ -147,4 +192,4 @@
|
|||
<string name="settings_appearance_theme_m3dynamic">Material You</string>
|
||||
<string name="settings_appearance_theme_m3dynamic_unsupported">Material You (unsupported)</string>
|
||||
<string name="settings_appearance_theme_m3dynamic_unsupported_toast">Material You is not supported on this device.</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue