Merge branch 'develop' into renovate/kotlin

This commit is contained in:
ganfra 2025-02-19 14:40:11 +01:00 committed by GitHub
commit b0d465e631
450 changed files with 4051 additions and 1909 deletions

View file

@ -20,7 +20,7 @@ jobs:
- run: | - run: |
npm install --save-dev @babel/plugin-transform-flow-strip-types npm install --save-dev @babel/plugin-transform-flow-strip-types
- name: Danger - name: Danger
uses: danger/danger-js@12.3.3 uses: danger/danger-js@12.3.4
with: with:
args: "--dangerfile ./tools/danger/dangerfile.js" args: "--dangerfile ./tools/danger/dangerfile.js"
env: env:

View file

@ -294,7 +294,7 @@ jobs:
yarn add danger-plugin-lint-report --dev yarn add danger-plugin-lint-report --dev
- name: Danger lint - name: Danger lint
if: always() if: always()
uses: danger/danger-js@12.3.3 uses: danger/danger-js@12.3.4
with: with:
args: "--dangerfile ./tools/danger/dangerfile-lint.js" args: "--dangerfile ./tools/danger/dangerfile-lint.js"
env: env:

View file

@ -25,6 +25,7 @@
<locale android:name="ru"/> <locale android:name="ru"/>
<locale android:name="sk"/> <locale android:name="sk"/>
<locale android:name="sv"/> <locale android:name="sv"/>
<locale android:name="tr"/>
<locale android:name="uk"/> <locale android:name="uk"/>
<locale android:name="uz"/> <locale android:name="uz"/>
<locale android:name="zh-CN"/> <locale android:name="zh-CN"/>

View file

@ -1,8 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<network-security-config> <network-security-config xmlns:tools="http://schemas.android.com/tools">
<!-- Ref: https://developer.android.com/training/articles/security-config.html --> <!-- Ref: https://developer.android.com/training/articles/security-config.html -->
<!-- By default, do not allow clearText traffic --> <!-- By default, do not allow clearText traffic -->
<base-config cleartextTrafficPermitted="false" /> <base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
<certificates
src="user"
tools:ignore="AcceptsUserCertificates" />
</trust-anchors>
</base-config>
<!-- Allow clearText traffic on some specified host --> <!-- Allow clearText traffic on some specified host -->
<domain-config cleartextTrafficPermitted="true"> <domain-config cleartextTrafficPermitted="true">
@ -24,12 +31,4 @@
<domain includeSubdomains="true">lan</domain> <domain includeSubdomains="true">lan</domain>
<domain includeSubdomains="true">localdomain</domain> <domain includeSubdomains="true">localdomain</domain>
</domain-config> </domain-config>
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config> </network-security-config>

View file

@ -75,7 +75,6 @@ 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.PermalinkData
import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails
import io.element.android.libraries.matrix.api.verification.SessionVerificationServiceListener import io.element.android.libraries.matrix.api.verification.SessionVerificationServiceListener
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.services.appnavstate.api.AppNavigationStateService import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -105,7 +104,6 @@ class LoggedInFlowNode @AssistedInject constructor(
private val sendingQueue: SendQueues, private val sendingQueue: SendQueues,
private val logoutEntryPoint: LogoutEntryPoint, private val logoutEntryPoint: LogoutEntryPoint,
private val incomingVerificationEntryPoint: IncomingVerificationEntryPoint, private val incomingVerificationEntryPoint: IncomingVerificationEntryPoint,
private val enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase,
snackbarDispatcher: SnackbarDispatcher, snackbarDispatcher: SnackbarDispatcher,
) : BaseFlowNode<LoggedInFlowNode.NavTarget>( ) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
@ -420,9 +418,6 @@ class LoggedInFlowNode @AssistedInject constructor(
} }
logoutEntryPoint.nodeBuilder(this, buildContext) logoutEntryPoint.nodeBuilder(this, buildContext)
.onSuccessfulLogoutPendingAction {
enableNativeSlidingSyncUseCase()
}
.callback(callback) .callback(callback)
.build() .build()
} }

View file

@ -7,6 +7,7 @@
package io.element.android.appnav.di package io.element.android.appnav.di
import androidx.annotation.VisibleForTesting
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
@ -21,9 +22,9 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
@ -53,13 +54,28 @@ class SyncOrchestrator @AssistedInject constructor(
* *
* Before observing the state, a first attempt at starting the sync service will happen if it's not already running. * Before observing the state, a first attempt at starting the sync service will happen if it's not already running.
*/ */
@OptIn(FlowPreview::class)
fun start() { fun start() {
if (!started.compareAndSet(false, true)) { if (!started.compareAndSet(false, true)) {
Timber.tag(tag).d("already started, exiting early") Timber.tag(tag).d("already started, exiting early")
return return
} }
coroutineScope.launch {
// Perform an initial sync if the sync service is not running, to check whether the homeserver is accessible
// Otherwise, if the device is offline the sync service will never start and the SyncState will be Idle, not Offline
Timber.tag(tag).d("performing initial sync attempt")
syncService.startSync()
// Wait until the sync service is not idle, either it will be running or in error/offline state
syncService.syncState.first { it != SyncState.Idle }
observeStates()
}
}
@OptIn(FlowPreview::class)
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun observeStates() = coroutineScope.launch {
Timber.tag(tag).d("start observing the app and network state") Timber.tag(tag).d("start observing the app and network state")
combine( combine(
@ -76,7 +92,7 @@ class SyncOrchestrator @AssistedInject constructor(
Timber.tag(tag).d("isAppActive=$isAppActive, isNetworkAvailable=$isNetworkAvailable") Timber.tag(tag).d("isAppActive=$isAppActive, isNetworkAvailable=$isNetworkAvailable")
if (syncState == SyncState.Running && !isAppActive) { if (syncState == SyncState.Running && !isAppActive) {
SyncStateAction.StopSync SyncStateAction.StopSync
} else if (syncState != SyncState.Running && isAppActive && isNetworkAvailable) { } else if (syncState == SyncState.Idle && isAppActive && isNetworkAvailable) {
SyncStateAction.StartSync SyncStateAction.StartSync
} else { } else {
SyncStateAction.NoOp SyncStateAction.NoOp
@ -87,7 +103,10 @@ class SyncOrchestrator @AssistedInject constructor(
// Don't stop the sync immediately, wait a bit to avoid starting/stopping the sync too often // Don't stop the sync immediately, wait a bit to avoid starting/stopping the sync too often
if (action == SyncStateAction.StopSync) 3.seconds else 0.seconds if (action == SyncStateAction.StopSync) 3.seconds else 0.seconds
} }
.onEach { action -> .onCompletion {
Timber.tag(tag).d("has been stopped")
}
.collect { action ->
when (action) { when (action) {
SyncStateAction.StartSync -> { SyncStateAction.StartSync -> {
syncService.startSync() syncService.startSync()
@ -98,10 +117,6 @@ class SyncOrchestrator @AssistedInject constructor(
SyncStateAction.NoOp -> Unit SyncStateAction.NoOp -> Unit
} }
} }
.onCompletion {
Timber.tag(tag).d("has been stopped")
}
.launchIn(coroutineScope)
} }
} }

View file

@ -22,6 +22,7 @@ import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.encryption.RecoveryState
@ -31,7 +32,6 @@ import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.sync.isOnline import io.element.android.libraries.matrix.api.sync.isOnline
import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.pushproviders.api.RegistrationFailure import io.element.android.libraries.pushproviders.api.RegistrationFailure
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
@ -51,7 +51,7 @@ class LoggedInPresenter @Inject constructor(
private val sessionVerificationService: SessionVerificationService, private val sessionVerificationService: SessionVerificationService,
private val analyticsService: AnalyticsService, private val analyticsService: AnalyticsService,
private val encryptionService: EncryptionService, private val encryptionService: EncryptionService,
private val enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase, private val buildMeta: BuildMeta,
) : Presenter<LoggedInState> { ) : Presenter<LoggedInState> {
@Composable @Composable
override fun present(): LoggedInState { override fun present(): LoggedInState {
@ -103,12 +103,10 @@ class LoggedInPresenter @Inject constructor(
} }
} }
LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch { LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch {
forceNativeSlidingSyncMigration = matrixClient.forceNativeSlidingSyncMigration().getOrDefault(false) forceNativeSlidingSyncMigration = matrixClient.needsForcedNativeSlidingSyncMigration().getOrDefault(false)
} }
LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch { LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch {
// Enable native sliding sync if it wasn't already the case // Force the logout since Native Sliding Sync is already enforced by the SDK
enableNativeSlidingSyncUseCase()
// Then force the logout
matrixClient.logout(userInitiated = true, ignoreSdkError = true) matrixClient.logout(userInitiated = true, ignoreSdkError = true)
} }
} }
@ -119,20 +117,15 @@ class LoggedInPresenter @Inject constructor(
pusherRegistrationState = pusherRegistrationState.value, pusherRegistrationState = pusherRegistrationState.value,
ignoreRegistrationError = ignoreRegistrationError, ignoreRegistrationError = ignoreRegistrationError,
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration, forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,
appName = buildMeta.applicationName,
eventSink = ::handleEvent eventSink = ::handleEvent
) )
} }
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is. // Force the user to log out if they were using the proxy sliding sync as it's no longer supported by the SDK
private suspend fun MatrixClient.forceNativeSlidingSyncMigration(): Result<Boolean> = runCatching { private suspend fun MatrixClient.needsForcedNativeSlidingSyncMigration(): Result<Boolean> = runCatching {
val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow() val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow()
if (currentSlidingSyncVersion == SlidingSyncVersion.Proxy) { currentSlidingSyncVersion == SlidingSyncVersion.Proxy
val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow()
availableSlidingSyncVersions.contains(SlidingSyncVersion.Native) &&
!availableSlidingSyncVersions.contains(SlidingSyncVersion.Proxy)
} else {
false
}
} }
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) { private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {

View file

@ -14,5 +14,6 @@ data class LoggedInState(
val pusherRegistrationState: AsyncData<Unit>, val pusherRegistrationState: AsyncData<Unit>,
val ignoreRegistrationError: Boolean, val ignoreRegistrationError: Boolean,
val forceNativeSlidingSyncMigration: Boolean, val forceNativeSlidingSyncMigration: Boolean,
val appName: String,
val eventSink: (LoggedInEvents) -> Unit, val eventSink: (LoggedInEvents) -> Unit,
) )

View file

@ -24,10 +24,12 @@ fun aLoggedInState(
showSyncSpinner: Boolean = false, showSyncSpinner: Boolean = false,
pusherRegistrationState: AsyncData<Unit> = AsyncData.Uninitialized, pusherRegistrationState: AsyncData<Unit> = AsyncData.Uninitialized,
forceNativeSlidingSyncMigration: Boolean = false, forceNativeSlidingSyncMigration: Boolean = false,
appName: String = "Element X",
) = LoggedInState( ) = LoggedInState(
showSyncSpinner = showSyncSpinner, showSyncSpinner = showSyncSpinner,
pusherRegistrationState = pusherRegistrationState, pusherRegistrationState = pusherRegistrationState,
ignoreRegistrationError = false, ignoreRegistrationError = false,
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration, forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,
appName = appName,
eventSink = {}, eventSink = {},
) )

View file

@ -73,9 +73,12 @@ fun LoggedInView(
// Set the force migration dialog here so it's always displayed over every screen // Set the force migration dialog here so it's always displayed over every screen
if (state.forceNativeSlidingSyncMigration) { if (state.forceNativeSlidingSyncMigration) {
ForceNativeSlidingSyncMigrationDialog(onSubmit = { ForceNativeSlidingSyncMigrationDialog(
state.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync) appName = state.appName,
}) onSubmit = {
state.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
}
)
} }
} }
@ -98,11 +101,12 @@ private fun Throwable.getReason(): String? {
@Composable @Composable
private fun ForceNativeSlidingSyncMigrationDialog( private fun ForceNativeSlidingSyncMigrationDialog(
appName: String,
onSubmit: () -> Unit, onSubmit: () -> Unit,
) { ) {
ErrorDialog( ErrorDialog(
title = null, title = null,
content = stringResource(R.string.banner_migrate_to_native_sliding_sync_force_logout_title), content = stringResource(R.string.banner_migrate_to_native_sliding_sync_app_force_logout_title, appName),
submitText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action), submitText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action),
onSubmit = onSubmit, onSubmit = onSubmit,
canDismiss = false, canDismiss = false,

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="banner_migrate_to_native_sliding_sync_action">ıkış Yap ve Yükselt"</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Ana sunucunuz artık eski protokolü desteklemiyor. Lütfen oturumu kapatın ve uygulamayı kullanmaya devam etmek için tekrar oturum açın."</string>
</resources>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="banner_migrate_to_native_sliding_sync_action">"Log Out &amp; Upgrade"</string> <string name="banner_migrate_to_native_sliding_sync_action">"Log Out &amp; Upgrade"</string>
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s no longer supports the old protocol. Please log out and log back in to continue using the app."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app."</string> <string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app."</string>
</resources> </resources>

View file

@ -31,6 +31,50 @@ class SyncOrchestratorTest {
@get:Rule @get:Rule
val warmUpRule = WarmUpRule() val warmUpRule = WarmUpRule()
@Test
fun `when the sync wasn't running before, an initial sync will take place, even with no network`() = runTest {
val startSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val syncService = FakeSyncService(initialSyncState = SyncState.Idle).apply {
startSyncLambda = startSyncRecorder
}
val networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Disconnected)
val syncOrchestrator = createSyncOrchestrator(
syncService = syncService,
networkMonitor = networkMonitor,
)
// We start observing with an initial sync
syncOrchestrator.start()
// Advance the time just enough to make sure the initial sync has run
advanceTimeBy(1.milliseconds)
startSyncRecorder.assertions().isCalledOnce()
}
@Test
fun `when the sync wasn't running before, an initial sync will take place`() = runTest {
val startSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
val syncService = FakeSyncService(initialSyncState = SyncState.Idle).apply {
startSyncLambda = startSyncRecorder
}
val networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Connected)
val syncOrchestrator = createSyncOrchestrator(
syncService = syncService,
networkMonitor = networkMonitor,
)
// We start observing with an initial sync
syncOrchestrator.start()
// Advance the time just enough to make sure the initial sync has run
advanceTimeBy(1.milliseconds)
startSyncRecorder.assertions().isCalledOnce()
// If we wait for a while, the sync will not be started again by the observer since it's already running
advanceTimeBy(10.seconds)
startSyncRecorder.assertions().isCalledOnce()
}
@Test @Test
fun `when the app goes to background and the sync was running, it will be stopped after a delay`() = runTest { fun `when the app goes to background and the sync was running, it will be stopped after a delay`() = runTest {
val stopSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) } val stopSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
@ -46,7 +90,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -78,7 +122,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -126,7 +170,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -169,7 +213,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -213,7 +257,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -256,7 +300,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// Advance the time to make sure the orchestrator has had time to start processing the inputs // Advance the time to make sure the orchestrator has had time to start processing the inputs
advanceTimeBy(100.milliseconds) advanceTimeBy(100.milliseconds)
@ -285,7 +329,7 @@ class SyncOrchestratorTest {
) )
// We start observing // We start observing
syncOrchestrator.start() syncOrchestrator.observeStates()
// This should still not trigger a sync, since there is no network // This should still not trigger a sync, since there is no network
advanceTimeBy(10.seconds) advanceTimeBy(10.seconds)

View file

@ -14,6 +14,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.CryptoSessionStateChange import im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
@ -26,12 +27,11 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.push.test.FakePushService import io.element.android.libraries.push.test.FakePushService
import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.Distributor
@ -46,7 +46,6 @@ import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -92,6 +91,7 @@ class LoggedInPresenterTest {
val roomListService = FakeRoomListService() val roomListService = FakeRoomListService()
val verificationService = FakeSessionVerificationService() val verificationService = FakeSessionVerificationService()
val encryptionService = FakeEncryptionService() val encryptionService = FakeEncryptionService()
val buildMeta = aBuildMeta()
val presenter = LoggedInPresenter( val presenter = LoggedInPresenter(
matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService), matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
syncService = FakeSyncService(initialSyncState = SyncState.Running), syncService = FakeSyncService(initialSyncState = SyncState.Running),
@ -99,7 +99,7 @@ class LoggedInPresenterTest {
sessionVerificationService = verificationService, sessionVerificationService = verificationService,
analyticsService = analyticsService, analyticsService = analyticsService,
encryptionService = encryptionService, encryptionService = encryptionService,
enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this), buildMeta = buildMeta,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -518,28 +518,9 @@ class LoggedInPresenterTest {
} }
} }
@Test
fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest {
val matrixClient = FakeMatrixClient(
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
availableSlidingSyncVersionsLambda = { Result.success(emptyList()) },
)
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability)
expectNoEvents()
}
}
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@Test @Test
fun `present - LogoutAndMigrateToNativeSlidingSync enables native sliding sync and logs out the user`() = runTest { fun `present - LogoutAndMigrateToNativeSlidingSync logs out the user`() = runTest {
val logoutLambda = lambdaRecorder<Boolean, Boolean, String?> { userInitiated, ignoreSdkError -> val logoutLambda = lambdaRecorder<Boolean, Boolean, String?> { userInitiated, ignoreSdkError ->
assertThat(userInitiated).isTrue() assertThat(userInitiated).isTrue()
assertThat(ignoreSdkError).isTrue() assertThat(ignoreSdkError).isTrue()
@ -548,21 +529,16 @@ class LoggedInPresenterTest {
val matrixClient = FakeMatrixClient().apply { val matrixClient = FakeMatrixClient().apply {
this.logoutLambda = logoutLambda this.logoutLambda = logoutLambda
} }
val appPreferencesStore = InMemoryAppPreferencesStore() val presenter = createLoggedInPresenter(matrixClient = matrixClient)
val enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(appPreferencesStore, this)
val presenter = createLoggedInPresenter(matrixClient = matrixClient, enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse()
initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync) initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
advanceUntilIdle() advanceUntilIdle()
assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue()
assertThat(logoutLambda.assertions().isCalledOnce()) assertThat(logoutLambda.assertions().isCalledOnce())
} }
} }
@ -579,8 +555,8 @@ class LoggedInPresenterTest {
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(), sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
encryptionService: EncryptionService = FakeEncryptionService(), encryptionService: EncryptionService = FakeEncryptionService(),
pushService: PushService = FakePushService(), pushService: PushService = FakePushService(),
enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this),
matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService), matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService),
buildMeta: BuildMeta = aBuildMeta(),
): LoggedInPresenter { ): LoggedInPresenter {
return LoggedInPresenter( return LoggedInPresenter(
matrixClient = matrixClient, matrixClient = matrixClient,
@ -589,7 +565,7 @@ class LoggedInPresenterTest {
sessionVerificationService = sessionVerificationService, sessionVerificationService = sessionVerificationService,
analyticsService = analyticsService, analyticsService = analyticsService,
encryptionService = encryptionService, encryptionService = encryptionService,
enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase, buildMeta = buildMeta,
) )
} }
} }

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_settings_help_us_improve">"Sorunları tanımlamamıza yardımcı olmak için anonim kullanım verilerini paylaşın."</string>
<string name="screen_analytics_settings_read_terms">"Tüm şartlarımızı okuyabilirsiniz %1$s."</string>
<string name="screen_analytics_settings_read_terms_content_link">"burada"</string>
<string name="screen_analytics_settings_share_data">"Analitik verileri paylaşın"</string>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_analytics_prompt_data_usage">"Hiçbir kişisel veriyi kaydetmeyeceğiz veya profillemeyeceğiz"</string>
<string name="screen_analytics_prompt_help_us_improve">"Sorunları tanımlamamıza yardımcı olmak için anonim kullanım verilerini paylaşın."</string>
<string name="screen_analytics_prompt_read_terms">"Tüm şartlarımızı okuyabilirsiniz %1$s."</string>
<string name="screen_analytics_prompt_read_terms_content_link">"burada"</string>
<string name="screen_analytics_prompt_settings">"Bu özelliği istediğiniz zaman kapatabilirsiniz"</string>
<string name="screen_analytics_prompt_third_party_sharing">"Verilerinizi üçüncü taraflarla paylaşmayacağız"</string>
<string name="screen_analytics_prompt_title">"%1$s geliştirilmesine yardımcı olun"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Devam eden çağrı"</string>
<string name="call_foreground_service_message_android">"Aramaya geri dönmek için dokunun"</string>
<string name="call_foreground_service_title_android">"☎️ Çağrı devam ediyor"</string>
<string name="screen_incoming_call_subtitle_android">"Gelen Element Call"</string>
</resources>

View file

@ -6,7 +6,7 @@
<string name="screen_create_room_private_option_description">"Паведамленні ў гэтым пакоі зашыфраваны. Гэта шыфраванне нельга адключыць."</string> <string name="screen_create_room_private_option_description">"Паведамленні ў гэтым пакоі зашыфраваны. Гэта шыфраванне нельга адключыць."</string>
<string name="screen_create_room_private_option_title">"Прыватны пакой (толькі па запрашэнні)"</string> <string name="screen_create_room_private_option_title">"Прыватны пакой (толькі па запрашэнні)"</string>
<string name="screen_create_room_public_option_description">"Паведамленні не зашыфраваны, і кожны можа іх прачытаць. Вы можаце ўключыць шыфраванне пазней."</string> <string name="screen_create_room_public_option_description">"Паведамленні не зашыфраваны, і кожны можа іх прачытаць. Вы можаце ўключыць шыфраванне пазней."</string>
<string name="screen_create_room_public_option_title">"Публічны пакой (для ўсіх)"</string> <string name="screen_create_room_public_option_title">"Публічны пакой"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"Хто заўгодна"</string> <string name="screen_create_room_room_access_section_anyone_option_title">"Хто заўгодна"</string>
<string name="screen_create_room_room_access_section_header">"Доступ у пакой"</string> <string name="screen_create_room_room_access_section_header">"Доступ у пакой"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Папрасіце далучыцца"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Папрасіце далучыцца"</string>

View file

@ -6,7 +6,6 @@
<string name="screen_create_room_private_option_description">"Съобщенията в тази стая са шифровани. Шифроването не може да бъде изключено впоследствие."</string> <string name="screen_create_room_private_option_description">"Съобщенията в тази стая са шифровани. Шифроването не може да бъде изключено впоследствие."</string>
<string name="screen_create_room_private_option_title">"Частна стая (само с покана)"</string> <string name="screen_create_room_private_option_title">"Частна стая (само с покана)"</string>
<string name="screen_create_room_public_option_description">"Съобщенията не са шифровани и всеки може да ги прочете. Можете да активирате шифроването на по-късна дата."</string> <string name="screen_create_room_public_option_description">"Съобщенията не са шифровани и всеки може да ги прочете. Можете да активирате шифроването на по-късна дата."</string>
<string name="screen_create_room_public_option_title">"Публична стая (всеки)"</string>
<string name="screen_create_room_room_name_label">"Име на стаята"</string> <string name="screen_create_room_room_name_label">"Име на стаята"</string>
<string name="screen_create_room_title">"Създаване на стая"</string> <string name="screen_create_room_title">"Създаване на стая"</string>
<string name="screen_create_room_topic_label">"Тема за разговор (незадължително)"</string> <string name="screen_create_room_topic_label">"Тема за разговор (незадължително)"</string>

View file

@ -7,14 +7,14 @@
<string name="screen_create_room_private_option_title">"Privater Chatroom"</string> <string name="screen_create_room_private_option_title">"Privater Chatroom"</string>
<string name="screen_create_room_public_option_description">"Jeder kann diesen Chatroom finden. <string name="screen_create_room_public_option_description">"Jeder kann diesen Chatroom finden.
Sie können dies aber jederzeit in den Chatroomeinstellungen ändern."</string> Sie können dies aber jederzeit in den Chatroomeinstellungen ändern."</string>
<string name="screen_create_room_public_option_title">"Öffentlicher Chatroom"</string> <string name="screen_create_room_public_option_title">"Öffentlicher Raum"</string>
<string name="screen_create_room_room_access_section_anyone_option_description">"Jeder kann diesem Chatroom beitreten"</string> <string name="screen_create_room_room_access_section_anyone_option_description">"Jeder kann diesem Chatroom beitreten"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"Jemand"</string> <string name="screen_create_room_room_access_section_anyone_option_title">"Jemand"</string>
<string name="screen_create_room_room_access_section_header">"Chatroom Zugang"</string> <string name="screen_create_room_room_access_section_header">"Chatroom Zugang"</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Jeder kann darum bitten, dem Chatroom beizutreten, aber ein Administrator oder ein Moderator muss die Anfrage akzeptieren."</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Jeder kann darum bitten, dem Chatroom beizutreten, aber ein Administrator oder ein Moderator muss die Anfrage akzeptieren."</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Beitritt beantragen"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Beitritt beantragen"</string>
<string name="screen_create_room_room_address_section_footer">"Damit dieser Chatroom im öffentlichen Chatroomverzeichnis sichtbar ist, benötigen Sie eine Chatroomadresse."</string> <string name="screen_create_room_room_address_section_footer">"Damit dieser Chatroom im öffentlichen Chatroomverzeichnis sichtbar ist, benötigen Sie eine Chatroomadresse."</string>
<string name="screen_create_room_room_address_section_title">"Chatroom Adresse"</string> <string name="screen_create_room_room_address_section_title">"Chatroomadresse"</string>
<string name="screen_create_room_room_name_label">"Raumname"</string> <string name="screen_create_room_room_name_label">"Raumname"</string>
<string name="screen_create_room_room_visibility_section_title">" Sichtbarkeit des Chatrooms"</string> <string name="screen_create_room_room_visibility_section_title">" Sichtbarkeit des Chatrooms"</string>
<string name="screen_create_room_title">"Raum erstellen"</string> <string name="screen_create_room_title">"Raum erstellen"</string>

View file

@ -14,7 +14,6 @@
<string name="screen_create_room_room_access_section_knocking_option_description">"Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στο δωμάτιο, αλλά ένας διαχειριστής ή συντονιστής θα πρέπει να αποδεχθεί το αίτημα"</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στο δωμάτιο, αλλά ένας διαχειριστής ή συντονιστής θα πρέπει να αποδεχθεί το αίτημα"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Αίτημα συμμετοχής"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Αίτημα συμμετοχής"</string>
<string name="screen_create_room_room_address_section_footer">"Για να είναι ορατό αυτό το δωμάτιο στον κατάλογο των δημόσιων δωματίων, θα χρειαστείς μια διεύθυνση δωματίου."</string> <string name="screen_create_room_room_address_section_footer">"Για να είναι ορατό αυτό το δωμάτιο στον κατάλογο των δημόσιων δωματίων, θα χρειαστείς μια διεύθυνση δωματίου."</string>
<string name="screen_create_room_room_address_section_title">"Διεύθυνση δωματίου"</string>
<string name="screen_create_room_room_name_label">"Όνομα δωματίου"</string> <string name="screen_create_room_room_name_label">"Όνομα δωματίου"</string>
<string name="screen_create_room_room_visibility_section_title">"Ορατότητα δωματίου"</string> <string name="screen_create_room_room_visibility_section_title">"Ορατότητα δωματίου"</string>
<string name="screen_create_room_title">"Δημιούργησε ένα δωμάτιο"</string> <string name="screen_create_room_title">"Δημιούργησε ένα δωμάτιο"</string>

View file

@ -6,7 +6,6 @@
<string name="screen_create_room_private_option_description">"Los mensajes de esta sala están cifrados. La encriptación no se puede desactivar después."</string> <string name="screen_create_room_private_option_description">"Los mensajes de esta sala están cifrados. La encriptación no se puede desactivar después."</string>
<string name="screen_create_room_private_option_title">"Sala privada (sólo con invitación)"</string> <string name="screen_create_room_private_option_title">"Sala privada (sólo con invitación)"</string>
<string name="screen_create_room_public_option_description">"Los mensajes no están cifrados y cualquiera puede leerlos. Puedes activar la encriptación más adelante."</string> <string name="screen_create_room_public_option_description">"Los mensajes no están cifrados y cualquiera puede leerlos. Puedes activar la encriptación más adelante."</string>
<string name="screen_create_room_public_option_title">"Sala pública (cualquiera)"</string>
<string name="screen_create_room_room_name_label">"Nombre de la sala"</string> <string name="screen_create_room_room_name_label">"Nombre de la sala"</string>
<string name="screen_create_room_title">"Crear una sala"</string> <string name="screen_create_room_title">"Crear una sala"</string>
<string name="screen_create_room_topic_label">"Tema (opcional)"</string> <string name="screen_create_room_topic_label">"Tema (opcional)"</string>

View file

@ -6,7 +6,7 @@
<string name="screen_create_room_private_option_description">"پیام‌های این اتاق رمز شده‌اند. رمزنگاری نمی‌تواند از این پس تغییر کند."</string> <string name="screen_create_room_private_option_description">"پیام‌های این اتاق رمز شده‌اند. رمزنگاری نمی‌تواند از این پس تغییر کند."</string>
<string name="screen_create_room_private_option_title">"اتاق خصوصی (فقط دعوت)"</string> <string name="screen_create_room_private_option_title">"اتاق خصوصی (فقط دعوت)"</string>
<string name="screen_create_room_public_option_description">"پیام‌ها رمزنگاری نشده و هرکسی می‌تواند بخواندشان. می‌توانید بعداً رمزنگاری را به کار بیندازید."</string> <string name="screen_create_room_public_option_description">"پیام‌ها رمزنگاری نشده و هرکسی می‌تواند بخواندشان. می‌توانید بعداً رمزنگاری را به کار بیندازید."</string>
<string name="screen_create_room_public_option_title">"اتاق عمومی (هرکسی)"</string> <string name="screen_create_room_public_option_title">"اتاق عمومی"</string>
<string name="screen_create_room_room_name_label">"نام اتاق"</string> <string name="screen_create_room_room_name_label">"نام اتاق"</string>
<string name="screen_create_room_title">"ایجاد اتاق"</string> <string name="screen_create_room_title">"ایجاد اتاق"</string>
<string name="screen_create_room_topic_label">"موضوع (اختیاری)"</string> <string name="screen_create_room_topic_label">"موضوع (اختیاری)"</string>

View file

@ -14,7 +14,7 @@ Ezt bármikor módosíthatja a szobabeállításokban."</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Bárki kérheti, hogy csatlakozzon a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést"</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Bárki kérheti, hogy csatlakozzon a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Csatlakozás kérése"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Csatlakozás kérése"</string>
<string name="screen_create_room_room_address_section_footer">"Ahhoz, hogy ez a szoba látható legyen a nyilvános szobák címtárában, meg kell adnia a szoba címét."</string> <string name="screen_create_room_room_address_section_footer">"Ahhoz, hogy ez a szoba látható legyen a nyilvános szobák címtárában, meg kell adnia a szoba címét."</string>
<string name="screen_create_room_room_address_section_title">"Szoba címe"</string> <string name="screen_create_room_room_address_section_title">"A szoba címe"</string>
<string name="screen_create_room_room_name_label">"Szoba neve"</string> <string name="screen_create_room_room_name_label">"Szoba neve"</string>
<string name="screen_create_room_room_visibility_section_title">"Szoba láthatósága"</string> <string name="screen_create_room_room_visibility_section_title">"Szoba láthatósága"</string>
<string name="screen_create_room_title">"Szoba létrehozása"</string> <string name="screen_create_room_title">"Szoba létrehozása"</string>

View file

@ -14,7 +14,6 @@ Anda dapat mengubah ini kapan pun dalam pengaturan ruangan."</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Siapa pun dapat meminta untuk bergabung dengan ruangan tetapi administrator atau moderator harus menerima permintaan tersebut"</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Siapa pun dapat meminta untuk bergabung dengan ruangan tetapi administrator atau moderator harus menerima permintaan tersebut"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Minta untuk bergabung"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Minta untuk bergabung"</string>
<string name="screen_create_room_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string> <string name="screen_create_room_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_create_room_room_address_section_title">"Alamat ruangan"</string>
<string name="screen_create_room_room_name_label">"Nama ruangan"</string> <string name="screen_create_room_room_name_label">"Nama ruangan"</string>
<string name="screen_create_room_room_visibility_section_title">"Keterlihatan ruangan"</string> <string name="screen_create_room_room_visibility_section_title">"Keterlihatan ruangan"</string>
<string name="screen_create_room_title">"Buat ruangan"</string> <string name="screen_create_room_title">"Buat ruangan"</string>

View file

@ -7,7 +7,6 @@
<string name="screen_create_room_private_option_title">"კერძო ოთახი"</string> <string name="screen_create_room_private_option_title">"კერძო ოთახი"</string>
<string name="screen_create_room_public_option_description">"ყველას ამ ოთახის მოძებნა შეუძლია. <string name="screen_create_room_public_option_description">"ყველას ამ ოთახის მოძებნა შეუძლია.
თქვენ ნებისმიერ დროს შეგიძლიათ ამის შეცვლა ოთახის პარამეტრებში."</string> თქვენ ნებისმიერ დროს შეგიძლიათ ამის შეცვლა ოთახის პარამეტრებში."</string>
<string name="screen_create_room_public_option_title">"საჯარო ოთახი"</string>
<string name="screen_create_room_room_name_label">"ოთახის სახელი"</string> <string name="screen_create_room_room_name_label">"ოთახის სახელი"</string>
<string name="screen_create_room_title">"ოთახის შექმნა"</string> <string name="screen_create_room_title">"ოთახის შექმნა"</string>
<string name="screen_create_room_topic_label">"თემა (სურვილისამებრ)"</string> <string name="screen_create_room_topic_label">"თემა (სურვილისამებრ)"</string>

View file

@ -7,7 +7,6 @@
<string name="screen_create_room_private_option_title">"Sala privativa (somente por convite)"</string> <string name="screen_create_room_private_option_title">"Sala privativa (somente por convite)"</string>
<string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala. <string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala.
Você pode mudar isso a qualquer momento nas configurações da sala."</string> Você pode mudar isso a qualquer momento nas configurações da sala."</string>
<string name="screen_create_room_public_option_title">"Sala pública (qualquer pessoa)"</string>
<string name="screen_create_room_room_name_label">"Nome da sala"</string> <string name="screen_create_room_room_name_label">"Nome da sala"</string>
<string name="screen_create_room_title">"Criar uma sala"</string> <string name="screen_create_room_title">"Criar uma sala"</string>
<string name="screen_create_room_topic_label">"Tópico (opcional)"</string> <string name="screen_create_room_topic_label">"Tópico (opcional)"</string>

View file

@ -3,7 +3,7 @@
<string name="screen_create_room_action_create_room">"Nova sala"</string> <string name="screen_create_room_action_create_room">"Nova sala"</string>
<string name="screen_create_room_add_people_title">"Convidar pessoas"</string> <string name="screen_create_room_add_people_title">"Convidar pessoas"</string>
<string name="screen_create_room_error_creating_room">"Ocorreu um erro ao criar a sala"</string> <string name="screen_create_room_error_creating_room">"Ocorreu um erro ao criar a sala"</string>
<string name="screen_create_room_private_option_description">"Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são encriptadas ponta a ponta."</string> <string name="screen_create_room_private_option_description">"Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são cifradas ponta-a-ponta."</string>
<string name="screen_create_room_private_option_title">"Sala privada"</string> <string name="screen_create_room_private_option_title">"Sala privada"</string>
<string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala. <string name="screen_create_room_public_option_description">"Qualquer um pode encontrar esta sala.
Pode alterar esta opção nas definições da sala."</string> Pode alterar esta opção nas definições da sala."</string>

View file

@ -14,7 +14,6 @@ Puteți modifica acest lucru oricând în setări."</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Oricine poate cere să se alăture camerei, dar un administrator sau un moderator va trebui să accepte solicitarea"</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Oricine poate cere să se alăture camerei, dar un administrator sau un moderator va trebui să accepte solicitarea"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Cereți să vă alăturați"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Cereți să vă alăturați"</string>
<string name="screen_create_room_room_address_section_footer">"Pentru ca această cameră să fie vizibilă în directorul de camere publice, veți avea nevoie de o adresă de cameră."</string> <string name="screen_create_room_room_address_section_footer">"Pentru ca această cameră să fie vizibilă în directorul de camere publice, veți avea nevoie de o adresă de cameră."</string>
<string name="screen_create_room_room_address_section_title">"Adresa camerei"</string>
<string name="screen_create_room_room_name_label">"Numele camerei"</string> <string name="screen_create_room_room_name_label">"Numele camerei"</string>
<string name="screen_create_room_title">"Creați o cameră"</string> <string name="screen_create_room_title">"Creați o cameră"</string>
<string name="screen_create_room_topic_label">"Subiect (opțional)"</string> <string name="screen_create_room_topic_label">"Subiect (opțional)"</string>

View file

@ -13,7 +13,9 @@ Du kan ändra detta när som helst i rumsinställningarna."</string>
<string name="screen_create_room_room_access_section_header">"Rumsåtkomst"</string> <string name="screen_create_room_room_access_section_header">"Rumsåtkomst"</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Vem som helst kan be om att gå med i rummet men en administratör eller en moderator måste acceptera begäran"</string> <string name="screen_create_room_room_access_section_knocking_option_description">"Vem som helst kan be om att gå med i rummet men en administratör eller en moderator måste acceptera begäran"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Be om att gå med"</string> <string name="screen_create_room_room_access_section_knocking_option_title">"Be om att gå med"</string>
<string name="screen_create_room_room_address_section_footer">"För att detta rum ska vara synligt i den allmänna rumskatalogen behöver du en rumsadress."</string>
<string name="screen_create_room_room_name_label">"Rumsnamn"</string> <string name="screen_create_room_room_name_label">"Rumsnamn"</string>
<string name="screen_create_room_room_visibility_section_title">"Rumssynlighet"</string>
<string name="screen_create_room_title">"Skapa ett rum"</string> <string name="screen_create_room_title">"Skapa ett rum"</string>
<string name="screen_create_room_topic_label">"Ämne (valfritt)"</string> <string name="screen_create_room_topic_label">"Ämne (valfritt)"</string>
<string name="screen_start_chat_error_starting_chat">"Ett fel uppstod när du försökte starta en chatt"</string> <string name="screen_start_chat_error_starting_chat">"Ett fel uppstod när du försökte starta en chatt"</string>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_create_room_action_create_room">"Yeni oda"</string>
<string name="screen_create_room_add_people_title">"İnsanları davet et"</string>
<string name="screen_create_room_error_creating_room">"Oda oluşturulurken bir hata oluştu"</string>
<string name="screen_create_room_private_option_description">"Bu odaya yalnızca davet edilen kişiler erişebilir. Tüm mesajlar uçtan uca şifrelenir."</string>
<string name="screen_create_room_private_option_title">"Özel oda"</string>
<string name="screen_create_room_public_option_description">"Bu odayı herkes bulabilir.
Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz."</string>
<string name="screen_create_room_public_option_title">"Herkese açık oda"</string>
<string name="screen_create_room_room_access_section_anyone_option_description">"Bu odaya herkes katılabilir"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"Herkes"</string>
<string name="screen_create_room_room_access_section_header">"Oda Erişimi"</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Herkes odaya katılmayı isteyebilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekecektir"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Katılmak için sor"</string>
<string name="screen_create_room_room_address_section_footer">"Bu odanın genel oda dizininde görünür olması için bir oda adresine ihtiyacınız olacaktır."</string>
<string name="screen_create_room_room_address_section_title">"Oda adresi"</string>
<string name="screen_create_room_room_name_label">"Oda adı"</string>
<string name="screen_create_room_room_visibility_section_title">"Oda görünürlüğü"</string>
<string name="screen_create_room_title">"Bir oda oluştur"</string>
<string name="screen_create_room_topic_label">"Konu (isteğe bağlı)"</string>
<string name="screen_start_chat_error_starting_chat">"Sohbet başlatmaya çalışırken bir hata oluştu"</string>
</resources>

View file

@ -7,7 +7,7 @@
<string name="screen_create_room_private_option_title">"Приватна кімната (тільки за запрошенням)"</string> <string name="screen_create_room_private_option_title">"Приватна кімната (тільки за запрошенням)"</string>
<string name="screen_create_room_public_option_description">"Будь-хто може знайти цю кімнату. <string name="screen_create_room_public_option_description">"Будь-хто може знайти цю кімнату.
Ви можете змінити це в будь-який час у налаштуваннях кімнати."</string> Ви можете змінити це в будь-який час у налаштуваннях кімнати."</string>
<string name="screen_create_room_public_option_title">"Публічна кімната"</string> <string name="screen_create_room_public_option_title">"Загальнодоступна кімната"</string>
<string name="screen_create_room_room_access_section_anyone_option_description">"Будь-хто може приєднатися до цієї кімнати"</string> <string name="screen_create_room_room_access_section_anyone_option_description">"Будь-хто може приєднатися до цієї кімнати"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"Кожний"</string> <string name="screen_create_room_room_access_section_anyone_option_title">"Кожний"</string>
<string name="screen_create_room_room_access_section_header">"Доступ до кімнати"</string> <string name="screen_create_room_room_access_section_header">"Доступ до кімнати"</string>

View file

@ -6,7 +6,6 @@
<string name="screen_create_room_private_option_description">"Bu xonadagi xabarlar shifrlangan. Keyinchalik shifrlashni ochirib bolmaydi."</string> <string name="screen_create_room_private_option_description">"Bu xonadagi xabarlar shifrlangan. Keyinchalik shifrlashni ochirib bolmaydi."</string>
<string name="screen_create_room_private_option_title">"Shaxsiy xona (faqat taklif)"</string> <string name="screen_create_room_private_option_title">"Shaxsiy xona (faqat taklif)"</string>
<string name="screen_create_room_public_option_description">"Xabarlar shifrlanmagan va har kim ularni o\'qiy oladi. Keyinchalik shifrlashni yoqishingiz mumkin."</string> <string name="screen_create_room_public_option_description">"Xabarlar shifrlanmagan va har kim ularni o\'qiy oladi. Keyinchalik shifrlashni yoqishingiz mumkin."</string>
<string name="screen_create_room_public_option_title">"Jamoat xonasi (har kim)"</string>
<string name="screen_create_room_room_name_label">"Xona nomi"</string> <string name="screen_create_room_room_name_label">"Xona nomi"</string>
<string name="screen_create_room_title">"Xonani yaratish"</string> <string name="screen_create_room_title">"Xonani yaratish"</string>
<string name="screen_create_room_topic_label">"Mavzu (ixtiyoriy)"</string> <string name="screen_create_room_topic_label">"Mavzu (ixtiyoriy)"</string>

View file

@ -7,7 +7,7 @@
<string name="screen_create_room_private_option_title">"私密聊天室"</string> <string name="screen_create_room_private_option_title">"私密聊天室"</string>
<string name="screen_create_room_public_option_description">"任何人都可以找到此聊天室。 <string name="screen_create_room_public_option_description">"任何人都可以找到此聊天室。
您隨時都可以在聊天室設定中變更此設定。"</string> 您隨時都可以在聊天室設定中變更此設定。"</string>
<string name="screen_create_room_public_option_title">"公開聊天室"</string> <string name="screen_create_room_public_option_title">"公開聊天室"</string>
<string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此聊天室"</string> <string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此聊天室"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string> <string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string>
<string name="screen_create_room_room_access_section_header">"聊天室存取權"</string> <string name="screen_create_room_room_access_section_header">"聊天室存取權"</string>

View file

@ -7,7 +7,7 @@
<string name="screen_create_room_private_option_title">"私有聊天室"</string> <string name="screen_create_room_private_option_title">"私有聊天室"</string>
<string name="screen_create_room_public_option_description">"任何人都能找到此聊天室。 <string name="screen_create_room_public_option_description">"任何人都能找到此聊天室。
你可以随时在聊天室设置中更改。"</string> 你可以随时在聊天室设置中更改。"</string>
<string name="screen_create_room_public_option_title">"公聊天室"</string> <string name="screen_create_room_public_option_title">"公聊天室"</string>
<string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此房间"</string> <string name="screen_create_room_room_access_section_anyone_option_description">"任何人都可以加入此房间"</string>
<string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string> <string name="screen_create_room_room_access_section_anyone_option_title">"任何人"</string>
<string name="screen_create_room_room_access_section_header">"房间访问权限"</string> <string name="screen_create_room_room_access_section_header">"房间访问权限"</string>

View file

@ -10,5 +10,5 @@
<string name="screen_deactivate_account_list_item_2">"Vous retirer de tous les salons et toutes les discussions."</string> <string name="screen_deactivate_account_list_item_2">"Vous retirer de tous les salons et toutes les discussions."</string>
<string name="screen_deactivate_account_list_item_3">"Supprimer les informations de votre compte du serveur didentité."</string> <string name="screen_deactivate_account_list_item_3">"Supprimer les informations de votre compte du serveur didentité."</string>
<string name="screen_deactivate_account_list_item_4">"Rendre vos messages invisibles aux futurs membres des salons si vous choisissez de les supprimer. Vos messages seront toujours visibles pour les utilisateurs qui les ont déjà récupérés."</string> <string name="screen_deactivate_account_list_item_4">"Rendre vos messages invisibles aux futurs membres des salons si vous choisissez de les supprimer. Vos messages seront toujours visibles pour les utilisateurs qui les ont déjà récupérés."</string>
<string name="screen_deactivate_account_title">"Désactiver votre compte"</string> <string name="screen_deactivate_account_title">"Désactiver le compte"</string>
</resources> </resources>

View file

@ -10,5 +10,5 @@
<string name="screen_deactivate_account_list_item_2">"Ti rimuove da tutte le stanze di chat."</string> <string name="screen_deactivate_account_list_item_2">"Ti rimuove da tutte le stanze di chat."</string>
<string name="screen_deactivate_account_list_item_3">"Elimina le informazioni del tuo account dal nostro server di identità."</string> <string name="screen_deactivate_account_list_item_3">"Elimina le informazioni del tuo account dal nostro server di identità."</string>
<string name="screen_deactivate_account_list_item_4">"I tuoi messaggi saranno ancora visibili agli utenti registrati, ma non saranno disponibili per gli utenti nuovi o non registrati se decidi di eliminarli."</string> <string name="screen_deactivate_account_list_item_4">"I tuoi messaggi saranno ancora visibili agli utenti registrati, ma non saranno disponibili per gli utenti nuovi o non registrati se decidi di eliminarli."</string>
<string name="screen_deactivate_account_title">"Disattivazione dell\'account"</string> <string name="screen_deactivate_account_title">"Disattiva account"</string>
</resources> </resources>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_deactivate_account_confirmation_dialog_content">"Lütfen hesabınızı devre dışı bırakmak istediğinizi onaylayın. Bu işlem geri alınamaz."</string>
<string name="screen_deactivate_account_delete_all_messages">"Tüm mesajlarımı sil"</string>
<string name="screen_deactivate_account_delete_all_messages_notice">"Uyarı: Gelecekteki kullanıcılar eksik konuşmalar görebilir."</string>
<string name="screen_deactivate_account_description">"Hesabınızı devre dışı bırakmak %1$s, şunları yapacaktır:"</string>
<string name="screen_deactivate_account_description_bold_part">"geri alınamaz"</string>
<string name="screen_deactivate_account_list_item_1">"%1$s (tekrar giriş yapamazsınız ve kimliğiniz yeniden kullanılamaz)."</string>
<string name="screen_deactivate_account_list_item_1_bold_part">"Kalıcı olarak devre dışı bırak"</string>
<string name="screen_deactivate_account_list_item_2">"Sizi tüm sohbet odalarından çıkarmak."</string>
<string name="screen_deactivate_account_list_item_3">"Hesap bilgileriniz kimlik sunucumuzdan silinecek."</string>
<string name="screen_deactivate_account_list_item_4">"Mesajlarınız kayıtlı kullanıcılar tarafından görülmeye devam eder, ancak silmeyi seçerseniz yeni veya kayıtlı olmayan kullanıcılar tarafından görüntülenemeyecek."</string>
<string name="screen_deactivate_account_title">"Hesabı devre dışı bırak"</string>
</resources>

View file

@ -10,5 +10,5 @@
<string name="screen_deactivate_account_list_item_2">"Видалити вас з усіх чатів."</string> <string name="screen_deactivate_account_list_item_2">"Видалити вас з усіх чатів."</string>
<string name="screen_deactivate_account_list_item_3">"Видаліть інформацію свого облікового запису з нашого сервера ідентифікації."</string> <string name="screen_deactivate_account_list_item_3">"Видаліть інформацію свого облікового запису з нашого сервера ідентифікації."</string>
<string name="screen_deactivate_account_list_item_4">"Ваші повідомлення залишатимуться видимими для зареєстрованих користувачів, але недоступними для нових або незареєстрованих користувачів, якщо ви вирішите їх видалити."</string> <string name="screen_deactivate_account_list_item_4">"Ваші повідомлення залишатимуться видимими для зареєстрованих користувачів, але недоступними для нових або незареєстрованих користувачів, якщо ви вирішите їх видалити."</string>
<string name="screen_deactivate_account_title">"Відключити обліковий запис"</string> <string name="screen_deactivate_account_title">"Деактивувати обліковий запис"</string>
</resources> </resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_notification_optin_subtitle">"Ayarlarınızı daha sonra değiştirebilirsiniz."</string>
<string name="screen_notification_optin_title">"Bildirimlere izin verin ve hiçbir mesajı kaçırmayın"</string>
<string name="screen_welcome_bullet_1">"Çağrılar, anketler, arama ve daha fazlası bu yıl içinde eklenecek."</string>
<string name="screen_welcome_bullet_2">"Şifrelenmiş odalar için mesaj geçmişi henüz mevcut değil."</string>
<string name="screen_welcome_bullet_3">"Düşüncelerinizi bizimle paylaşmanızı çok isteriz. Ayarlar sayfasından düşüncelerinizi bize iletin."</string>
<string name="screen_welcome_button">"Hadi başlayalım!"</string>
<string name="screen_welcome_subtitle">"İşte bilmeniz gerekenler:"</string>
<string name="screen_welcome_title">"%1$s hoş geldiniz!"</string>
</resources>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_invites_decline_chat_message">"%1$s katılma davetini reddetmek istediğinizden emin misiniz?"</string>
<string name="screen_invites_decline_chat_title">"Daveti reddet"</string>
<string name="screen_invites_decline_direct_chat_message">"%1$s ile bu özel sohbeti reddetmek istediğinizden emin misiniz?"</string>
<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>
</resources>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Ano, zrušit"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Ano, zrušit"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Opravdu chcete zrušit svou žádost o vstup do této místnosti?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Opravdu chcete zrušit svou žádost o vstup do této místnosti?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Zrušit žádost o vstup"</string> <string name="screen_join_room_cancel_knock_alert_title">"Zrušit žádost o vstup"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Ano, odmítnout a zablokovat"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Opravdu chcete odmítnout pozvánku do této místnosti? Tím také zabráníte tomu, aby vás %1$s kontaktoval(a) nebo pozval(a) do místností."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Odmítnout pozvání a zablokovat"</string>
<string name="screen_join_room_decline_and_block_button_title">"Odmítnout a zablokovat"</string>
<string name="screen_join_room_fail_message">"Vstup do místnosti se nezdařil."</string> <string name="screen_join_room_fail_message">"Vstup do místnosti se nezdařil."</string>
<string name="screen_join_room_fail_reason">"Tato místnost je buď určena pouze pro zvané, nebo do ní může být omezen přístup na úrovni prostoru."</string> <string name="screen_join_room_fail_reason">"Tato místnost je buď určena pouze pro zvané, nebo do ní může být omezen přístup na úrovni prostoru."</string>
<string name="screen_join_room_forget_action">"Zapomenout na tuto místnost"</string> <string name="screen_join_room_forget_action">"Zapomenout na tuto místnost"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Zpráva (nepovinné)"</string> <string name="screen_join_room_knock_message_description">"Zpráva (nepovinné)"</string>
<string name="screen_join_room_knock_sent_description">"Pokud bude váš požadavek přijat, obdržíte pozvánku na vstup do místnosti."</string> <string name="screen_join_room_knock_sent_description">"Pokud bude váš požadavek přijat, obdržíte pozvánku na vstup do místnosti."</string>
<string name="screen_join_room_knock_sent_title">"Žádost o vstup odeslána"</string> <string name="screen_join_room_knock_sent_title">"Žádost o vstup odeslána"</string>
<string name="screen_join_room_loading_alert_message">"Náhled místnosti se nám nepodařilo zobrazit. To může být způsobeno problémy se sítí nebo serverem."</string>
<string name="screen_join_room_loading_alert_title">"Náhled této místnosti jsme nemohli zobrazit"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s zatím nepodporuje prostory. Prostory můžete používat na webu."</string> <string name="screen_join_room_space_not_supported_description">"%1$s zatím nepodporuje prostory. Prostory můžete používat na webu."</string>
<string name="screen_join_room_space_not_supported_title">"Prostory zatím nejsou podporovány"</string> <string name="screen_join_room_space_not_supported_title">"Prostory zatím nejsou podporovány"</string>
<string name="screen_join_room_subtitle_knock">"Klikněte na tlačítko níže a správce místnosti bude informován. Po schválení se budete moci připojit ke konverzaci."</string> <string name="screen_join_room_subtitle_knock">"Klikněte na tlačítko níže a správce místnosti bude informován. Po schválení se budete moci připojit ke konverzaci."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Ja, abbrechen"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Ja, abbrechen"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Möchten Sie Ihre Beitrittsanfrage für diesen Chatroom wirklich stornieren?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Möchten Sie Ihre Beitrittsanfrage für diesen Chatroom wirklich stornieren?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Beitrittsanfrage stornieren"</string> <string name="screen_join_room_cancel_knock_alert_title">"Beitrittsanfrage stornieren"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Ja, ablehnen und blockieren"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Sind Sie sicher, dass Sie die Einladung zu diesem Raum ablehnen möchten? Dadurch wird auch verhindert, dass %1$s Sie kontaktiert oder in Räume einlädt."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Einladung ablehnen und blockieren"</string>
<string name="screen_join_room_decline_and_block_button_title">"Ablehnen und blockieren"</string>
<string name="screen_join_room_fail_message">"Der Beitritt zum Chatroom schlug fehl."</string> <string name="screen_join_room_fail_message">"Der Beitritt zum Chatroom schlug fehl."</string>
<string name="screen_join_room_fail_reason">"Dieser Chatroom ist entweder nur auf Einladung zugänglich oder es kann zu Zugangsbeschränkungen auf Spaceebene kommen."</string> <string name="screen_join_room_fail_reason">"Dieser Chatroom ist entweder nur auf Einladung zugänglich oder es kann zu Zugangsbeschränkungen auf Spaceebene kommen."</string>
<string name="screen_join_room_forget_action">"Vergessen Sie diesen Raum"</string> <string name="screen_join_room_forget_action">"Vergessen Sie diesen Raum"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Nachricht (optional)"</string> <string name="screen_join_room_knock_message_description">"Nachricht (optional)"</string>
<string name="screen_join_room_knock_sent_description">"Falls Ihre Anfrage, dem Raum beizutreten, akzeptiert wird, werden Sie eine Einladung erhalten."</string> <string name="screen_join_room_knock_sent_description">"Falls Ihre Anfrage, dem Raum beizutreten, akzeptiert wird, werden Sie eine Einladung erhalten."</string>
<string name="screen_join_room_knock_sent_title">"Beitrittsanfrage geschickt"</string> <string name="screen_join_room_knock_sent_title">"Beitrittsanfrage geschickt"</string>
<string name="screen_join_room_loading_alert_message">"Wir konnten die Chatroomvorschau nicht anzeigen. Dies kann an Netzwerk- oder Serverproblemen liegen."</string>
<string name="screen_join_room_loading_alert_title">"Wir konnten diese Chatroomvorschau nicht anzeigen"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s unterstützt noch keine Spaces. Du kannst auf Spaces im Web zugreifen."</string> <string name="screen_join_room_space_not_supported_description">"%1$s unterstützt noch keine Spaces. Du kannst auf Spaces im Web zugreifen."</string>
<string name="screen_join_room_space_not_supported_title">"Spaces werden noch nicht unterstützt"</string> <string name="screen_join_room_space_not_supported_title">"Spaces werden noch nicht unterstützt"</string>
<string name="screen_join_room_subtitle_knock">"Klopfe an um einen Administrator zu benachrichtigen. Nach der Freigabe kannst du dich an der Unterhaltung beteiligen."</string> <string name="screen_join_room_subtitle_knock">"Klopfe an um einen Administrator zu benachrichtigen. Nach der Freigabe kannst du dich an der Unterhaltung beteiligen."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Jah, tühista"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Jah, tühista"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Kas sa oled kindel, et soovid tühistada oma palve jututoaga liitumiseks?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Kas sa oled kindel, et soovid tühistada oma palve jututoaga liitumiseks?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Tühista liitumispalve"</string> <string name="screen_join_room_cancel_knock_alert_title">"Tühista liitumispalve"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Jah, keeldu ja blokeeri"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Kas sa oled kindel, et soovid keelduda kutsest sellesse jututuppa? Samaga kaob kasutajal %1$s võimalus sinuga suhelda ja saata sulle jututubade kutseid."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Keeldu kutsest ja blokeeri"</string>
<string name="screen_join_room_decline_and_block_button_title">"Keeldu ja blokeeri"</string>
<string name="screen_join_room_fail_message">"Jututoaga liitumine ei õnnestunud."</string> <string name="screen_join_room_fail_message">"Jututoaga liitumine ei õnnestunud."</string>
<string name="screen_join_room_fail_reason">"Ligipääs siia jututuppa on võimalik vaid kutse alusel või kehtivad siin kogukonnakohased piirangud."</string> <string name="screen_join_room_fail_reason">"Ligipääs siia jututuppa on võimalik vaid kutse alusel või kehtivad siin kogukonnakohased piirangud."</string>
<string name="screen_join_room_forget_action">"Unusta see jututuba"</string> <string name="screen_join_room_forget_action">"Unusta see jututuba"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Selgitus (kui soovid lisada)"</string> <string name="screen_join_room_knock_message_description">"Selgitus (kui soovid lisada)"</string>
<string name="screen_join_room_knock_sent_description">"Kui sinu liitumispalvega ollakse nõus, siis saad kutse jututoaga liitumiseks."</string> <string name="screen_join_room_knock_sent_description">"Kui sinu liitumispalvega ollakse nõus, siis saad kutse jututoaga liitumiseks."</string>
<string name="screen_join_room_knock_sent_title">"Liitumispalve on saadetud"</string> <string name="screen_join_room_knock_sent_title">"Liitumispalve on saadetud"</string>
<string name="screen_join_room_loading_alert_message">"Me ei saanud jututoa eelvaadet näidata. See võib olla põhjustatud võrguühenduse või serveri vigadest."</string>
<string name="screen_join_room_loading_alert_title">"Meil ei õnnestunud selle jututoa eelvaadet kuvada"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s veel ei toeta kogukondadega liitumise ja kasutamise võimalust. Vajadusel saad seda teha veebiliidese vahendusel."</string> <string name="screen_join_room_space_not_supported_description">"%1$s veel ei toeta kogukondadega liitumise ja kasutamise võimalust. Vajadusel saad seda teha veebiliidese vahendusel."</string>
<string name="screen_join_room_space_not_supported_title">"Kogukonnad pole veel toetatud"</string> <string name="screen_join_room_space_not_supported_title">"Kogukonnad pole veel toetatud"</string>
<string name="screen_join_room_subtitle_knock">"Klõpsi allolevat nuppu ja jututoa haldaja saab asjakohase teate. Sa saad liituda, kui haldaja sinu soovi heaks kiidab."</string> <string name="screen_join_room_subtitle_knock">"Klõpsi allolevat nuppu ja jututoa haldaja saab asjakohase teate. Sa saad liituda, kui haldaja sinu soovi heaks kiidab."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Oui, annuler"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Oui, annuler"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Êtes-vous sûr de vouloir annuler votre demande daccès à ce salon ?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Êtes-vous sûr de vouloir annuler votre demande daccès à ce salon ?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Annuler la demande dadhésion"</string> <string name="screen_join_room_cancel_knock_alert_title">"Annuler la demande dadhésion"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Oui, refuser et bloquer"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Êtes-vous sûr de vouloir refuser linvitation à rejoindre ce salon ? Cela empêchera également %1$s de vous contacter ou de vous inviter dans les salons."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Refuser linvitation et bloquer"</string>
<string name="screen_join_room_decline_and_block_button_title">"Refuser et bloquer"</string>
<string name="screen_join_room_fail_message">"Rejoindre le salon a échoué."</string> <string name="screen_join_room_fail_message">"Rejoindre le salon a échoué."</string>
<string name="screen_join_room_fail_reason">"Ce salon est accessible uniquement sur invitation ou il peut y avoir des restrictions daccès au niveau du Space."</string> <string name="screen_join_room_fail_reason">"Ce salon est accessible uniquement sur invitation ou il peut y avoir des restrictions daccès au niveau du Space."</string>
<string name="screen_join_room_forget_action">"Oublier ce salon"</string> <string name="screen_join_room_forget_action">"Oublier ce salon"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Message (facultatif)"</string> <string name="screen_join_room_knock_message_description">"Message (facultatif)"</string>
<string name="screen_join_room_knock_sent_description">"Vous recevrez une invitation à rejoindre le salon si votre demande est acceptée."</string> <string name="screen_join_room_knock_sent_description">"Vous recevrez une invitation à rejoindre le salon si votre demande est acceptée."</string>
<string name="screen_join_room_knock_sent_title">"Demande de rejoindre le salon envoyée"</string> <string name="screen_join_room_knock_sent_title">"Demande de rejoindre le salon envoyée"</string>
<string name="screen_join_room_loading_alert_message">"Impossible dafficher laperçu du salon. Cela peut être dû à des problèmes de réseau ou de serveur."</string>
<string name="screen_join_room_loading_alert_title">"Impossible dafficher laperçu de ce salon"</string>
<string name="screen_join_room_space_not_supported_description">"Les Spaces ne sont pas encore pris en charge par %1$s . Vous pouvez voir les Spaces sur le Web."</string> <string name="screen_join_room_space_not_supported_description">"Les Spaces ne sont pas encore pris en charge par %1$s . Vous pouvez voir les Spaces sur le Web."</string>
<string name="screen_join_room_space_not_supported_title">"Les Spaces ne sont pas encore pris en charge"</string> <string name="screen_join_room_space_not_supported_title">"Les Spaces ne sont pas encore pris en charge"</string>
<string name="screen_join_room_subtitle_knock">"Cliquez ci-dessous et un administrateur sera prévenu. Une fois votre demande approuvée, pour pourrez rejoindre la discussion."</string> <string name="screen_join_room_subtitle_knock">"Cliquez ci-dessous et un administrateur sera prévenu. Une fois votre demande approuvée, pour pourrez rejoindre la discussion."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Igen, visszavonás"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Igen, visszavonás"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Biztos, hogy visszavonja a szobához való csatlakozási kérését?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Biztos, hogy visszavonja a szobához való csatlakozási kérését?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Csatlakozási kérés visszavonása"</string> <string name="screen_join_room_cancel_knock_alert_title">"Csatlakozási kérés visszavonása"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Igen, elutasítás és blokkolás"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Biztos, hogy elutasítja a meghívást, hogy csatlakozzon ehhez a szobához? Ez azt is megakadályozza, hogy %1$s kapcsolatba lépjen Önnel, vagy szobákba hívja."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Meghívó elutasítása és blokkolás"</string>
<string name="screen_join_room_decline_and_block_button_title">"Elutasítás és blokkolás"</string>
<string name="screen_join_room_fail_message">"A szobához való csatlakozás sikertelen."</string> <string name="screen_join_room_fail_message">"A szobához való csatlakozás sikertelen."</string>
<string name="screen_join_room_fail_reason">"Ebbe a szobába csak meghívóval vagy tértagsággal lehet belépni."</string> <string name="screen_join_room_fail_reason">"Ebbe a szobába csak meghívóval vagy tértagsággal lehet belépni."</string>
<string name="screen_join_room_forget_action">"Szoba elfelejtése"</string> <string name="screen_join_room_forget_action">"Szoba elfelejtése"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Üzenet (nem kötelező)"</string> <string name="screen_join_room_knock_message_description">"Üzenet (nem kötelező)"</string>
<string name="screen_join_room_knock_sent_description">"Ha a kérését elfogadják, meghívót kap a szobához való csatlakozáshoz."</string> <string name="screen_join_room_knock_sent_description">"Ha a kérését elfogadják, meghívót kap a szobához való csatlakozáshoz."</string>
<string name="screen_join_room_knock_sent_title">"Csatlakozási kérés elküldve"</string> <string name="screen_join_room_knock_sent_title">"Csatlakozási kérés elküldve"</string>
<string name="screen_join_room_loading_alert_message">"Nem tudtuk megjeleníteni a szoba előnézetét. Ennek az oka hálózati vagy kiszolgálóprobléma is lehet."</string>
<string name="screen_join_room_loading_alert_title">"Nem tudtuk megjeleníteni a szoba előnézetét"</string>
<string name="screen_join_room_space_not_supported_description">"Az %1$s még nem támogatja a tereket. A tereket a weben érheti el."</string> <string name="screen_join_room_space_not_supported_description">"Az %1$s még nem támogatja a tereket. A tereket a weben érheti el."</string>
<string name="screen_join_room_space_not_supported_title">"A terek még nem támogatottak"</string> <string name="screen_join_room_space_not_supported_title">"A terek még nem támogatottak"</string>
<string name="screen_join_room_subtitle_knock">"Kattintson az alábbi gombra, és a szoba adminisztrátora értesítést kap. A jóváhagyást követően csatlakozhat a beszélgetéshez."</string> <string name="screen_join_room_subtitle_knock">"Kattintson az alábbi gombra, és a szoba adminisztrátora értesítést kap. A jóváhagyást követően csatlakozhat a beszélgetéshez."</string>

View file

@ -1,14 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_join_room_ban_by_message">"Zostałeś zbanowany z tego pokoju przez %1$s."</string>
<string name="screen_join_room_ban_message">"Zostałeś zbanowany z tego pokoju"</string>
<string name="screen_join_room_ban_reason">"Powód: %1$s."</string>
<string name="screen_join_room_cancel_knock_action">"Anuluj prośbę"</string> <string name="screen_join_room_cancel_knock_action">"Anuluj prośbę"</string>
<string name="screen_join_room_cancel_knock_alert_confirmation">"Tak, anuluj"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Tak, anuluj"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Czy na pewno chcesz anulować prośbę o dołączenie do tego pokoju?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Czy na pewno chcesz anulować prośbę o dołączenie do tego pokoju?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Anuluj prośbę o dołączenie"</string> <string name="screen_join_room_cancel_knock_alert_title">"Anuluj prośbę o dołączenie"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Tak, odrzuć i zablokuj"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Czy na pewno chcesz odrzucić zaproszenie dołączenia do tego pokoju? %1$s nie będzie mógł się również z Tobą skontaktować, ani zaprosić Cię do pokoju."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Odrzuć zaproszenie i zablokuj"</string>
<string name="screen_join_room_decline_and_block_button_title">"Odrzuć i zablokuj"</string>
<string name="screen_join_room_fail_message">"Nie udało się dołączyć do pokoju."</string>
<string name="screen_join_room_fail_reason">"Ten pokój wymaga zaproszenia lub jest ograniczony z poziomu przestrzeni."</string>
<string name="screen_join_room_forget_action">"Zapomnij o tym pokoju"</string>
<string name="screen_join_room_invite_required_message">"Potrzebujesz zaproszenia, aby dołączyć do tego pokoju"</string>
<string name="screen_join_room_join_action">"Dołącz do pokoju"</string> <string name="screen_join_room_join_action">"Dołącz do pokoju"</string>
<string name="screen_join_room_join_restricted_message">"Aby dołączyć, musisz uzyskać zaproszenie lub być członkiem danej przestrzeni."</string>
<string name="screen_join_room_knock_action">"Wyślij prośbę o dołączenie"</string> <string name="screen_join_room_knock_action">"Wyślij prośbę o dołączenie"</string>
<string name="screen_join_room_knock_message_description">"Wiadomość (opcjonalne)"</string> <string name="screen_join_room_knock_message_description">"Wiadomość (opcjonalne)"</string>
<string name="screen_join_room_knock_sent_description">"Otrzymasz zaproszenie dołączenia do pokoju, jeśli prośba zostanie zaakceptowana."</string> <string name="screen_join_room_knock_sent_description">"Otrzymasz zaproszenie dołączenia do pokoju, jeśli prośba zostanie zaakceptowana."</string>
<string name="screen_join_room_knock_sent_title">"Wysłano prośbę o dołączenie"</string> <string name="screen_join_room_knock_sent_title">"Wysłano prośbę o dołączenie"</string>
<string name="screen_join_room_loading_alert_message">"Nie udało się wyświetlić podglądu pokoju. Może to być spowodowane problemami z siecią lub serwerem."</string>
<string name="screen_join_room_loading_alert_title">"Nie udało nam się wyświetlić podglądu tego pokoju"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s jeszcze nie obsługuje przestrzeni. Uzyskaj dostęp do przestrzeni w wersji web."</string> <string name="screen_join_room_space_not_supported_description">"%1$s jeszcze nie obsługuje przestrzeni. Uzyskaj dostęp do przestrzeni w wersji web."</string>
<string name="screen_join_room_space_not_supported_title">"Przestrzenie nie są jeszcze obsługiwane"</string> <string name="screen_join_room_space_not_supported_title">"Przestrzenie nie są jeszcze obsługiwane"</string>
<string name="screen_join_room_subtitle_knock">"Kliknij przycisk poniżej, aby powiadomić administratora pokoju. Po zatwierdzeniu będziesz mógł dołączyć do rozmowy."</string> <string name="screen_join_room_subtitle_knock">"Kliknij przycisk poniżej, aby powiadomić administratora pokoju. Po zatwierdzeniu będziesz mógł dołączyć do rozmowy."</string>

View file

@ -1,14 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_join_room_ban_by_message">"Foste banido desta sala por %1$s."</string>
<string name="screen_join_room_ban_message">"Foste banido desta sala."</string>
<string name="screen_join_room_ban_reason">"Razão: %1$s."</string>
<string name="screen_join_room_cancel_knock_action">"Cancelar pedido"</string> <string name="screen_join_room_cancel_knock_action">"Cancelar pedido"</string>
<string name="screen_join_room_cancel_knock_alert_confirmation">"Sim, cancelar"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Sim, cancelar"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Tens a certeza de que queres cancelar o teu pedido de entrada nesta sala?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Tens a certeza de que queres cancelar o teu pedido de entrada nesta sala?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Cancela o pedido de adesão"</string> <string name="screen_join_room_cancel_knock_alert_title">"Cancela o pedido de adesão"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Sim, recusar &amp; bloquear"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Tens a certeza de que queres recusar o convite para entrar nesta sala? Isto também evitará que %1$s te contacte ou te convide para salas."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Recusar convite &amp; bloquear"</string>
<string name="screen_join_room_decline_and_block_button_title">"Recusar e bloquear"</string>
<string name="screen_join_room_fail_message">"Falha ao entrar na sala."</string>
<string name="screen_join_room_fail_reason">"A entrada nesta sala ou está limitada a convites ou a alguma configuração de espaço."</string>
<string name="screen_join_room_forget_action">"Esquecer esta sala"</string>
<string name="screen_join_room_invite_required_message">"Precisas de um convite para entrares nesta sala"</string>
<string name="screen_join_room_join_action">"Entrar na sala"</string> <string name="screen_join_room_join_action">"Entrar na sala"</string>
<string name="screen_join_room_join_restricted_message">"Podes ter que ser convidado ou pertenceres a um espaço para poderes entrar."</string>
<string name="screen_join_room_knock_action">"Bater à porta"</string> <string name="screen_join_room_knock_action">"Bater à porta"</string>
<string name="screen_join_room_knock_message_description">"Mensagem (opcional)"</string> <string name="screen_join_room_knock_message_description">"Mensagem (opcional)"</string>
<string name="screen_join_room_knock_sent_description">"Irá receber um convite para participar na sala se seu pedido for aceite."</string> <string name="screen_join_room_knock_sent_description">"Irá receber um convite para participar na sala se seu pedido for aceite."</string>
<string name="screen_join_room_knock_sent_title">"Pedido de adesão enviado"</string> <string name="screen_join_room_knock_sent_title">"Pedido de adesão enviado"</string>
<string name="screen_join_room_loading_alert_message">"Não conseguimos exibir a pré-visualização da sala. Isso pode ser devido a problemas de rede ou servidor."</string>
<string name="screen_join_room_loading_alert_title">"Não foi possível exibir a pré-visualização desta sala"</string>
<string name="screen_join_room_space_not_supported_description">"A %1$s ainda não funciona com espaços. Podes usá-los na aplicação web."</string> <string name="screen_join_room_space_not_supported_description">"A %1$s ainda não funciona com espaços. Podes usá-los na aplicação web."</string>
<string name="screen_join_room_space_not_supported_title">"Os espaços ainda não estão implementados"</string> <string name="screen_join_room_space_not_supported_title">"Os espaços ainda não estão implementados"</string>
<string name="screen_join_room_subtitle_knock">"Carrega no botão abaixo para notificar um administrador da sala. Poderás entrar quando te aprovarem."</string> <string name="screen_join_room_subtitle_knock">"Carrega no botão abaixo para notificar um administrador da sala. Poderás entrar quando te aprovarem."</string>

View file

@ -17,6 +17,7 @@
<string name="screen_join_room_knock_message_description">"Сообщение (опционально)"</string> <string name="screen_join_room_knock_message_description">"Сообщение (опционально)"</string>
<string name="screen_join_room_knock_sent_description">"Вы получите приглашение присоединиться к комнате, как только ваш запрос будет принят."</string> <string name="screen_join_room_knock_sent_description">"Вы получите приглашение присоединиться к комнате, как только ваш запрос будет принят."</string>
<string name="screen_join_room_knock_sent_title">"Запрос на присоединение отправлен"</string> <string name="screen_join_room_knock_sent_title">"Запрос на присоединение отправлен"</string>
<string name="screen_join_room_loading_alert_message">"Не удалось отобразить предварительный просмотр комнаты. Это может быть связано с проблемами сети или сервера."</string>
<string name="screen_join_room_space_not_supported_description">"%1$s еще не поддерживает пространства. Вы можете получить к ним доступ в веб-версии."</string> <string name="screen_join_room_space_not_supported_description">"%1$s еще не поддерживает пространства. Вы можете получить к ним доступ в веб-версии."</string>
<string name="screen_join_room_space_not_supported_title">"Пространства пока не поддерживаются"</string> <string name="screen_join_room_space_not_supported_title">"Пространства пока не поддерживаются"</string>
<string name="screen_join_room_subtitle_knock">"Нажмите кнопку ниже и администратор комнаты получит уведомление. После одобрения вы сможете присоединиться к обсуждению."</string> <string name="screen_join_room_subtitle_knock">"Нажмите кнопку ниже и администратор комнаты получит уведомление. После одобрения вы сможете присоединиться к обсуждению."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Áno, zrušiť"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Áno, zrušiť"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Ste si istí, že chcete zrušiť svoju žiadosť o vstup do tejto miestnosti?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Ste si istí, že chcete zrušiť svoju žiadosť o vstup do tejto miestnosti?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Zrušiť žiadosť o pripojenie"</string> <string name="screen_join_room_cancel_knock_alert_title">"Zrušiť žiadosť o pripojenie"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Áno, odmietnuť a zablokovať"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Ste si istí, že chcete odmietnuť pozvanie na vstup do tejto miestnosti? To tiež zabráni tomu, aby vás %1$s kontaktoval/a alebo vás pozval/a do miestností."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Odmietnuť pozvánku a zablokovať"</string>
<string name="screen_join_room_decline_and_block_button_title">"Odmietnuť a zablokovať"</string>
<string name="screen_join_room_fail_message">"Pripojenie do miestnosti zlyhalo."</string> <string name="screen_join_room_fail_message">"Pripojenie do miestnosti zlyhalo."</string>
<string name="screen_join_room_fail_reason">"Táto miestnosť je buď len pre pozvaných, alebo môžu existovať obmedzenia na prístup na úrovni priestoru."</string> <string name="screen_join_room_fail_reason">"Táto miestnosť je buď len pre pozvaných, alebo môžu existovať obmedzenia na prístup na úrovni priestoru."</string>
<string name="screen_join_room_forget_action">"Zabudnúť túto miestnosť"</string> <string name="screen_join_room_forget_action">"Zabudnúť túto miestnosť"</string>
@ -17,6 +21,8 @@
<string name="screen_join_room_knock_message_description">"Správa (voliteľné)"</string> <string name="screen_join_room_knock_message_description">"Správa (voliteľné)"</string>
<string name="screen_join_room_knock_sent_description">"Ak bude vaša žiadosť prijatá, dostanete pozvánku na vstup do miestnosti."</string> <string name="screen_join_room_knock_sent_description">"Ak bude vaša žiadosť prijatá, dostanete pozvánku na vstup do miestnosti."</string>
<string name="screen_join_room_knock_sent_title">"Žiadosť o pripojenie bola odoslaná"</string> <string name="screen_join_room_knock_sent_title">"Žiadosť o pripojenie bola odoslaná"</string>
<string name="screen_join_room_loading_alert_message">"Nepodarilo sa zobraziť ukážku miestnosti. Môže to byť spôsobené problémami so sieťou alebo serverom."</string>
<string name="screen_join_room_loading_alert_title">"Ukážku tejto miestnosti sa nepodarilo zobraziť"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s zatiaľ nepodporuje priestory. K priestorom môžete pristupovať na webe."</string> <string name="screen_join_room_space_not_supported_description">"%1$s zatiaľ nepodporuje priestory. K priestorom môžete pristupovať na webe."</string>
<string name="screen_join_room_space_not_supported_title">"Priestory zatiaľ nie sú podporované"</string> <string name="screen_join_room_space_not_supported_title">"Priestory zatiaľ nie sú podporované"</string>
<string name="screen_join_room_subtitle_knock">"Kliknite na tlačidlo nižšie a správca miestnosti bude informovaný. Po schválení sa budete môcť pripojiť ku konverzácii."</string> <string name="screen_join_room_subtitle_knock">"Kliknite na tlačidlo nižšie a správca miestnosti bude informovaný. Po schválení sa budete môcť pripojiť ku konverzácii."</string>

View file

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_join_room_cancel_knock_action">"Avbryt begäran"</string> <string name="screen_join_room_cancel_knock_action">"Avbryt begäran"</string>
<string name="screen_join_room_cancel_knock_alert_confirmation">"Ja, avbryt"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Är du säker på att du vill avbryta din begäran om att gå med i det här rummet?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Avbryt begäran om att gå med"</string>
<string name="screen_join_room_join_action">"Gå med i rummet"</string> <string name="screen_join_room_join_action">"Gå med i rummet"</string>
<string name="screen_join_room_knock_action">"Knacka för att gå med"</string> <string name="screen_join_room_knock_action">"Knacka för att gå med"</string>
<string name="screen_join_room_knock_message_description">"Meddelande (valfritt)"</string> <string name="screen_join_room_knock_message_description">"Meddelande (valfritt)"</string>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_join_room_ban_by_message">"%1$s tarafından bu odadan yasaklandınız."</string>
<string name="screen_join_room_ban_message">"Bu odadan yasaklandın"</string>
<string name="screen_join_room_ban_reason">"Neden: %1$s."</string>
<string name="screen_join_room_cancel_knock_action">"İsteği iptal et"</string>
<string name="screen_join_room_cancel_knock_alert_confirmation">"Evet, iptal et"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Bu odaya katılma isteğinizi iptal etmek istediğinizden emin misiniz?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Katılma isteğini iptal et"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Evet, reddet ve engelle"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Bu odaya katılma davetini reddetmek istediğinizden emin misiniz? Bu aynı zamanda %1$s sizinle iletişim kurmasını veya sizi odalara davet etmesini de engeller."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Daveti reddet ve engelle"</string>
<string name="screen_join_room_decline_and_block_button_title">"Reddet ve engelle"</string>
<string name="screen_join_room_fail_message">"Odaya katılım başarısız oldu."</string>
<string name="screen_join_room_fail_reason">"Bu odaya yalnızca davetle girilebilir veya alan düzeyinde erişim kısıtlamaları olabilir."</string>
<string name="screen_join_room_forget_action">"Bu odayı unut"</string>
<string name="screen_join_room_invite_required_message">"Bu odaya katılmak için bir davete ihtiyacınız var"</string>
<string name="screen_join_room_join_action">"Odaya katıl"</string>
<string name="screen_join_room_join_restricted_message">"Katılmak için davet edilmeniz veya bir alana üye olmanız gerekebilir."</string>
<string name="screen_join_room_knock_action">"Katılma isteği gönder"</string>
<string name="screen_join_room_knock_message_description">"Mesaj (isteğe bağlı)"</string>
<string name="screen_join_room_knock_sent_description">"Talebiniz kabul edilirse odaya katılmanız için bir davet alacaksınız."</string>
<string name="screen_join_room_knock_sent_title">"Katılma isteği gönderildi"</string>
<string name="screen_join_room_loading_alert_message">"Oda önizlemesini görüntüleyemedik. Bunun nedeni ağ veya sunucu sorunları olabilir."</string>
<string name="screen_join_room_loading_alert_title">"Bu oda önizlemesini görüntüleyemedik"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s henüz alanları desteklemiyor. Alanlara web üzerinden erişebilirsiniz."</string>
<string name="screen_join_room_space_not_supported_title">"Alanlar henüz desteklenmiyor"</string>
<string name="screen_join_room_subtitle_knock">"Aşağıdaki düğmeyi tıkladığınızda bir oda yöneticisi bilgilendirilecektir. Onaylandıktan sonra görüşmeye katılabilirsiniz."</string>
<string name="screen_join_room_subtitle_no_preview">"Mesaj geçmişini görüntülemek için bu odaya üye olmanız gerekmektedir."</string>
<string name="screen_join_room_title_knock">"Bu odaya katılmak ister misiniz?"</string>
<string name="screen_join_room_title_no_preview">"Önizleme mevcut değil"</string>
</resources>

View file

@ -1,14 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_join_room_ban_by_message">"%1$s забороняє вам відвідувати цю кімнату."</string>
<string name="screen_join_room_ban_message">"Вам заборонили відвідувати цю кімнату"</string>
<string name="screen_join_room_ban_reason">"Причина: %1$s."</string>
<string name="screen_join_room_cancel_knock_action">"Скасувати запит"</string> <string name="screen_join_room_cancel_knock_action">"Скасувати запит"</string>
<string name="screen_join_room_cancel_knock_alert_confirmation">"Так, скасувати"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Так, скасувати"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Ви впевнені, що бажаєте скасувати свій запит на приєднання до цієї кімнати?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Ви впевнені, що бажаєте скасувати свій запит на приєднання до цієї кімнати?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Скасувати запит на приєднання"</string> <string name="screen_join_room_cancel_knock_alert_title">"Скасувати запит на приєднання"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Так, відхилити та заблокувати"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Ви впевнені, що хочете відхилити запрошення приєднатися до цієї кімнати? Це також завадить %1$s зв\'язатися з вами або запрошувати вас в кімнати."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Відхилити запрошення та заблокувати"</string>
<string name="screen_join_room_decline_and_block_button_title">"Відхилити та заблокувати"</string>
<string name="screen_join_room_fail_message">"Не вдалося приєднатися до кімнати."</string>
<string name="screen_join_room_fail_reason">"Ця кімната доступна лише за запрошенням або на рівні простору можуть бути обмеження доступу."</string>
<string name="screen_join_room_forget_action">"Забути цю кімнату"</string>
<string name="screen_join_room_invite_required_message">"Вам потрібне запрошення, щоб приєднатися до цієї кімнати"</string>
<string name="screen_join_room_join_action">"Приєднатися до кімнати"</string> <string name="screen_join_room_join_action">"Приєднатися до кімнати"</string>
<string name="screen_join_room_join_restricted_message">"Можливо, вам знадобиться отримати запрошення або стати учасником простору, щоб приєднатися."</string>
<string name="screen_join_room_knock_action">"Постукати, щоб приєднатися"</string> <string name="screen_join_room_knock_action">"Постукати, щоб приєднатися"</string>
<string name="screen_join_room_knock_message_description">"Повідомлення (необов\'язково)"</string> <string name="screen_join_room_knock_message_description">"Повідомлення (необов\'язково)"</string>
<string name="screen_join_room_knock_sent_description">"Ви отримаєте запрошення приєднатися до кімнати, якщо ваш запит буде прийнятий."</string> <string name="screen_join_room_knock_sent_description">"Ви отримаєте запрошення приєднатися до кімнати, якщо ваш запит буде прийнятий."</string>
<string name="screen_join_room_knock_sent_title">"Запит на приєднання надіслано"</string> <string name="screen_join_room_knock_sent_title">"Запит на приєднання надіслано"</string>
<string name="screen_join_room_loading_alert_message">"Ми не змогли показати попередній перегляд кімнати. Це може бути пов\'язано з проблемами мережі або сервера."</string>
<string name="screen_join_room_loading_alert_title">"Ми не можемо показати попередній перегляд цієї кімнати"</string>
<string name="screen_join_room_space_not_supported_description">"%1$s ще не підтримує простори. Ви можете отримати доступ до них у вебверсії."</string> <string name="screen_join_room_space_not_supported_description">"%1$s ще не підтримує простори. Ви можете отримати доступ до них у вебверсії."</string>
<string name="screen_join_room_space_not_supported_title">"Простори поки що не підтримуються"</string> <string name="screen_join_room_space_not_supported_title">"Простори поки що не підтримуються"</string>
<string name="screen_join_room_subtitle_knock">"Натисніть кнопку нижче, і адміністратор кімнати отримає сповіщення. Ви зможете приєднатися до розмови після схвалення."</string> <string name="screen_join_room_subtitle_knock">"Натисніть кнопку нижче, і адміністратор кімнати отримає сповіщення. Ви зможете приєднатися до розмови після схвалення."</string>

View file

@ -7,6 +7,10 @@
<string name="screen_join_room_cancel_knock_alert_confirmation">"Yes, cancel"</string> <string name="screen_join_room_cancel_knock_alert_confirmation">"Yes, cancel"</string>
<string name="screen_join_room_cancel_knock_alert_description">"Are you sure that you want to cancel your request to join this room?"</string> <string name="screen_join_room_cancel_knock_alert_description">"Are you sure that you want to cancel your request to join this room?"</string>
<string name="screen_join_room_cancel_knock_alert_title">"Cancel request to join"</string> <string name="screen_join_room_cancel_knock_alert_title">"Cancel request to join"</string>
<string name="screen_join_room_decline_and_block_alert_confirmation">"Yes, decline &amp; block"</string>
<string name="screen_join_room_decline_and_block_alert_message">"Are you sure you want to decline the invite to join this room? This will also prevent %1$s from contacting you or inviting you to rooms."</string>
<string name="screen_join_room_decline_and_block_alert_title">"Decline invite &amp; block"</string>
<string name="screen_join_room_decline_and_block_button_title">"Decline and block"</string>
<string name="screen_join_room_fail_message">"Joining the room failed."</string> <string name="screen_join_room_fail_message">"Joining the room failed."</string>
<string name="screen_join_room_fail_reason">"This room is either invite-only or there might be restrictions to access at space level."</string> <string name="screen_join_room_fail_reason">"This room is either invite-only or there might be restrictions to access at space level."</string>
<string name="screen_join_room_forget_action">"Forget this room"</string> <string name="screen_join_room_forget_action">"Forget this room"</string>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Прыняць"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Приемане"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Aceptar"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"پذیرش"</string>
</resources>

View file

@ -24,7 +24,7 @@
<string name="screen_knock_requests_list_empty_state_description">"Ha valaki csatlakozni kíván a szobához, itt láthatja a kérését."</string> <string name="screen_knock_requests_list_empty_state_description">"Ha valaki csatlakozni kíván a szobához, itt láthatja a kérését."</string>
<string name="screen_knock_requests_list_empty_state_title">"Nincs függőben lévő csatlakozási kérelem"</string> <string name="screen_knock_requests_list_empty_state_title">"Nincs függőben lévő csatlakozási kérelem"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Csatlakozási kérések betöltése…"</string> <string name="screen_knock_requests_list_initial_loading_title">"Csatlakozási kérések betöltése…"</string>
<string name="screen_knock_requests_list_title">"Csatlakozási kérelmek"</string> <string name="screen_knock_requests_list_title">"Csatlakozási kérelem"</string>
<plurals name="screen_room_multiple_knock_requests_title"> <plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s és még %2$d felhasználó szeretne csatlakozni ehhez a szobához"</item> <item quantity="one">"%1$s és még %2$d felhasználó szeretne csatlakozni ehhez a szobához"</item>
<item quantity="other">"%1$s és még %2$d felhasználó szeretne csatlakozni ehhez a szobához"</item> <item quantity="other">"%1$s és még %2$d felhasználó szeretne csatlakozni ehhez a szobához"</item>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"მიღება"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Godta"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Accepteren"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Aceitar"</string>
</resources>

View file

@ -4,15 +4,26 @@
<string name="screen_knock_requests_list_accept_all_alert_description">"Tens a certeza de que queres aceitar todos os pedidos de entrada?"</string> <string name="screen_knock_requests_list_accept_all_alert_description">"Tens a certeza de que queres aceitar todos os pedidos de entrada?"</string>
<string name="screen_knock_requests_list_accept_all_alert_title">"Aceitar todos os pedidos"</string> <string name="screen_knock_requests_list_accept_all_alert_title">"Aceitar todos os pedidos"</string>
<string name="screen_knock_requests_list_accept_all_button_title">"Aceitar todos"</string> <string name="screen_knock_requests_list_accept_all_button_title">"Aceitar todos"</string>
<string name="screen_knock_requests_list_accept_all_failed_alert_description">"Não foi possível aceitar todos os pedidos. Queres tentar novamente?"</string>
<string name="screen_knock_requests_list_accept_all_failed_alert_title">"Falha ao aceitar todos os pedidos"</string>
<string name="screen_knock_requests_list_accept_all_loading_title">"A aceitar todos os pedidos de entrada"</string>
<string name="screen_knock_requests_list_accept_failed_alert_description">"Não foi possível aceitar este pedido. Queres tentar novamente?"</string>
<string name="screen_knock_requests_list_accept_failed_alert_title">"Falha ao aceitar pedido"</string>
<string name="screen_knock_requests_list_accept_loading_title">"A aceitar pedido de entrada"</string>
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Sim, recusar e proibir"</string> <string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Sim, recusar e proibir"</string>
<string name="screen_knock_requests_list_ban_alert_description">"Tens a certeza de que queres recusar e banir %1$s? Este utilizador não poderá voltar a pedir para entrar nesta sala."</string> <string name="screen_knock_requests_list_ban_alert_description">"Tens a certeza de que queres recusar e banir %1$s? Este utilizador não poderá voltar a pedir para entrar nesta sala."</string>
<string name="screen_knock_requests_list_ban_alert_title">"Recusar e banir"</string> <string name="screen_knock_requests_list_ban_alert_title">"Recusar e banir"</string>
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Sim, recusar"</string> <string name="screen_knock_requests_list_ban_loading_title">"A rejeitar pedido e a banir o utilizador"</string>
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Sim, rejeitar"</string>
<string name="screen_knock_requests_list_decline_alert_description">"Tens a certeza que queres recusar o pedido de entrada de %1$s?"</string> <string name="screen_knock_requests_list_decline_alert_description">"Tens a certeza que queres recusar o pedido de entrada de %1$s?"</string>
<string name="screen_knock_requests_list_decline_alert_title">"Recusar entrada"</string> <string name="screen_knock_requests_list_decline_alert_title">"Rejeitar entrada"</string>
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Recusar e banir"</string> <string name="screen_knock_requests_list_decline_and_ban_action_title">"Recusar e banir"</string>
<string name="screen_knock_requests_list_decline_failed_alert_description">"Não foi possível rejeitar este pedido. Queres tentar novamente?"</string>
<string name="screen_knock_requests_list_decline_failed_alert_title">"Falha ao rejeitar pedido"</string>
<string name="screen_knock_requests_list_decline_loading_title">"A rejeitar pedido de entrada"</string>
<string name="screen_knock_requests_list_empty_state_description">"Quando alguém pedir para entrar na sala, irás poder rever o pedido aqui."</string> <string name="screen_knock_requests_list_empty_state_description">"Quando alguém pedir para entrar na sala, irás poder rever o pedido aqui."</string>
<string name="screen_knock_requests_list_empty_state_title">"Sem pedidos de entrada"</string> <string name="screen_knock_requests_list_empty_state_title">"Sem pedidos de entrada"</string>
<string name="screen_knock_requests_list_initial_loading_title">"A carregar pedidos de entrada…"</string>
<string name="screen_knock_requests_list_title">"Pedidos de entrada"</string> <string name="screen_knock_requests_list_title">"Pedidos de entrada"</string>
<plurals name="screen_room_multiple_knock_requests_title"> <plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s +%2$d outro querem entrar nesta sala"</item> <item quantity="one">"%1$s +%2$d outro querem entrar nesta sala"</item>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Acceptați"</string>
</resources>

View file

@ -24,14 +24,14 @@
<string name="screen_knock_requests_list_empty_state_description">"Вы сможете увидеть запрос, когда кто-то попросит присоединиться к комнате."</string> <string name="screen_knock_requests_list_empty_state_description">"Вы сможете увидеть запрос, когда кто-то попросит присоединиться к комнате."</string>
<string name="screen_knock_requests_list_empty_state_title">"Нет ожидающих запросов на присоединение"</string> <string name="screen_knock_requests_list_empty_state_title">"Нет ожидающих запросов на присоединение"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Загрузка запросов на присоединение…"</string> <string name="screen_knock_requests_list_initial_loading_title">"Загрузка запросов на присоединение…"</string>
<string name="screen_knock_requests_list_title">"Запросы на присоединение"</string> <string name="screen_knock_requests_list_title">"Запросы на вступление"</string>
<plurals name="screen_room_multiple_knock_requests_title"> <plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s +%2$d хочет присоединиться к этой комнате"</item> <item quantity="one">"%1$s +%2$d хочет присоединиться к этой комнате"</item>
<item quantity="few">"%1$s +%2$d хотят присоединиться к этой комнате"</item> <item quantity="few">"%1$s +%2$d хотят присоединиться к этой комнате"</item>
<item quantity="many">"%1$s +%2$d хотят присоединиться к этой комнате"</item> <item quantity="many">"%1$s +%2$d хотят присоединиться к этой комнате"</item>
</plurals> </plurals>
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Показать все"</string> <string name="screen_room_multiple_knock_requests_view_all_button_title">"Показать все"</string>
<string name="screen_room_single_knock_request_accept_button_title">"Принять"</string> <string name="screen_room_single_knock_request_accept_button_title">"Разрешить"</string>
<string name="screen_room_single_knock_request_title">"%1$s хочет присоединиться к этой комнате"</string> <string name="screen_room_single_knock_request_title">"%1$s хочет присоединиться к этой комнате"</string>
<string name="screen_room_single_knock_request_view_button_title">"Просмотр"</string> <string name="screen_room_single_knock_request_view_button_title">"Просмотр"</string>
</resources> </resources>

View file

@ -24,7 +24,7 @@
<string name="screen_knock_requests_list_empty_state_description">"Keď niekto požiada, aby sa pripojil k miestnosti, jeho žiadosť si môžete pozrieť tu."</string> <string name="screen_knock_requests_list_empty_state_description">"Keď niekto požiada, aby sa pripojil k miestnosti, jeho žiadosť si môžete pozrieť tu."</string>
<string name="screen_knock_requests_list_empty_state_title">"Žiadna čakajúca žiadosť o pripojenie"</string> <string name="screen_knock_requests_list_empty_state_title">"Žiadna čakajúca žiadosť o pripojenie"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Načítavajú sa žiadosti o pripojenie…"</string> <string name="screen_knock_requests_list_initial_loading_title">"Načítavajú sa žiadosti o pripojenie…"</string>
<string name="screen_knock_requests_list_title">"Žiadosti o pripojenie"</string> <string name="screen_knock_requests_list_title">"Žiadosti o vstup"</string>
<plurals name="screen_room_multiple_knock_requests_title"> <plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s +%2$d ďalší chcú vstúpiť do tejto miestnosti"</item> <item quantity="one">"%1$s +%2$d ďalší chcú vstúpiť do tejto miestnosti"</item>
<item quantity="few">"%1$s +%2$d ďalší chcú vstúpiť do tejto miestnosti"</item> <item quantity="few">"%1$s +%2$d ďalší chcú vstúpiť do tejto miestnosti"</item>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_knock_requests_list_accept_all_alert_confirm_button_title">"Ja, acceptera alla"</string>
<string name="screen_knock_requests_list_accept_all_alert_description">"Är du säker på att du vill acceptera alla förfrågningar om att gå med?"</string>
<string name="screen_knock_requests_list_accept_all_alert_title">"Acceptera alla förfrågningar"</string>
<string name="screen_knock_requests_list_accept_all_button_title">"Acceptera alla"</string>
<string name="screen_knock_requests_list_accept_all_failed_alert_title">"Misslyckades att acceptera alla förfrågningar"</string>
<string name="screen_knock_requests_list_accept_all_loading_title">"Accepterar alla förfrågningar om att gå med"</string>
<string name="screen_knock_requests_list_accept_loading_title">"Accepterar begäran om att gå med"</string>
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Ja, avslå och förbjud"</string>
<string name="screen_knock_requests_list_ban_alert_description">"Är du säker på att du vill avvisa och förbjuda%1$s? Den här användaren kommer inte att kunna begära åtkomst för att gå med i det här rummet igen."</string>
<string name="screen_knock_requests_list_ban_alert_title">"Avvisa och förbjud åtkomst"</string>
<string name="screen_knock_requests_list_ban_loading_title">"Avvisar och bannar åtkomst"</string>
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Ja, avböj"</string>
<string name="screen_knock_requests_list_decline_alert_description">"Är du säker på att du vill avslå %1$s begäran om att gå med i det här rummet?"</string>
<string name="screen_knock_requests_list_decline_alert_title">"Avvisa åtkomst"</string>
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Avvisa och förbjud"</string>
<string name="screen_knock_requests_list_decline_loading_title">"Avvisa begäran om att gå med"</string>
<string name="screen_knock_requests_list_empty_state_description">"När någon begär om att gå med i rummet, kan du se deras förfrågan här."</string>
<string name="screen_knock_requests_list_empty_state_title">"Ingen väntande begäran om att gå med"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Laddar förfrågningar om att gå med …"</string>
<string name="screen_knock_requests_list_title">"Begäran om att gå med"</string>
<plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s+ %2$d annan vill gå med i detta rum"</item>
<item quantity="other">"%1$s+ %2$d andra vill gå med i detta rum"</item>
</plurals>
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Visa alla"</string>
<string name="screen_room_single_knock_request_accept_button_title">"Godkänn"</string>
<string name="screen_room_single_knock_request_title">"%1$s vill gå med i det här rummet"</string>
<string name="screen_room_single_knock_request_view_button_title">"Visa"</string>
</resources>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_knock_requests_list_accept_all_alert_confirm_button_title">"Evet, tümünü kabul et"</string>
<string name="screen_knock_requests_list_accept_all_alert_description">"Tüm katılma isteklerini kabul etmek istediğinizden emin misiniz?"</string>
<string name="screen_knock_requests_list_accept_all_alert_title">"Tüm istekleri kabul et"</string>
<string name="screen_knock_requests_list_accept_all_button_title">"Tümünü kabul et"</string>
<string name="screen_knock_requests_list_accept_all_failed_alert_description">"Tüm istekleri kabul edemedik. Tekrar denemek ister misiniz?"</string>
<string name="screen_knock_requests_list_accept_all_failed_alert_title">"Tüm istekler kabul edilemedi"</string>
<string name="screen_knock_requests_list_accept_all_loading_title">"Tüm katılım istekleri kabul ediliyor"</string>
<string name="screen_knock_requests_list_accept_failed_alert_description">"Bu isteği kabul edemedik. Tekrar denemek ister misiniz?"</string>
<string name="screen_knock_requests_list_accept_failed_alert_title">"İstek kabul edilemedi"</string>
<string name="screen_knock_requests_list_accept_loading_title">"Katılma isteği kabul ediliyor"</string>
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Evet, reddet ve yasakla"</string>
<string name="screen_knock_requests_list_ban_alert_description">"%1$s reddetmek ve yasaklamak istediğinizden emin misiniz? Bu kullanıcı, bu odaya tekrar katılmak için erişim isteğinde bulunamaz."</string>
<string name="screen_knock_requests_list_ban_alert_title">"Reddet ve erişimi yasakla"</string>
<string name="screen_knock_requests_list_ban_loading_title">"Reddediliyor ve erişim yasaklanıyor"</string>
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Evet, reddet"</string>
<string name="screen_knock_requests_list_decline_alert_description">"Bu odaya katılma isteğini reddetmek istediğinizden emin misiniz %1$s?"</string>
<string name="screen_knock_requests_list_decline_alert_title">"Erişimi reddet"</string>
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Reddet ve yasakla"</string>
<string name="screen_knock_requests_list_decline_failed_alert_description">"Bu isteği reddedemedik. Tekrar denemek ister misiniz?"</string>
<string name="screen_knock_requests_list_decline_failed_alert_title">"İsteği reddetme başarısız oldu"</string>
<string name="screen_knock_requests_list_decline_loading_title">"Katılma isteği reddediliyor"</string>
<string name="screen_knock_requests_list_empty_state_description">"Birisi odaya katılmak istediğinde, isteklerini burada görebileceksiniz."</string>
<string name="screen_knock_requests_list_empty_state_title">"Bekleyen katılım isteği yok"</string>
<string name="screen_knock_requests_list_initial_loading_title">"Katılma istekleri yükleniyor…"</string>
<string name="screen_knock_requests_list_title">"Katılma istekleri"</string>
<plurals name="screen_room_multiple_knock_requests_title">
<item quantity="one">"%1$s +%2$d kişi daha bu odaya katılmak istiyor"</item>
<item quantity="other">"%1$s +%2$d kişi daha bu odaya katılmak istiyor"</item>
</plurals>
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Tümünü görüntüle"</string>
<string name="screen_room_single_knock_request_accept_button_title">"Kabul et"</string>
<string name="screen_room_single_knock_request_title">"%1$s bu odaya katılmak istiyor"</string>
<string name="screen_room_single_knock_request_view_button_title">"Görüntüle"</string>
</resources>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_single_knock_request_accept_button_title">"Qabul qiling"</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="leave_conversation_alert_subtitle">"Bu sohbetten ayrılmak istediğinizden emin misiniz? Bu sohbet herkese açık değil ve davet olmadan tekrar katılamayacaksınız."</string>
<string name="leave_room_alert_empty_subtitle">"Bu odadan ayrılmak istediğinizden emin misiniz? Burada tek kişi sizsiniz. Ayrılırsanız, siz de dahil olmak üzere gelecekte kimse katılamayacak."</string>
<string name="leave_room_alert_private_subtitle">"Bu odadan ayrılmak istediğinizden emin misiniz? Bu oda herkese açık değildir ve davet olmadan tekrar katılamazsınız."</string>
<string name="leave_room_alert_subtitle">"Odadan çıkmak istediğinden emin misin?"</string>
</resources>

View file

@ -3,6 +3,7 @@
<string name="screen_app_lock_biometric_authentication">"biometrisk autentisering"</string> <string name="screen_app_lock_biometric_authentication">"biometrisk autentisering"</string>
<string name="screen_app_lock_biometric_unlock">"biometrisk upplåsning"</string> <string name="screen_app_lock_biometric_unlock">"biometrisk upplåsning"</string>
<string name="screen_app_lock_biometric_unlock_title_android">"Lås upp med biometri"</string> <string name="screen_app_lock_biometric_unlock_title_android">"Lås upp med biometri"</string>
<string name="screen_app_lock_confirm_biometric_authentication_android">"Bekräfta biometriskt"</string>
<string name="screen_app_lock_forgot_pin">"Glömt PIN-kod?"</string> <string name="screen_app_lock_forgot_pin">"Glömt PIN-kod?"</string>
<string name="screen_app_lock_settings_change_pin">"Byt PIN-kod"</string> <string name="screen_app_lock_settings_change_pin">"Byt PIN-kod"</string>
<string name="screen_app_lock_settings_enable_biometric_unlock">"Tillåt biometrisk upplåsning"</string> <string name="screen_app_lock_settings_enable_biometric_unlock">"Tillåt biometrisk upplåsning"</string>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_app_lock_biometric_authentication">"biyometrik kimlik doğrulama"</string>
<string name="screen_app_lock_biometric_unlock">"biyometrik kilit açma"</string>
<string name="screen_app_lock_biometric_unlock_title_android">"Biyometrik ile kilit aç"</string>
<string name="screen_app_lock_confirm_biometric_authentication_android">"Biyometrik doğrulama"</string>
<string name="screen_app_lock_forgot_pin">"PIN\'i unuttum"</string>
<string name="screen_app_lock_settings_change_pin">"PIN kodunu değiştir"</string>
<string name="screen_app_lock_settings_enable_biometric_unlock">"Biyometrik kilit açmaya izin ver"</string>
<string name="screen_app_lock_settings_remove_pin">"PIN kodunu kaldır"</string>
<string name="screen_app_lock_settings_remove_pin_alert_message">"PIN\'i kaldırmak istediğinizden emin misiniz?"</string>
<string name="screen_app_lock_settings_remove_pin_alert_title">"PIN\'i kaldır?"</string>
<string name="screen_app_lock_setup_biometric_unlock_allow_title">"İzin ver %1$s"</string>
<string name="screen_app_lock_setup_biometric_unlock_skip">"PIN kullanmayı tercih ederim"</string>
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"%1$s kullanarak oturum açarken kendinize zaman kazandırın"</string>
<string name="screen_app_lock_setup_choose_pin">"PIN Seç"</string>
<string name="screen_app_lock_setup_confirm_pin">"PIN\'i onayla"</string>
<string name="screen_app_lock_setup_pin_context">"Sohbetlerinize ekstra güvenlik eklemek için %1$s kilitleyin.
Hatırlanabilir bir şey seçin. Bu PIN\'i unutursanız, uygulamadan çıkış yaparsınız."</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_content">"Güvenlik nedeniyle bunu PIN kodunuz olarak seçemezsiniz"</string>
<string name="screen_app_lock_setup_pin_forbidden_dialog_title">"Farklı bir PIN seçin"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Lütfen aynı PIN\'i iki kez girin"</string>
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PIN\'ler eşleşmiyor"</string>
<string name="screen_app_lock_signout_alert_message">"Devam etmek için yeniden oturum açmanız ve yeni bir PIN oluşturmanız gerekir"</string>
<string name="screen_app_lock_signout_alert_title">"Oturumunuz kapatılıyor"</string>
<plurals name="screen_app_lock_subtitle">
<item quantity="one">"Kilidi açmak için %1$d deneme hakkınız var"</item>
<item quantity="other">"Kilidi açmak için %1$d deneme hakkınız var"</item>
</plurals>
<plurals name="screen_app_lock_subtitle_wrong_pin">
<item quantity="one">"Yanlış PIN. %1$d kere daha şansınız var"</item>
<item quantity="other">"Yanlış PIN. %1$d kere daha şansınız var"</item>
</plurals>
<string name="screen_app_lock_use_biometric_android">"Biyometrik kullan"</string>
<string name="screen_app_lock_use_pin_android">"PIN kullan"</string>
<string name="screen_signout_in_progress_dialog_content">"Oturum kapatılıyor…"</string>
</resources>

View file

@ -12,6 +12,7 @@
<string name="screen_change_account_provider_subtitle">"Използвайте друг доставчик на акаунт, като например собствен частен сървър или работен акаунт."</string> <string name="screen_change_account_provider_subtitle">"Използвайте друг доставчик на акаунт, като например собствен частен сървър или работен акаунт."</string>
<string name="screen_change_account_provider_title">"Промяна на доставчика на акаунт"</string> <string name="screen_change_account_provider_title">"Промяна на доставчика на акаунт"</string>
<string name="screen_change_server_subtitle">"Какъв е адресът на вашия сървър?"</string> <string name="screen_change_server_subtitle">"Какъв е адресът на вашия сървър?"</string>
<string name="screen_create_account_title">"Създаване на акаунт"</string>
<string name="screen_login_error_deactivated_account">"Този акаунт бе деактивиран."</string> <string name="screen_login_error_deactivated_account">"Този акаунт бе деактивиран."</string>
<string name="screen_login_error_invalid_credentials">"Неправилно потребителско име и/или парола"</string> <string name="screen_login_error_invalid_credentials">"Неправилно потребителско име и/или парола"</string>
<string name="screen_login_form_header">"Въведете своите данни"</string> <string name="screen_login_form_header">"Въведете своите данни"</string>

View file

@ -21,6 +21,7 @@
<string name="screen_change_server_form_notice">"Solo puedes conectarte a un servidor que soporte sliding sync. El administrador de tu servidor tendrá que configurarlo. %1$s"</string> <string name="screen_change_server_form_notice">"Solo puedes conectarte a un servidor que soporte sliding sync. El administrador de tu servidor tendrá que configurarlo. %1$s"</string>
<string name="screen_change_server_subtitle">"¿Cuál es la dirección de tu servidor?"</string> <string name="screen_change_server_subtitle">"¿Cuál es la dirección de tu servidor?"</string>
<string name="screen_change_server_title">"Selecciona tu servidor"</string> <string name="screen_change_server_title">"Selecciona tu servidor"</string>
<string name="screen_create_account_title">"Crear cuenta"</string>
<string name="screen_login_error_deactivated_account">"Esta cuenta ha sido desactivada."</string> <string name="screen_login_error_deactivated_account">"Esta cuenta ha sido desactivada."</string>
<string name="screen_login_error_invalid_credentials">"Usuario y/o contraseña incorrectos"</string> <string name="screen_login_error_invalid_credentials">"Usuario y/o contraseña incorrectos"</string>
<string name="screen_login_error_invalid_user_id">"Este no es un id de usuario válido. Formato esperado: \'@user:homeserver.org\'"</string> <string name="screen_login_error_invalid_user_id">"Este no es un id de usuario válido. Formato esperado: \'@user:homeserver.org\'"</string>

View file

@ -19,6 +19,7 @@
<string name="screen_change_server_form_notice">"თქვენ შეგიძლიათ დაუკავშირდეთ მხოლოდ იმ სერვერს, რომელიც მხარს უჭერს \"sliding sync\"-ს. თქვენი სახლის სერვერის ადმინისტრატორს დასჭირდება მისი კონფიგურაცია.%1$s"</string> <string name="screen_change_server_form_notice">"თქვენ შეგიძლიათ დაუკავშირდეთ მხოლოდ იმ სერვერს, რომელიც მხარს უჭერს \"sliding sync\"-ს. თქვენი სახლის სერვერის ადმინისტრატორს დასჭირდება მისი კონფიგურაცია.%1$s"</string>
<string name="screen_change_server_subtitle">"რა არის თქვენი სერვერის მისამართი?"</string> <string name="screen_change_server_subtitle">"რა არის თქვენი სერვერის მისამართი?"</string>
<string name="screen_change_server_title">"აირჩიეთ თქვენი სერვერი"</string> <string name="screen_change_server_title">"აირჩიეთ თქვენი სერვერი"</string>
<string name="screen_create_account_title">"ანგარიშის შექმნა"</string>
<string name="screen_login_error_deactivated_account">"ეს ანგარიში დეაქტივირებულია."</string> <string name="screen_login_error_deactivated_account">"ეს ანგარიში დეაქტივირებულია."</string>
<string name="screen_login_error_invalid_credentials">"არასწორი მომხმარებლის სახელი და/ან პაროლი"</string> <string name="screen_login_error_invalid_credentials">"არასწორი მომხმარებლის სახელი და/ან პაროლი"</string>
<string name="screen_login_error_invalid_user_id">"მოცემული მომხმარებლის იდენტიფიკატორი არასწორია. დასაშვები ფორმატი: @user:homeserver.org"</string> <string name="screen_login_error_invalid_user_id">"მოცემული მომხმარებლის იდენტიფიკატორი არასწორია. დასაშვები ფორმატი: @user:homeserver.org"</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_account_provider_change">"Bytt kontotilbyder"</string>
<string name="screen_account_provider_form_hint">"Hjemmeserveradresse"</string> <string name="screen_account_provider_form_hint">"Hjemmeserveradresse"</string>
<string name="screen_account_provider_form_subtitle">"Søk etter et selskap, fellesskap eller privat server."</string> <string name="screen_account_provider_form_subtitle">"Søk etter et selskap, fellesskap eller privat server."</string>
<string name="screen_account_provider_form_title">"Finn en kontoleverandør"</string> <string name="screen_account_provider_form_title">"Finn en kontoleverandør"</string>
@ -7,10 +8,15 @@
<string name="screen_account_provider_signin_title">"Du er i ferd med å logge inn på %s"</string> <string name="screen_account_provider_signin_title">"Du er i ferd med å logge inn på %s"</string>
<string name="screen_account_provider_signup_subtitle">"Det er her samtalene dine vil ligge - akkurat som du ville brukt en e-postleverandør til å oppbevare e-postene dine."</string> <string name="screen_account_provider_signup_subtitle">"Det er her samtalene dine vil ligge - akkurat som du ville brukt en e-postleverandør til å oppbevare e-postene dine."</string>
<string name="screen_account_provider_signup_title">"Du er i ferd med å opprette en konto på %s"</string> <string name="screen_account_provider_signup_title">"Du er i ferd med å opprette en konto på %s"</string>
<string name="screen_change_account_provider_other">"Annet"</string>
<string name="screen_change_account_provider_subtitle">"Bruk en annen kontotilbyder, for eksempel din egen private server eller en arbeidskonto."</string>
<string name="screen_change_account_provider_title">"Bytt kontotilbyder"</string>
<string name="screen_change_server_error_invalid_homeserver">"Vi kunne ikke nå denne hjemmeserveren. Kontroller at du har skrevet inn hjemmeserverens URL riktig. Hvis URL-en er riktig, kontakt administratoren for hjemmeserveren din for å få mer hjelp."</string> <string name="screen_change_server_error_invalid_homeserver">"Vi kunne ikke nå denne hjemmeserveren. Kontroller at du har skrevet inn hjemmeserverens URL riktig. Hvis URL-en er riktig, kontakt administratoren for hjemmeserveren din for å få mer hjelp."</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Denne serveren støtter for øyeblikket ikke sliding sync."</string> <string name="screen_change_server_error_no_sliding_sync_message">"Denne serveren støtter for øyeblikket ikke sliding sync."</string>
<string name="screen_change_server_form_header">"URL til hjemmeserver"</string> <string name="screen_change_server_form_header">"URL til hjemmeserver"</string>
<string name="screen_change_server_form_notice">"Du kan bare koble til en eksisterende server som støtter sliding sync. Administrator for din hjemmeserver må konfigurere det. %1$s"</string>
<string name="screen_change_server_subtitle">"Hva er adressen til serveren din?"</string> <string name="screen_change_server_subtitle">"Hva er adressen til serveren din?"</string>
<string name="screen_create_account_title">"Opprett konto"</string>
<string name="screen_login_error_deactivated_account">"Denne kontoen er deaktivert."</string> <string name="screen_login_error_deactivated_account">"Denne kontoen er deaktivert."</string>
<string name="screen_login_error_invalid_credentials">"Feil brukernavn og/eller passord"</string> <string name="screen_login_error_invalid_credentials">"Feil brukernavn og/eller passord"</string>
<string name="screen_login_error_invalid_user_id">"Dette er ikke en gyldig brukeridentifikator. Forventet format: \'@bruker:homeserver.org\'"</string> <string name="screen_login_error_invalid_user_id">"Dette er ikke en gyldig brukeridentifikator. Forventet format: \'@bruker:homeserver.org\'"</string>
@ -18,6 +24,8 @@
<string name="screen_login_form_header">"Skriv inn opplysningene dine"</string> <string name="screen_login_form_header">"Skriv inn opplysningene dine"</string>
<string name="screen_login_subtitle">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string> <string name="screen_login_subtitle">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string>
<string name="screen_login_title">"Velkommen tilbake!"</string> <string name="screen_login_title">"Velkommen tilbake!"</string>
<string name="screen_login_title_with_homeserver">"Logg inn på %1$s"</string>
<string name="screen_server_confirmation_change_server">"Bytt kontotilbyder"</string>
<string name="screen_server_confirmation_message_login_element_dot_io">"En privat server for Element-ansatte."</string> <string name="screen_server_confirmation_message_login_element_dot_io">"En privat server for Element-ansatte."</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string> <string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix er et åpent nettverk for sikker, desentralisert kommunikasjon."</string>
<string name="screen_server_confirmation_message_register">"Det er her samtalene dine vil ligge - akkurat som du ville brukt en e-postleverandør til å oppbevare e-postene dine."</string> <string name="screen_server_confirmation_message_register">"Det er her samtalene dine vil ligge - akkurat som du ville brukt en e-postleverandør til å oppbevare e-postene dine."</string>

View file

@ -19,6 +19,7 @@
<string name="screen_change_server_form_notice">"Você só pode se conectar a um servidor existente que ofereça suporte à tecnologia sliding sync. O administrador do seu servidor precisará configurá-lo. %1$s"</string> <string name="screen_change_server_form_notice">"Você só pode se conectar a um servidor existente que ofereça suporte à tecnologia sliding sync. O administrador do seu servidor precisará configurá-lo. %1$s"</string>
<string name="screen_change_server_subtitle">"Qual é o endereço do seu servidor?"</string> <string name="screen_change_server_subtitle">"Qual é o endereço do seu servidor?"</string>
<string name="screen_change_server_title">"Selecione seu servidor"</string> <string name="screen_change_server_title">"Selecione seu servidor"</string>
<string name="screen_create_account_title">"Criar conta"</string>
<string name="screen_login_error_deactivated_account">"Essa conta foi desativada."</string> <string name="screen_login_error_deactivated_account">"Essa conta foi desativada."</string>
<string name="screen_login_error_invalid_credentials">"Nome de usuário e/ou senha incorretos"</string> <string name="screen_login_error_invalid_credentials">"Nome de usuário e/ou senha incorretos"</string>
<string name="screen_login_error_invalid_user_id">"Esse não é um identificador de usuário válido. Formato esperado: \'@usuário:servidor.org\'"</string> <string name="screen_login_error_invalid_user_id">"Esse não é um identificador de usuário válido. Formato esperado: \'@usuário:servidor.org\'"</string>

View file

@ -44,8 +44,8 @@
<string name="screen_qr_code_login_device_not_signed_in_scan_state_subtitle">"O outro dispositivo não tem a sessão iniciada"</string> <string name="screen_qr_code_login_device_not_signed_in_scan_state_subtitle">"O outro dispositivo não tem a sessão iniciada"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"O início de sessão foi cancelado no outro dispositivo."</string> <string name="screen_qr_code_login_error_cancelled_subtitle">"O início de sessão foi cancelado no outro dispositivo."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Pedido de início de sessão cancelado"</string> <string name="screen_qr_code_login_error_cancelled_title">"Pedido de início de sessão cancelado"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"O início de sessão foi recusado no outro dispositivo."</string> <string name="screen_qr_code_login_error_declined_subtitle">"O início de sessão foi rejeitado no outro dispositivo."</string>
<string name="screen_qr_code_login_error_declined_title">"Início de sessão cancelado"</string> <string name="screen_qr_code_login_error_declined_title">"Início de sessão rejeitado"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"O início de sessão expirou. Por favor, tenta novamente."</string> <string name="screen_qr_code_login_error_expired_subtitle">"O início de sessão expirou. Por favor, tenta novamente."</string>
<string name="screen_qr_code_login_error_expired_title">"O início de sessão não foi concluído a tempo"</string> <string name="screen_qr_code_login_error_expired_title">"O início de sessão não foi concluído a tempo"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"O teu outro dispositivo não suporta o início de sessão na %s com um código QR. <string name="screen_qr_code_login_error_linking_not_suported_subtitle">"O teu outro dispositivo não suporta o início de sessão na %s com um código QR.

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_account_provider_change">"Hesap sağlayıcısını değiştir"</string>
<string name="screen_account_provider_form_hint">"Ana sunucu adresi"</string>
<string name="screen_account_provider_form_notice">"Bir arama terimi veya alan adı adresi girin."</string>
<string name="screen_account_provider_form_subtitle">"Bir şirket, topluluk veya özel sunucu arayın."</string>
<string name="screen_account_provider_form_title">"Bir hesap sağlayıcısı bulun"</string>
<string name="screen_account_provider_signin_subtitle">"Konuşmalarınızın saklanacağı yer burasıdır - tıpkı e-postalarınızı saklamak için bir e-posta sağlayıcısı kullandığınız gibi."</string>
<string name="screen_account_provider_signin_title">"Oturum açmak üzeresiniz %s"</string>
<string name="screen_account_provider_signup_subtitle">"Konuşmalarınızın saklanacağı yer burasıdır - tıpkı e-postalarınızı saklamak için bir e-posta sağlayıcısı kullandığınız gibi."</string>
<string name="screen_account_provider_signup_title">"%s üzerinde bir hesap oluşturmak üzeresiniz"</string>
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org, Matrix.org Vakfı tarafından yönetilen, güvenli, merkezi olmayan iletişim için halka açık Matrix ağında büyük, ücretsiz bir sunucudur."</string>
<string name="screen_change_account_provider_other">"Diğer"</string>
<string name="screen_change_account_provider_subtitle">"Kendi özel sunucunuz veya iş hesabınız gibi farklı bir hesap sağlayıcı kullanın."</string>
<string name="screen_change_account_provider_title">"Hesap sağlayıcısını değiştir"</string>
<string name="screen_change_server_error_invalid_homeserver">"Bu ana sunucuya ulaşamadık. Lütfen ana sunucu URL\'sini doğru girip girmediğinizi kontrol edin. URL doğruysa, daha fazla yardım için ana sunucu yöneticinize başvurun."</string>
<string name="screen_change_server_error_invalid_well_known">"Sliding sync, iyi bilinen dosyadaki bir sorun nedeniyle kullanılamıyor:
%1$s"</string>
<string name="screen_change_server_error_no_sliding_sync_message">"Bu sunucu şu anda sliding sync desteklemiyor."</string>
<string name="screen_change_server_form_header">"Ana sunucu URL\'si"</string>
<string name="screen_change_server_form_notice">"Yalnızca sliding sync destekleyen mevcut bir sunucuya bağlanabilirsiniz. Ana sunucu yöneticinizin bunu yapılandırması gerekecektir. %1$s"</string>
<string name="screen_change_server_subtitle">"Sunucunuzun adresi nedir?"</string>
<string name="screen_change_server_title">"Sunucunuzu seçin"</string>
<string name="screen_create_account_title">"Hesap oluştur"</string>
<string name="screen_login_error_deactivated_account">"Hesap devre dışı bırakıldı."</string>
<string name="screen_login_error_invalid_credentials">"Yanlış kullanıcı adı ve/veya şifre"</string>
<string name="screen_login_error_invalid_user_id">"Bu geçerli bir kullanıcı tanımlayıcısı değil. Kullanılması gereken biçim: \'@user:homeserver.org\'"</string>
<string name="screen_login_error_refresh_tokens">"Bu sunucu, yenileme belirteçlerini kullanacak şekilde yapılandırılmıştır. Parola tabanlı oturum açma kullanılırken bunlar desteklenmez."</string>
<string name="screen_login_error_unsupported_authentication">"Seçilen ana sunucu parola veya OIDC oturum açmayı desteklemiyor. Lütfen yöneticinizle iletişime geçin veya başka bir ana sunucu seçin."</string>
<string name="screen_login_form_header">"Bilgilerinizi girin"</string>
<string name="screen_login_subtitle">"Matrix, güvenli, merkezi olmayan iletişim için açık bir ağdır."</string>
<string name="screen_login_title">"Tekrar hoş geldiniz!"</string>
<string name="screen_login_title_with_homeserver">"%1$s adresinde oturum aç"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Güvenli bir bağlantı kuruluyor"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Yeni cihaza güvenli bir bağlantı kurulamadı. Mevcut cihazlarınız hala güvende ve onlar için endişelenmenize gerek yok."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Şimdi ne olacak?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Bunun bir ağ sorunu olması ihtimaline karşı bir QR koduyla tekrar oturum açmayı deneyin"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"Aynı sorunla karşılaşırsanız, farklı bir wifi ağı deneyin veya wifi yerine mobil verinizi kullanın"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"Bu işe yaramazsa, manuel olarak oturum açın"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"Bağlantı güvenli değil"</string>
<string name="screen_qr_code_login_device_code_subtitle">"Bu cihazda gösterilen iki haneyi girmeniz istenecektir."</string>
<string name="screen_qr_code_login_device_code_title">"Aşağıdaki numarayı diğer cihazınıza girin"</string>
<string name="screen_qr_code_login_device_not_signed_in_scan_state_description">"Diğer cihazınızda oturum açın ve ardından tekrar deneyin veya zaten oturum açmış başka bir cihaz kullanın."</string>
<string name="screen_qr_code_login_device_not_signed_in_scan_state_subtitle">"Diğer cihaz oturum açmamış"</string>
<string name="screen_qr_code_login_error_cancelled_subtitle">"Oturum açma işlemi diğer cihazda iptal edildi."</string>
<string name="screen_qr_code_login_error_cancelled_title">"Oturum açma isteği iptal edildi"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Diğer cihazda oturum açma işlemi reddedildi."</string>
<string name="screen_qr_code_login_error_declined_title">"Oturum açma reddedildi"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Oturum açma süresi doldu. Lütfen tekrar deneyin."</string>
<string name="screen_qr_code_login_error_expired_title">"Oturum açma işlemi zamanında tamamlanmadı"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Diğer cihazınız %s QR koduyla oturum açmayı desteklemiyor.
Manuel olarak oturum açmayı deneyin veya QR kodunu başka bir cihazla tarayın."</string>
<string name="screen_qr_code_login_error_linking_not_suported_title">"QR kodu desteklenmiyor"</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Hesap sağlayıcınız %1$s desteklemiyor."</string>
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s desteklenmiyor"</string>
<string name="screen_qr_code_login_initial_state_button_title">"Taramaya hazır"</string>
<string name="screen_qr_code_login_initial_state_item_1">"Bir masaüstü cihazda %1$s açın"</string>
<string name="screen_qr_code_login_initial_state_item_2">"Avatarınıza tıklayın"</string>
<string name="screen_qr_code_login_initial_state_item_3">"Seç %1$s"</string>
<string name="screen_qr_code_login_initial_state_item_3_action">"\"Yeni cihaz bağla\""</string>
<string name="screen_qr_code_login_initial_state_item_4">"QR kodunu bu cihazla tarayın"</string>
<string name="screen_qr_code_login_initial_state_subtitle">"Yalnızca hesap sağlayıcınız destekliyorsa kullanılabilir."</string>
<string name="screen_qr_code_login_initial_state_title">"QR kodunu almak için %1$s uygulamasını başka bir cihazda açın"</string>
<string name="screen_qr_code_login_invalid_scan_state_description">"Diğer cihazda gösterilen QR kodunu kullan."</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Tekrar deneyin"</string>
<string name="screen_qr_code_login_invalid_scan_state_subtitle">"Yanlış QR kodu"</string>
<string name="screen_qr_code_login_no_camera_permission_button">"Kamera ayarlarına git"</string>
<string name="screen_qr_code_login_no_camera_permission_state_description">"Devam etmek için %1$s cihazınızın kamerasını kullanmasına izin vermeniz gerekir."</string>
<string name="screen_qr_code_login_no_camera_permission_state_title">"QR kodunu taramak için kamera erişimine izin verin"</string>
<string name="screen_qr_code_login_scanning_state_title">"QR kodunu tara"</string>
<string name="screen_qr_code_login_start_over_button">"Yeniden Başla"</string>
<string name="screen_qr_code_login_unknown_error_description">"Beklenmeyen bir hata oluştu. Lütfen tekrar deneyin."</string>
<string name="screen_qr_code_login_verify_code_loading">"Diğer cihazınız bekleniyor"</string>
<string name="screen_qr_code_login_verify_code_subtitle">"Hesap sağlayıcınız, oturum açmayı doğrulamak için aşağıdaki kodu isteyebilir."</string>
<string name="screen_qr_code_login_verify_code_title">"Doğrulama kodunuz"</string>
<string name="screen_server_confirmation_change_server">"Hesap sağlayıcısını değiştir"</string>
<string name="screen_server_confirmation_message_login_element_dot_io">"Element çalışanları için özel bir sunucu."</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix, güvenli, merkezi olmayan iletişim için açık bir ağdır."</string>
<string name="screen_server_confirmation_message_register">"Konuşmalarınızın saklanacağı yer burasıdır - tıpkı e-postalarınızı saklamak için bir e-posta sağlayıcısı kullandığınız gibi."</string>
<string name="screen_server_confirmation_title_login">"%1$s sunucusunda oturum açmak üzeresiniz"</string>
<string name="screen_server_confirmation_title_register">"%1$s sunucusunda bir hesap oluşturmak üzeresiniz"</string>
</resources>

View file

@ -19,6 +19,7 @@
<string name="screen_change_server_form_notice">"Siz faqat siljish sinxronlashni qo\'llab-quvvatlaydigan mavjud serverga ulanishingiz mumkin. Uy serveringiz administratori uni sozlashi kerak.%1$s"</string> <string name="screen_change_server_form_notice">"Siz faqat siljish sinxronlashni qo\'llab-quvvatlaydigan mavjud serverga ulanishingiz mumkin. Uy serveringiz administratori uni sozlashi kerak.%1$s"</string>
<string name="screen_change_server_subtitle">"Serveringizning manzili nima?"</string> <string name="screen_change_server_subtitle">"Serveringizning manzili nima?"</string>
<string name="screen_change_server_title">"Serveringizni tanlang"</string> <string name="screen_change_server_title">"Serveringizni tanlang"</string>
<string name="screen_create_account_title">"Hisob yaratish"</string>
<string name="screen_login_error_deactivated_account">"Bu hisob ochirilgan."</string> <string name="screen_login_error_deactivated_account">"Bu hisob ochirilgan."</string>
<string name="screen_login_error_invalid_credentials">"Notog\'ri foydalanuvchi nomi va/yoki parol"</string> <string name="screen_login_error_invalid_credentials">"Notog\'ri foydalanuvchi nomi va/yoki parol"</string>
<string name="screen_login_error_invalid_user_id">"Bu haqiqiy foydalanuvchi identifikatori emas. Kutilayotgan format: \'@user:homeserver.org\'"</string> <string name="screen_login_error_invalid_user_id">"Bu haqiqiy foydalanuvchi identifikatori emas. Kutilayotgan format: \'@user:homeserver.org\'"</string>

View file

@ -16,7 +16,6 @@ interface LogoutEntryPoint : FeatureEntryPoint {
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
interface NodeBuilder { interface NodeBuilder {
fun onSuccessfulLogoutPendingAction(action: () -> Unit): NodeBuilder
fun callback(callback: Callback): NodeBuilder fun callback(callback: Callback): NodeBuilder
fun build(): Node fun build(): Node
} }

View file

@ -27,15 +27,6 @@ class DefaultLogoutEntryPoint @Inject constructor() : LogoutEntryPoint {
return this return this
} }
override fun onSuccessfulLogoutPendingAction(action: () -> Unit): LogoutEntryPoint.NodeBuilder {
plugins += object : LogoutNode.SuccessfulLogoutPendingAction, Plugin {
override fun onSuccessfulLogoutPendingAction() {
action()
}
}
return this
}
override fun build(): Node { override fun build(): Node {
return parentNode.createNode<LogoutNode>(buildContext, plugins) return parentNode.createNode<LogoutNode>(buildContext, plugins)
} }

View file

@ -32,12 +32,6 @@ class LogoutNode @AssistedInject constructor(
plugins<LogoutEntryPoint.Callback>().forEach { it.onChangeRecoveryKeyClick() } plugins<LogoutEntryPoint.Callback>().forEach { it.onChangeRecoveryKeyClick() }
} }
interface SuccessfulLogoutPendingAction : Plugin {
fun onSuccessfulLogoutPendingAction()
}
private val customOnSuccessfulLogoutPendingAction = plugins<SuccessfulLogoutPendingAction>().firstOrNull()
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val state = presenter.present() val state = presenter.present()
@ -47,7 +41,6 @@ class LogoutNode @AssistedInject constructor(
state = state, state = state,
onChangeRecoveryKeyClick = ::onChangeRecoveryKeyClick, onChangeRecoveryKeyClick = ::onChangeRecoveryKeyClick,
onSuccessLogout = { onSuccessLogout = {
customOnSuccessfulLogoutPendingAction?.onSuccessfulLogoutPendingAction()
onSuccessLogout(activity, isDark, it) onSuccessLogout(activity, isDark, it)
}, },
onBackClick = ::navigateUp, onBackClick = ::navigateUp,

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_signout_confirmation_dialog_content">ıkış yapmak istediğinize emin misiniz?"</string>
<string name="screen_signout_confirmation_dialog_submit">"Oturumu kapat"</string>
<string name="screen_signout_confirmation_dialog_title">"Oturumu kapat"</string>
<string name="screen_signout_in_progress_dialog_content">"Oturum kapatılıyor…"</string>
<string name="screen_signout_key_backup_disabled_subtitle">"Son oturumunuzdan çıkmak üzeresiniz. Şimdi çıkış yaparsanız, şifrelenmiş mesajlarınıza erişiminizi kaybedersiniz."</string>
<string name="screen_signout_key_backup_disabled_title">"Yedeklemeyi kapattınız"</string>
<string name="screen_signout_key_backup_offline_subtitle">"Çevrimdışı olduğunuzda anahtarlarınız hala yedekleniyordu. Oturumu kapatmadan önce anahtarlarınızın yedeklenebilmesi için yeniden bağlanın."</string>
<string name="screen_signout_key_backup_offline_title">"Anahtarlarınız hala yedekleniyor"</string>
<string name="screen_signout_key_backup_ongoing_subtitle">"Lütfen oturumu kapatmadan önce bunun tamamlanmasını bekleyin."</string>
<string name="screen_signout_key_backup_ongoing_title">"Anahtarlarınız hala yedekleniyor"</string>
<string name="screen_signout_preference_item">"Oturumu kapat"</string>
<string name="screen_signout_recovery_disabled_subtitle">"Son oturumunuzdan çıkmak üzeresiniz. Şimdi çıkış yaparsanız şifrelenmiş mesajlarınıza erişiminizi kaybedersiniz."</string>
<string name="screen_signout_recovery_disabled_title">"Kurtarma ayarlanmadı"</string>
<string name="screen_signout_save_recovery_key_subtitle">"Son oturumunuzdan çıkmak üzeresiniz. Şimdi oturumu kapatırsanız şifrelenmiş mesajlarınıza erişiminizi kaybedebilirsiniz."</string>
<string name="screen_signout_save_recovery_key_title">"Kurtarma anahtarınızı kaydettiniz mi?"</string>
</resources>

View file

@ -71,6 +71,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.room.alias.matches
import io.element.android.libraries.matrix.api.room.joinedRoomMembers import io.element.android.libraries.matrix.api.room.joinedRoomMembers
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
import io.element.android.libraries.matrix.ui.messages.LocalRoomMemberProfilesCache import io.element.android.libraries.matrix.ui.messages.LocalRoomMemberProfilesCache
import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache import io.element.android.libraries.matrix.ui.messages.RoomMemberProfilesCache
@ -187,8 +188,11 @@ class MessagesFlowNode @AssistedInject constructor(
callbacks.forEach { it.onRoomDetailsClick() } callbacks.forEach { it.onRoomDetailsClick() }
} }
override fun onEventClick(event: TimelineItem.Event): Boolean { override fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
return processEventClick(event) return processEventClick(
timelineMode = if (isLive) Timeline.Mode.LIVE else Timeline.Mode.FOCUSED_ON_EVENT,
event = event,
)
} }
override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) { override fun onPreviewAttachments(attachments: ImmutableList<Attachment>) {
@ -316,7 +320,10 @@ class MessagesFlowNode @AssistedInject constructor(
NavTarget.PinnedMessagesList -> { NavTarget.PinnedMessagesList -> {
val callback = object : PinnedMessagesListNode.Callback { val callback = object : PinnedMessagesListNode.Callback {
override fun onEventClick(event: TimelineItem.Event) { override fun onEventClick(event: TimelineItem.Event) {
processEventClick(event) processEventClick(
timelineMode = Timeline.Mode.PINNED_EVENTS,
event = event,
)
} }
override fun onUserDataClick(userId: UserId) { override fun onUserDataClick(userId: UserId) {
@ -358,11 +365,14 @@ class MessagesFlowNode @AssistedInject constructor(
callbacks.forEach { it.onPermalinkClick(permalinkData, pushToBackstack = false) } callbacks.forEach { it.onPermalinkClick(permalinkData, pushToBackstack = false) }
} }
private fun processEventClick(event: TimelineItem.Event): Boolean { private fun processEventClick(
timelineMode: Timeline.Mode,
event: TimelineItem.Event,
): Boolean {
val navTarget = when (event.content) { val navTarget = when (event.content) {
is TimelineItemImageContent -> { is TimelineItemImageContent -> {
buildMediaViewerNavTarget( buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event, event = event,
content = event.content, content = event.content,
mediaSource = event.content.mediaSource, mediaSource = event.content.mediaSource,
@ -374,7 +384,7 @@ class MessagesFlowNode @AssistedInject constructor(
if encrypted on certain bridges */ if encrypted on certain bridges */
event.content.preferredMediaSource?.let { preferredMediaSource -> event.content.preferredMediaSource?.let { preferredMediaSource ->
buildMediaViewerNavTarget( buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event, event = event,
content = event.content, content = event.content,
mediaSource = preferredMediaSource, mediaSource = preferredMediaSource,
@ -384,7 +394,7 @@ class MessagesFlowNode @AssistedInject constructor(
} }
is TimelineItemVideoContent -> { is TimelineItemVideoContent -> {
buildMediaViewerNavTarget( buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos, mode = MediaViewerEntryPoint.MediaViewerMode.TimelineImagesAndVideos(timelineMode),
event = event, event = event,
content = event.content, content = event.content,
mediaSource = event.content.mediaSource, mediaSource = event.content.mediaSource,
@ -393,7 +403,7 @@ class MessagesFlowNode @AssistedInject constructor(
} }
is TimelineItemFileContent -> { is TimelineItemFileContent -> {
buildMediaViewerNavTarget( buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios, mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
event = event, event = event,
content = event.content, content = event.content,
mediaSource = event.content.mediaSource, mediaSource = event.content.mediaSource,
@ -402,7 +412,7 @@ class MessagesFlowNode @AssistedInject constructor(
} }
is TimelineItemAudioContent -> { is TimelineItemAudioContent -> {
buildMediaViewerNavTarget( buildMediaViewerNavTarget(
mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios, mode = MediaViewerEntryPoint.MediaViewerMode.TimelineFilesAndAudios(timelineMode),
event = event, event = event,
content = event.content, content = event.content,
mediaSource = event.content.mediaSource, mediaSource = event.content.mediaSource,

View file

@ -89,7 +89,7 @@ class MessagesNode @AssistedInject constructor(
interface Callback : Plugin { interface Callback : Plugin {
fun onRoomDetailsClick() fun onRoomDetailsClick()
fun onEventClick(event: TimelineItem.Event): Boolean fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean
fun onPreviewAttachments(attachments: ImmutableList<Attachment>) fun onPreviewAttachments(attachments: ImmutableList<Attachment>)
fun onUserDataClick(userId: UserId) fun onUserDataClick(userId: UserId)
fun onPermalinkClick(data: PermalinkData) fun onPermalinkClick(data: PermalinkData)
@ -120,12 +120,12 @@ class MessagesNode @AssistedInject constructor(
callbacks.forEach { it.onRoomDetailsClick() } callbacks.forEach { it.onRoomDetailsClick() }
} }
private fun onEventClick(event: TimelineItem.Event): Boolean { private fun onEventClick(isLive: Boolean, event: TimelineItem.Event): Boolean {
// Note: cannot use `callbacks.all { it.onEventClick(event) }` because: // Note: cannot use `callbacks.all { it.onEventClick(event) }` because:
// - if callbacks is empty, it will return true and we want to return false. // - if callbacks is empty, it will return true and we want to return false.
// - if a callback returns false, the other callback will not be invoked. // - if a callback returns false, the other callback will not be invoked.
return callbacks.takeIf { it.isNotEmpty() } return callbacks.takeIf { it.isNotEmpty() }
?.map { it.onEventClick(event) } ?.map { it.onEventClick(isLive, event) }
?.all { it } ?.all { it }
.orFalse() .orFalse()
} }

View file

@ -33,6 +33,7 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
import io.element.android.features.messages.impl.messagecomposer.observeRoomMemberIdentityStateChange
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
import io.element.android.features.messages.impl.timeline.TimelineController import io.element.android.features.messages.impl.timeline.TimelineController
import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineEvents
@ -78,6 +79,7 @@ import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -154,7 +156,9 @@ class MessagesPresenter @AssistedInject constructor(
var hasDismissedInviteDialog by rememberSaveable { var hasDismissedInviteDialog by rememberSaveable {
mutableStateOf(false) mutableStateOf(false)
} }
val roomMemberIdentityStateChanges by produceState(persistentListOf()) {
observeRoomMemberIdentityStateChange(room)
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
// Remove the unread flag on entering but don't send read receipts // Remove the unread flag on entering but don't send read receipts
// as those will be handled by the timeline. // as those will be handled by the timeline.
@ -211,6 +215,7 @@ class MessagesPresenter @AssistedInject constructor(
roomAvatar = roomAvatar, roomAvatar = roomAvatar,
heroes = heroes, heroes = heroes,
composerState = composerState, composerState = composerState,
roomMemberIdentityStateChanges = roomMemberIdentityStateChanges,
userEventPermissions = userEventPermissions, userEventPermissions = userEventPermissions,
voiceMessageComposerState = voiceMessageComposerState, voiceMessageComposerState = voiceMessageComposerState,
timelineState = timelineState, timelineState = timelineState,

View file

@ -10,6 +10,7 @@ package io.element.android.features.messages.impl
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.actionlist.ActionListState
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
import io.element.android.features.messages.impl.crypto.identity.RoomMemberIdentityStateChange
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
import io.element.android.features.messages.impl.timeline.TimelineState import io.element.android.features.messages.impl.timeline.TimelineState
@ -33,6 +34,7 @@ data class MessagesState(
val heroes: ImmutableList<AvatarData>, val heroes: ImmutableList<AvatarData>,
val userEventPermissions: UserEventPermissions, val userEventPermissions: UserEventPermissions,
val composerState: MessageComposerState, val composerState: MessageComposerState,
val roomMemberIdentityStateChanges: ImmutableList<RoomMemberIdentityStateChange>,
val voiceMessageComposerState: VoiceMessageComposerState, val voiceMessageComposerState: VoiceMessageComposerState,
val timelineState: TimelineState, val timelineState: TimelineState,
val timelineProtectionState: TimelineProtectionState, val timelineProtectionState: TimelineProtectionState,

View file

@ -11,6 +11,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.actionlist.ActionListState
import io.element.android.features.messages.impl.actionlist.anActionListState import io.element.android.features.messages.impl.actionlist.anActionListState
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
import io.element.android.features.messages.impl.crypto.identity.RoomMemberIdentityStateChange
import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState import io.element.android.features.messages.impl.crypto.identity.anIdentityChangeState
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
@ -41,6 +42,7 @@ 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.core.RoomId
import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.MessageComposerMode
import io.element.android.libraries.textcomposer.model.aTextEditorStateRich import io.element.android.libraries.textcomposer.model.aTextEditorStateRich
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.persistentSetOf
@ -92,6 +94,7 @@ fun aMessagesState(
isFullScreen = false, isFullScreen = false,
mode = MessageComposerMode.Normal, mode = MessageComposerMode.Normal,
), ),
roomMemberIdentityStateChanges: ImmutableList<RoomMemberIdentityStateChange> = persistentListOf(),
voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(), voiceMessageComposerState: VoiceMessageComposerState = aVoiceMessageComposerState(),
timelineState: TimelineState = aTimelineState( timelineState: TimelineState = aTimelineState(
timelineItems = aTimelineItemList(aTimelineItemTextContent()), timelineItems = aTimelineItemList(aTimelineItemTextContent()),
@ -117,6 +120,7 @@ fun aMessagesState(
heroes = persistentListOf(), heroes = persistentListOf(),
userEventPermissions = userEventPermissions, userEventPermissions = userEventPermissions,
composerState = composerState, composerState = composerState,
roomMemberIdentityStateChanges = roomMemberIdentityStateChanges,
voiceMessageComposerState = voiceMessageComposerState, voiceMessageComposerState = voiceMessageComposerState,
timelineProtectionState = timelineProtectionState, timelineProtectionState = timelineProtectionState,
identityChangeState = identityChangeState, identityChangeState = identityChangeState,

View file

@ -55,6 +55,7 @@ import io.element.android.features.messages.impl.actionlist.ActionListView
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStateView import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStateView
import io.element.android.features.messages.impl.messagecomposer.AttachmentsBottomSheet import io.element.android.features.messages.impl.messagecomposer.AttachmentsBottomSheet
import io.element.android.features.messages.impl.messagecomposer.DisabledComposerView
import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents import io.element.android.features.messages.impl.messagecomposer.MessageComposerEvents
import io.element.android.features.messages.impl.messagecomposer.MessageComposerView import io.element.android.features.messages.impl.messagecomposer.MessageComposerView
import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsPickerView import io.element.android.features.messages.impl.messagecomposer.suggestions.SuggestionsPickerView
@ -97,6 +98,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState 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.EventId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.TextEditorState
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@ -109,7 +111,7 @@ fun MessagesView(
state: MessagesState, state: MessagesState,
onBackClick: () -> Unit, onBackClick: () -> Unit,
onRoomDetailsClick: () -> Unit, onRoomDetailsClick: () -> Unit,
onEventContentClick: (event: TimelineItem.Event) -> Boolean, onEventContentClick: (isLive: Boolean, event: TimelineItem.Event) -> Boolean,
onUserDataClick: (UserId) -> Unit, onUserDataClick: (UserId) -> Unit,
onLinkClick: (String, Boolean) -> Unit, onLinkClick: (String, Boolean) -> Unit,
onSendLocationClick: () -> Unit, onSendLocationClick: () -> Unit,
@ -140,7 +142,7 @@ fun MessagesView(
fun onContentClick(event: TimelineItem.Event) { fun onContentClick(event: TimelineItem.Event) {
Timber.v("onMessageClick= ${event.id}") Timber.v("onMessageClick= ${event.id}")
val hideKeyboard = onEventContentClick(event) val hideKeyboard = onEventContentClick(state.timelineState.isLive, event)
if (hideKeyboard) { if (hideKeyboard) {
localView.hideKeyboard() localView.hideKeyboard()
} }
@ -425,13 +427,20 @@ private fun MessagesViewComposerBottomSheetContents(
onLinkClick = onLinkClick, onLinkClick = onLinkClick,
) )
} }
MessageComposerView( val verificationViolation = state.roomMemberIdentityStateChanges.firstOrNull {
state = state.composerState, it.identityState == IdentityState.VerificationViolation
voiceMessageState = state.voiceMessageComposerState, }
subcomposing = subcomposing, if (verificationViolation != null) {
enableVoiceMessages = state.enableVoiceMessages, DisabledComposerView(modifier = Modifier.fillMaxWidth())
modifier = Modifier.fillMaxWidth(), } else {
) MessageComposerView(
state = state.composerState,
voiceMessageState = state.voiceMessageComposerState,
subcomposing = subcomposing,
enableVoiceMessages = state.enableVoiceMessages,
modifier = Modifier.fillMaxWidth(),
)
}
} }
} else { } else {
CantSendMessageBanner() CantSendMessageBanner()
@ -535,7 +544,7 @@ internal fun MessagesViewPreview(@PreviewParameter(MessagesStateProvider::class)
state = state, state = state,
onBackClick = {}, onBackClick = {},
onRoomDetailsClick = {}, onRoomDetailsClick = {},
onEventContentClick = { false }, onEventContentClick = { _, _ -> false },
onUserDataClick = {}, onUserDataClick = {},
onLinkClick = { _, _ -> }, onLinkClick = { _, _ -> },
onSendLocationClick = {}, onSendLocationClick = {},

View file

@ -10,5 +10,6 @@ package io.element.android.features.messages.impl.crypto.identity
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
sealed interface IdentityChangeEvent { sealed interface IdentityChangeEvent {
data class Submit(val userId: UserId) : IdentityChangeEvent data class PinIdentity(val userId: UserId) : IdentityChangeEvent
data class WithdrawVerification(val userId: UserId) : IdentityChangeEvent
} }

View file

@ -8,30 +8,16 @@
package io.element.android.features.messages.impl.crypto.identity package io.element.android.features.messages.impl.crypto.identity
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.ProduceStateScope
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import io.element.android.features.messages.impl.messagecomposer.observeRoomMemberIdentityStateChange
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
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.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.matrix.ui.model.getAvatarData
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -44,12 +30,17 @@ class IdentityChangeStatePresenter @Inject constructor(
override fun present(): IdentityChangeState { override fun present(): IdentityChangeState {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val roomMemberIdentityStateChange by produceState(persistentListOf()) { val roomMemberIdentityStateChange by produceState(persistentListOf()) {
observeRoomMemberIdentityStateChange() observeRoomMemberIdentityStateChange(room)
} }
fun handleEvent(event: IdentityChangeEvent) { fun handleEvent(event: IdentityChangeEvent) {
when (event) { when (event) {
is IdentityChangeEvent.Submit -> coroutineScope.pinUserIdentity(event.userId) is IdentityChangeEvent.WithdrawVerification -> {
coroutineScope.withdrawVerification(event.userId)
}
is IdentityChangeEvent.PinIdentity -> {
coroutineScope.pinUserIdentity(event.userId)
}
} }
} }
@ -59,56 +50,17 @@ class IdentityChangeStatePresenter @Inject constructor(
) )
} }
@OptIn(ExperimentalCoroutinesApi::class)
private fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange() {
room.syncUpdateFlow
.filter {
// Room cannot become unencrypted, so we can just apply a filter here.
room.isEncrypted
}
.distinctUntilChanged()
.flatMapLatest {
combine(room.identityStateChangesFlow, room.membersStateFlow) { identityStateChanges, membersState ->
identityStateChanges.map { identityStateChange ->
val member = membersState.roomMembers()
?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId }
?.toIdentityRoomMember()
?: createDefaultRoomMemberForIdentityChange(identityStateChange.userId)
RoomMemberIdentityStateChange(
identityRoomMember = member,
identityState = identityStateChange.identityState,
)
}
}
.distinctUntilChanged()
.onEach { roomMemberIdentityStateChanges ->
value = roomMemberIdentityStateChanges.toPersistentList()
}
}
.launchIn(this)
}
private fun CoroutineScope.pinUserIdentity(userId: UserId) = launch { private fun CoroutineScope.pinUserIdentity(userId: UserId) = launch {
encryptionService.pinUserIdentity(userId) encryptionService.pinUserIdentity(userId)
.onFailure { .onFailure {
Timber.e(it, "Failed to pin identity for user $userId") Timber.e(it, "Failed to pin identity for user $userId")
} }
} }
private fun CoroutineScope.withdrawVerification(userId: UserId) = launch {
encryptionService.withdrawVerification(userId)
.onFailure {
Timber.e(it, "Failed to withdraw verification for user $userId")
}
}
} }
private fun RoomMember.toIdentityRoomMember() = IdentityRoomMember(
userId = userId,
displayNameOrDefault = displayNameOrDefault,
avatarData = getAvatarData(AvatarSize.ComposerAlert),
)
private fun createDefaultRoomMemberForIdentityChange(userId: UserId) = IdentityRoomMember(
userId = userId,
displayNameOrDefault = userId.extractedDisplayName,
avatarData = AvatarData(
id = userId.value,
name = null,
url = null,
size = AvatarSize.ComposerAlert,
),
)

View file

@ -30,7 +30,7 @@ class IdentityChangeStateProvider : PreviewParameterProvider<IdentityChangeState
roomMemberIdentityStateChanges = listOf( roomMemberIdentityStateChanges = listOf(
aRoomMemberIdentityStateChange( aRoomMemberIdentityStateChange(
identityRoomMember = anIdentityRoomMember(displayNameOrDefault = "Alice"), identityRoomMember = anIdentityRoomMember(displayNameOrDefault = "Alice"),
identityState = IdentityState.PinViolation, identityState = IdentityState.VerificationViolation,
), ),
), ),
), ),
@ -47,9 +47,10 @@ internal fun aRoomMemberIdentityStateChange(
internal fun anIdentityChangeState( internal fun anIdentityChangeState(
roomMemberIdentityStateChanges: List<RoomMemberIdentityStateChange> = emptyList(), roomMemberIdentityStateChanges: List<RoomMemberIdentityStateChange> = emptyList(),
eventSink: (IdentityChangeEvent) -> Unit = {},
) = IdentityChangeState( ) = IdentityChangeState(
roomMemberIdentityStateChanges = roomMemberIdentityStateChanges.toImmutableList(), roomMemberIdentityStateChanges = roomMemberIdentityStateChanges.toImmutableList(),
eventSink = {}, eventSink = eventSink,
) )
internal fun anIdentityRoomMember( internal fun anIdentityRoomMember(

View file

@ -7,6 +7,7 @@
package io.element.android.features.messages.impl.crypto.identity package io.element.android.features.messages.impl.crypto.identity
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -17,10 +18,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.appconfig.LearnMoreConfig import io.element.android.appconfig.LearnMoreConfig
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
import io.element.android.libraries.matrix.api.encryption.identity.isAViolation
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@Composable @Composable
@ -29,63 +32,90 @@ fun IdentityChangeStateView(
onLinkClick: (String, Boolean) -> Unit, onLinkClick: (String, Boolean) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
// Pick the first identity change to PinViolation // Pick the first identity change that is a violation
val pinViolationIdentityChange = state.roomMemberIdentityStateChanges.firstOrNull { val identityChangeViolation = state.roomMemberIdentityStateChanges.firstOrNull {
// For now only render PinViolation it.identityState.isAViolation()
it.identityState == IdentityState.PinViolation
} }
if (pinViolationIdentityChange != null) { when (identityChangeViolation?.identityState) {
ComposerAlertMolecule( IdentityState.PinViolation -> ViolationAlert(
identityChangeViolation = identityChangeViolation,
onLinkClick = onLinkClick,
textId = CommonStrings.crypto_identity_change_pin_violation_new,
isCritical = false,
submitTextId = CommonStrings.action_ok,
onSubmitClick = { state.eventSink(IdentityChangeEvent.PinIdentity(identityChangeViolation.identityRoomMember.userId)) },
modifier = modifier, modifier = modifier,
avatar = pinViolationIdentityChange.identityRoomMember.avatarData,
content = buildAnnotatedString {
val learnMoreStr = stringResource(CommonStrings.action_learn_more)
val displayName = pinViolationIdentityChange.identityRoomMember.displayNameOrDefault
val userIdStr = stringResource(
CommonStrings.crypto_identity_change_pin_violation_new_user_id,
pinViolationIdentityChange.identityRoomMember.userId,
)
val fullText = stringResource(
id = CommonStrings.crypto_identity_change_pin_violation_new,
displayName,
userIdStr,
learnMoreStr,
)
append(fullText)
val userIdStartIndex = fullText.indexOf(userIdStr)
addStyle(
style = SpanStyle(
fontWeight = FontWeight.Bold,
),
start = userIdStartIndex,
end = userIdStartIndex + userIdStr.length,
)
val learnMoreStartIndex = fullText.lastIndexOf(learnMoreStr)
addStyle(
style = SpanStyle(
textDecoration = TextDecoration.Underline,
fontWeight = FontWeight.Bold,
),
start = learnMoreStartIndex,
end = learnMoreStartIndex + learnMoreStr.length,
)
addLink(
url = LinkAnnotation.Url(
url = LearnMoreConfig.IDENTITY_CHANGE_URL,
linkInteractionListener = {
onLinkClick(LearnMoreConfig.IDENTITY_CHANGE_URL, true)
}
),
start = learnMoreStartIndex,
end = learnMoreStartIndex + learnMoreStr.length,
)
},
onSubmitClick = { state.eventSink(IdentityChangeEvent.Submit(pinViolationIdentityChange.identityRoomMember.userId)) },
isCritical = pinViolationIdentityChange.identityState == IdentityState.VerificationViolation,
) )
IdentityState.VerificationViolation -> ViolationAlert(
identityChangeViolation = identityChangeViolation,
onLinkClick = onLinkClick,
textId = CommonStrings.crypto_identity_change_verification_violation_new,
isCritical = true,
submitTextId = CommonStrings.crypto_identity_change_withdraw_verification_action,
onSubmitClick = { state.eventSink(IdentityChangeEvent.WithdrawVerification(identityChangeViolation.identityRoomMember.userId)) },
modifier = modifier,
)
else -> Unit
} }
} }
@Composable
private fun ViolationAlert(
identityChangeViolation: RoomMemberIdentityStateChange,
onLinkClick: (String, Boolean) -> Unit,
@StringRes textId: Int,
isCritical: Boolean,
@StringRes submitTextId: Int,
onSubmitClick: () -> Unit,
modifier: Modifier = Modifier,
) {
ComposerAlertMolecule(
modifier = modifier,
avatar = identityChangeViolation.identityRoomMember.avatarData,
content = buildAnnotatedString {
val learnMoreStr = stringResource(CommonStrings.action_learn_more)
val displayName = identityChangeViolation.identityRoomMember.displayNameOrDefault
val userIdStr = stringResource(
CommonStrings.crypto_identity_change_pin_violation_new_user_id,
identityChangeViolation.identityRoomMember.userId,
)
val fullText = stringResource(textId, displayName, userIdStr, learnMoreStr)
append(fullText)
val userIdStartIndex = fullText.indexOf(userIdStr)
addStyle(
style = SpanStyle(
fontWeight = FontWeight.Bold,
),
start = userIdStartIndex,
end = userIdStartIndex + userIdStr.length,
)
val learnMoreStartIndex = fullText.lastIndexOf(learnMoreStr)
addStyle(
style = SpanStyle(
textDecoration = TextDecoration.Underline,
fontWeight = FontWeight.Bold,
color = ElementTheme.colors.textPrimary
),
start = learnMoreStartIndex,
end = learnMoreStartIndex + learnMoreStr.length,
)
addLink(
url = LinkAnnotation.Url(
url = LearnMoreConfig.IDENTITY_CHANGE_URL,
linkInteractionListener = {
onLinkClick(LearnMoreConfig.IDENTITY_CHANGE_URL, true)
}
),
start = learnMoreStartIndex,
end = learnMoreStartIndex + learnMoreStr.length,
)
},
submitText = stringResource(submitTextId),
onSubmitClick = onSubmitClick,
isCritical = isCritical,
)
}
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun IdentityChangeStateViewPreview( internal fun IdentityChangeStateViewPreview(

View file

@ -33,7 +33,7 @@ internal fun MessagesViewWithIdentityChangePreview(
), ),
onBackClick = {}, onBackClick = {},
onRoomDetailsClick = {}, onRoomDetailsClick = {},
onEventContentClick = { false }, onEventContentClick = { _, _ -> false },
onUserDataClick = {}, onUserDataClick = {},
onLinkClick = { _, _ -> }, onLinkClick = { _, _ -> },
onSendLocationClick = {}, onSendLocationClick = {},

View file

@ -0,0 +1,101 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeightIn
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.textcomposer.R
@Composable
internal fun DisabledComposerView(
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.padding(3.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(
modifier = Modifier
.size(48.dp),
enabled = false,
onClick = {},
) {
Icon(
modifier = Modifier.size(30.dp),
resourceId = CommonDrawables.ic_plus_composer,
contentDescription = stringResource(R.string.rich_text_editor_a11y_add_attachment),
tint = ElementTheme.colors.iconDisabled,
)
}
val bgColor = ElementTheme.colors.bgCanvasDisabled
val borderColor = ElementTheme.colors.borderDisabled
Box(
modifier = Modifier
.clip(RoundedCornerShape(21.dp))
.border(0.5.dp, borderColor, RoundedCornerShape(21.dp))
.background(color = bgColor)
.size(42.dp)
.requiredHeightIn(min = 42.dp)
.weight(1f),
)
Spacer(modifier = Modifier.width(8.dp))
IconButton(
modifier = Modifier
.padding(start = 2.dp)
.size(48.dp),
enabled = false,
onClick = {},
) {
Icon(
modifier = Modifier.size(30.dp),
imageVector = CompoundIcons.SendSolid(),
contentDescription = "",
tint = ElementTheme.colors.iconQuaternary
)
}
}
}
@PreviewsDayNight
@Composable
internal fun DisabledComposerViewPreview() = ElementPreview {
Column {
DisabledComposerView(
modifier = Modifier.height(IntrinsicSize.Min),
)
}
}

View file

@ -389,6 +389,7 @@ class MessageComposerPresenter @AssistedInject constructor(
} }
} }
} }
return MessageComposerState( return MessageComposerState(
textEditorState = textEditorState, textEditorState = textEditorState,
isFullScreen = isFullScreen.value, isFullScreen = isFullScreen.value,

View file

@ -0,0 +1,74 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.runtime.ProduceStateScope
import io.element.android.features.messages.impl.crypto.identity.IdentityRoomMember
import io.element.android.features.messages.impl.crypto.identity.RoomMemberIdentityStateChange
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.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.matrix.ui.model.getAvatarData
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@OptIn(ExperimentalCoroutinesApi::class)
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: MatrixRoom) {
room.syncUpdateFlow
.filter {
// Room cannot become unencrypted, so we can just apply a filter here.
room.isEncrypted
}
.distinctUntilChanged()
.flatMapLatest {
combine(room.identityStateChangesFlow, room.membersStateFlow) { identityStateChanges, membersState ->
identityStateChanges.map { identityStateChange ->
val member = membersState.roomMembers()
?.firstOrNull { roomMember -> roomMember.userId == identityStateChange.userId }
?.toIdentityRoomMember()
?: createDefaultRoomMemberForIdentityChange(identityStateChange.userId)
RoomMemberIdentityStateChange(
identityRoomMember = member,
identityState = identityStateChange.identityState,
)
}
}
.distinctUntilChanged()
.onEach { roomMemberIdentityStateChanges ->
value = roomMemberIdentityStateChanges.toPersistentList()
}
}
.launchIn(this)
}
private fun RoomMember.toIdentityRoomMember() = IdentityRoomMember(
userId = userId,
displayNameOrDefault = displayNameOrDefault,
avatarData = getAvatarData(AvatarSize.ComposerAlert),
)
private fun createDefaultRoomMemberForIdentityChange(userId: UserId) = IdentityRoomMember(
userId = userId,
displayNameOrDefault = userId.extractedDisplayName,
avatarData = AvatarData(
id = userId.value,
name = null,
url = null,
size = AvatarSize.ComposerAlert,
),
)

View file

@ -139,6 +139,7 @@ internal fun MessageComposerViewPreview(
enableVoiceMessages = true, enableVoiceMessages = true,
subcomposing = false, subcomposing = false,
) )
DisabledComposerView()
} }
} }

Some files were not shown because too many files have changed in this diff Show more