Feature : Report room (#4654)
* feature (report room) : introduce all presentation classes. * feature (report room) : branch entry point in the room list * refactor (matrix ui) : move some code from appnav to matrix ui * feature (report room) : add api on room * feature (report room) : adjust ui * feature (report room) : branch api * feature (decline invite and block) : move things around and introduce presentation classes * feature (decline invite and block) : continue to move things * feature (report room) : remove reference to "conversation" for now * feature (report room) : add report room action to room detail screen * feature (report room) : enabled button state * feature (report room) : improve code and reuse * feature (report room) : add feature flag * feature (report room) : change feature flag to static bool * feature (report room) : add tests * feature (report room) : fix ui with new api on ListItem * feature (report room) : clean up and add more tests. * Update screenshots * feature (report room) : more test and fix issue * feature (report room) : update strings * feature (report room) : fix konsist preview * feature (report room) : disable feature * Update screenshots * var -> val * Improve preview of AcceptDeclineInviteView * Improve preview consistency * Add missing test on DismissErrorAndHideContent * Update screenshots * Add missing tests --------- Co-authored-by: ElementBot <android@element.io> Co-authored-by: Benoit Marty <benoit@matrix.org>
This commit is contained in:
parent
db6bc7c04f
commit
c2568f84d2
229 changed files with 3995 additions and 1210 deletions
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.features.reportroom.api.ReportRoomEntryPoint
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultReportRoomEntryPoint @Inject constructor() : ReportRoomEntryPoint {
|
||||
override fun createNode(parentNode: Node, buildContext: BuildContext, roomId: RoomId): Node {
|
||||
return parentNode.createNode<ReportRoomNode>(buildContext, plugins = listOf(ReportRoomNode.Inputs(roomId)))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import javax.inject.Inject
|
||||
|
||||
interface ReportRoom {
|
||||
suspend operator fun invoke(
|
||||
roomId: RoomId,
|
||||
shouldReport: Boolean,
|
||||
reason: String,
|
||||
shouldLeave: Boolean,
|
||||
): Result<Unit>
|
||||
|
||||
sealed class Exception : kotlin.Exception() {
|
||||
data object RoomNotFound : Exception()
|
||||
data object LeftRoomFailed : Exception()
|
||||
data object ReportRoomFailed : Exception()
|
||||
}
|
||||
}
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultReportRoom @Inject constructor(
|
||||
private val client: MatrixClient,
|
||||
) : ReportRoom {
|
||||
override suspend operator fun invoke(
|
||||
roomId: RoomId,
|
||||
shouldReport: Boolean,
|
||||
reason: String,
|
||||
shouldLeave: Boolean
|
||||
): Result<Unit> {
|
||||
val room = client.getRoom(roomId)
|
||||
?: return Result.failure(ReportRoom.Exception.RoomNotFound)
|
||||
|
||||
if (shouldReport) {
|
||||
room
|
||||
.reportRoom(reason.takeIf { it.isNotBlank() })
|
||||
.onFailure {
|
||||
return Result.failure(ReportRoom.Exception.ReportRoomFailed)
|
||||
}
|
||||
}
|
||||
if (shouldLeave) {
|
||||
room
|
||||
.leave()
|
||||
.onFailure {
|
||||
return Result.failure(ReportRoom.Exception.LeftRoomFailed)
|
||||
}
|
||||
}
|
||||
return Result.success(Unit)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
sealed interface ReportRoomEvents {
|
||||
data class UpdateReason(val reason: String) : ReportRoomEvents
|
||||
data object ToggleLeaveRoom : ReportRoomEvents
|
||||
data object Report : ReportRoomEvents
|
||||
data object ClearReportAction : ReportRoomEvents
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class ReportRoomNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
presenterFactory: ReportRoomPresenter.Factory,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
data class Inputs(val roomId: RoomId) : NodeInputs
|
||||
|
||||
private val roomId = inputs<Inputs>().roomId
|
||||
private val presenter: ReportRoomPresenter = presenterFactory.create(roomId = roomId)
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
ReportRoomView(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
onBackClick = ::navigateUp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ReportRoomPresenter @AssistedInject constructor(
|
||||
@Assisted private val roomId: RoomId,
|
||||
private val reportRoom: ReportRoom,
|
||||
) : Presenter<ReportRoomState> {
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(roomId: RoomId): ReportRoomPresenter
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun present(): ReportRoomState {
|
||||
var reason by rememberSaveable { mutableStateOf("") }
|
||||
var leaveRoom by rememberSaveable { mutableStateOf(false) }
|
||||
var reportAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
fun handleEvents(event: ReportRoomEvents) {
|
||||
when (event) {
|
||||
ReportRoomEvents.Report -> coroutineScope.reportRoom(reason, leaveRoom, reportAction)
|
||||
ReportRoomEvents.ToggleLeaveRoom -> {
|
||||
leaveRoom = !leaveRoom
|
||||
}
|
||||
is ReportRoomEvents.UpdateReason -> {
|
||||
reason = event.reason
|
||||
}
|
||||
ReportRoomEvents.ClearReportAction -> {
|
||||
reportAction.value = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
}
|
||||
return ReportRoomState(
|
||||
reason = reason,
|
||||
leaveRoom = leaveRoom,
|
||||
reportAction = reportAction.value,
|
||||
eventSink = ::handleEvents
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.reportRoom(
|
||||
reason: String,
|
||||
shouldLeave: Boolean,
|
||||
action: MutableState<AsyncAction<Unit>>
|
||||
) = launch {
|
||||
val previousFailure = action.value as? AsyncAction.Failure
|
||||
val shouldReport = previousFailure?.error !is ReportRoom.Exception.LeftRoomFailed
|
||||
runUpdatingState(action) {
|
||||
reportRoom(
|
||||
roomId = roomId,
|
||||
shouldReport = shouldReport,
|
||||
reason = reason,
|
||||
shouldLeave = shouldLeave
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
||||
data class ReportRoomState(
|
||||
val reason: String,
|
||||
val leaveRoom: Boolean,
|
||||
val reportAction: AsyncAction<Unit>,
|
||||
val eventSink: (ReportRoomEvents) -> Unit
|
||||
) {
|
||||
val canReport: Boolean = reason.isNotBlank()
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
||||
open class ReportRoomStateProvider : PreviewParameterProvider<ReportRoomState> {
|
||||
companion object {
|
||||
private const val A_REPORT_ROOM_REASON = "Inappropriate content"
|
||||
}
|
||||
|
||||
override val values: Sequence<ReportRoomState>
|
||||
get() = sequenceOf(
|
||||
aReportRoomState(),
|
||||
aReportRoomState(reason = A_REPORT_ROOM_REASON),
|
||||
aReportRoomState(leaveRoom = true),
|
||||
aReportRoomState(reason = A_REPORT_ROOM_REASON, reportAction = AsyncAction.Loading),
|
||||
aReportRoomState(reason = A_REPORT_ROOM_REASON, reportAction = AsyncAction.Failure(Exception("Failed to report"))),
|
||||
)
|
||||
}
|
||||
|
||||
fun aReportRoomState(
|
||||
reason: String = "",
|
||||
leaveRoom: Boolean = false,
|
||||
reportAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
eventSink: (ReportRoomEvents) -> Unit = {}
|
||||
) = ReportRoomState(
|
||||
reason = reason,
|
||||
leaveRoom = leaveRoom,
|
||||
reportAction = reportAction,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.reportroom.impl
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReportRoomView(
|
||||
state: ReportRoomState,
|
||||
onBackClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
val isReporting = state.reportAction is AsyncAction.Loading
|
||||
AsyncActionView(
|
||||
async = state.reportAction,
|
||||
onSuccess = { onBackClick() },
|
||||
errorTitle = { failure ->
|
||||
when (failure) {
|
||||
is ReportRoom.Exception.LeftRoomFailed -> stringResource(R.string.screen_report_room_leave_failed_alert_title)
|
||||
else -> stringResource(CommonStrings.dialog_title_error)
|
||||
}
|
||||
},
|
||||
errorMessage = { failure ->
|
||||
when (failure) {
|
||||
is ReportRoom.Exception.LeftRoomFailed -> stringResource(R.string.screen_report_room_leave_failed_alert_message)
|
||||
else -> stringResource(CommonStrings.error_unknown)
|
||||
}
|
||||
},
|
||||
onRetry = {
|
||||
state.eventSink(ReportRoomEvents.Report)
|
||||
},
|
||||
onErrorDismiss = { state.eventSink(ReportRoomEvents.ClearReportAction) }
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.screen_report_room_title),
|
||||
style = ElementTheme.typography.aliasScreenTitle,
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
BackButton(onClick = onBackClick)
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = modifier
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
.imePadding()
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
TextField(
|
||||
value = state.reason,
|
||||
onValueChange = { state.eventSink(ReportRoomEvents.UpdateReason(it)) },
|
||||
placeholder = stringResource(R.string.screen_report_room_reason_placeholder),
|
||||
minLines = 3,
|
||||
enabled = !isReporting,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.heightIn(min = 90.dp),
|
||||
supportingText = stringResource(R.string.screen_report_room_reason_footer),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
ListItem(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
headlineContent = {
|
||||
Text(text = stringResource(CommonStrings.action_leave_room))
|
||||
},
|
||||
onClick = {
|
||||
state.eventSink(ReportRoomEvents.ToggleLeaveRoom)
|
||||
},
|
||||
trailingContent = ListItemContent.Switch(checked = state.leaveRoom)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Button(
|
||||
text = stringResource(CommonStrings.action_report),
|
||||
enabled = state.canReport && !isReporting,
|
||||
destructive = true,
|
||||
showProgress = isReporting,
|
||||
onClick = {
|
||||
focusManager.clearFocus(force = true)
|
||||
state.eventSink(ReportRoomEvents.Report)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun ReportRoomViewPreview(
|
||||
@PreviewParameter(ReportRoomStateProvider::class) state: ReportRoomState
|
||||
) = ElementPreview {
|
||||
ReportRoomView(
|
||||
state = state,
|
||||
onBackClick = {},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Vaše hlášení bylo úspěšně odesláno, ale při pokusu o opuštění místnosti jsme narazili na problém. Zkuste to prosím znovu."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Nelze opustit místnost"</string>
|
||||
<string name="screen_report_room_reason_footer">"Nahlaste tuto místnost svému administrátorovi. Pokud jsou zprávy zašifrované, váš administrátor je nebude moci číst."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Popište důvod…"</string>
|
||||
<string name="screen_report_room_title">"Nahlásit místnost"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Cyflwynwyd eich adroddiad yn llwyddiannus, ond cododd problem wrth geisio gadael yr ystafell. Ceisiwch eto."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Methu Gadael yr Ystafell"</string>
|
||||
<string name="screen_report_room_reason_footer">"Adroddwch yr ystafell hon i\'ch gweinyddwr. Os yw\'r negeseuon wedi\'u hamgryptio, fydd eich gweinyddwr ddim yn gallu eu darllen."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Disgrifiwch y rheswm…"</string>
|
||||
<string name="screen_report_room_title">"Adrodd ar ystafell"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Ihr Bericht wurde erfolgreich übermittelt, aber beim Versuch, den Raum zu verlassen, ist ein Problem aufgetreten. Bitte versuchen Sie es erneut."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Der Chatroom kann nicht verlassen werden"</string>
|
||||
<string name="screen_report_room_reason_footer">"Melden Sie diesen Chatroom Ihrem Administrator. Wenn die Nachrichten verschlüsselt sind, kann Ihr Administrator sie nicht lesen."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Beschreiben Sie den Grund…"</string>
|
||||
<string name="screen_report_room_title">"Chatroom melden"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Η αναφορά σας υποβλήθηκε με επιτυχία, αλλά αντιμετωπίσαμε πρόβλημα κατά την προσπάθεια αποχώρησης από το δωμάτιο. Παρακαλώ προσπαθήστε ξανά."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Δεν είναι δυνατή η αποχώρηση από το δωμάτιο"</string>
|
||||
<string name="screen_report_room_reason_footer">"Αναφέρετε αυτό το δωμάτιο στον διαχειριστή σας. Εάν τα μηνύματα είναι κρυπτογραφημένα, ο διαχειριστής σας δε θα μπορεί να τα διαβάσει."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Περιγράψτε τον λόγο αναφοράς…"</string>
|
||||
<string name="screen_report_room_title">"Αναφορά δωματίου"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Jututoast haldajale teatamine õnnestus, kuid jututost lahkumisel tekkis viga. Palun proovi uuesti lahkuda."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Pole võimalik lahkuda jututoast"</string>
|
||||
<string name="screen_report_room_reason_footer">"Teata sellest jututoast süsteemi haldajale. Kui sõnumid on krüptitud, ei saa haldaja neid lugeda."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Kirjelda põhjust…"</string>
|
||||
<string name="screen_report_room_title">"Teata jututoast"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Ilmoituksesi lähetettiin onnistuneesti, mutta kohtasimme ongelman yrittäessämme poistua huoneesta. Yritä uudelleen."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Huoneesta poistuminen epäonnistui"</string>
|
||||
<string name="screen_report_room_reason_footer">"Ilmoita tästä huoneesta palvelimesi ylläpitäjälle. Jos viestit on salattu, ylläpitäjäsi ei voi lukea niitä."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Kuvaile syytä…"</string>
|
||||
<string name="screen_report_room_title">"Ilmoita huoneesta"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Votre rapport a été envoyé avec succès, mais nous avons rencontré un problème en essayant de quitter le salon. Veuillez réessayer."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Impossible de quitter le salon"</string>
|
||||
<string name="screen_report_room_reason_footer">"Signaler ce salon à votre admin. Si les messages sont chiffrés, votre admin ne pourra pas les lire."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Décrivez la raison…"</string>
|
||||
<string name="screen_report_room_title">"Signaler le salon"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"A jelentése sikeresen el lett küldve, de hibát találtunk a szoba elhagyása során. Próbálja újra."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Nem tudja elhagyni a szobát"</string>
|
||||
<string name="screen_report_room_reason_footer">"A szoba jelentése a rendszergazdának. Ha az üzenetek titkosítva vannak, akkor a rendszergazda nem fogja tudni elolvasni őket."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Írja le az okot…"</string>
|
||||
<string name="screen_report_room_title">"Szoba jelentése"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Rapporten din ble sendt inn, men vi oppdaget et problem da vi prøvde å forlate rommet. Prøv igjen."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Kan ikke forlate rommet"</string>
|
||||
<string name="screen_report_room_reason_footer">"Rapporter dette rommet til administratoren din. Hvis meldingene er kryptert, vil administratoren ikke kunne lese dem."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Beskriv årsaken…"</string>
|
||||
<string name="screen_report_room_title">"Rapporter rom"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Twoje zgłoszenie zostało wysłane pomyślnie, ale napotkaliśmy problem podczas opuszczania pokoju. Spróbuj ponownie."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Nie można wyjść z pokoju"</string>
|
||||
<string name="screen_report_room_reason_footer">"Zgłoś ten pokój swojemu administratorowi. Jeśli wiadomości są zaszyfrowane, administrator nie będzie mógł ich odczytać."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Opisz powód…"</string>
|
||||
<string name="screen_report_room_title">"Zgłoś pokój"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Невозможно покинуть комнату"</string>
|
||||
<string name="screen_report_room_reason_footer">"Сообщите об этой комнате своему администратору. Если сообщения зашифрованы, ваш администратор не сможет их прочитать."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Опишите причину…"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Vaša správa bola úspešne odoslaná, ale pri pokuse o opustenie miestnosti sme narazili na problém. Skúste to prosím znova."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Nie je možné opustiť miestnosť"</string>
|
||||
<string name="screen_report_room_reason_footer">"Nahláste túto miestnosť svojmu správcovi. Ak sú správy zašifrované, váš správca ich nebude môcť prečítať."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Popíšte dôvod…"</string>
|
||||
<string name="screen_report_room_title">"Nahlásiť miestnosť"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Din anmälan skickades in framgångsrikt, men vi stötte på ett problem när vi försökte lämna rummet. Vänligen försök igen."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Kunde inte lämna rummet"</string>
|
||||
<string name="screen_report_room_reason_footer">"Anmäl det här rummet till din administratör. Om meddelandena är krypterade kommer din administratör inte att kunna läsa dem."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Beskriv anledningen …"</string>
|
||||
<string name="screen_report_room_title">"Rapportera rum"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Ваша скарга надіслана, але ми зіткнулися з проблемою під час спроби вийти з кімнати. Повторіть спробу."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Не вдалося вийти з кімнати"</string>
|
||||
<string name="screen_report_room_reason_footer">"Поскаржтеся на цю кімнату своєму адміністратору. Якщо повідомлення зашифровані, ваш адміністратор не зможе їх прочитати."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Опишіть причину…"</string>
|
||||
<string name="screen_report_room_title">"Поскаржитися на кімнату"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"您的回報已成功遞交,但我們嘗試離開聊天室時遇到了問題。請再試一次。"</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"無法離開聊天室"</string>
|
||||
<string name="screen_report_room_reason_footer">"將此聊天室回報給您的管理員。若訊息已加密,您的管理員將無法讀取它們。"</string>
|
||||
<string name="screen_report_room_title">"回報聊天室"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_report_room_leave_failed_alert_message">"Your report was submitted successfully, but we encountered an issue while trying to leave the room. Please try again."</string>
|
||||
<string name="screen_report_room_leave_failed_alert_title">"Unable to Leave Room"</string>
|
||||
<string name="screen_report_room_reason_footer">"Report this room to your admin. If the messages are encrypted, your admin will not be able to read them."</string>
|
||||
<string name="screen_report_room_reason_placeholder">"Describe the reason to report…"</string>
|
||||
<string name="screen_report_room_title">"Report room"</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue