Merge branch 'develop' into julioromano/poll_history_entry_point

This commit is contained in:
ganfra 2023-12-13 17:22:55 +01:00
commit 72cdc0eee0
738 changed files with 9387 additions and 1581 deletions

View file

@ -33,6 +33,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.coroutines.coroutineContext
class AttachmentsPreviewPresenter @AssistedInject constructor(
@ -114,6 +115,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
sendActionState.value = SendActionState.Done
},
onFailure = { error ->
Timber.e(error, "Failed to send attachment")
if (error is CancellationException) {
throw error
} else {

View file

@ -72,6 +72,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import kotlin.coroutines.coroutineContext
import kotlin.time.Duration.Companion.seconds
@ -432,6 +433,7 @@ class MessageComposerPresenter @Inject constructor(
attachmentState.value = AttachmentsState.None
}
.onFailure { cause ->
Timber.e(cause, "Failed to send attachment")
attachmentState.value = AttachmentsState.None
if (cause is CancellationException) {
throw cause

View file

@ -175,6 +175,9 @@ class TimelinePresenter @AssistedInject constructor(
}
return TimelineState(
timelineRoomInfo = TimelineRoomInfo(
isDirect = room.isDirect
),
highlightedEventId = highlightedEventId.value,
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
paginationState = paginationState,

View file

@ -27,6 +27,7 @@ import kotlinx.collections.immutable.ImmutableList
@Immutable
data class TimelineState(
val timelineItems: ImmutableList<TimelineItem>,
val timelineRoomInfo: TimelineRoomInfo,
val showReadReceipts: Boolean,
val highlightedEventId: EventId?,
val userHasPermissionToSendMessage: Boolean,
@ -35,3 +36,8 @@ data class TimelineState(
val sessionState: SessionState,
val eventSink: (TimelineEvents) -> Unit
)
@Immutable
data class TimelineRoomInfo(
val isDirect: Boolean,
)

View file

@ -47,6 +47,7 @@ import kotlin.random.Random
fun aTimelineState(timelineItems: ImmutableList<TimelineItem> = persistentListOf()) = TimelineState(
timelineItems = timelineItems,
timelineRoomInfo = aTimelineRoomInfo(),
showReadReceipts = false,
paginationState = MatrixTimeline.PaginationState(
isBackPaginating = false,
@ -212,3 +213,9 @@ internal fun aGroupedEvents(id: Long = 0): TimelineItem.GroupedEvents {
aggregatedReadReceipts = events.flatMap { it.readReceiptState.receipts }.toImmutableList(),
)
}
internal fun aTimelineRoomInfo(
isDirect: Boolean = false,
) = TimelineRoomInfo(
isDirect = isDirect,
)

View file

@ -118,6 +118,7 @@ fun TimelineView(
) { timelineItem ->
TimelineItemRow(
timelineItem = timelineItem,
timelineRoomInfo = state.timelineRoomInfo,
showReadReceipts = state.showReadReceipts,
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true
&& state.timelineItems.first().identifier() == timelineItem.identifier(),

View file

@ -17,17 +17,21 @@
package io.element.android.features.messages.impl.timeline.components
import androidx.compose.runtime.Composable
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
import io.element.android.features.messages.impl.timeline.model.TimelineItem
// For previews
@Composable
internal fun ATimelineItemEventRow(
event: TimelineItem.Event,
timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(),
showReadReceipts: Boolean = false,
isLastOutgoingMessage: Boolean = false,
isHighlighted: Boolean = false,
) = TimelineItemEventRow(
event = event,
timelineRoomInfo = timelineRoomInfo,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = isHighlighted,

View file

@ -35,17 +35,17 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleState
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleStateProvider
import io.element.android.libraries.core.extensions.to01
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.messageFromMeBackground
import io.element.android.libraries.designsystem.theme.messageFromOtherBackground
import io.element.android.compound.theme.ElementTheme
private val BUBBLE_RADIUS = 12.dp
private val BUBBLE_INCOMING_OFFSET = 16.dp
@ -91,10 +91,10 @@ fun MessageEventBubble(
}
fun Modifier.offsetForItem(): Modifier {
return if (state.isMine) {
this
} else {
offset(x = BUBBLE_INCOMING_OFFSET)
return when {
state.isMine -> this
state.timelineRoomInfo.isDirect -> this
else -> offset(x = BUBBLE_INCOMING_OFFSET)
}
}

View file

@ -60,6 +60,7 @@ import androidx.compose.ui.zIndex
import androidx.constraintlayout.compose.ConstrainScope
import androidx.constraintlayout.compose.ConstraintLayout
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
@ -101,6 +102,7 @@ import kotlin.math.roundToInt
@Composable
fun TimelineItemEventRow(
event: TimelineItem.Event,
timelineRoomInfo: TimelineRoomInfo,
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
isHighlighted: Boolean,
@ -163,9 +165,8 @@ fun TimelineItemEventRow(
state = state.draggableState,
),
event = event,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = isHighlighted,
timelineRoomInfo = timelineRoomInfo,
interactionSource = interactionSource,
onClick = onClick,
onLongClick = onLongClick,
@ -175,7 +176,6 @@ fun TimelineItemEventRow(
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
onMoreReactionsClicked = { onMoreReactionsClick(event) },
onReadReceiptsClicked = { onReadReceiptClick(event) },
eventSink = eventSink,
)
}
@ -183,9 +183,8 @@ fun TimelineItemEventRow(
} else {
TimelineItemEventRowContent(
event = event,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = isHighlighted,
timelineRoomInfo = timelineRoomInfo,
interactionSource = interactionSource,
onClick = onClick,
onLongClick = onLongClick,
@ -195,10 +194,20 @@ fun TimelineItemEventRow(
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
onMoreReactionsClicked = { onMoreReactionsClick(event) },
onReadReceiptsClicked = { onReadReceiptClick(event) },
eventSink = eventSink,
)
}
// Read receipts / Send state
TimelineItemReadReceiptView(
state = ReadReceiptViewState(
sendState = event.localSendState,
isLastOutgoingMessage = isLastOutgoingMessage,
receipts = event.readReceiptState.receipts,
),
showReadReceipts = showReadReceipts,
onReadReceiptsClicked = { onReadReceiptClick(event) },
modifier = Modifier.padding(top = 4.dp),
)
}
}
@ -228,9 +237,8 @@ private fun SwipeSensitivity(
@Composable
private fun TimelineItemEventRowContent(
event: TimelineItem.Event,
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
isHighlighted: Boolean,
timelineRoomInfo: TimelineRoomInfo,
interactionSource: MutableInteractionSource,
onClick: () -> Unit,
onLongClick: () -> Unit,
@ -238,7 +246,6 @@ private fun TimelineItemEventRowContent(
inReplyToClicked: () -> Unit,
onUserDataClicked: () -> Unit,
onReactionClicked: (emoji: String) -> Unit,
onReadReceiptsClicked: () -> Unit,
onReactionLongClicked: (emoji: String) -> Unit,
onMoreReactionsClicked: (event: TimelineItem.Event) -> Unit,
eventSink: (TimelineEvents) -> Unit,
@ -259,12 +266,11 @@ private fun TimelineItemEventRowContent(
sender,
message,
reactions,
readReceipts,
) = createRefs()
// Sender
val avatarStrokeSize = 3.dp
if (event.showSenderInformation) {
if (event.showSenderInformation && !timelineRoomInfo.isDirect) {
MessageSenderInformation(
event.safeSenderName,
event.senderAvatar,
@ -284,6 +290,7 @@ private fun TimelineItemEventRowContent(
groupPosition = event.groupPosition,
isMine = event.isMine,
isHighlighted = isHighlighted,
timelineRoomInfo = timelineRoomInfo,
)
MessageEventBubble(
modifier = Modifier
@ -326,25 +333,6 @@ private fun TimelineItemEventRowContent(
.padding(start = if (event.isMine) 16.dp else 36.dp, end = 16.dp)
)
}
// Read receipts / Send state
TimelineItemReadReceiptView(
state = ReadReceiptViewState(
sendState = event.localSendState,
isLastOutgoingMessage = isLastOutgoingMessage,
receipts = event.readReceiptState.receipts,
),
showReadReceipts = showReadReceipts,
onReadReceiptsClicked = onReadReceiptsClicked,
modifier = Modifier
.constrainAs(readReceipts) {
if (event.reactionsState.reactions.isNotEmpty()) {
top.linkTo(reactions.bottom, margin = 4.dp)
} else {
top.linkTo(message.bottom, margin = 4.dp)
}
}
)
}
}
@ -378,6 +366,7 @@ private fun MessageSenderInformation(
Avatar(senderAvatar)
Spacer(modifier = Modifier.width(4.dp))
Text(
modifier = Modifier.clipToBounds(),
text = sender,
maxLines = 1,
overflow = TextOverflow.Ellipsis,

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.messages.impl.timeline.components
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@PreviewsDayNight
@Composable
internal fun TimelineItemEventRowForDirectRoomPreview() = ElementPreview {
Column {
sequenceOf(false, true).forEach {
ATimelineItemEventRow(
event = aTimelineItemEvent(
isMine = it,
content = aTimelineItemTextContent().copy(
body = "A long text which will be displayed on several lines and" +
" hopefully can be manually adjusted to test different behaviors."
),
groupPosition = TimelineItemGroupPosition.First,
),
timelineRoomInfo = aTimelineRoomInfo(
isDirect = true,
),
)
ATimelineItemEventRow(
event = aTimelineItemEvent(
isMine = it,
content = aTimelineItemImageContent().copy(
aspectRatio = 5f
),
groupPosition = TimelineItemGroupPosition.Last,
),
timelineRoomInfo = aTimelineRoomInfo(
isDirect = true,
),
)
}
}
}

View file

@ -24,8 +24,10 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import io.element.android.features.messages.impl.R
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.aGroupedEvents
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView
import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState
import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView
@ -40,6 +42,7 @@ import io.element.android.libraries.matrix.api.core.UserId
@Composable
fun TimelineItemGroupedEventsRow(
timelineItem: TimelineItem.GroupedEvents,
timelineRoomInfo: TimelineRoomInfo,
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
highlightedItem: String?,
@ -66,6 +69,7 @@ fun TimelineItemGroupedEventsRow(
isExpanded = isExpanded.value,
onExpandGroupClick = ::onExpandGroupClick,
timelineItem = timelineItem,
timelineRoomInfo = timelineRoomInfo,
highlightedItem = highlightedItem,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
@ -89,6 +93,7 @@ private fun TimelineItemGroupedEventsRowContent(
isExpanded: Boolean,
onExpandGroupClick: () -> Unit,
timelineItem: TimelineItem.GroupedEvents,
timelineRoomInfo: TimelineRoomInfo,
highlightedItem: String?,
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
@ -121,6 +126,7 @@ private fun TimelineItemGroupedEventsRowContent(
timelineItem.events.forEach { subGroupEvent ->
TimelineItemRow(
timelineItem = subGroupEvent,
timelineRoomInfo = timelineRoomInfo,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
highlightedItem = highlightedItem,
@ -148,7 +154,8 @@ private fun TimelineItemGroupedEventsRowContent(
receipts = timelineItem.aggregatedReadReceipts,
),
showReadReceipts = true,
onReadReceiptsClicked = { /* No op for group event */ })
onReadReceiptsClicked = onExpandGroupClick
)
}
}
}
@ -160,6 +167,7 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi
isExpanded = true,
onExpandGroupClick = {},
timelineItem = aGroupedEvents(),
timelineRoomInfo = aTimelineRoomInfo(),
highlightedItem = null,
showReadReceipts = true,
isLastOutgoingMessage = false,
@ -184,6 +192,7 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi
isExpanded = false,
onExpandGroupClick = {},
timelineItem = aGroupedEvents(),
timelineRoomInfo = aTimelineRoomInfo(),
highlightedItem = null,
showReadReceipts = true,
isLastOutgoingMessage = false,

View file

@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.timeline.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
@ -29,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.UserId
@Composable
internal fun TimelineItemRow(
timelineItem: TimelineItem,
timelineRoomInfo: TimelineRoomInfo,
showReadReceipts: Boolean,
isLastOutgoingMessage: Boolean,
highlightedItem: String?,
@ -71,6 +73,7 @@ internal fun TimelineItemRow(
} else {
TimelineItemEventRow(
event = timelineItem,
timelineRoomInfo = timelineRoomInfo,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
isHighlighted = highlightedItem == timelineItem.identifier(),
@ -93,6 +96,7 @@ internal fun TimelineItemRow(
is TimelineItem.GroupedEvents -> {
TimelineItemGroupedEventsRow(
timelineItem = timelineItem,
timelineRoomInfo = timelineRoomInfo,
showReadReceipts = showReadReceipts,
isLastOutgoingMessage = isLastOutgoingMessage,
highlightedItem = highlightedItem,

View file

@ -16,6 +16,8 @@
package io.element.android.features.messages.impl.timeline.components.group
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -26,6 +28,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -76,9 +79,17 @@ fun GroupHeaderView(
color = MaterialTheme.colorScheme.secondary,
style = ElementTheme.typography.fontBodyMdRegular,
)
val rotation: Float by animateFloatAsState(
targetValue = if (isExpanded) 90f else 0f,
animationSpec = tween(
delayMillis = 0,
durationMillis = 300,
),
label = "chevron"
)
Icon(
modifier = Modifier.rotate(if (isExpanded) 180f else 0f),
imageVector = CompoundIcons.ChevronDown,
modifier = Modifier.rotate(rotation),
imageVector = CompoundIcons.ChevronRight,
contentDescription = null,
tint = MaterialTheme.colorScheme.secondary
)

View file

@ -16,10 +16,12 @@
package io.element.android.features.messages.impl.timeline.model.bubble
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
data class BubbleState(
val groupPosition: TimelineItemGroupPosition,
val isMine: Boolean,
val isHighlighted: Boolean,
val timelineRoomInfo: TimelineRoomInfo,
)

View file

@ -17,6 +17,8 @@
package io.element.android.features.messages.impl.timeline.model.bubble
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
@ -29,7 +31,11 @@ open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
).map { groupPosition ->
sequenceOf(false, true).map { isMine ->
sequenceOf(false, true).map { isHighlighted ->
BubbleState(groupPosition, isMine = isMine, isHighlighted = isHighlighted)
aBubbleState(
groupPosition = groupPosition,
isMine = isMine,
isHighlighted = isHighlighted,
)
}
}
.flatten()
@ -37,8 +43,14 @@ open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
.flatten()
}
fun aBubbleState() = BubbleState(
groupPosition = TimelineItemGroupPosition.First,
isMine = false,
isHighlighted = false,
internal fun aBubbleState(
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.First,
isMine: Boolean = false,
isHighlighted: Boolean = false,
timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(),
) = BubbleState(
groupPosition = groupPosition,
isMine = isMine,
isHighlighted = isHighlighted,
timelineRoomInfo = timelineRoomInfo,
)

View file

@ -24,6 +24,7 @@ import io.element.android.libraries.di.CacheDirectory
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.mxc.MxcTools
import java.io.File
/**
@ -66,6 +67,7 @@ interface VoiceMessageMediaRepo {
class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
@CacheDirectory private val cacheDir: File,
mxcTools: MxcTools,
private val matrixMediaLoader: MatrixMediaLoader,
@Assisted private val mediaSource: MediaSource,
@Assisted("mimeType") private val mimeType: String?,
@ -101,7 +103,7 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
}
}
private val cachedFile: File? = mxcUri2FilePath(mediaSource.url)?.let {
private val cachedFile: File? = mxcTools.mxcUri2FilePath(mediaSource.url)?.let {
File("${cacheDir.path}/$CACHE_VOICE_SUBDIR/$it")
}
}
@ -110,24 +112,3 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
* Subdirectory of the application's cache directory where voice messages are stored.
*/
private const val CACHE_VOICE_SUBDIR = "temp/voice"
/**
* Regex to match a Matrix Content (mxc://) URI.
*
* See: https://spec.matrix.org/v1.8/client-server-api/#matrix-content-mxc-uris
*/
private val mxcRegex = Regex("""^mxc:\/\/([^\/]+)\/([^\/]+)$""")
/**
* Sanitizes an mxcUri to be used as a relative file path.
*
* @param mxcUri the Matrix Content (mxc://) URI of the voice message.
* @return the relative file path as "<server-name>/<media-id>" or null if the mxcUri is invalid.
*/
private fun mxcUri2FilePath(mxcUri: String): String? = mxcRegex.matchEntire(mxcUri)?.let { match ->
buildString {
append(match.groupValues[1])
append("/")
append(match.groupValues[2])
}
}

View file

@ -17,6 +17,7 @@
<string name="room_timeline_beginning_of_room">"Dies ist der Anfang von %1$s."</string>
<string name="room_timeline_beginning_of_room_no_name">"Dies ist der Anfang dieses Gesprächs."</string>
<string name="room_timeline_read_marker_title">"Neu"</string>
<string name="screen_room_mentions_at_room_subtitle">"Den ganzen Raum benachrichtigen"</string>
<string name="screen_report_content_block_user_hint">"Prüfe, ob du alle aktuellen und zukünftigen Nachrichten dieses Benutzers ausblenden möchtest"</string>
<string name="screen_room_attachment_source_camera">"Kamera"</string>
<string name="screen_room_attachment_source_camera_photo">"Foto machen"</string>
@ -27,6 +28,7 @@
<string name="screen_room_attachment_source_poll">"Umfrage"</string>
<string name="screen_room_attachment_text_formatting">"Textformatierung"</string>
<string name="screen_room_encrypted_history_banner">"Der Nachrichtenverlauf ist derzeit in diesem Raum nicht verfügbar"</string>
<string name="screen_room_encrypted_history_banner_unverified">"Der Nachrichtenverlauf ist in diesem Raum nicht verfügbar. Verifiziere dieses Gerät, um deinen Nachrichtenverlauf zu sehen."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Benutzerdetails konnten nicht abgerufen werden"</string>
<string name="screen_room_invite_again_alert_message">"Möchtest du sie wieder einladen?"</string>
<string name="screen_room_invite_again_alert_title">"Du bist allein in diesem Chat"</string>
@ -42,6 +44,7 @@
<string name="screen_room_notification_settings_error_loading_settings">"Beim Laden der Benachrichtigungseinstellungen ist ein Fehler aufgetreten."</string>
<string name="screen_room_notification_settings_error_restoring_default">"Fehler beim Wiederherstellen des Standardmodus. Bitte versuche es erneut."</string>
<string name="screen_room_notification_settings_error_setting_mode">"Fehler beim Einstellen des Modus. Bitte versuche es erneut."</string>
<string name="screen_room_notification_settings_mentions_only_disclaimer">"Dein Homeserver unterstützt diese Option in verschlüsselten Räumen nicht. Du wirst in diesem Raum nicht benachrichtigt."</string>
<string name="screen_room_notification_settings_mode_all_messages">"Alle Nachrichten"</string>
<string name="screen_room_notification_settings_room_custom_settings_title">"Benachrichtige mich in diesem Raum bei"</string>
<string name="screen_room_reactions_show_less">"Weniger anzeigen"</string>
@ -50,6 +53,8 @@
<string name="screen_room_retry_send_menu_title">"Deine Nachricht konnte nicht gesendet werden"</string>
<string name="screen_room_timeline_add_reaction">"Emoji hinzufügen"</string>
<string name="screen_room_timeline_less_reactions">"Weniger anzeigen"</string>
<string name="screen_room_voice_message_tooltip">"Zum Aufnehmen gedrückt halten"</string>
<string name="screen_room_mentions_at_room_title">"Alle"</string>
<string name="screen_report_content_block_user">"Benutzer sperren"</string>
<string name="screen_room_error_failed_processing_media">"Fehler beim Verarbeiten des hochgeladenen Mediums. Bitte versuche es erneut."</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Nur Erwähnungen und Schlüsselwörter"</string>

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="emoji_picker_category_activity">"Tevékenységek"</string>
<string name="emoji_picker_category_flags">"Zászlók"</string>
<string name="emoji_picker_category_foods">"Étel és ital"</string>
<string name="emoji_picker_category_nature">"Állatok és természet"</string>
<string name="emoji_picker_category_objects">"Tárgyak"</string>
<string name="emoji_picker_category_people">"Mosolyok és emberek"</string>
<string name="emoji_picker_category_places">"Utazás és helyek"</string>
<string name="emoji_picker_category_symbols">"Szimbólumok"</string>
<string name="report_content_explanation">"Ez az üzenet jelentve lesz a Matrix-kiszolgáló rendszergazdájának. Nem fogja tudni elolvasni a titkosított üzeneteket."</string>
<string name="report_content_hint">"A tartalom jelentésének oka"</string>
<string name="room_timeline_beginning_of_room">"Ez a(z) %1$s kezdete."</string>
<string name="room_timeline_beginning_of_room_no_name">"Ez a beszélgetés kezdete."</string>
<string name="room_timeline_read_marker_title">"Új"</string>
<string name="screen_room_mentions_at_room_subtitle">"Teljes szoba értesítése"</string>
<string name="screen_report_content_block_user_hint">"Jelölje be, ha el akarja rejteni az összes jelenlegi és jövőbeli üzenetet ettől a felhasználótól"</string>
<string name="screen_room_attachment_source_camera">"Kamera"</string>
<string name="screen_room_attachment_source_camera_photo">"Fénykép készítése"</string>
<string name="screen_room_attachment_source_camera_video">"Videó rögzítése"</string>
<string name="screen_room_attachment_source_files">"Melléklet"</string>
<string name="screen_room_attachment_source_gallery">"Fénykép- és videótár"</string>
<string name="screen_room_attachment_source_location">"Hely"</string>
<string name="screen_room_attachment_source_poll">"Szavazás"</string>
<string name="screen_room_attachment_text_formatting">"Szövegformázás"</string>
<string name="screen_room_encrypted_history_banner">"Az üzenetelőzmények jelenleg nem érhetők el."</string>
<string name="screen_room_encrypted_history_banner_unverified">"Az üzenetelőzmények nem érhetők el ebben a szobában. Ellenőrizze ezt az eszközt, hogy lássa az előzményeket."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Nem sikerült letölteni a felhasználói adatokat"</string>
<string name="screen_room_invite_again_alert_message">"Visszahívja?"</string>
<string name="screen_room_invite_again_alert_title">"Egyedül van ebben a csevegésben"</string>
<string name="screen_room_message_copied">"Üzenet másolva"</string>
<string name="screen_room_no_permission_to_post">"Nincs jogosultsága arra, hogy bejegyzést tegyen közzé ebben a szobában"</string>
<string name="screen_room_notification_settings_allow_custom">"Egyéni beállítás engedélyezése"</string>
<string name="screen_room_notification_settings_allow_custom_footnote">"Ennek bekapcsolása felülírja az alapértelmezett beállítást"</string>
<string name="screen_room_notification_settings_custom_settings_title">"Értesítések kérése ebben a csevegésben ezekről:"</string>
<string name="screen_room_notification_settings_default_setting_footnote">"Megváltoztathatja a %1$s."</string>
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"globális beállításokban"</string>
<string name="screen_room_notification_settings_default_setting_title">"Alapértelmezett beállítás"</string>
<string name="screen_room_notification_settings_edit_remove_setting">"Egyéni beállítás eltávolítása"</string>
<string name="screen_room_notification_settings_error_loading_settings">"Hiba történt az értesítési beállítások betöltésekor."</string>
<string name="screen_room_notification_settings_error_restoring_default">"Nem sikerült visszaállítani az alapértelmezett módot, próbálja újra."</string>
<string name="screen_room_notification_settings_error_setting_mode">"Nem sikerült a mód beállítása, próbálja újra."</string>
<string name="screen_room_notification_settings_mentions_only_disclaimer">"A Matrix-kiszolgálója nem támogatja ezt a beállítást a titkosított szobákban, egyes szobákban nem fog értesítéseket kapni."</string>
<string name="screen_room_notification_settings_mode_all_messages">"Összes üzenet"</string>
<string name="screen_room_notification_settings_room_custom_settings_title">"Ebben a szobában, értesítés ezekről:"</string>
<string name="screen_room_reactions_show_less">"Kevesebb megjelenítése"</string>
<string name="screen_room_reactions_show_more">"Több megjelenítése"</string>
<string name="screen_room_retry_send_menu_send_again_action">"Újraküldés"</string>
<string name="screen_room_retry_send_menu_title">"Az üzenet elküldése sikertelen"</string>
<string name="screen_room_timeline_add_reaction">"Emodzsi hozzáadása"</string>
<string name="screen_room_timeline_less_reactions">"Kevesebb megjelenítése"</string>
<string name="screen_room_voice_message_tooltip">"Tartsa a rögzítéshez"</string>
<string name="screen_room_mentions_at_room_title">"Mindenki"</string>
<string name="screen_report_content_block_user">"Felhasználó letiltása"</string>
<string name="screen_room_error_failed_processing_media">"Nem sikerült feldolgozni a feltöltendő médiát, próbálja újra."</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Csak említések és kulcsszavak"</string>
</resources>

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="emoji_picker_category_activity">"Aktivitas"</string>
<string name="emoji_picker_category_flags">"Bendera"</string>
<string name="emoji_picker_category_foods">"Makanan &amp; Minuman"</string>
<string name="emoji_picker_category_nature">"Hewan &amp; Alam"</string>
<string name="emoji_picker_category_objects">"Objek"</string>
<string name="emoji_picker_category_people">"Senyuman &amp; Orang"</string>
<string name="emoji_picker_category_places">"Wisata &amp; Tempat"</string>
<string name="emoji_picker_category_symbols">"Simbol"</string>
<plurals name="room_timeline_state_changes">
<item quantity="other">"%1$d perubahan ruangan"</item>
</plurals>
<string name="report_content_explanation">"Pesan ini akan dilaporkan ke administrator homeserver Anda. Mereka tidak akan dapat membaca pesan terenkripsi apa pun."</string>
<string name="report_content_hint">"Alasan melaporkan konten ini"</string>
<string name="room_timeline_beginning_of_room">"Ini adalah awal dari %1$s."</string>
<string name="room_timeline_beginning_of_room_no_name">"Ini adalah awal dari percakapan ini."</string>
<string name="room_timeline_read_marker_title">"Baru"</string>
<string name="screen_room_mentions_at_room_subtitle">"Beri tahu seluruh ruangan"</string>
<string name="screen_report_content_block_user_hint">"Centang jika Anda ingin menyembunyikan semua pesan saat ini dan yang akan datang dari pengguna ini"</string>
<string name="screen_room_attachment_source_camera">"Kamera"</string>
<string name="screen_room_attachment_source_camera_photo">"Ambil foto"</string>
<string name="screen_room_attachment_source_camera_video">"Rekam video"</string>
<string name="screen_room_attachment_source_files">"Lampiran"</string>
<string name="screen_room_attachment_source_gallery">"Pustaka Foto &amp; Video"</string>
<string name="screen_room_attachment_source_location">"Lokasi"</string>
<string name="screen_room_attachment_source_poll">"Pemungutan suara"</string>
<string name="screen_room_attachment_text_formatting">"Pemformatan Teks"</string>
<string name="screen_room_encrypted_history_banner">"Riwayat pesan saat ini tidak tersedia di ruangan ini"</string>
<string name="screen_room_encrypted_history_banner_unverified">"Riwayat pesan tidak tersedia di ruangan ini. Verifikasi perangkat ini untuk melihat riwayat pesan."</string>
<string name="screen_room_error_failed_retrieving_user_details">"Tidak dapat mengambil detail pengguna"</string>
<string name="screen_room_invite_again_alert_message">"Apakah Anda ingin mengundang mereka kembali?"</string>
<string name="screen_room_invite_again_alert_title">"Anda sendirian di obrolan ini"</string>
<string name="screen_room_message_copied">"Pesan disalin"</string>
<string name="screen_room_no_permission_to_post">"Anda tidak memiliki izin untuk mengirim di ruangan ini"</string>
<string name="screen_room_notification_settings_allow_custom">"Izinkan pengaturan khusus"</string>
<string name="screen_room_notification_settings_allow_custom_footnote">"Mengaktifkan ini akan mengganti pengaturan bawaan Anda"</string>
<string name="screen_room_notification_settings_custom_settings_title">"Beri tahu saya di obrolan ini tentang"</string>
<string name="screen_room_notification_settings_default_setting_footnote">"Anda dapat mengubahnya di %1$s Anda."</string>
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"pengaturan global"</string>
<string name="screen_room_notification_settings_default_setting_title">"Pengaturan bawaan"</string>
<string name="screen_room_notification_settings_edit_remove_setting">"Hapus pengaturan khusus"</string>
<string name="screen_room_notification_settings_error_loading_settings">"Terjadi kesalahan saat memuat pengaturan pemberitahuan."</string>
<string name="screen_room_notification_settings_error_restoring_default">"Gagal memulihkan mode bawaan, silakan coba lagi."</string>
<string name="screen_room_notification_settings_error_setting_mode">"Gagal mengatur mode, silakan coba lagi."</string>
<string name="screen_room_notification_settings_mentions_only_disclaimer">"Homeserver Anda tidak mendukung opsi ini dalam ruangan terenkripsi, Anda tidak akan diberi tahu dalam ruangan ini."</string>
<string name="screen_room_notification_settings_mode_all_messages">"Semua pesan"</string>
<string name="screen_room_notification_settings_room_custom_settings_title">"Di ruangan ini, beri tahu saya tentang"</string>
<string name="screen_room_reactions_show_less">"Tampilkan lebih sedikit"</string>
<string name="screen_room_reactions_show_more">"Tampilkan lebih banyak"</string>
<string name="screen_room_retry_send_menu_send_again_action">"Kirim ulang"</string>
<string name="screen_room_retry_send_menu_title">"Pesan Anda gagal dikirim"</string>
<string name="screen_room_timeline_add_reaction">"Tambahkan emoji"</string>
<string name="screen_room_timeline_less_reactions">"Tampilkan lebih sedikit"</string>
<string name="screen_room_voice_message_tooltip">"Tahan untuk merekam"</string>
<string name="screen_room_mentions_at_room_title">"Semua orang"</string>
<string name="screen_report_content_block_user">"Blokir pengguna"</string>
<string name="screen_room_error_failed_processing_media">"Gagal memproses media untuk diunggah, silakan coba lagi."</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Sebutan dan Kata Kunci saja"</string>
</resources>