Merge pull request #4862 from element-hq/feature/fga/room-version-upgrade
Feature : room version upgrade
This commit is contained in:
@@ -9,6 +9,7 @@ package io.element.android.features.messages.impl
|
||||
|
||||
import io.element.android.features.messages.impl.attachments.Attachment
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
@@ -19,4 +20,5 @@ interface MessagesNavigator {
|
||||
fun onReportContentClick(eventId: EventId, senderId: UserId)
|
||||
fun onEditPollClick(eventId: EventId)
|
||||
fun onPreviewAttachment(attachments: ImmutableList<Attachment>)
|
||||
fun onNavigateToRoom(roomId: RoomId)
|
||||
}
|
||||
|
||||
@@ -49,18 +49,21 @@ import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.alias.matches
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -70,6 +73,7 @@ import kotlinx.coroutines.launch
|
||||
class MessagesNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
@ApplicationContext private val context: Context,
|
||||
@SessionCoroutineScope
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val room: BaseRoom,
|
||||
@@ -157,7 +161,7 @@ class MessagesNode @AssistedInject constructor(
|
||||
callbacks.forEach { it.onUserDataClick(permalink.userId) }
|
||||
}
|
||||
is PermalinkData.RoomLink -> {
|
||||
handleRoomLinkClick(activity, permalink, eventSink)
|
||||
handleRoomLinkClick(permalink, eventSink)
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
if (customTab) {
|
||||
@@ -173,7 +177,6 @@ class MessagesNode @AssistedInject constructor(
|
||||
}
|
||||
|
||||
private fun handleRoomLinkClick(
|
||||
context: Context,
|
||||
roomLink: PermalinkData.RoomLink,
|
||||
eventSink: (TimelineEvents) -> Unit,
|
||||
) {
|
||||
@@ -183,7 +186,7 @@ class MessagesNode @AssistedInject constructor(
|
||||
eventSink(TimelineEvents.FocusOnEvent(eventId))
|
||||
} else {
|
||||
// Click on the same room, ignore
|
||||
context.toast("Already viewing this room!")
|
||||
displaySameRoomToast()
|
||||
}
|
||||
} else {
|
||||
callbacks.forEach { it.onPermalinkClick(roomLink) }
|
||||
@@ -210,6 +213,15 @@ class MessagesNode @AssistedInject constructor(
|
||||
callbacks.forEach { it.onPreviewAttachments(attachments) }
|
||||
}
|
||||
|
||||
override fun onNavigateToRoom(roomId: RoomId) {
|
||||
if (roomId == room.roomId) {
|
||||
displaySameRoomToast()
|
||||
} else {
|
||||
val permalinkData = PermalinkData.RoomLink(roomId.toRoomIdOrAlias())
|
||||
callbacks.forEach { it.onPermalinkClick(permalinkData) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun onViewAllPinnedMessagesClick() {
|
||||
callbacks.forEach { it.onViewAllPinnedEvents() }
|
||||
}
|
||||
@@ -230,6 +242,10 @@ class MessagesNode @AssistedInject constructor(
|
||||
callbacks.forEach { it.onViewKnockRequests() }
|
||||
}
|
||||
|
||||
private fun displaySameRoomToast() {
|
||||
context.toast(CommonStrings.screen_room_permalink_same_room_android)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val activity = requireNotNull(LocalActivity.current)
|
||||
@@ -255,13 +271,13 @@ class MessagesNode @AssistedInject constructor(
|
||||
onCreatePollClick = this::onCreatePollClick,
|
||||
onJoinCallClick = this::onJoinCallClick,
|
||||
onViewAllPinnedMessagesClick = this::onViewAllPinnedMessagesClick,
|
||||
modifier = modifier,
|
||||
knockRequestsBannerView = {
|
||||
knockRequestsBannerRenderer.View(
|
||||
modifier = Modifier,
|
||||
onViewRequestsClick = this::onViewKnockRequestsClick
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
roomMemberModerationRenderer.Render(
|
||||
state = state.roomMemberModerationState,
|
||||
|
||||
@@ -270,6 +270,7 @@ class MessagesPresenter @AssistedInject constructor(
|
||||
pinnedMessagesBannerState = pinnedMessagesBannerState,
|
||||
dmUserVerificationState = dmUserVerificationState,
|
||||
roomMemberModerationState = roomMemberModerationState,
|
||||
successorRoom = roomInfo.successorRoom,
|
||||
eventSink = { handleEvents(it) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
@@ -56,5 +57,6 @@ data class MessagesState(
|
||||
val pinnedMessagesBannerState: PinnedMessagesBannerState,
|
||||
val dmUserVerificationState: IdentityState?,
|
||||
val roomMemberModerationState: RoomMemberModerationState,
|
||||
val successorRoom: SuccessorRoom?,
|
||||
val eventSink: (MessagesEvents) -> Unit
|
||||
)
|
||||
|
||||
@@ -44,6 +44,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.textcomposer.model.MessageComposerMode
|
||||
import io.element.android.libraries.textcomposer.model.aTextEditorStateRich
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
@@ -87,6 +88,7 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
||||
),
|
||||
aMessagesState(roomName = AsyncData.Success("A DM with a very looong name"), dmUserVerificationState = IdentityState.Verified),
|
||||
aMessagesState(roomName = AsyncData.Success("A DM with a very looong name"), dmUserVerificationState = IdentityState.VerificationViolation),
|
||||
aMessagesState(successorRoom = SuccessorRoom(RoomId("!id:domain"), null)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -119,6 +121,7 @@ fun aMessagesState(
|
||||
pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(),
|
||||
dmUserVerificationState: IdentityState? = null,
|
||||
roomMemberModerationState: RoomMemberModerationState = aRoomMemberModerationState(),
|
||||
successorRoom: SuccessorRoom? = null,
|
||||
eventSink: (MessagesEvents) -> Unit = {},
|
||||
) = MessagesState(
|
||||
roomId = RoomId("!id:domain"),
|
||||
@@ -147,6 +150,7 @@ fun aMessagesState(
|
||||
pinnedMessagesBannerState = pinnedMessagesBannerState,
|
||||
dmUserVerificationState = dmUserVerificationState,
|
||||
roomMemberModerationState = roomMemberModerationState,
|
||||
successorRoom = successorRoom,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ import io.element.android.features.messages.impl.voicemessages.composer.VoiceMes
|
||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
|
||||
import io.element.android.features.roomcall.api.RoomCallState
|
||||
import io.element.android.libraries.androidutils.ui.hideKeyboard
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
@@ -90,6 +91,7 @@ import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.toAnnotatedString
|
||||
import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
@@ -101,8 +103,10 @@ import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.textcomposer.model.TextEditorState
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
@@ -211,8 +215,8 @@ fun MessagesView(
|
||||
onMessageLongClick = ::onMessageLongClick,
|
||||
onUserDataClick = {
|
||||
hidingKeyboard {
|
||||
state.eventSink(MessagesEvents.OnUserClicked(it))
|
||||
}
|
||||
state.eventSink(MessagesEvents.OnUserClicked(it))
|
||||
}
|
||||
},
|
||||
onLinkClick = { link, customTab ->
|
||||
if (customTab) {
|
||||
@@ -410,6 +414,9 @@ private fun MessagesViewContent(
|
||||
MessagesViewComposerBottomSheetContents(
|
||||
subcomposing = subcomposing,
|
||||
state = state,
|
||||
onRoomSuccessorClick = { roomId ->
|
||||
state.timelineState.eventSink(TimelineEvents.NavigateToRoom(roomId = roomId))
|
||||
},
|
||||
onLinkClick = { url, customTab -> onLinkClick(Link(url), customTab) },
|
||||
)
|
||||
},
|
||||
@@ -424,52 +431,59 @@ private fun MessagesViewContent(
|
||||
private fun MessagesViewComposerBottomSheetContents(
|
||||
subcomposing: Boolean,
|
||||
state: MessagesState,
|
||||
onRoomSuccessorClick: (RoomId) -> Unit,
|
||||
onLinkClick: (String, Boolean) -> Unit,
|
||||
) {
|
||||
if (state.userEventPermissions.canSendMessage) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
SuggestionsPickerView(
|
||||
modifier = Modifier
|
||||
.heightIn(max = 230.dp)
|
||||
// Consume all scrolling, preventing the bottom sheet from being dragged when interacting with the list of suggestions
|
||||
.nestedScroll(object : NestedScrollConnection {
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
||||
return available
|
||||
}
|
||||
}),
|
||||
roomId = state.roomId,
|
||||
roomName = state.roomName.dataOrNull(),
|
||||
roomAvatarData = state.roomAvatar.dataOrNull(),
|
||||
suggestions = state.composerState.suggestions,
|
||||
onSelectSuggestion = {
|
||||
state.composerState.eventSink(MessageComposerEvents.InsertSuggestion(it))
|
||||
when {
|
||||
state.successorRoom != null -> {
|
||||
SuccessorRoomBanner(roomSuccessor = state.successorRoom, onRoomSuccessorClick = onRoomSuccessorClick)
|
||||
}
|
||||
state.userEventPermissions.canSendMessage -> {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
SuggestionsPickerView(
|
||||
modifier = Modifier
|
||||
.heightIn(max = 230.dp)
|
||||
// Consume all scrolling, preventing the bottom sheet from being dragged when interacting with the list of suggestions
|
||||
.nestedScroll(object : NestedScrollConnection {
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
||||
return available
|
||||
}
|
||||
}),
|
||||
roomId = state.roomId,
|
||||
roomName = state.roomName.dataOrNull(),
|
||||
roomAvatarData = state.roomAvatar.dataOrNull(),
|
||||
suggestions = state.composerState.suggestions,
|
||||
onSelectSuggestion = {
|
||||
state.composerState.eventSink(MessageComposerEvents.InsertSuggestion(it))
|
||||
}
|
||||
)
|
||||
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
||||
if (state.composerState.suggestions.isEmpty() &&
|
||||
state.composerState.textEditorState is TextEditorState.Markdown) {
|
||||
IdentityChangeStateView(
|
||||
state = state.identityChangeState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
val verificationViolation = state.identityChangeState.roomMemberIdentityStateChanges.firstOrNull {
|
||||
it.identityState == IdentityState.VerificationViolation
|
||||
}
|
||||
if (verificationViolation != null) {
|
||||
DisabledComposerView(modifier = Modifier.fillMaxWidth())
|
||||
} else {
|
||||
MessageComposerView(
|
||||
state = state.composerState,
|
||||
voiceMessageState = state.voiceMessageComposerState,
|
||||
subcomposing = subcomposing,
|
||||
enableVoiceMessages = state.enableVoiceMessages,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
)
|
||||
// Do not show the identity change if user is composing a Rich message or is seeing suggestion(s).
|
||||
if (state.composerState.suggestions.isEmpty() &&
|
||||
state.composerState.textEditorState is TextEditorState.Markdown) {
|
||||
IdentityChangeStateView(
|
||||
state = state.identityChangeState,
|
||||
onLinkClick = onLinkClick,
|
||||
)
|
||||
}
|
||||
val verificationViolation = state.identityChangeState.roomMemberIdentityStateChanges.firstOrNull {
|
||||
it.identityState == IdentityState.VerificationViolation
|
||||
}
|
||||
if (verificationViolation != null) {
|
||||
DisabledComposerView(modifier = Modifier.fillMaxWidth())
|
||||
} else {
|
||||
MessageComposerView(
|
||||
state = state.composerState,
|
||||
voiceMessageState = state.voiceMessageComposerState,
|
||||
subcomposing = subcomposing,
|
||||
enableVoiceMessages = state.enableVoiceMessages,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CantSendMessageBanner()
|
||||
else -> {
|
||||
CantSendMessageBanner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,9 +586,9 @@ private fun RoomAvatarAndNameRow(
|
||||
private fun CantSendMessageBanner() {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(ElementTheme.colors.bgSubtleSecondary)
|
||||
.padding(16.dp),
|
||||
.fillMaxWidth()
|
||||
.background(ElementTheme.colors.bgSubtleSecondary)
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
@@ -588,6 +602,22 @@ private fun CantSendMessageBanner() {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SuccessorRoomBanner(
|
||||
roomSuccessor: SuccessorRoom,
|
||||
onRoomSuccessorClick: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ComposerAlertMolecule(
|
||||
avatar = null,
|
||||
content = stringResource(R.string.screen_room_timeline_tombstoned_room_message).toAnnotatedString(),
|
||||
onSubmitClick = { onRoomSuccessorClick(roomSuccessor.roomId) },
|
||||
modifier = modifier,
|
||||
isCritical = false,
|
||||
submitText = stringResource(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class) state: MessagesState) = ElementPreview {
|
||||
|
||||
@@ -106,7 +106,8 @@ class PinnedMessagesListPresenter @AssistedInject constructor(
|
||||
renderTypingNotifications = false,
|
||||
typingMembers = persistentListOf(),
|
||||
reserveSpace = false,
|
||||
)
|
||||
),
|
||||
predecessorRoom = room.predecessorRoom(),
|
||||
)
|
||||
}
|
||||
val timelineProtectionState = timelineProtectionPresenter.present()
|
||||
|
||||
@@ -9,6 +9,7 @@ package io.element.android.features.messages.impl.timeline
|
||||
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
|
||||
import kotlin.time.Duration
|
||||
@@ -30,6 +31,7 @@ sealed interface TimelineEvents {
|
||||
data class ComputeVerifiedUserSendFailure(val event: TimelineItem.Event) : EventFromTimelineItem
|
||||
data class ShowShieldDialog(val messageShield: MessageShield) : EventFromTimelineItem
|
||||
data class LoadMore(val direction: Timeline.PaginationDirection) : EventFromTimelineItem
|
||||
data class NavigateToRoom(val roomId: RoomId) : EventFromTimelineItem
|
||||
|
||||
/**
|
||||
* Events coming from a poll item.
|
||||
|
||||
@@ -178,6 +178,9 @@ class TimelinePresenter @AssistedInject constructor(
|
||||
is TimelineEvents.ComputeVerifiedUserSendFailure -> {
|
||||
resolveVerifiedUserSendFailureState.eventSink(ResolveVerifiedUserSendFailureEvents.ComputeForMessage(event.event))
|
||||
}
|
||||
is TimelineEvents.NavigateToRoom -> {
|
||||
navigator.onNavigateToRoom(event.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,8 +260,9 @@ class TimelinePresenter @AssistedInject constructor(
|
||||
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
|
||||
userHasPermissionToSendReaction = userHasPermissionToSendReaction,
|
||||
roomCallState = roomCallState,
|
||||
pinnedEventIds = roomInfo.pinnedEventIds.orEmpty(),
|
||||
pinnedEventIds = roomInfo.pinnedEventIds,
|
||||
typingNotificationState = typingNotificationState,
|
||||
predecessorRoom = room.predecessorRoom(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import io.element.android.features.messages.impl.typing.TypingNotificationState
|
||||
import io.element.android.features.roomcall.api.RoomCallState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlin.time.Duration
|
||||
@@ -77,4 +78,5 @@ data class TimelineRoomInfo(
|
||||
val roomCallState: RoomCallState,
|
||||
val pinnedEventIds: List<EventId>,
|
||||
val typingNotificationState: TypingNotificationState,
|
||||
val predecessorRoom: PredecessorRoom?,
|
||||
)
|
||||
|
||||
@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageShield
|
||||
@@ -246,6 +247,7 @@ internal fun aTimelineRoomInfo(
|
||||
userHasPermissionToSendMessage: Boolean = true,
|
||||
pinnedEventIds: List<EventId> = emptyList(),
|
||||
typingNotificationState: TypingNotificationState = aTypingNotificationState(),
|
||||
predecessorRoom: PredecessorRoom? = null,
|
||||
) = TimelineRoomInfo(
|
||||
isDm = isDm,
|
||||
name = name,
|
||||
@@ -254,4 +256,5 @@ internal fun aTimelineRoomInfo(
|
||||
roomCallState = aStandByCallState(),
|
||||
pinnedEventIds = pinnedEventIds,
|
||||
typingNotificationState = typingNotificationState,
|
||||
predecessorRoom = predecessorRoom,
|
||||
)
|
||||
|
||||
@@ -41,7 +41,15 @@ fun TimelineItemVirtualRow(
|
||||
when (virtual.model) {
|
||||
is TimelineItemDaySeparatorModel -> TimelineItemDaySeparatorView(virtual.model)
|
||||
TimelineItemReadMarkerModel -> TimelineItemReadMarkerView()
|
||||
TimelineItemRoomBeginningModel -> TimelineItemRoomBeginningView(roomName = timelineRoomInfo.name)
|
||||
TimelineItemRoomBeginningModel -> {
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = timelineRoomInfo.predecessorRoom,
|
||||
roomName = timelineRoomInfo.name,
|
||||
onPredecessorRoomClick = { roomId ->
|
||||
eventSink(TimelineEvents.NavigateToRoom(roomId))
|
||||
},
|
||||
)
|
||||
}
|
||||
is TimelineItemLoadingIndicatorModel -> {
|
||||
TimelineLoadingMoreIndicator(virtual.model.direction)
|
||||
val latestEventSink by rememberUpdatedState(eventSink)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.virtual
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -19,44 +20,74 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.messages.impl.R
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.toAnnotatedString
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
|
||||
@Composable
|
||||
fun TimelineItemRoomBeginningView(
|
||||
roomName: String?,
|
||||
predecessorRoom: PredecessorRoom?,
|
||||
onPredecessorRoomClick: (RoomId) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth()
|
||||
) {
|
||||
val text = if (roomName == null) {
|
||||
stringResource(id = R.string.screen_room_timeline_beginning_of_room_no_name)
|
||||
} else {
|
||||
stringResource(id = R.string.screen_room_timeline_beginning_of_room, roomName)
|
||||
if (predecessorRoom != null) {
|
||||
ComposerAlertMolecule(
|
||||
avatar = null,
|
||||
content = stringResource(R.string.screen_room_timeline_upgraded_room_message).toAnnotatedString(),
|
||||
onSubmitClick = { onPredecessorRoomClick(predecessorRoom.roomId) },
|
||||
isCritical = false,
|
||||
submitText = stringResource(R.string.screen_room_timeline_upgraded_room_action)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val text = if (roomName == null) {
|
||||
stringResource(id = R.string.screen_room_timeline_beginning_of_room_no_name)
|
||||
} else {
|
||||
stringResource(id = R.string.screen_room_timeline_beginning_of_room, roomName)
|
||||
}
|
||||
Text(
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
text = text,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
text = text,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TimelineItemRoomBeginningViewPreview() = ElementPreview {
|
||||
Column {
|
||||
Column(verticalArrangement = spacedBy(16.dp)) {
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = null,
|
||||
roomName = null,
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = null,
|
||||
roomName = "Room Name",
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
TimelineItemRoomBeginningView(
|
||||
predecessorRoom = PredecessorRoom(RoomId("!roomId:matrix.org"), EventId("\$eventId:matrix.org")),
|
||||
roomName = "Room Name",
|
||||
onPredecessorRoomClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
<item quantity="few">"%1$d změny místnosti"</item>
|
||||
<item quantity="other">"%1$d změn místnosti"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_timeline_tombstoned_room_action">"Přejít do nové místnosti"</string>
|
||||
<string name="screen_room_timeline_tombstoned_room_message">"Tato místnost byla nahrazena a již není aktivní"</string>
|
||||
<string name="screen_room_timeline_upgraded_room_action">"Zobrazit staré zprávy"</string>
|
||||
<string name="screen_room_timeline_upgraded_room_message">"Tato místnost je pokračováním jiné místnosti"</string>
|
||||
<plurals name="screen_room_typing_many_members">
|
||||
<item quantity="one">"%1$s, %2$s a %3$d další"</item>
|
||||
<item quantity="few">"%1$s, %2$s a %3$d další"</item>
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
<item quantity="one">"%1$d room change"</item>
|
||||
<item quantity="other">"%1$d room changes"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_timeline_tombstoned_room_action">"Jump to new room"</string>
|
||||
<string name="screen_room_timeline_tombstoned_room_message">"This room has been replaced and is no longer active"</string>
|
||||
<string name="screen_room_timeline_upgraded_room_action">"See old messages"</string>
|
||||
<string name="screen_room_timeline_upgraded_room_message">"This room is a continuation of another room"</string>
|
||||
<plurals name="screen_room_typing_many_members">
|
||||
<item quantity="one">"%1$s, %2$s and %3$d other"</item>
|
||||
<item quantity="other">"%1$s, %2$s and %3$d others"</item>
|
||||
|
||||
@@ -9,6 +9,7 @@ package io.element.android.features.messages.impl
|
||||
|
||||
import io.element.android.features.messages.impl.attachments.Attachment
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
@@ -20,6 +21,7 @@ class FakeMessagesNavigator(
|
||||
private val onReportContentClickLambda: (eventId: EventId, senderId: UserId) -> Unit = { _, _ -> lambdaError() },
|
||||
private val onEditPollClickLambda: (eventId: EventId) -> Unit = { _ -> lambdaError() },
|
||||
private val onPreviewAttachmentLambda: (attachments: ImmutableList<Attachment>) -> Unit = { _ -> lambdaError() },
|
||||
private val onNavigateToRoomLambda: (roomId: RoomId) -> Unit = { _ -> lambdaError() }
|
||||
) : MessagesNavigator {
|
||||
override fun onShowEventDebugInfoClick(eventId: EventId?, debugInfo: TimelineItemDebugInfo) {
|
||||
onShowEventDebugInfoClickLambda(eventId, debugInfo)
|
||||
@@ -40,4 +42,8 @@ class FakeMessagesNavigator(
|
||||
override fun onPreviewAttachment(attachments: ImmutableList<Attachment>) {
|
||||
onPreviewAttachmentLambda(attachments)
|
||||
}
|
||||
|
||||
override fun onNavigateToRoom(roomId: RoomId) {
|
||||
onNavigateToRoomLambda(roomId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
@@ -57,6 +58,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||
@@ -1130,6 +1132,57 @@ class MessagesPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - room with successor room includes successor info in state`() = runTest {
|
||||
val successorRoomId = RoomId("!successor:server.org")
|
||||
val successorReason = "This room has been moved to a new location"
|
||||
val room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canUserSendMessageResult = { _, _ -> Result.success(true) },
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
canRedactOtherResult = { Result.success(true) },
|
||||
canUserJoinCallResult = { Result.success(true) },
|
||||
canUserPinUnpinResult = { Result.success(true) },
|
||||
initialRoomInfo = aRoomInfo(
|
||||
successorRoom = SuccessorRoom(
|
||||
roomId = successorRoomId,
|
||||
reason = successorReason
|
||||
)
|
||||
)
|
||||
),
|
||||
typingNoticeResult = { Result.success(Unit) },
|
||||
)
|
||||
val presenter = createMessagesPresenter(joinedRoom = room)
|
||||
presenter.testWithLifecycleOwner {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.successorRoom).isNotNull()
|
||||
assertThat(initialState.successorRoom?.roomId).isEqualTo(successorRoomId)
|
||||
assertThat(initialState.successorRoom?.reason).isEqualTo(successorReason)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - room without successor room has null successor info in state`() = runTest {
|
||||
val room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canUserSendMessageResult = { _, _ -> Result.success(true) },
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
canRedactOtherResult = { Result.success(true) },
|
||||
canUserJoinCallResult = { Result.success(true) },
|
||||
canUserPinUnpinResult = { Result.success(true) },
|
||||
initialRoomInfo = aRoomInfo(successorRoom = null)
|
||||
),
|
||||
typingNoticeResult = { Result.success(Unit) },
|
||||
)
|
||||
val presenter = createMessagesPresenter(joinedRoom = room)
|
||||
presenter.testWithLifecycleOwner {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.successorRoom).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - when room is encrypted and a DM, the DM user's identity state is fetched onResume`() = runTest {
|
||||
val room = FakeJoinedRoom(
|
||||
|
||||
@@ -52,7 +52,9 @@ import io.element.android.features.messages.impl.timeline.components.receipt.aRe
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.getDisplayName
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
@@ -65,6 +67,7 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||
import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams
|
||||
import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParamsAndResult
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.assertNoNodeWithText
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.pressBack
|
||||
@@ -560,6 +563,36 @@ class MessagesViewTest {
|
||||
rule.onNodeWithText("This is a pinned message").performClick()
|
||||
eventsRecorder.assertSingle(TimelineEvents.FocusOnEvent(AN_EVENT_ID, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on successor room button emits expected event`() {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvents>()
|
||||
val successorRoomId = RoomId("!successor:server.org")
|
||||
val state = aMessagesState(
|
||||
successorRoom = SuccessorRoom(
|
||||
roomId = successorRoomId,
|
||||
reason = "This room has been upgraded"
|
||||
),
|
||||
timelineState = aTimelineState(eventSink = eventsRecorder)
|
||||
)
|
||||
rule.setMessagesView(state = state)
|
||||
val text = rule.activity.getString(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
// The bottomsheet subcompose seems to make the node to appear twice
|
||||
rule.onAllNodesWithText(text).onFirst().performClick()
|
||||
eventsRecorder.assertSingle(TimelineEvents.NavigateToRoom(successorRoomId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no banner shown when there is no successor room`() {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvents>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
successorRoom = null,
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
rule.setMessagesView(state = state)
|
||||
rule.assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_message)
|
||||
rule.assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setMessagesView(
|
||||
|
||||
@@ -32,6 +32,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
@@ -64,6 +65,7 @@ import io.element.android.tests.testutils.test
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
@@ -80,7 +82,7 @@ import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Suppress("LargeClass")
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
|
||||
class TimelinePresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
@@ -705,6 +707,73 @@ class TimelinePresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - timeline room info includes predecessor room when room has predecessor`() = runTest {
|
||||
val predecessorRoomId = RoomId("!predecessor:server.org")
|
||||
val predecessorEventId = EventId("\$predecessorEvent:server.org")
|
||||
val predecessorRoom = PredecessorRoom(
|
||||
roomId = predecessorRoomId,
|
||||
lastEventId = predecessorEventId
|
||||
)
|
||||
|
||||
val room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canUserSendMessageResult = { _, _ -> Result.success(true) },
|
||||
predecessorRoomResult = { predecessorRoom }
|
||||
),
|
||||
)
|
||||
|
||||
val presenter = createTimelinePresenter(room = room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNotNull()
|
||||
assertThat(initialState.timelineRoomInfo.predecessorRoom?.roomId).isEqualTo(predecessorRoomId)
|
||||
assertThat(initialState.timelineRoomInfo.predecessorRoom?.lastEventId).isEqualTo(predecessorEventId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - timeline room info no predecessor`() = runTest {
|
||||
val room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canUserSendMessageResult = { _, _ -> Result.success(true) },
|
||||
predecessorRoomResult = { null }
|
||||
),
|
||||
)
|
||||
val presenter = createTimelinePresenter(room = room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - timeline event navigate to room`() = runTest {
|
||||
val room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canUserSendMessageResult = { _, _ -> Result.success(true) },
|
||||
),
|
||||
)
|
||||
val onNavigateToRoomLambda = lambdaRecorder<RoomId, Unit> {}
|
||||
val navigator = FakeMessagesNavigator(
|
||||
onNavigateToRoomLambda = onNavigateToRoomLambda
|
||||
)
|
||||
val presenter = createTimelinePresenter(room = room, messagesNavigator = navigator)
|
||||
presenter.test {
|
||||
val initialState = awaitFirstItem()
|
||||
initialState.eventSink(TimelineEvents.NavigateToRoom(A_ROOM_ID))
|
||||
assert(onNavigateToRoomLambda)
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
value(A_ROOM_ID)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
|
||||
return awaitItem()
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ internal fun RoomSummaryRow(
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(id = R.string.screen_join_room_knock_sent_title),
|
||||
text = stringResource(id = R.string.screen_roomlist_knock_event_sent_description),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Odmítnout chat"</string>
|
||||
<string name="screen_invites_empty_list">"Žádné pozvánky"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) vás pozval(a)"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Žádost o vstup odeslána"</string>
|
||||
<string name="screen_migration_message">"Jedná se o jednorázový proces, prosíme o strpení."</string>
|
||||
<string name="screen_migration_title">"Nastavení vašeho účtu"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Vytvořte novou konverzaci nebo místnost"</string>
|
||||
@@ -37,9 +36,11 @@ Prozatím můžete zrušit výběr filtrů, abyste viděli své další chaty"</
|
||||
<string name="screen_roomlist_filter_unreads">"Nepřečtené"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gratulujeme!
|
||||
Nemáte žádné nepřečtené zprávy!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Žádost o vstup odeslána"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Všechny chaty"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Označit jako přečtené"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Označit jako nepřečtené"</string>
|
||||
<string name="screen_roomlist_tombstoned_room_description">"Tato místnost byla aktualizována"</string>
|
||||
<string name="session_verification_banner_message">"Zdá se, že používáte nové zařízení. Ověřte přihlášení, abyste měli přístup k zašifrovaným zprávám."</string>
|
||||
<string name="session_verification_banner_title">"Ověřte, že jste to vy"</string>
|
||||
</resources>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Gwrthod sgwrs"</string>
|
||||
<string name="screen_invites_empty_list">"Dim Gwahoddiadau"</string>
|
||||
<string name="screen_invites_invited_you">"Mae %1$s (%2$s) wedi eich gwahodd"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Anfonwyd y cais i ymuno"</string>
|
||||
<string name="screen_migration_message">"Mae hon yn broses un tro, diolch am aros."</string>
|
||||
<string name="screen_migration_title">"Creu eich cyfrif."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Crëwch sgwrs neu ystafell newydd"</string>
|
||||
@@ -37,6 +36,7 @@ Am y tro, gallwch ddad-ddewis hidlwyr er mwyn gweld eich sgyrsiau eraill"</strin
|
||||
<string name="screen_roomlist_filter_unreads">"Heb ei ddarllen"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Llongyfarchiadau!
|
||||
Does gennych chi ddim negeseuon heb eu darllen!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Anfonwyd y cais i ymuno"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Sgyrsiau"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marcio fel wedi\'i ddarllen"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marcio fel heb ei ddarllen"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Einladung ablehnen"</string>
|
||||
<string name="screen_invites_empty_list">"Keine Einladungen"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) hat dich eingeladen"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Beitrittsanfrage geschickt"</string>
|
||||
<string name="screen_migration_message">"Dies ist ein einmaliger Vorgang, danke fürs Warten."</string>
|
||||
<string name="screen_migration_title">"Dein Konto wird eingerichtet."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Eine Unterthaltung oder Raum erstellen"</string>
|
||||
@@ -37,6 +36,7 @@ Deaktivieren Sie den entsprechenden Filter, um Ihre anderen Chatrooms zu sehen"<
|
||||
<string name="screen_roomlist_filter_unreads">"Ungelesen"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Glückwunsch!
|
||||
Sie haben keine ungelesenen Nachrichten!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Beitrittsanfrage geschickt"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Chats"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Als gelesen markieren"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Als ungelesen markieren"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Απόρριψη συνομιλίας"</string>
|
||||
<string name="screen_invites_empty_list">"Χωρίς προσκλήσεις"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) σέ προσκάλεσε"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Το αίτημα συμμετοχής στάλθηκε"</string>
|
||||
<string name="screen_migration_message">"Αυτή είναι μια εφάπαξ διαδικασία, ευχαριστώ που περίμενες."</string>
|
||||
<string name="screen_migration_title">"Ρύθμιση του λογαριασμού σου."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Δημιουργία νέας συνομιλίας ή δωματίου"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"Μη αναγνωσμένα"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Συγχαρητήρια!
|
||||
Δεν έχεις μη αναγνωσμένα μηνύματα!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Το αίτημα συμμετοχής στάλθηκε"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Συνομιλίες"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Επισήμανση ως αναγνωσμένου"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Επισήμανση ως μη αναγνωσμένου"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Rechazar el chat"</string>
|
||||
<string name="screen_invites_empty_list">"Sin invitaciones"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) te invitó"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Solicitud de unión enviada"</string>
|
||||
<string name="screen_migration_message">"Este proceso solo se hace una vez, gracias por esperar."</string>
|
||||
<string name="screen_migration_title">"Configura tu cuenta"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Crear una nueva conversación o sala"</string>
|
||||
@@ -37,6 +36,7 @@ Por ahora, puedes deseleccionar los filtros para ver tus otros chats"</string>
|
||||
<string name="screen_roomlist_filter_unreads">"No leídos"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"¡Felicidades!
|
||||
¡No tienes ningún mensaje sin leer!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Solicitud de unión enviada"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Chats"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marcar como leído"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marcar como no leído"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Keeldu vestlusest"</string>
|
||||
<string name="screen_invites_empty_list">"Kutseid pole"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) saatis sulle kutse"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Liitumispalve on saadetud"</string>
|
||||
<string name="screen_migration_message">"Tänud, et ootad - seda toimingut on vaja teha vaid üks kord."</string>
|
||||
<string name="screen_migration_title">"Seadistame sinu kasutajakontot."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Loo uus vestlus või jututuba"</string>
|
||||
@@ -37,6 +36,7 @@ Aga seni… oma teiste vestluste nägemiseks pead eemaldama filtrid"</string>
|
||||
<string name="screen_roomlist_filter_unreads">"Lugemata"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Õnnitleme!
|
||||
Sul pole ühtegi lugemata sõnumit!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Liitumispalve on saadetud"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Vestlused"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Märgi loetuks"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Märgi mitteloetuks"</string>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Baztertu txata"</string>
|
||||
<string name="screen_invites_empty_list">"Ez dago gonbidapenik"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(e)k (%2$s) gonbidatu zaitu"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Sartzeko eskaera bidali da"</string>
|
||||
<string name="screen_migration_message">"Behin egin beharreko prozesua da; eskerrik asko itxaroteagatik."</string>
|
||||
<string name="screen_migration_title">"Zure kontua konfiguratzen."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Sortu elkarrizketa edo gela berria"</string>
|
||||
@@ -33,6 +32,7 @@ Oraingoz, iragazkiak desautatu ditzakezu zure gainerako txatak ikusteko"</string
|
||||
<string name="screen_roomlist_filter_unreads">"Irakurri gabeak"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Bejondeizula!
|
||||
Ez duzu irakurri gabeko mezurik!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Sartzeko eskaera bidali da"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Txatak"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Markatu irakurritzat"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Markatu irakurri gabetzat"</string>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"رد گپ"</string>
|
||||
<string name="screen_invites_empty_list">"بدون دعوت"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) دعوتتان کرد"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"درخواست پیوستن فرستاده شد"</string>
|
||||
<string name="screen_migration_message">"فرایندی یک باره است. ممنون از شکیباییتان."</string>
|
||||
<string name="screen_migration_title">"برپایی حسابتان."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"ایجاد اتاق یا گفتوگویی جدید"</string>
|
||||
@@ -31,6 +30,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"نخواندهها"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"تبریک!
|
||||
هیچ پیام نخواندهای ندارید!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"درخواست پیوستن فرستاده شد"</string>
|
||||
<string name="screen_roomlist_main_space_title">"گپها"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"علامتگذاری به عنوان خوانده شده"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"نشان به ناخوانده"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Hylkää keskustelu"</string>
|
||||
<string name="screen_invites_empty_list">"Ei kutsuja"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) kutsui sinut"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Liittymispyyntö lähetetty"</string>
|
||||
<string name="screen_migration_message">"Tämä on kertaluonteinen prosessi, kiitos odottamisesta."</string>
|
||||
<string name="screen_migration_title">"Tiliä määritetään."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Luo uusi keskustelu tai huone"</string>
|
||||
@@ -37,6 +36,7 @@ Toistaiseksi voit poistaa suodattimien valinnan, jotta näet muut keskustelut."<
|
||||
<string name="screen_roomlist_filter_unreads">"Lukemattomat"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Onnittelut!
|
||||
Sinulla ei ole lukemattomia viestejä!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Liittymispyyntö lähetetty"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Keskustelut"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Merkitse luetuksi"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Merkitse lukemattomaksi"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Refuser l’invitation"</string>
|
||||
<string name="screen_invites_empty_list">"Aucune invitation"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) vous a invité(e)"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Demande de rejoindre le salon envoyée"</string>
|
||||
<string name="screen_migration_message">"Il s’agit d’une opération ponctuelle, merci d’attendre quelques instants."</string>
|
||||
<string name="screen_migration_title">"Configuration de votre compte."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Créer une nouvelle discussion ou un nouveau salon"</string>
|
||||
@@ -37,6 +36,7 @@ En attendant, vous pouvez désélectionner des filtres pour voir vos autres salo
|
||||
<string name="screen_roomlist_filter_unreads">"Non-lus"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Félicitations !
|
||||
Vous n’avez plus de messages non-lus !"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Demande de rejoindre le salon envoyée"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Conversations"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marquer comme lu"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marquer comme non lu"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Csevegés elutasítása"</string>
|
||||
<string name="screen_invites_empty_list">"Nincsenek meghívások"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) meghívta"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Csatlakozási kérés elküldve"</string>
|
||||
<string name="screen_migration_message">"Ez egy egyszeri folyamat, köszönjük a türelmét."</string>
|
||||
<string name="screen_migration_title">"A fiók beállítása."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Új beszélgetés vagy szoba létrehozása"</string>
|
||||
@@ -37,6 +36,7 @@ Egyelőre törölheti a szűrőket a többi csevegés megtekintéséhez."</strin
|
||||
<string name="screen_roomlist_filter_unreads">"Olvasatlan"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gratulálunk!
|
||||
Nincs olvasatlan üzenete!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Csatlakozási kérés elküldve"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Összes csevegés"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Megjelölés olvasottként"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Megjelölés olvasatlanként"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Tolak obrolan"</string>
|
||||
<string name="screen_invites_empty_list">"Tidak ada undangan"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) mengundang Anda"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Permintaan untuk bergabung dikirim"</string>
|
||||
<string name="screen_migration_message">"Ini adalah proses satu kali, terima kasih telah menunggu."</string>
|
||||
<string name="screen_migration_title">"Menyiapkan akun Anda."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Buat percakapan atau ruangan baru"</string>
|
||||
@@ -37,6 +36,7 @@ Untuk sementara, Anda dapat membatalkan pilihan saringan untuk melihat percakapa
|
||||
<string name="screen_roomlist_filter_unreads">"Belum dibaca"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Selamat!
|
||||
Anda tidak memiliki pesan yang belum dibaca!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Permintaan untuk bergabung dikirim"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Semua Obrolan"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Tandai sebagai dibaca"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Tandai sebagai belum dibaca"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Rifiuta l\'invito alla conversazione"</string>
|
||||
<string name="screen_invites_empty_list">"Nessun invito"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) ti ha invitato"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Richiesta di accesso inviata"</string>
|
||||
<string name="screen_migration_message">"Si tratta di una procedura che si effettua una sola volta, grazie per l\'attesa."</string>
|
||||
<string name="screen_migration_title">"Configurazione del tuo account."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Crea una nuova conversazione o stanza"</string>
|
||||
@@ -37,6 +36,7 @@ Per il momento, puoi deselezionare i filtri per vedere le altre conversazioni."<
|
||||
<string name="screen_roomlist_filter_unreads">"Non letti"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Congratulazioni!
|
||||
Non hai messaggi non letti!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Richiesta di accesso inviata"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Tutte le conversazioni"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Segna come letto"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Segna come non letto"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Avslå chat"</string>
|
||||
<string name="screen_invites_empty_list">"Ingen invitasjoner"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(%2$s) inviterte deg"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Forespørsel om å bli med sendt"</string>
|
||||
<string name="screen_migration_message">"Dette er en engangsprosess, takk for at du venter."</string>
|
||||
<string name="screen_migration_title">"Setter opp kontoen din."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Opprett en ny samtale eller et nytt rom"</string>
|
||||
@@ -37,6 +36,7 @@ Inntil videre kan du velge bort filtre for å se de andre chattene dine"</string
|
||||
<string name="screen_roomlist_filter_unreads">"Uleste"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gratulerer!
|
||||
Du har ingen uleste meldinger!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Forespørsel om å bli med sendt"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Chatter"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marker som lest"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Merk som ulest"</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Chat weigeren"</string>
|
||||
<string name="screen_invites_empty_list">"Geen uitnodigingen"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) heeft je uitgenodigd"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Verzoek om toe te treden verzonden"</string>
|
||||
<string name="screen_migration_message">"Dit is een eenmalig proces, bedankt voor het wachten."</string>
|
||||
<string name="screen_migration_title">"Je account instellen."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Begin een nieuw gesprek of maak een nieuwe kamer"</string>
|
||||
@@ -35,6 +34,7 @@ Voor nu kun je filters deselecteren om je andere chats te zien"</string>
|
||||
<string name="screen_roomlist_filter_unreads">"Ongelezen"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gefeliciteerd!
|
||||
Je hebt geen ongelezen berichten!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Verzoek om toe te treden verzonden"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Chats"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Markeren als gelezen"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Markeren als ongelezen"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Odrzuć czat"</string>
|
||||
<string name="screen_invites_empty_list">"Brak zaproszeń"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) zaprosił Cię"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Wysłano prośbę o dołączenie"</string>
|
||||
<string name="screen_migration_message">"Jest to jednorazowy proces, dziękujemy za czekanie."</string>
|
||||
<string name="screen_migration_title">"Konfigurowanie Twojego konta."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Utwórz nową rozmowę lub pokój"</string>
|
||||
@@ -37,6 +36,7 @@ Na razie możesz wyczyścić filtry, aby zobaczyć pozostałe czaty"</string>
|
||||
<string name="screen_roomlist_filter_unreads">"Nieprzeczytane"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gratulacje!
|
||||
Nie masz żadnych nieprzeczytanych wiadomości!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Wysłano prośbę o dołączenie"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Wszystkie czaty"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Oznacz jako przeczytane"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Oznacz jako nieprzeczytane"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Recusar chat"</string>
|
||||
<string name="screen_invites_empty_list">"Sem convites"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(%2$s) convidou você"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_migration_message">"Este é um processo único, obrigado por esperar."</string>
|
||||
<string name="screen_migration_title">"Configurando sua conta."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Criar uma nova conversa ou sala"</string>
|
||||
@@ -37,6 +36,7 @@ Por enquanto, você pode desmarcar os filtros para ver seus outros bate-papos"</
|
||||
<string name="screen_roomlist_filter_unreads">"Não lidos"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Parabéns!
|
||||
Você não tem nenhuma mensagem não lida!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Conversas"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marcar como lido"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marcar como não lido"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Rejeitar conversa"</string>
|
||||
<string name="screen_invites_empty_list">"Sem convites"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) convidou-te"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_migration_message">"Este processo só acontece uma única vez, obrigado por esperares."</string>
|
||||
<string name="screen_migration_title">"A configurar a tua conta…"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Criar uma nova conversa ou sala"</string>
|
||||
@@ -37,6 +36,7 @@ Por enquanto, podes anular a seleção dos filtros para veres as tuas outras con
|
||||
<string name="screen_roomlist_filter_unreads">"Por ler"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Parabéns!
|
||||
Não tens nenhuma mensagem por ler!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Conversas"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marcar como lida"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marcar como não lida"</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Refuzați conversația"</string>
|
||||
<string name="screen_invites_empty_list">"Nicio invitație"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) v-a invitat."</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Cererea de alăturare a fost trimisă"</string>
|
||||
<string name="screen_migration_message">"Acesta este un proces care se desfășoară o singură dată, vă mulțumim pentru așteptare."</string>
|
||||
<string name="screen_migration_title">"Contul dumneavoastră se configurează"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Creați o conversație sau o cameră nouă"</string>
|
||||
@@ -35,6 +34,7 @@ Deocamdată, puteți deselecta filtrele pentru a vedea celelalte chat-uri"</stri
|
||||
<string name="screen_roomlist_filter_unreads">"Necitite"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Felicitari!
|
||||
Nu aveți mesaje necitite!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Cererea de alăturare a fost trimisă"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Toate conversatiile"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Marcați ca citită"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Marcați ca necitită"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Отклонить чат"</string>
|
||||
<string name="screen_invites_empty_list">"Нет приглашений"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) пригласил вас"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Запрос на присоединение отправлен"</string>
|
||||
<string name="screen_migration_message">"Это одноразовый процесс, спасибо, что подождали."</string>
|
||||
<string name="screen_migration_title">"Настройка учетной записи."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Создайте новую беседу или комнату"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"Непрочитанные"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Поздравляем!
|
||||
У вас нет непрочитанных сообщений!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Запрос на присоединение отправлен"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Все чаты"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Пометить как прочитанное"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Отметить как непрочитанное"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Odmietnuť konverzáciu"</string>
|
||||
<string name="screen_invites_empty_list">"Žiadne pozvánky"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) vás pozval/a"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Žiadosť o pripojenie bola odoslaná"</string>
|
||||
<string name="screen_migration_message">"Ide o jednorazový proces, ďakujeme za trpezlivosť."</string>
|
||||
<string name="screen_migration_title">"Nastavenie vášho účtu."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Vytvorte novú konverzáciu alebo miestnosť"</string>
|
||||
@@ -37,6 +36,7 @@ Zatiaľ môžete zrušiť výber filtrov, aby ste videli ostatné konverzácie"<
|
||||
<string name="screen_roomlist_filter_unreads">"Neprečítané"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Gratulujeme!
|
||||
Nemáte žiadne neprečítané správy!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Žiadosť o pripojenie bola odoslaná"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Všetky konverzácie"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Označiť ako prečítané"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Označiť ako neprečítané"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Avböj chatt"</string>
|
||||
<string name="screen_invites_empty_list">"Inga inbjudningar"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) bjöd in dig"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Begäran om att gå med skickad"</string>
|
||||
<string name="screen_migration_message">"Detta är en engångsprocess, tack för att du väntar."</string>
|
||||
<string name="screen_migration_title">"Konfigurerar ditt konto"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Skapa en ny konversation eller ett nytt rum"</string>
|
||||
@@ -37,6 +36,7 @@ För tillfället kan du avmarkera filter för att se dina andra chattar"</string
|
||||
<string name="screen_roomlist_filter_unreads">"Olästa"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Grattis!
|
||||
Du har inga olästa meddelanden!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Begäran om att gå med skickad"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Alla chattar"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Markera som läst"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Markera som oläst"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Sohbeti reddet"</string>
|
||||
<string name="screen_invites_empty_list">"Davet Yok"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) sizi davet etti"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Katılma isteği gönderildi"</string>
|
||||
<string name="screen_migration_message">"Bu tek seferlik bir işlemdir, beklediğiniz için teşekkürler."</string>
|
||||
<string name="screen_migration_title">"Hesabınızı ayarlanıyor."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Yeni bir sohbet veya oda oluşturun"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"Okunmamış"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Tebrikler!
|
||||
Okunmamış mesajınız yok!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Katılma isteği gönderildi"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Sohbetler"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Okundu olarak işaretle"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Okunmamış olarak işaretle"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Відхилити бесіду"</string>
|
||||
<string name="screen_invites_empty_list">"Немає запрошень"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) запрошує вас"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Запит на приєднання надіслано"</string>
|
||||
<string name="screen_migration_message">"Це одноразовий процес, дякую за очікування."</string>
|
||||
<string name="screen_migration_title">"Налаштування облікового запису."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Створити нову розмову або кімнату"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"Непрочитані"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Вітаємо!
|
||||
У вас немає непрочитаних повідомлень!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Запит на приєднання надіслано"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Бесіди"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Позначити прочитаним"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Позначити непрочитаним"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"拒絕聊天"</string>
|
||||
<string name="screen_invites_empty_list">"沒有邀請"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(%2$s)邀請您"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"已傳送加入請求"</string>
|
||||
<string name="screen_migration_message">"這是一次性的程序,感謝您耐心等候。"</string>
|
||||
<string name="screen_migration_title">"正在設定您的帳號。"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"建立新的對話或聊天室"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"未讀"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"恭喜!
|
||||
您沒有任何未讀的訊息!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"已傳送加入請求"</string>
|
||||
<string name="screen_roomlist_main_space_title">"所有聊天室"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"標為已讀"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"標為未讀"</string>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"拒绝聊天"</string>
|
||||
<string name="screen_invites_empty_list">"没有邀请"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s)邀请了你"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"加入请求已发送"</string>
|
||||
<string name="screen_migration_message">"这是一个一次性的过程,感谢您的等待。"</string>
|
||||
<string name="screen_migration_title">"设置您的账户。"</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"创建新的对话或聊天室"</string>
|
||||
@@ -37,6 +36,7 @@
|
||||
<string name="screen_roomlist_filter_unreads">"未读"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"恭喜!
|
||||
没有任何未读消息!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"加入请求已发送"</string>
|
||||
<string name="screen_roomlist_main_space_title">"全部聊天"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"标记为已读"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"标记为未读"</string>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<string name="screen_invites_decline_direct_chat_title">"Decline chat"</string>
|
||||
<string name="screen_invites_empty_list">"No Invites"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) invited you"</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Request to join sent"</string>
|
||||
<string name="screen_migration_message">"This is a one time process, thanks for waiting."</string>
|
||||
<string name="screen_migration_title">"Setting up your account."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Create a new conversation or room"</string>
|
||||
@@ -40,9 +39,11 @@ For now, you can deselect filters in order to see your other chats"</string>
|
||||
<string name="screen_roomlist_filter_unreads">"Unreads"</string>
|
||||
<string name="screen_roomlist_filter_unreads_empty_state_title">"Congrats!
|
||||
You don’t have any unread messages!"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Request to join sent"</string>
|
||||
<string name="screen_roomlist_main_space_title">"Chats"</string>
|
||||
<string name="screen_roomlist_mark_as_read">"Mark as read"</string>
|
||||
<string name="screen_roomlist_mark_as_unread">"Mark as unread"</string>
|
||||
<string name="screen_roomlist_tombstoned_room_description">"This room has been upgraded"</string>
|
||||
<string name="session_verification_banner_message">"Looks like you’re using a new device. Verify with another device to access your encrypted messages."</string>
|
||||
<string name="session_verification_banner_title">"Verify it’s you"</string>
|
||||
</resources>
|
||||
|
||||
@@ -39,7 +39,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun ComposerAlertMolecule(
|
||||
avatar: AvatarData,
|
||||
avatar: AvatarData?,
|
||||
content: AnnotatedString,
|
||||
onSubmitClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -71,9 +71,9 @@ fun ComposerAlertMolecule(
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Avatar(
|
||||
avatarData = avatar,
|
||||
)
|
||||
if (avatar != null) {
|
||||
Avatar(avatarData = avatar)
|
||||
}
|
||||
Text(
|
||||
text = content,
|
||||
modifier = Modifier.weight(1f),
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -55,6 +56,8 @@ interface BaseRoom : Closeable {
|
||||
*/
|
||||
fun info(): RoomInfo = roomInfoFlow.value
|
||||
|
||||
fun predecessorRoom(): PredecessorRoom?
|
||||
|
||||
/**
|
||||
* A one-to-one is a room with exactly 2 members.
|
||||
* See [the Matrix spec](https://spec.matrix.org/latest/client-server-api/#default-underride-rules).
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.libraries.matrix.api.room.tombstone
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
/**
|
||||
*
|
||||
* When a room A is tombstoned, it is replaced by a room B. The room A is the
|
||||
* predecessor of B, and B is the successor of A. This type holds information
|
||||
* about the predecessor room.
|
||||
*
|
||||
* A room is tombstoned if it has received a m.room.tombstone state event.
|
||||
*
|
||||
*/
|
||||
data class PredecessorRoom(
|
||||
/**
|
||||
* The ID of the replaced room.
|
||||
*/
|
||||
val roomId: RoomId,
|
||||
/**
|
||||
* The event ID of the last known event in the predecessor room.
|
||||
*/
|
||||
val lastEventId: EventId,
|
||||
)
|
||||
@@ -5,7 +5,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
package io.element.android.libraries.matrix.api.room.tombstone
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
||||
@@ -14,11 +14,11 @@ import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.impl.room.history.map
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.tombstone.map
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentMap
|
||||
@@ -28,7 +28,6 @@ import uniffi.matrix_sdk_base.EncryptionState
|
||||
import org.matrix.rustcomponents.sdk.Membership as RustMembership
|
||||
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
import org.matrix.rustcomponents.sdk.SuccessorRoom as RustSuccessorRoom
|
||||
|
||||
class RoomInfoMapper {
|
||||
fun map(rustRoomInfo: RustRoomInfo): RoomInfo = rustRoomInfo.let {
|
||||
@@ -88,11 +87,6 @@ fun RustRoomNotificationMode.map(): RoomNotificationMode = when (this) {
|
||||
RustRoomNotificationMode.MUTE -> RoomNotificationMode.MUTE
|
||||
}
|
||||
|
||||
fun RustSuccessorRoom.map(): SuccessorRoom = SuccessorRoom(
|
||||
roomId = RoomId(roomId),
|
||||
reason = reason,
|
||||
)
|
||||
|
||||
/**
|
||||
* Map a RoomHero to a MatrixUser. There is not need to create a RoomHero type on the application side.
|
||||
*/
|
||||
|
||||
@@ -24,12 +24,14 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.impl.room.draft.into
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsMapper
|
||||
import io.element.android.libraries.matrix.impl.room.tombstone.map
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
|
||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||
@@ -78,6 +80,10 @@ class RustBaseRoom(
|
||||
})
|
||||
}.stateIn(roomCoroutineScope, started = SharingStarted.Lazily, initialValue = initialRoomInfo)
|
||||
|
||||
override fun predecessorRoom(): PredecessorRoom? {
|
||||
return innerRoom.predecessorRoom()?.map()
|
||||
}
|
||||
|
||||
override suspend fun subscribeToSync() = roomSyncSubscriber.subscribe(roomId)
|
||||
|
||||
override suspend fun updateMembers() {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.libraries.matrix.impl.room.tombstone
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import org.matrix.rustcomponents.sdk.PredecessorRoom as RustPredecessorRoom
|
||||
|
||||
fun RustPredecessorRoom.map(): PredecessorRoom {
|
||||
return PredecessorRoom(
|
||||
roomId = RoomId(roomId),
|
||||
lastEventId = EventId(lastEventId),
|
||||
)
|
||||
}
|
||||
@@ -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.libraries.matrix.impl.room.tombstone
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import org.matrix.rustcomponents.sdk.SuccessorRoom as RustSuccessorRoom
|
||||
|
||||
fun RustSuccessorRoom.map(): SuccessorRoom {
|
||||
return SuccessorRoom(
|
||||
roomId = RoomId(roomId),
|
||||
reason = reason
|
||||
)
|
||||
}
|
||||
@@ -27,6 +27,11 @@ import org.matrix.rustcomponents.sdk.RoomListService
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import org.matrix.rustcomponents.sdk.RoomList as InnerRoomList
|
||||
|
||||
private val ROOM_LIST_RUST_FILTERS = listOf(
|
||||
RoomListEntriesDynamicFilterKind.NonLeft,
|
||||
RoomListEntriesDynamicFilterKind.DeduplicateVersions
|
||||
)
|
||||
|
||||
internal class RoomListFactory(
|
||||
private val innerRoomListService: RoomListService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
@@ -55,11 +60,11 @@ internal class RoomListFactory(
|
||||
|
||||
coroutineScope.launch(coroutineContext) {
|
||||
innerRoomList = innerProvider()
|
||||
innerRoomList?.let { innerRoomList ->
|
||||
innerRoomList.let { innerRoomList ->
|
||||
innerRoomList.entriesFlow(
|
||||
pageSize = pageSize,
|
||||
roomListDynamicEvents = dynamicEvents,
|
||||
initialFilterKind = RoomListEntriesDynamicFilterKind.NonLeft
|
||||
initialFilterKind = RoomListEntriesDynamicFilterKind.All(ROOM_LIST_RUST_FILTERS),
|
||||
).onEach { update ->
|
||||
processor.postUpdate(update)
|
||||
}.launchIn(this)
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
@@ -66,6 +67,7 @@ class FakeBaseRoom(
|
||||
private val getRoomVisibilityResult: () -> Result<RoomVisibility> = { lambdaError() },
|
||||
private val forgetResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val reportRoomResult: (String?) -> Result<Unit> = { lambdaError() },
|
||||
private val predecessorRoomResult: () -> PredecessorRoom? = { null },
|
||||
) : BaseRoom {
|
||||
private val _roomInfoFlow: MutableStateFlow<RoomInfo> = MutableStateFlow(initialRoomInfo)
|
||||
override val roomInfoFlow: StateFlow<RoomInfo> = _roomInfoFlow
|
||||
@@ -215,6 +217,8 @@ class FakeBaseRoom(
|
||||
}
|
||||
|
||||
override suspend fun reportRoom(reason: String?) = reportRoomResult(reason)
|
||||
|
||||
override fun predecessorRoom(): PredecessorRoom? = predecessorRoomResult()
|
||||
}
|
||||
|
||||
fun defaultRoomPowerLevels() = RoomPowerLevels(
|
||||
|
||||
@@ -15,9 +15,9 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
|
||||
@@ -15,10 +15,10 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
@@ -396,7 +396,6 @@ Ydych chi\'n siŵr eich bod am barhau?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Wrthi\'n llwytho neges…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Dangos y Cyfan"</string>
|
||||
<string name="screen_room_title">"Sgwrs"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Anfonwyd y cais i ymuno"</string>
|
||||
<string name="screen_share_location_title">"Rhannu lleoliad"</string>
|
||||
<string name="screen_share_my_location_action">"Rhannu fy lleoliad"</string>
|
||||
<string name="screen_share_open_apple_maps">"Agor yn Apple Maps"</string>
|
||||
|
||||
@@ -372,7 +372,6 @@ Möchten Sie wirklich fortfahren?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Nachricht wird geladen…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Alle anzeigen"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Beitrittsanfrage geschickt"</string>
|
||||
<string name="screen_share_location_title">"Standort teilen"</string>
|
||||
<string name="screen_share_my_location_action">"Meinen Standort teilen"</string>
|
||||
<string name="screen_share_open_apple_maps">"In Apple Maps öffnen"</string>
|
||||
|
||||
@@ -372,7 +372,6 @@
|
||||
<string name="screen_room_pinned_banner_loading_description">"Φόρτωση μηνύματος…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Προβολή Όλων"</string>
|
||||
<string name="screen_room_title">"Συνομιλία"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Το αίτημα συμμετοχής στάλθηκε"</string>
|
||||
<string name="screen_share_location_title">"Κοινή χρήση τοποθεσίας"</string>
|
||||
<string name="screen_share_my_location_action">"Κοινή χρήση της τοποθεσίας μου"</string>
|
||||
<string name="screen_share_open_apple_maps">"Άνοιγμα στο Apple Maps"</string>
|
||||
|
||||
@@ -372,7 +372,6 @@ Motivo: %1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Cargando mensaje…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Ver todos"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Solicitud de unión enviada"</string>
|
||||
<string name="screen_share_location_title">"Compartir ubicación"</string>
|
||||
<string name="screen_share_my_location_action">"Compartir mi ubicación"</string>
|
||||
<string name="screen_share_open_apple_maps">"Abrir en Apple Maps"</string>
|
||||
|
||||
@@ -330,7 +330,6 @@ Arrazoia: %1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Mezua kargatzen…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Ikusi guztia"</string>
|
||||
<string name="screen_room_title">"Txata"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Sartzeko eskaera bidali da"</string>
|
||||
<string name="screen_share_location_title">"Partekatu kokapena"</string>
|
||||
<string name="screen_share_my_location_action">"Partekatu nire kokapena"</string>
|
||||
<string name="screen_share_open_apple_maps">"Ireki Apple Maps-en"</string>
|
||||
|
||||
@@ -323,7 +323,6 @@
|
||||
<string name="screen_room_pinned_banner_loading_description">"بار کردن پشامها…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"نمایش همه"</string>
|
||||
<string name="screen_room_title">"گپ"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"درخواست پیوستن فرستاده شد"</string>
|
||||
<string name="screen_share_location_title">"همرسانی موقعیت"</string>
|
||||
<string name="screen_share_my_location_action">"همرسانی مکانم"</string>
|
||||
<string name="screen_share_open_apple_maps">"گشودن در نقشههای اپل"</string>
|
||||
|
||||
@@ -334,7 +334,6 @@ Alasan: %1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Memuat pesan…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Lihat Semua"</string>
|
||||
<string name="screen_room_title">"Obrolan"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Permintaan untuk bergabung dikirim"</string>
|
||||
<string name="screen_share_location_title">"Bagikan lokasi"</string>
|
||||
<string name="screen_share_my_location_action">"Bagikan lokasi saya"</string>
|
||||
<string name="screen_share_open_apple_maps">"Buka di Apple Maps"</string>
|
||||
|
||||
@@ -359,7 +359,6 @@ Sei sicuro di voler continuare?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Caricamento messaggio…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Mostra tutti"</string>
|
||||
<string name="screen_room_title">"Conversazione"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Richiesta di accesso inviata"</string>
|
||||
<string name="screen_share_location_title">"Condividi posizione"</string>
|
||||
<string name="screen_share_my_location_action">"Condividi la mia posizione"</string>
|
||||
<string name="screen_share_open_apple_maps">"Apri in Apple Maps"</string>
|
||||
|
||||
@@ -323,7 +323,6 @@ Reden: %1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Bericht laden…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Bekijk alles"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Verzoek om toe te treden verzonden"</string>
|
||||
<string name="screen_share_location_title">"Locatie delen"</string>
|
||||
<string name="screen_share_my_location_action">"Deel mijn locatie"</string>
|
||||
<string name="screen_share_open_apple_maps">"Openen in Apple Maps"</string>
|
||||
|
||||
@@ -378,7 +378,6 @@ Czy na pewno chcesz kontynuować?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Wczytywanie wiadomości…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Wyświetl wszystkie"</string>
|
||||
<string name="screen_room_title">"Czat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Wysłano prośbę o dołączenie"</string>
|
||||
<string name="screen_share_location_title">"Udostępnij lokalizację"</string>
|
||||
<string name="screen_share_my_location_action">"Udostępnij moją lokalizację"</string>
|
||||
<string name="screen_share_open_apple_maps">"Otwórz w Apple Maps"</string>
|
||||
|
||||
@@ -372,7 +372,6 @@ Você tem certeza de que deseja continuar?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Carregando mensagem…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Ver tudo"</string>
|
||||
<string name="screen_room_title">"Bate-papo"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_share_location_title">"Compartilhar localização"</string>
|
||||
<string name="screen_share_my_location_action">"Compartilhar minha localização"</string>
|
||||
<string name="screen_share_open_apple_maps">"Abrir no Apple Maps"</string>
|
||||
|
||||
@@ -372,7 +372,6 @@ Tens a certeza de que queres continuar?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"A carregar mensagem…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Ver todas"</string>
|
||||
<string name="screen_room_title">"Conversa"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Pedido de adesão enviado"</string>
|
||||
<string name="screen_share_location_title">"Partilhar localização"</string>
|
||||
<string name="screen_share_my_location_action">"Partilhar a minha localização"</string>
|
||||
<string name="screen_share_open_apple_maps">"Abrir no Apple Maps"</string>
|
||||
|
||||
@@ -327,7 +327,6 @@ Motiv:%1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Se încarcă mesajul…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Vedeți toate"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Cererea de alăturare a fost trimisă"</string>
|
||||
<string name="screen_share_location_title">"Partajați locația"</string>
|
||||
<string name="screen_share_my_location_action">"Distribuiți locația mea"</string>
|
||||
<string name="screen_share_open_apple_maps">"Deschideți în Apple Maps"</string>
|
||||
|
||||
@@ -378,7 +378,6 @@ Naozaj chcete pokračovať?"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Načítava sa správa…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Zobraziť všetko"</string>
|
||||
<string name="screen_room_title">"Konverzácia"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Žiadosť o pripojenie bola odoslaná"</string>
|
||||
<string name="screen_share_location_title">"Zdieľať polohu"</string>
|
||||
<string name="screen_share_my_location_action">"Zdieľať moju polohu"</string>
|
||||
<string name="screen_share_open_apple_maps">"Otvoriť v Apple Maps"</string>
|
||||
|
||||
@@ -348,7 +348,6 @@ Neden: %1$s."</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Mesaj yükleniyor…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Tümünü görüntüle"</string>
|
||||
<string name="screen_room_title">"Sohbet"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Katılma isteği gönderildi"</string>
|
||||
<string name="screen_share_location_title">"Konum paylaş"</string>
|
||||
<string name="screen_share_my_location_action">"Konumumu paylaş"</string>
|
||||
<string name="screen_share_open_apple_maps">"Apple Maps\'de aç"</string>
|
||||
|
||||
@@ -378,7 +378,6 @@
|
||||
<string name="screen_room_pinned_banner_loading_description">"Завантаження повідомлення…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"Переглянути всі"</string>
|
||||
<string name="screen_room_title">"Бесіда"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Запит на приєднання надіслано"</string>
|
||||
<string name="screen_share_location_title">"Поділитися розташуванням"</string>
|
||||
<string name="screen_share_my_location_action">"Поділитися моїм розташуванням"</string>
|
||||
<string name="screen_share_open_apple_maps">"Відкрити в Apple Maps"</string>
|
||||
|
||||
@@ -366,7 +366,6 @@
|
||||
<string name="screen_room_pinned_banner_loading_description">"正在載入訊息……"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"檢視全部"</string>
|
||||
<string name="screen_room_title">"聊天"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"已傳送加入請求"</string>
|
||||
<string name="screen_share_location_title">"分享位置"</string>
|
||||
<string name="screen_share_my_location_action">"分享我的位置"</string>
|
||||
<string name="screen_share_open_apple_maps">"在 Apple Maps 中開啟"</string>
|
||||
|
||||
@@ -357,7 +357,6 @@
|
||||
<string name="screen_room_pinned_banner_loading_description">"正在加载消息…"</string>
|
||||
<string name="screen_room_pinned_banner_view_all_button_title">"查看全部"</string>
|
||||
<string name="screen_room_title">"聊天"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"加入请求已发送"</string>
|
||||
<string name="screen_share_location_title">"分享位置"</string>
|
||||
<string name="screen_share_my_location_action">"分享我的位置"</string>
|
||||
<string name="screen_share_open_apple_maps">"在 Apple Maps 中打开"</string>
|
||||
|
||||
@@ -381,6 +381,7 @@ Are you sure you want to continue?"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"Failed processing media to upload, please try again."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"Could not retrieve user details"</string>
|
||||
<string name="screen_room_event_pill">"Message in %1$s"</string>
|
||||
<string name="screen_room_permalink_same_room_android">"Already viewing this room!"</string>
|
||||
<string name="screen_room_pinned_banner_indicator">"%1$s of %2$s"</string>
|
||||
<string name="screen_room_pinned_banner_indicator_description">"%1$s Pinned messages"</string>
|
||||
<string name="screen_room_pinned_banner_loading_description">"Loading message…"</string>
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.ui.test.hasTestTag
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.compose.ui.test.onFirst
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import org.junit.rules.TestRule
|
||||
@@ -54,3 +55,8 @@ fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.pressBackKey() {
|
||||
fun SemanticsNodeInteractionsProvider.pressTag(tag: String) {
|
||||
onNode(hasTestTag(tag)).performClick()
|
||||
}
|
||||
|
||||
fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.assertNoNodeWithText(@StringRes res: Int) {
|
||||
val text = activity.getString(res)
|
||||
onNodeWithText(text).assertDoesNotExist()
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -165,14 +165,14 @@
|
||||
"name" : ":features:roomlist:impl",
|
||||
"includeRegex" : [
|
||||
"screen_roomlist_.*",
|
||||
"screen\\.roomlist\\..*",
|
||||
"session_verification_banner_.*",
|
||||
"confirm_recovery_key_banner_.*",
|
||||
"banner\\.set_up_recovery\\..*",
|
||||
"banner\\.battery_optimization\\..*",
|
||||
"full_screen_intent_banner_.*",
|
||||
"screen_migration_.*",
|
||||
"screen_invites_.*",
|
||||
"screen\\.join_room\\.knock_sent_title"
|
||||
"screen_invites_.*"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -211,6 +211,7 @@
|
||||
"screen_room_message.*",
|
||||
"screen_room_retry.*",
|
||||
"screen_room_timeline.*",
|
||||
"screen\\.room_timeline.*",
|
||||
"screen_room_typing.*"
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user