Merge pull request #4212 from element-hq/feature/fga/room_settings_security_privacy
Feature : room settings - security and privacy
This commit is contained in:
commit
346e3648e8
125 changed files with 3387 additions and 347 deletions
|
|
@ -8,6 +8,8 @@
|
|||
package io.element.android.libraries.matrix.api.createroom
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import java.util.Optional
|
||||
|
||||
data class CreateRoomParameters(
|
||||
|
|
@ -19,6 +21,6 @@ data class CreateRoomParameters(
|
|||
val preset: RoomPreset,
|
||||
val invite: List<UserId>? = null,
|
||||
val avatar: String? = null,
|
||||
val joinRuleOverride: JoinRuleOverride = JoinRuleOverride.None,
|
||||
val joinRuleOverride: JoinRule? = null,
|
||||
val roomAliasName: Optional<String> = Optional.empty(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 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.createroom
|
||||
|
||||
/**
|
||||
* Rules to override the default room join rules.
|
||||
*/
|
||||
sealed interface JoinRuleOverride {
|
||||
data object Knock : JoinRuleOverride
|
||||
data object None : JoinRuleOverride
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.createroom
|
||||
|
||||
enum class RoomVisibility {
|
||||
PUBLIC,
|
||||
PRIVATE,
|
||||
}
|
||||
|
|
@ -24,10 +24,13 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
|||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
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.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
|
|
@ -43,7 +46,7 @@ interface MatrixRoom : Closeable {
|
|||
val sessionId: SessionId
|
||||
val roomId: RoomId
|
||||
val displayName: String
|
||||
val alias: RoomAlias?
|
||||
val canonicalAlias: RoomAlias?
|
||||
val alternativeAliases: List<RoomAlias>
|
||||
val topic: String?
|
||||
val avatarUrl: String?
|
||||
|
|
@ -403,4 +406,60 @@ interface MatrixRoom : Closeable {
|
|||
suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle): Result<Unit>
|
||||
|
||||
override fun close() = destroy()
|
||||
|
||||
/**
|
||||
* Update the canonical alias of the room.
|
||||
*
|
||||
* Note that publishing the alias in the room directory is done separately.
|
||||
*/
|
||||
suspend fun updateCanonicalAlias(
|
||||
canonicalAlias: RoomAlias?,
|
||||
alternativeAliases: List<RoomAlias>
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Update the room's visibility in the room directory.
|
||||
*/
|
||||
suspend fun updateRoomVisibility(roomVisibility: RoomVisibility): Result<Unit>
|
||||
|
||||
/**
|
||||
* Update room history visibility for this room.
|
||||
*/
|
||||
suspend fun updateHistoryVisibility(historyVisibility: RoomHistoryVisibility): Result<Unit>
|
||||
|
||||
/**
|
||||
* Returns the visibility for this room in the room directory.
|
||||
* If the room is not published, the result will be [RoomVisibility.Private].
|
||||
*/
|
||||
suspend fun getRoomVisibility(): Result<RoomVisibility>
|
||||
|
||||
/**
|
||||
* Publish a new room alias for this room in the room directory.
|
||||
*
|
||||
* Returns:
|
||||
* - `true` if the room alias didn't exist and it's now published.
|
||||
* - `false` if the room alias was already present so it couldn't be
|
||||
* published.
|
||||
*/
|
||||
suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Remove an existing room alias for this room in the room directory.
|
||||
*
|
||||
* Returns:
|
||||
* - `true` if the room alias was present and it's now removed from the
|
||||
* room directory.
|
||||
* - `false` if the room alias didn't exist so it couldn't be removed.
|
||||
*/
|
||||
suspend fun removeRoomAliasFromRoomDirectory(roomAlias: RoomAlias): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Enable End-to-end encryption in this room.
|
||||
*/
|
||||
suspend fun enableEncryption(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Update the join rule for this room.
|
||||
*/
|
||||
suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
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.user.MatrixUser
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -71,6 +72,7 @@ data class MatrixRoomInfo(
|
|||
val heroes: ImmutableList<MatrixUser>,
|
||||
val pinnedEventIds: ImmutableList<EventId>,
|
||||
val creator: UserId?,
|
||||
val historyVisibility: RoomHistoryVisibility,
|
||||
) {
|
||||
val aliases: List<RoomAlias>
|
||||
get() = listOfNotNull(canonicalAlias) + alternativeAliases
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fun MatrixRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean {
|
|||
roomIdOrAlias.roomId == roomId
|
||||
}
|
||||
is RoomIdOrAlias.Alias -> {
|
||||
roomIdOrAlias.roomAlias == alias || roomIdOrAlias.roomAlias in alternativeAliases
|
||||
roomIdOrAlias.roomAlias == canonicalAlias || roomIdOrAlias.roomAlias in alternativeAliases
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.history
|
||||
|
||||
sealed interface RoomHistoryVisibility {
|
||||
/**
|
||||
* Previous events are accessible to newly joined members from the point
|
||||
* they were invited onwards.
|
||||
*
|
||||
* Events stop being accessible when the member's state changes to
|
||||
* something other than *invite* or *join*.
|
||||
*/
|
||||
data object Invited : RoomHistoryVisibility
|
||||
|
||||
/**
|
||||
* Previous events are accessible to newly joined members from the point
|
||||
* they joined the room onwards.
|
||||
* Events stop being accessible when the member's state changes to
|
||||
* something other than *join*.
|
||||
*/
|
||||
data object Joined : RoomHistoryVisibility
|
||||
|
||||
/**
|
||||
* Previous events are always accessible to newly joined members.
|
||||
*
|
||||
* All events in the room are accessible, even those sent when the member
|
||||
* was not a part of the room.
|
||||
*/
|
||||
data object Shared : RoomHistoryVisibility
|
||||
|
||||
/**
|
||||
* All events while this is the `HistoryVisibility` value may be shared by
|
||||
* any participating homeserver with anyone, regardless of whether they
|
||||
* have ever joined the room.
|
||||
*/
|
||||
data object WorldReadable : RoomHistoryVisibility
|
||||
|
||||
/**
|
||||
* A custom visibility value.
|
||||
*/
|
||||
data class Custom(val value: String) : RoomHistoryVisibility
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.roomdirectory
|
||||
|
||||
/**
|
||||
* Enum class representing the visibility of a room in the room directory.
|
||||
*/
|
||||
sealed interface RoomVisibility {
|
||||
/**
|
||||
* Indicates that the room will be shown in the published room list.
|
||||
*/
|
||||
data object Public : RoomVisibility
|
||||
|
||||
/**
|
||||
* Indicates that the room will not be shown in the published room list.
|
||||
*/
|
||||
data object Private : RoomVisibility
|
||||
|
||||
/**
|
||||
* A custom value that's not present in the spec.
|
||||
*/
|
||||
data class Custom(val value: String) : RoomVisibility
|
||||
}
|
||||
|
|
@ -23,9 +23,7 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
|||
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.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.JoinRuleOverride
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
|
|
@ -38,8 +36,10 @@ import io.element.android.libraries.matrix.api.room.PendingRoom
|
|||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||
|
|
@ -59,8 +59,10 @@ import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
|||
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomFactory
|
||||
import io.element.android.libraries.matrix.impl.room.TimelineEventTypeFilterFactory
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
|
||||
import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
|
||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||
|
|
@ -112,9 +114,7 @@ import kotlin.jvm.optionals.getOrNull
|
|||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import org.matrix.rustcomponents.sdk.CreateRoomParameters as RustCreateRoomParameters
|
||||
import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
|
||||
import org.matrix.rustcomponents.sdk.RoomPreset as RustRoomPreset
|
||||
import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
|
||||
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
||||
|
||||
class RustMatrixClient(
|
||||
|
|
@ -310,36 +310,23 @@ class RustMatrixClient(
|
|||
topic = createRoomParams.topic,
|
||||
isEncrypted = createRoomParams.isEncrypted,
|
||||
isDirect = createRoomParams.isDirect,
|
||||
visibility = when (createRoomParams.visibility) {
|
||||
RoomVisibility.PUBLIC -> RustRoomVisibility.Public
|
||||
RoomVisibility.PRIVATE -> RustRoomVisibility.Private
|
||||
},
|
||||
preset = when (createRoomParams.visibility) {
|
||||
RoomVisibility.PRIVATE -> {
|
||||
if (createRoomParams.isDirect) {
|
||||
RustRoomPreset.TRUSTED_PRIVATE_CHAT
|
||||
} else {
|
||||
RustRoomPreset.PRIVATE_CHAT
|
||||
}
|
||||
}
|
||||
RoomVisibility.PUBLIC -> {
|
||||
RustRoomPreset.PUBLIC_CHAT
|
||||
}
|
||||
visibility = createRoomParams.visibility.map(),
|
||||
preset = when (createRoomParams.preset) {
|
||||
RoomPreset.PRIVATE_CHAT -> RustRoomPreset.PRIVATE_CHAT
|
||||
RoomPreset.TRUSTED_PRIVATE_CHAT -> RustRoomPreset.TRUSTED_PRIVATE_CHAT
|
||||
RoomPreset.PUBLIC_CHAT -> RustRoomPreset.PUBLIC_CHAT
|
||||
},
|
||||
invite = createRoomParams.invite?.map { it.value },
|
||||
avatar = createRoomParams.avatar,
|
||||
powerLevelContentOverride = defaultRoomCreationPowerLevels.copy(
|
||||
invite = if (createRoomParams.joinRuleOverride == JoinRuleOverride.Knock) {
|
||||
invite = if (createRoomParams.joinRuleOverride == JoinRule.Knock) {
|
||||
// override the invite power level so it's the same as kick.
|
||||
RoomMember.Role.MODERATOR.powerLevel.toInt()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
),
|
||||
joinRuleOverride = when (createRoomParams.joinRuleOverride) {
|
||||
JoinRuleOverride.Knock -> RustJoinRule.Knock
|
||||
JoinRuleOverride.None -> null
|
||||
},
|
||||
joinRuleOverride = createRoomParams.joinRuleOverride?.map(),
|
||||
canonicalAlias = createRoomParams.roomAliasName.getOrNull(),
|
||||
)
|
||||
val roomId = RoomId(innerClient.createRoom(rustParams))
|
||||
|
|
@ -358,7 +345,7 @@ class RustMatrixClient(
|
|||
name = null,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
visibility = RoomVisibility.PRIVATE,
|
||||
visibility = RoomVisibility.Private,
|
||||
preset = RoomPreset.TRUSTED_PRIVATE_CHAT,
|
||||
invite = listOf(userId),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
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 kotlinx.collections.immutable.ImmutableMap
|
||||
|
|
@ -60,6 +61,7 @@ class MatrixRoomInfoMapper {
|
|||
numUnreadMessages = it.numUnreadMessages.toLong(),
|
||||
numUnreadMentions = it.numUnreadMentions.toLong(),
|
||||
numUnreadNotifications = it.numUnreadNotifications.toLong(),
|
||||
historyVisibility = it.historyVisibility.map(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,11 +38,14 @@ import io.element.android.libraries.matrix.api.room.RoomMember
|
|||
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.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
|
|
@ -51,10 +54,13 @@ import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
|||
import io.element.android.libraries.matrix.impl.core.RustSendHandle
|
||||
import io.element.android.libraries.matrix.impl.mapper.map
|
||||
import io.element.android.libraries.matrix.impl.room.draft.into
|
||||
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.knock.RustKnockRequest
|
||||
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.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.timeline.RustTimeline
|
||||
import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
|
||||
import io.element.android.libraries.matrix.impl.util.MessageEventContent
|
||||
|
|
@ -101,6 +107,7 @@ import org.matrix.rustcomponents.sdk.KnockRequest as InnerKnockRequest
|
|||
import org.matrix.rustcomponents.sdk.Room as InnerRoom
|
||||
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class RustMatrixRoom(
|
||||
override val sessionId: SessionId,
|
||||
private val deviceId: DeviceId,
|
||||
|
|
@ -306,7 +313,7 @@ class RustMatrixRoom(
|
|||
override val isEncrypted: Boolean
|
||||
get() = runCatching { innerRoom.isEncrypted() }.getOrDefault(false)
|
||||
|
||||
override val alias: RoomAlias?
|
||||
override val canonicalAlias: RoomAlias?
|
||||
get() = runCatching { innerRoom.canonicalAlias()?.let(::RoomAlias) }.getOrDefault(null)
|
||||
|
||||
override val alternativeAliases: List<RoomAlias>
|
||||
|
|
@ -805,6 +812,54 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun updateCanonicalAlias(canonicalAlias: RoomAlias?, alternativeAliases: List<RoomAlias>): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.updateCanonicalAlias(canonicalAlias?.value, alternativeAliases.map { it.value })
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.publishRoomAliasInRoomDirectory(roomAlias.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeRoomAliasFromRoomDirectory(roomAlias: RoomAlias): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.removeRoomAliasFromRoomDirectory(roomAlias.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateRoomVisibility(roomVisibility: RoomVisibility): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.updateRoomVisibility(roomVisibility.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateHistoryVisibility(historyVisibility: RoomHistoryVisibility): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.updateHistoryVisibility(historyVisibility.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.getRoomVisibility().map()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun enableEncryption(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.enableEncryption()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.updateJoinRules(joinRule.map())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTimeline(
|
||||
timeline: InnerTimeline,
|
||||
mode: Timeline.Mode,
|
||||
|
|
|
|||
|
|
@ -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.impl.room.history
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility
|
||||
|
||||
fun RoomHistoryVisibility.map(): RustRoomHistoryVisibility {
|
||||
return when (this) {
|
||||
RoomHistoryVisibility.WorldReadable -> RustRoomHistoryVisibility.WorldReadable
|
||||
RoomHistoryVisibility.Invited -> RustRoomHistoryVisibility.Invited
|
||||
RoomHistoryVisibility.Joined -> RustRoomHistoryVisibility.Joined
|
||||
RoomHistoryVisibility.Shared -> RustRoomHistoryVisibility.Shared
|
||||
is RoomHistoryVisibility.Custom -> RustRoomHistoryVisibility.Custom(value)
|
||||
}
|
||||
}
|
||||
|
||||
fun RustRoomHistoryVisibility.map(): RoomHistoryVisibility {
|
||||
return when (this) {
|
||||
RustRoomHistoryVisibility.WorldReadable -> RoomHistoryVisibility.WorldReadable
|
||||
RustRoomHistoryVisibility.Invited -> RoomHistoryVisibility.Invited
|
||||
RustRoomHistoryVisibility.Joined -> RoomHistoryVisibility.Joined
|
||||
RustRoomHistoryVisibility.Shared -> RoomHistoryVisibility.Shared
|
||||
is RustRoomHistoryVisibility.Custom -> RoomHistoryVisibility.Custom(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,3 +17,10 @@ fun RustAllowRule.map(): AllowRule {
|
|||
is RustAllowRule.Custom -> AllowRule.Custom(json)
|
||||
}
|
||||
}
|
||||
|
||||
fun AllowRule.map(): RustAllowRule {
|
||||
return when (this) {
|
||||
is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.toString())
|
||||
is AllowRule.Custom -> RustAllowRule.Custom(json)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,3 +21,15 @@ fun RustJoinRule.map(): JoinRule {
|
|||
is RustJoinRule.KnockRestricted -> JoinRule.KnockRestricted(rules.map { it.map() })
|
||||
}
|
||||
}
|
||||
|
||||
fun JoinRule.map(): RustJoinRule {
|
||||
return when (this) {
|
||||
JoinRule.Public -> RustJoinRule.Public
|
||||
JoinRule.Private -> RustJoinRule.Private
|
||||
JoinRule.Knock -> RustJoinRule.Knock
|
||||
JoinRule.Invite -> RustJoinRule.Invite
|
||||
is JoinRule.Restricted -> RustJoinRule.Restricted(rules.map { it.map() })
|
||||
is JoinRule.Custom -> RustJoinRule.Custom(value)
|
||||
is JoinRule.KnockRestricted -> RustJoinRule.KnockRestricted(rules.map { it.map() })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.roomdirectory
|
||||
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
|
||||
|
||||
fun RoomVisibility.map(): RustRoomVisibility {
|
||||
return when (this) {
|
||||
RoomVisibility.Public -> RustRoomVisibility.Public
|
||||
RoomVisibility.Private -> RustRoomVisibility.Private
|
||||
is RoomVisibility.Custom -> RustRoomVisibility.Custom(value)
|
||||
}
|
||||
}
|
||||
|
||||
fun RustRoomVisibility.map(): RoomVisibility {
|
||||
return when (this) {
|
||||
RustRoomVisibility.Public -> RoomVisibility.Public
|
||||
RustRoomVisibility.Private -> RoomVisibility.Private
|
||||
is RustRoomVisibility.Custom -> RoomVisibility.Custom(value)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ 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.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
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.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomHero
|
||||
|
|
@ -33,6 +34,7 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
import org.junit.Test
|
||||
import org.matrix.rustcomponents.sdk.Membership
|
||||
import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
|
||||
import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
|
||||
class MatrixRoomInfoMapperTest {
|
||||
|
|
@ -72,6 +74,7 @@ class MatrixRoomInfoMapperTest {
|
|||
numUnreadMentions = 14uL,
|
||||
pinnedEventIds = listOf(AN_EVENT_ID.value),
|
||||
roomCreator = A_USER_ID,
|
||||
historyVisibility = RustRoomHistoryVisibility.Joined,
|
||||
)
|
||||
)
|
||||
).isEqualTo(
|
||||
|
|
@ -113,6 +116,7 @@ class MatrixRoomInfoMapperTest {
|
|||
numUnreadMessages = 12L,
|
||||
numUnreadNotifications = 13L,
|
||||
numUnreadMentions = 14L,
|
||||
historyVisibility = RoomHistoryVisibility.Joined,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -188,6 +192,7 @@ class MatrixRoomInfoMapperTest {
|
|||
numUnreadMessages = 12L,
|
||||
numUnreadNotifications = 13L,
|
||||
numUnreadMentions = 14L,
|
||||
historyVisibility = RoomHistoryVisibility.Joined,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,10 +33,13 @@ import io.element.android.libraries.matrix.api.room.MessageEventType
|
|||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
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.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
|
|
@ -66,7 +69,7 @@ class FakeMatrixRoom(
|
|||
override val topic: String? = null,
|
||||
override val avatarUrl: String? = null,
|
||||
override var isEncrypted: Boolean = false,
|
||||
override val alias: RoomAlias? = null,
|
||||
override val canonicalAlias: RoomAlias? = null,
|
||||
override val alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
override val isPublic: Boolean = true,
|
||||
override val isSpace: Boolean = false,
|
||||
|
|
@ -145,6 +148,14 @@ class FakeMatrixRoom(
|
|||
private val subscribeToSyncLambda: () -> Unit = { lambdaError() },
|
||||
private val ignoreDeviceTrustAndResendResult: (Map<UserId, List<DeviceId>>, SendHandle) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val withdrawVerificationAndResendResult: (List<UserId>, SendHandle) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val updateCanonicalAliasResult: (RoomAlias?, List<RoomAlias>) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val updateRoomVisibilityResult: (RoomVisibility) -> Result<Unit> = { lambdaError() },
|
||||
private val updateRoomHistoryVisibilityResult: (RoomHistoryVisibility) -> Result<Unit> = { lambdaError() },
|
||||
private val roomVisibilityResult: () -> Result<RoomVisibility> = { lambdaError() },
|
||||
private val publishRoomAliasInRoomDirectoryResult: (RoomAlias) -> Result<Boolean> = { lambdaError() },
|
||||
private val removeRoomAliasFromRoomDirectoryResult: (RoomAlias) -> Result<Boolean> = { lambdaError() },
|
||||
private val enableEncryptionResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateJoinRuleResult: (JoinRule) -> Result<Unit> = { lambdaError() },
|
||||
) : MatrixRoom {
|
||||
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
|
||||
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
|
||||
|
|
@ -195,9 +206,11 @@ class FakeMatrixRoom(
|
|||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
fun enableEncryption() {
|
||||
isEncrypted = true
|
||||
emitSyncUpdate()
|
||||
override suspend fun enableEncryption(): Result<Unit> = simulateLongTask {
|
||||
enableEncryptionResult().onSuccess {
|
||||
isEncrypted = true
|
||||
emitSyncUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private val _syncUpdateFlow = MutableStateFlow(0L)
|
||||
|
|
@ -582,6 +595,34 @@ class FakeMatrixRoom(
|
|||
return withdrawVerificationAndResendResult(userIds, sendHandle)
|
||||
}
|
||||
|
||||
override suspend fun updateCanonicalAlias(canonicalAlias: RoomAlias?, alternativeAliases: List<RoomAlias>): Result<Unit> = simulateLongTask {
|
||||
updateCanonicalAliasResult(canonicalAlias, alternativeAliases)
|
||||
}
|
||||
|
||||
override suspend fun updateRoomVisibility(roomVisibility: RoomVisibility): Result<Unit> = simulateLongTask {
|
||||
updateRoomVisibilityResult(roomVisibility)
|
||||
}
|
||||
|
||||
override suspend fun updateHistoryVisibility(historyVisibility: RoomHistoryVisibility): Result<Unit> = simulateLongTask {
|
||||
updateRoomHistoryVisibilityResult(historyVisibility)
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = simulateLongTask {
|
||||
roomVisibilityResult()
|
||||
}
|
||||
|
||||
override suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean> = simulateLongTask {
|
||||
publishRoomAliasInRoomDirectoryResult(roomAlias)
|
||||
}
|
||||
|
||||
override suspend fun removeRoomAliasFromRoomDirectory(roomAlias: RoomAlias): Result<Boolean> = simulateLongTask {
|
||||
removeRoomAliasFromRoomDirectoryResult(roomAlias)
|
||||
}
|
||||
|
||||
override suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit> = simulateLongTask {
|
||||
updateJoinRuleResult(joinRule)
|
||||
}
|
||||
|
||||
fun givenRoomMembersState(state: MatrixRoomMembersState) {
|
||||
membersStateFlow.value = state
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
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.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
|
|
@ -58,6 +59,7 @@ fun aRoomInfo(
|
|||
numUnreadMessages: Long = 0,
|
||||
numUnreadNotifications: Long = 0,
|
||||
numUnreadMentions: Long = 0,
|
||||
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
|
||||
) = MatrixRoomInfo(
|
||||
id = id,
|
||||
name = name,
|
||||
|
|
@ -90,4 +92,5 @@ fun aRoomInfo(
|
|||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
historyVisibility = historyVisibility,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
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.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.roomlist.RoomSummary
|
||||
|
|
@ -71,6 +72,7 @@ fun aRoomSummary(
|
|||
numUnreadMessages: Long = 0,
|
||||
numUnreadNotifications: Long = 0,
|
||||
numUnreadMentions: Long = 0,
|
||||
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
) = RoomSummary(
|
||||
info = MatrixRoomInfo(
|
||||
|
|
@ -105,6 +107,7 @@ fun aRoomSummary(
|
|||
numUnreadMessages = numUnreadMessages,
|
||||
numUnreadNotifications = numUnreadNotifications,
|
||||
numUnreadMentions = numUnreadMentions,
|
||||
historyVisibility = historyVisibility,
|
||||
),
|
||||
lastMessage = lastMessage,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.ui.room.address
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun RoomAddressField(
|
||||
address: String,
|
||||
homeserverName: String,
|
||||
addressValidity: RoomAddressValidity,
|
||||
onAddressChange: (String) -> Unit,
|
||||
label: String,
|
||||
supportingText: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
TextField(
|
||||
modifier = modifier.testTag(TestTags.roomAddressField),
|
||||
value = address,
|
||||
label = label,
|
||||
leadingIcon = {
|
||||
Text(
|
||||
text = "#",
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
Text(
|
||||
text = homeserverName,
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
},
|
||||
supportingText = when (addressValidity) {
|
||||
RoomAddressValidity.InvalidSymbols -> {
|
||||
stringResource(CommonStrings.error_room_address_invalid_symbols)
|
||||
}
|
||||
RoomAddressValidity.NotAvailable -> {
|
||||
stringResource(CommonStrings.error_room_address_already_exists)
|
||||
}
|
||||
else -> supportingText
|
||||
},
|
||||
isError = addressValidity.isError(),
|
||||
onValueChange = onAddressChange,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun RoomAddressFieldPreview() = ElementPreview {
|
||||
RoomAddressField(
|
||||
address = "room",
|
||||
homeserverName = "element.io",
|
||||
addressValidity = RoomAddressValidity.Valid,
|
||||
onAddressChange = {},
|
||||
label = "Room address",
|
||||
supportingText = "This is the address that people will use to join your room",
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2024 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.ui.room.address
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
/**
|
||||
* Represents the validity state of a room address.
|
||||
* ie. whether it contains invalid characters, is already taken, or is valid.
|
||||
*/
|
||||
@Immutable
|
||||
sealed interface RoomAddressValidity {
|
||||
data object Unknown : RoomAddressValidity
|
||||
data object InvalidSymbols : RoomAddressValidity
|
||||
data object NotAvailable : RoomAddressValidity
|
||||
data object Valid : RoomAddressValidity
|
||||
|
||||
fun isError(): Boolean {
|
||||
return this is InvalidSymbols || this is NotAvailable
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.ui.room.address
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
|
||||
import io.element.android.libraries.matrix.api.roomAliasFromName
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun RoomAddressValidityEffect(
|
||||
client: MatrixClient,
|
||||
roomAliasHelper: RoomAliasHelper,
|
||||
newRoomAddress: String,
|
||||
knownRoomAddress: String?,
|
||||
onRoomAddressValidityChange: (RoomAddressValidity) -> Unit,
|
||||
) {
|
||||
val onChange by rememberUpdatedState(onRoomAddressValidityChange)
|
||||
LaunchedEffect(newRoomAddress) {
|
||||
if (newRoomAddress.isEmpty() || newRoomAddress == knownRoomAddress) {
|
||||
onChange(RoomAddressValidity.Unknown)
|
||||
return@LaunchedEffect
|
||||
}
|
||||
// debounce the room address validation
|
||||
delay(300)
|
||||
val roomAlias = client.roomAliasFromName(newRoomAddress).getOrNull()
|
||||
if (roomAlias == null || !roomAliasHelper.isRoomAliasValid(roomAlias)) {
|
||||
onChange(RoomAddressValidity.InvalidSymbols)
|
||||
} else {
|
||||
client.resolveRoomAlias(roomAlias)
|
||||
.onSuccess { resolved ->
|
||||
if (resolved.isPresent) {
|
||||
onChange(RoomAddressValidity.NotAvailable)
|
||||
} else {
|
||||
onChange(RoomAddressValidity.Valid)
|
||||
}
|
||||
}
|
||||
.onFailure {
|
||||
onChange(RoomAddressValidity.Valid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,4 +111,10 @@ object TestTags {
|
|||
* Generic call to action.
|
||||
*/
|
||||
val callToAction = TestTag("call_to_action")
|
||||
|
||||
/**
|
||||
* Room address field.
|
||||
*
|
||||
*/
|
||||
val roomAddressField = TestTag("room_address_field")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,8 +310,6 @@ Reason: %1$s."</string>
|
|||
<string name="invite_friends_text">"Hey, talk to me on %1$s: %2$s"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<string name="preference_rageshake">"Rageshake to report bug"</string>
|
||||
<string name="screen_edit_room_address_room_address_section_footer">"You’ll need a room address in order to make it visible in the directory."</string>
|
||||
<string name="screen_edit_room_address_title">"Room address"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string>
|
||||
<string name="screen_media_upload_preview_caption_warning">"Captions might not be visible to people using older apps."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
|
||||
|
|
@ -341,39 +339,6 @@ Reason: %1$s."</string>
|
|||
<string name="screen_room_pinned_banner_view_all_button_title">"View All"</string>
|
||||
<string name="screen_room_title">"Chat"</string>
|
||||
<string name="screen_roomlist_knock_event_sent_description">"Request to join sent"</string>
|
||||
<string name="screen_security_and_privacy_add_room_address_action">"Add room address"</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_description">"Anyone can ask to join the room but an administrator or moderator will have to accept the request."</string>
|
||||
<string name="screen_security_and_privacy_ask_to_join_option_title">"Ask to join"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Yes, enable encryption"</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Once enabled, encryption for a room cannot be disabled, Message history will only be visible for room members since they were invited or since they joined the room.
|
||||
No one besides the room members will be able to read messages. This may prevent bots and bridges to work correctly.
|
||||
We do not recommend enabling encryption for rooms that anyone can find and join."</string>
|
||||
<string name="screen_security_and_privacy_enable_encryption_alert_title">"Enable encryption?"</string>
|
||||
<string name="screen_security_and_privacy_encryption_section_footer">"Once enabled, encryption cannot be disabled."</string>
|
||||
<string name="screen_security_and_privacy_encryption_section_header">"Encryption"</string>
|
||||
<string name="screen_security_and_privacy_encryption_toggle_title">"Enable end-to-end encryption"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Anyone can find and join"</string>
|
||||
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Anyone"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"People can only join if they are invited"</string>
|
||||
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Invite only"</string>
|
||||
<string name="screen_security_and_privacy_room_access_section_header">"Room access"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_description">"Spaces are not currently supported"</string>
|
||||
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Space members"</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_footer">"You’ll need a room address in order to make it visible in the room directory."</string>
|
||||
<string name="screen_security_and_privacy_room_address_section_header">"Room address"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Allow for this room to be found by searching %1$s public room directory"</string>
|
||||
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Visible in public room directory"</string>
|
||||
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Anyone"</string>
|
||||
<string name="screen_security_and_privacy_room_history_section_header">"Who can read history"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Members only since they were invited"</string>
|
||||
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Members only since selecting this option"</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_footer">"Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.
|
||||
You can choose to publish your room in your homeserver public room directory."</string>
|
||||
<string name="screen_security_and_privacy_room_publishing_section_header">"Room publishing"</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_footer">"Room addresses are ways to find and access rooms. This also ensures you can easily share your room with others.
|
||||
The address is also required to make the room visible in %1$s public room directory."</string>
|
||||
<string name="screen_security_and_privacy_room_visibility_section_header">"Room visibility"</string>
|
||||
<string name="screen_security_and_privacy_title">"Security & privacy"</string>
|
||||
<string name="screen_share_location_title">"Share location"</string>
|
||||
<string name="screen_share_my_location_action">"Share my location"</string>
|
||||
<string name="screen_share_open_apple_maps">"Open in Apple Maps"</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue