Merge branch 'release/25.04.3' into main
This commit is contained in:
commit
a69d126e26
414 changed files with 4326 additions and 1704 deletions
2
.github/workflows/danger.yml
vendored
2
.github/workflows/danger.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
- run: |
|
||||
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||
- name: Danger
|
||||
uses: danger/danger-js@12.3.4
|
||||
uses: danger/danger-js@13.0.4
|
||||
with:
|
||||
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||
env:
|
||||
|
|
|
|||
2
.github/workflows/quality.yml
vendored
2
.github/workflows/quality.yml
vendored
|
|
@ -294,7 +294,7 @@ jobs:
|
|||
yarn add danger-plugin-lint-report --dev
|
||||
- name: Danger lint
|
||||
if: always()
|
||||
uses: danger/danger-js@12.3.4
|
||||
uses: danger/danger-js@13.0.4
|
||||
with:
|
||||
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
||||
* [Developer onboarding](#developer-onboarding)
|
||||
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
||||
* [Android Studio settings](#android-studio-settings)
|
||||
* [Compilation](#compilation)
|
||||
* [Strings](#strings)
|
||||
|
|
@ -28,18 +28,18 @@
|
|||
|
||||
<!--- END -->
|
||||
|
||||
## Contributing code to Matrix
|
||||
|
||||
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md
|
||||
|
||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
||||
|
||||
The rest of the document contains specific rules for Matrix Android projects
|
||||
|
||||
## Developer onboarding
|
||||
|
||||
For a detailed overview of the project, see [Developer Onboarding](./docs/_developer_onboarding.md).
|
||||
|
||||
## Contributing code to Matrix
|
||||
|
||||
If instead of contributing to the Element X Android project, you want to contribute to Synapse, the homeserver implementation, please read the [Synapse contribution guide](https://element-hq.github.io/synapse/latest/development/contributing_guide.html).
|
||||
|
||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
||||
|
||||
The rest of the document contains specific rules for Matrix Android projects.
|
||||
|
||||
## Android Studio settings
|
||||
|
||||
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ licensee {
|
|||
allow("Apache-2.0")
|
||||
allow("MIT")
|
||||
allow("BSD-2-Clause")
|
||||
allow("BSD-3-Clause")
|
||||
allowUrl("https://opensource.org/licenses/MIT")
|
||||
allowUrl("https://developer.android.com/studio/terms.html")
|
||||
allowUrl("https://www.zetetic.net/sqlcipher/license/")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<locale android:name="be"/>
|
||||
<locale android:name="bg"/>
|
||||
<locale android:name="cs"/>
|
||||
<locale android:name="cy"/>
|
||||
<locale android:name="de"/>
|
||||
<locale android:name="el"/>
|
||||
<locale android:name="en"/>
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
<locale android:name="in"/>
|
||||
<locale android:name="it"/>
|
||||
<locale android:name="ka"/>
|
||||
<locale android:name="lt"/>
|
||||
<locale android:name="nb"/>
|
||||
<locale android:name="nl"/>
|
||||
<locale android:name="pl"/>
|
||||
|
|
|
|||
|
|
@ -78,15 +78,21 @@ class SyncOrchestrator @AssistedInject constructor(
|
|||
internal fun observeStates() = coroutineScope.launch {
|
||||
Timber.tag(tag).d("start observing the app and network state")
|
||||
|
||||
val isAppActiveFlow = combine(
|
||||
appForegroundStateService.isInForeground,
|
||||
appForegroundStateService.isInCall,
|
||||
appForegroundStateService.isSyncingNotificationEvent,
|
||||
appForegroundStateService.hasRingingCall,
|
||||
) { isInForeground, isInCall, isSyncingNotificationEvent, hasRingingCall ->
|
||||
isInForeground || isInCall || isSyncingNotificationEvent || hasRingingCall
|
||||
}
|
||||
|
||||
combine(
|
||||
// small debounce to avoid spamming startSync when the state is changing quickly in case of error.
|
||||
syncService.syncState.debounce(100.milliseconds),
|
||||
networkMonitor.connectivity,
|
||||
appForegroundStateService.isInForeground,
|
||||
appForegroundStateService.isInCall,
|
||||
appForegroundStateService.isSyncingNotificationEvent,
|
||||
) { syncState, networkState, isInForeground, isInCall, isSyncingNotificationEvent ->
|
||||
val isAppActive = isInForeground || isInCall || isSyncingNotificationEvent
|
||||
isAppActiveFlow,
|
||||
) { syncState, networkState, isAppActive ->
|
||||
val isNetworkAvailable = networkState == NetworkStatus.Connected
|
||||
|
||||
Timber.tag(tag).d("isAppActive=$isAppActive, isNetworkAvailable=$isNetworkAvailable")
|
||||
|
|
|
|||
6
appnav/src/main/res/values-cy/translations.xml
Normal file
6
appnav/src/main/res/values-cy/translations.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?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">"Allgofnodi ac Uwchraddio"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"Nid yw %1$s bellach yn cefnogi\'r hen brotocol. Allgofnodwch a mewngofnodi\'n ôl i barhau i ddefnyddio\'r ap."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Nid yw eich gweinydd cartref yn cefnogi\'r hen brotocol mwyach. Allgofnodwch a mewngofnodwch yn ôl i barhau i ddefnyddio\'r ap."</string>
|
||||
</resources>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?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">"Logg ut og oppgrader"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s støtter ikke lenger den gamle protokollen. Logg ut og logg inn igjen for å fortsette å bruke appen."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Hjemmeserveren din støtter ikke lenger den gamle protokollen. Vennligst logg ut og inn igjen for å fortsette å bruke appen."</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -236,6 +236,50 @@ class SyncOrchestratorTest {
|
|||
stopSyncRecorder.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when the app was in background and we have an incoming ringing call, a sync will be started`() = runTest {
|
||||
val startSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
val stopSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
val syncService = FakeSyncService(initialSyncState = SyncState.Idle).apply {
|
||||
startSyncLambda = startSyncRecorder
|
||||
stopSyncLambda = stopSyncRecorder
|
||||
}
|
||||
val networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Connected)
|
||||
val appForegroundStateService = FakeAppForegroundStateService(
|
||||
initialForegroundValue = false,
|
||||
initialIsSyncingNotificationEventValue = false,
|
||||
initialHasRingingCall = false,
|
||||
)
|
||||
val syncOrchestrator = createSyncOrchestrator(
|
||||
syncService = syncService,
|
||||
networkMonitor = networkMonitor,
|
||||
appForegroundStateService = appForegroundStateService,
|
||||
)
|
||||
|
||||
// We start observing
|
||||
syncOrchestrator.observeStates()
|
||||
|
||||
// Advance the time to make sure the orchestrator has had time to start processing the inputs
|
||||
advanceTimeBy(100.milliseconds)
|
||||
|
||||
// Start sync was never called
|
||||
startSyncRecorder.assertions().isNeverCalled()
|
||||
|
||||
// Now we receive a ringing call
|
||||
appForegroundStateService.updateHasRingingCall(true)
|
||||
|
||||
// Start sync will be called shortly after
|
||||
advanceTimeBy(1.milliseconds)
|
||||
startSyncRecorder.assertions().isCalledOnce()
|
||||
|
||||
// If the sync is running and the ringing call notification is now over, the sync stops after a delay
|
||||
syncService.emitSyncState(SyncState.Running)
|
||||
appForegroundStateService.updateHasRingingCall(false)
|
||||
|
||||
advanceTimeBy(10.seconds)
|
||||
stopSyncRecorder.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when the app is in foreground, we sync for a notification and a call is ongoing, the sync will only stop when all conditions are false`() = runTest {
|
||||
val startSyncRecorder = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* [Sync](#sync)
|
||||
* [Rust SDK](#rust-sdk)
|
||||
* [Matrix Rust Component Kotlin](#matrix-rust-component-kotlin)
|
||||
* [Build the SDK locally](#build-the-sdk-locally)
|
||||
* [Building the SDK locally](#building-the-sdk-locally)
|
||||
* [The Android project](#the-android-project)
|
||||
* [Application](#application)
|
||||
* [Jetpack Compose](#jetpack-compose)
|
||||
|
|
@ -107,7 +107,7 @@ This is the goal of https://github.com/matrix-org/matrix-rust-components-kotlin.
|
|||
This repository is used for distributing kotlin releases of the Matrix Rust SDK.
|
||||
It'll provide the corresponding aar and also publish them on maven.
|
||||
|
||||
Most of the time you want to use the releases made on maven with gradle:
|
||||
Most of the time **you want to use the releases made on maven with gradle**:
|
||||
|
||||
```groovy
|
||||
implementation("org.matrix.rustcomponents:sdk-android:latest-version")
|
||||
|
|
@ -115,7 +115,9 @@ implementation("org.matrix.rustcomponents:sdk-android:latest-version")
|
|||
|
||||
You can also have access to the aars through the [release](https://github.com/matrix-org/matrix-rust-components-kotlin/releases) page.
|
||||
|
||||
#### Build the SDK locally
|
||||
#### Building the SDK locally
|
||||
|
||||
If you want to make changes to the SDK or test them before integrating it with your codebase, you can build the SDK locally too.
|
||||
|
||||
Prerequisites:
|
||||
* Install the Android NDK (Native Development Kit). To do this from within
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 665a15a1907a116816ffd1653bccfeaeeb7a2968
|
||||
Subproject commit 0299b8ec4f4233a39230d4c35b97f89728c35fd1
|
||||
2
fastlane/metadata/android/en-US/changelogs/202504030.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202504030.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Main changes in this version: bug fixes and improvements.
|
||||
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||
|
|
@ -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_analytics_settings_read_terms_content_link">"yma"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_help_us_improve">"Dalinkitės anoniminiais naudojimo duomenimis ir padėkite mums nustatyti problemas."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Galite perskaityti visas mūsų sąlygas %1$s ."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"čia"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Dalytis analitiniais duomenimis"</string>
|
||||
</resources>
|
||||
|
|
@ -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_analytics_prompt_read_terms_content_link">"yma"</string>
|
||||
</resources>
|
||||
|
|
@ -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">"Mes nekaupsime ir neprofiliuosime jokių asmens duomenų"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Dalinkitės anoniminiais naudojimo duomenimis ir padėkite mums nustatyti problemas."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Galite perskaityti visas mūsų sąlygas %1$s ."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"čia"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Tai galite bet kada išjungti"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"Mes nesidalinsime Jūsų duomenimis su trečiosiomis šalimis"</string>
|
||||
<string name="screen_analytics_prompt_title">"Padėkite pagerinti %1$s"</string>
|
||||
</resources>
|
||||
|
|
@ -66,6 +66,7 @@ dependencies {
|
|||
implementation(projects.appconfig)
|
||||
implementation(projects.features.enterprise.api)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.featureflag.api)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
package io.element.android.features.call.impl.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.ConsoleMessage
|
||||
|
|
@ -21,12 +25,17 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.content.getSystemService
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.call.impl.R
|
||||
import io.element.android.features.call.impl.pip.PictureInPictureEvents
|
||||
|
|
@ -35,6 +44,8 @@ import io.element.android.features.call.impl.pip.PictureInPictureStateProvider
|
|||
import io.element.android.features.call.impl.pip.aPictureInPictureState
|
||||
import io.element.android.features.call.impl.utils.WebViewPipController
|
||||
import io.element.android.features.call.impl.utils.WebViewWidgetMessageInterceptor
|
||||
import io.element.android.libraries.androidutils.compat.disableExternalAudioDevice
|
||||
import io.element.android.libraries.androidutils.compat.enableExternalAudioDevice
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
|
|
@ -147,9 +158,11 @@ private fun CallWebView(
|
|||
Text("WebView - can't be previewed")
|
||||
}
|
||||
} else {
|
||||
var audioDeviceCallback: AudioDeviceCallback? by remember { mutableStateOf(null) }
|
||||
AndroidView(
|
||||
modifier = modifier,
|
||||
factory = { context ->
|
||||
audioDeviceCallback = context.setupAudioConfiguration()
|
||||
WebView(context).apply {
|
||||
onWebViewCreate(this)
|
||||
setup(userAgent, onPermissionsRequest)
|
||||
|
|
@ -161,12 +174,41 @@ private fun CallWebView(
|
|||
}
|
||||
},
|
||||
onRelease = { webView ->
|
||||
// Reset audio mode
|
||||
webView.context.releaseAudioConfiguration(audioDeviceCallback)
|
||||
webView.destroy()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.setupAudioConfiguration(): AudioDeviceCallback? {
|
||||
val audioManager = getSystemService<AudioManager>() ?: return null
|
||||
// Set 'voice call' mode so volume keys actually control the call volume
|
||||
audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
audioManager.enableExternalAudioDevice()
|
||||
return object : AudioDeviceCallback() {
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
|
||||
Timber.d("Audio devices added")
|
||||
audioManager.enableExternalAudioDevice()
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
|
||||
Timber.d("Audio devices removed")
|
||||
audioManager.enableExternalAudioDevice()
|
||||
}
|
||||
}.also {
|
||||
audioManager.registerAudioDeviceCallback(it, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.releaseAudioConfiguration(audioDeviceCallback: AudioDeviceCallback?) {
|
||||
val audioManager = getSystemService<AudioManager>() ?: return
|
||||
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
|
||||
audioManager.disableExternalAudioDevice()
|
||||
audioManager.mode = AudioManager.MODE_NORMAL
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private fun WebView.setup(
|
||||
userAgent: String,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import io.element.android.libraries.matrix.api.MatrixClientProvider
|
|||
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
|
||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
|
||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -87,7 +88,9 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
private val notificationManagerCompat: NotificationManagerCompat,
|
||||
private val matrixClientProvider: MatrixClientProvider,
|
||||
private val defaultCurrentCallService: DefaultCurrentCallService,
|
||||
private val appForegroundStateService: AppForegroundStateService,
|
||||
) : ActiveCallManager {
|
||||
private val tag = "DefaultActiveCallManager"
|
||||
private var timedOutCallJob: Job? = null
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
|
|
@ -106,9 +109,11 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
|
||||
override suspend fun registerIncomingCall(notificationData: CallNotificationData) {
|
||||
mutex.withLock {
|
||||
appForegroundStateService.updateHasRingingCall(true)
|
||||
Timber.tag(tag).d("Received incoming call for room id: ${notificationData.roomId}")
|
||||
if (activeCall.value != null) {
|
||||
displayMissedCallNotification(notificationData)
|
||||
Timber.w("Already have an active call, ignoring incoming call: $notificationData")
|
||||
Timber.tag(tag).w("Already have an active call, ignoring incoming call: $notificationData")
|
||||
return
|
||||
}
|
||||
activeCall.value = ActiveCall(
|
||||
|
|
@ -129,6 +134,7 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
|
||||
// Acquire a wake lock to keep the device awake during the incoming call, so we can process the room info data
|
||||
if (activeWakeLock?.isHeld == false) {
|
||||
Timber.tag(tag).d("Acquiring partial wakelock")
|
||||
activeWakeLock.acquire(ElementCallConfig.RINGING_CALL_DURATION_SECONDS * 1000L)
|
||||
}
|
||||
}
|
||||
|
|
@ -139,10 +145,13 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
*/
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
suspend fun incomingCallTimedOut(displayMissedCallNotification: Boolean) = mutex.withLock {
|
||||
Timber.tag(tag).d("Incoming call timed out")
|
||||
|
||||
val previousActiveCall = activeCall.value ?: return
|
||||
val notificationData = (previousActiveCall.callState as? CallState.Ringing)?.notificationData ?: return
|
||||
activeCall.value = null
|
||||
if (activeWakeLock?.isHeld == true) {
|
||||
Timber.tag(tag).d("Releasing partial wakelock after timeout")
|
||||
activeWakeLock.release()
|
||||
}
|
||||
|
||||
|
|
@ -155,11 +164,12 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
|
||||
override suspend fun hungUpCall(callType: CallType) = mutex.withLock {
|
||||
if (activeCall.value?.callType != callType) {
|
||||
Timber.w("Call type $callType does not match the active call type, ignoring")
|
||||
Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring")
|
||||
return
|
||||
}
|
||||
cancelIncomingCallNotification()
|
||||
if (activeWakeLock?.isHeld == true) {
|
||||
Timber.tag(tag).d("Releasing partial wakelock after hang up")
|
||||
activeWakeLock.release()
|
||||
}
|
||||
timedOutCallJob?.cancel()
|
||||
|
|
@ -169,6 +179,7 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
override suspend fun joinedCall(callType: CallType) = mutex.withLock {
|
||||
cancelIncomingCallNotification()
|
||||
if (activeWakeLock?.isHeld == true) {
|
||||
Timber.tag(tag).d("Releasing partial wakelock after joining call")
|
||||
activeWakeLock.release()
|
||||
}
|
||||
timedOutCallJob?.cancel()
|
||||
|
|
@ -181,6 +192,7 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
|
||||
@SuppressLint("MissingPermission")
|
||||
private suspend fun showIncomingCallNotification(notificationData: CallNotificationData) {
|
||||
Timber.tag(tag).d("Displaying ringing call notification")
|
||||
val notification = ringingCallNotificationCreator.createNotification(
|
||||
sessionId = notificationData.sessionId,
|
||||
roomId = notificationData.roomId,
|
||||
|
|
@ -204,10 +216,13 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
}
|
||||
|
||||
private fun cancelIncomingCallNotification() {
|
||||
appForegroundStateService.updateHasRingingCall(false)
|
||||
Timber.tag(tag).d("Ringing call notification cancelled")
|
||||
notificationManagerCompat.cancel(NotificationIdProvider.getForegroundServiceNotificationId(ForegroundServiceType.INCOMING_CALL))
|
||||
}
|
||||
|
||||
private fun displayMissedCallNotification(notificationData: CallNotificationData) {
|
||||
Timber.tag(tag).d("Displaying missed call notification")
|
||||
coroutineScope.launch {
|
||||
onMissedCallNotificationHandler.addMissedCallNotification(
|
||||
sessionId = notificationData.sessionId,
|
||||
|
|
@ -227,14 +242,14 @@ class DefaultActiveCallManager @Inject constructor(
|
|||
.flatMapLatest { activeCall ->
|
||||
val callType = activeCall.callType as CallType.RoomCall
|
||||
// Get a flow of updated `hasRoomCall` and `activeRoomCallParticipants` values for the room
|
||||
matrixClientProvider.getOrRestore(callType.sessionId).getOrNull()
|
||||
?.getRoom(callType.roomId)
|
||||
?.roomInfoFlow
|
||||
?.map {
|
||||
Timber.d("Has room call status changed for ringing call: ${it.hasRoomCall}")
|
||||
it.hasRoomCall to (callType.sessionId in it.activeRoomCallParticipants)
|
||||
}
|
||||
?: flowOf()
|
||||
val room = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull()?.getRoom(callType.roomId) ?: run {
|
||||
Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall")
|
||||
return@flatMapLatest flowOf()
|
||||
}
|
||||
room.roomInfoFlow.map {
|
||||
Timber.tag(tag).d("Has room call status changed for ringing call: ${it.hasRoomCall}")
|
||||
it.hasRoomCall to (callType.sessionId in it.activeRoomCallParticipants)
|
||||
}
|
||||
}
|
||||
// We only want to check if the room active call status changes
|
||||
.distinctUntilChanged()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
package io.element.android.features.call.impl.utils
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import javax.inject.Inject
|
||||
|
||||
class CallIntentDataParser @Inject constructor() {
|
||||
|
|
@ -17,7 +18,7 @@ class CallIntentDataParser @Inject constructor() {
|
|||
)
|
||||
|
||||
fun parse(data: String?): String? {
|
||||
val parsedUrl = data?.let { Uri.parse(data) } ?: return null
|
||||
val parsedUrl = data?.toUri() ?: return null
|
||||
val scheme = parsedUrl.scheme
|
||||
return when {
|
||||
scheme in validHttpSchemes -> parsedUrl
|
||||
|
|
@ -37,7 +38,7 @@ class CallIntentDataParser @Inject constructor() {
|
|||
private fun Uri.getUrlParameter(): Uri? {
|
||||
return getQueryParameter("url")
|
||||
?.let { urlParameter ->
|
||||
Uri.parse(urlParameter).takeIf { uri ->
|
||||
urlParameter.toUri().takeIf { uri ->
|
||||
uri.scheme in validHttpSchemes && !uri.host.isNullOrBlank()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?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">"Galwad cyfredol"</string>
|
||||
<string name="call_foreground_service_message_android">"Tapio i ddychwelyd i\'r alwad"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ Galwad ar y gweill"</string>
|
||||
</resources>
|
||||
|
|
@ -35,6 +35,7 @@ import io.element.android.libraries.push.api.notifications.NotificationIdProvide
|
|||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
||||
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
|
||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import io.mockk.mockk
|
||||
|
|
@ -323,5 +324,6 @@ class DefaultActiveCallManagerTest {
|
|||
notificationManagerCompat = notificationManagerCompat,
|
||||
matrixClientProvider = matrixClientProvider,
|
||||
defaultCurrentCallService = DefaultCurrentCallService(),
|
||||
appForegroundStateService = FakeAppForegroundStateService(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_create_room_add_people_title">"Gwahodd pobl"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Gall unrhyw un ymuno â\'r ystafell hon"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Unrhyw un"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Mynediad i\'r Ystafell"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Gall unrhyw un ofyn am gael ymuno â\'r ystafell ond bydd rhaid i weinyddwr neu gymedrolwr dderbyn y cais"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Gofyn i gael ymuno"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"Er mwyn i\'r ystafell hon fod yn weladwy yn y cyfeiriadur ystafelloedd cyhoeddus, bydd angen cyfeiriad ystafell arnoch."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Cyfeiriad yr ystafell"</string>
|
||||
<string name="screen_create_room_room_name_label">"Enw\'r ystafell"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Gwelededd yr ystafell"</string>
|
||||
<string name="screen_create_room_title">"Creu ystafell"</string>
|
||||
</resources>
|
||||
|
|
@ -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_create_room_action_create_room">"Naujas kambarys"</string>
|
||||
<string name="screen_create_room_add_people_title">"Pakviesti žmonių"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Kuriant kambarį įvyko klaida"</string>
|
||||
<string name="screen_create_room_private_option_description">"Į šį kambarį gali patekti tik pakviesti žmonės. Visi pranešimai yra užšifruoti nuo pradžios iki galo."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privatus kambarys"</string>
|
||||
<string name="screen_create_room_public_option_description">"Bet kas gali rasti šį kambarį.
|
||||
Tai galite bet kada pakeisti kambario nustatymuose."</string>
|
||||
<string name="screen_create_room_room_name_label">"Kambario pavadinimas"</string>
|
||||
<string name="screen_create_room_title">"Kurti kambarį"</string>
|
||||
<string name="screen_create_room_topic_label">"Tema (nebūtina)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Bandant pradėti pokalbį įvyko klaida"</string>
|
||||
</resources>
|
||||
|
|
@ -9,8 +9,11 @@
|
|||
Du kan endre dette når som helst i rominnstillingene."</string>
|
||||
<string name="screen_create_room_public_option_title">"Offentlig rom"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_description">"Alle kan bli med i dette rommet"</string>
|
||||
<string name="screen_create_room_room_access_section_anyone_option_title">"Alle"</string>
|
||||
<string name="screen_create_room_room_access_section_header">"Tilgang til rom"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_description">"Alle kan be om å få bli med i rommet, men en administrator eller moderator må godta forespørselen"</string>
|
||||
<string name="screen_create_room_room_access_section_knocking_option_title">"Be om å bli med"</string>
|
||||
<string name="screen_create_room_room_address_section_footer">"For at dette rommet skal være synlig i den offentlige romkatalogen, trenger du en romadresse."</string>
|
||||
<string name="screen_create_room_room_address_section_title">"Romadresse"</string>
|
||||
<string name="screen_create_room_room_name_label">"Romnavn"</string>
|
||||
<string name="screen_create_room_room_visibility_section_title">"Romsynlighet"</string>
|
||||
|
|
@ -18,7 +21,10 @@ Du kan endre dette når som helst i rominnstillingene."</string>
|
|||
<string name="screen_create_room_topic_label">"Emne (valgfritt)"</string>
|
||||
<string name="screen_room_directory_search_title">"Romkatalog"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Det oppstod en feil når du prøvde å starte en chat"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_action">"Bli med i rommet med adresse"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_invalid_address">"Ikke en gyldig adresse"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_placeholder">"Gå inn…"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_room_found">"Matchende rom funnet"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_room_not_found">"Rom ikke funnet"</string>
|
||||
<string name="screen_start_chat_join_room_by_address_supporting_text">"f.eks. #rom-navn:matrix.org"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<string name="screen_create_room_action_create_room">"Nieuwe kamer"</string>
|
||||
<string name="screen_create_room_add_people_title">"Mensen uitnodigen"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Er is een fout opgetreden bij het aanmaken van de kamer"</string>
|
||||
<string name="screen_create_room_private_option_description">"Berichten in deze kamer zijn versleuteld. Versleuteling kan achteraf niet worden uitgeschakeld."</string>
|
||||
<string name="screen_create_room_private_option_description">"Alleen uitgenodigde personen hebben toegang tot deze kamer. Alle berichten zijn end-to-end versleuteld."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privé kamer"</string>
|
||||
<string name="screen_create_room_public_option_description">"Iedereen kan deze kamer vinden.
|
||||
Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen."</string>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<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_private_option_description">"Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são criptografadas de ponta a ponta."</string>
|
||||
<string name="screen_create_room_private_option_title">"Sala privativa (somente por convite)"</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.
|
||||
Você pode mudar isso a qualquer momento nas configurações da sala."</string>
|
||||
<string name="screen_create_room_room_name_label">"Nome da sala"</string>
|
||||
|
|
|
|||
|
|
@ -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_deactivate_account_title">"Cau cyfrif"</string>
|
||||
</resources>
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_deactivate_account_delete_all_messages">"Ezabatu nire mezu guztiak"</string>
|
||||
<string name="screen_deactivate_account_description">"Kontuaren desaktibazioa %1$s, honakoa eragingo du:"</string>
|
||||
<string name="screen_deactivate_account_description_bold_part">"ezin da desegin"</string>
|
||||
<string name="screen_deactivate_account_list_item_1_bold_part">"Ezgaitu betiko"</string>
|
||||
<string name="screen_deactivate_account_list_item_2">"Kendu zure burua txat gela guztietatik."</string>
|
||||
<string name="screen_deactivate_account_title">"Desaktibatu kontua"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -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_welcome_button">"Ffwrdd â ni!"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_join_room_decline_and_block_alert_confirmation">"Iawn, gwrthod a rhwystro"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_message">"Ydych chi\'n siŵr eich bod am wrthod y gwahoddiad i ymuno â\'r ystafell hon? Bydd hyn hefyd yn atal %1$s rhag cysylltu â chi neu eich gwahodd i ystafelloedd."</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_title">"Gwrthod gwahoddiad a rhwystro"</string>
|
||||
<string name="screen_join_room_decline_and_block_button_title">"Gwrthod a rhwystro"</string>
|
||||
</resources>
|
||||
|
|
@ -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">"Ar tikrai norite atmesti kvietimą prisijungti prie %1$s?"</string>
|
||||
<string name="screen_invites_decline_chat_title">"Atmesti kvietimą"</string>
|
||||
<string name="screen_invites_decline_direct_chat_message">"Ar tikrai norite atmesti šį privatų pokalbį su %1$s ?"</string>
|
||||
<string name="screen_invites_decline_direct_chat_title">"Atmesti pokalbį"</string>
|
||||
<string name="screen_invites_empty_list">"Jokių kvietimų"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(%2$s) pakvietė Jus"</string>
|
||||
</resources>
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
<string name="screen_invites_empty_list">"Ingen invitasjoner"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s(%2$s) inviterte deg"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_confirmation">"Ja, avslå og blokker"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_message">"Er du sikker på at du vil avslå invitasjonen til å bli med i dette rommet? Dette vil også forhindre %1$s fra å kontakte deg eller invitere deg til rom."</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_title">"Avslå invitasjon og blokker"</string>
|
||||
<string name="screen_join_room_decline_and_block_button_title">"Avslå og blokker"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
|
|||
),
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin),
|
||||
joinAction = AsyncAction.Failure(ClientException.Generic("Something went wrong"))
|
||||
joinAction = AsyncAction.Failure(ClientException.Generic("Something went wrong", null))
|
||||
),
|
||||
aJoinRoomState(
|
||||
contentState = aLoadedContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited(null))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_join_room_cancel_knock_action">"Diddymu cais"</string>
|
||||
<string name="screen_join_room_cancel_knock_alert_confirmation">"Iawn, diddymu"</string>
|
||||
<string name="screen_join_room_cancel_knock_alert_description">"Ydych chi\'n siŵr eich bod am ddiddymu\'ch cais i ymuno â\'r ystafell hon?"</string>
|
||||
<string name="screen_join_room_cancel_knock_alert_title">"Diddymu cais i ymuno"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_confirmation">"Iawn, gwrthod a rhwystro"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_message">"Ydych chi\'n siŵr eich bod am wrthod y gwahoddiad i ymuno â\'r ystafell hon? Bydd hyn hefyd yn atal %1$s rhag cysylltu â chi neu eich gwahodd i ystafelloedd."</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_title">"Gwrthod gwahoddiad a rhwystro"</string>
|
||||
<string name="screen_join_room_decline_and_block_button_title">"Gwrthod a rhwystro"</string>
|
||||
<string name="screen_join_room_knock_message_description">"Neges (dewisol)"</string>
|
||||
<string name="screen_join_room_knock_sent_description">"Byddwch yn derbyn gwahoddiad i ymuno â\'r ystafell os caiff eich cais ei dderbyn."</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Anfonwyd y cais i ymuno"</string>
|
||||
<string name="screen_join_room_loading_alert_message">"Doedd dim modd dangos rhagolwg yr ystafell. Gall hyn fod oherwydd problemau rhwydwaith neu weinydd."</string>
|
||||
<string name="screen_join_room_loading_alert_title">"Doedd dim modd dangos rhagolwg yr ystafell hon"</string>
|
||||
</resources>
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_join_room_ban_reason">"Arrazoia: %1$s."</string>
|
||||
<string name="screen_join_room_cancel_knock_action">"Utzi eskaera bertan behera"</string>
|
||||
<string name="screen_join_room_cancel_knock_alert_confirmation">"Bai, utzi bertan behera"</string>
|
||||
<string name="screen_join_room_forget_action">"Ahaztu gela hau"</string>
|
||||
<string name="screen_join_room_join_action">"Sartu gelan"</string>
|
||||
<string name="screen_join_room_knock_action">"Bidali batzeko eskaera"</string>
|
||||
<string name="screen_join_room_knock_message_description">"Mezua (aukerakoa)"</string>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
<string name="screen_join_room_cancel_knock_alert_description">"Er du sikker på at du vil kansellere forespørselen din om å bli med i dette rommet?"</string>
|
||||
<string name="screen_join_room_cancel_knock_alert_title">"Avbryt forespørsel om å bli med"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_confirmation">"Ja, avslå og blokker"</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_message">"Er du sikker på at du vil avslå invitasjonen til å bli med i dette rommet? Dette vil også forhindre %1$s fra å kontakte deg eller invitere deg til rom."</string>
|
||||
<string name="screen_join_room_decline_and_block_alert_title">"Avslå invitasjon og blokker"</string>
|
||||
<string name="screen_join_room_decline_and_block_button_title">"Avslå og blokker"</string>
|
||||
<string name="screen_join_room_fail_message">"Å bli med i rommet mislyktes."</string>
|
||||
|
|
@ -20,6 +21,8 @@
|
|||
<string name="screen_join_room_knock_message_description">"Melding (valgfritt)"</string>
|
||||
<string name="screen_join_room_knock_sent_description">"Du vil motta en invitasjon til å bli med i rommet hvis forespørselen din blir akseptert."</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Forespørsel om å bli med sendt"</string>
|
||||
<string name="screen_join_room_loading_alert_message">"Vi kunne ikke vise forhåndsvisningen av rommet. Dette kan skyldes nettverks- eller serverproblemer."</string>
|
||||
<string name="screen_join_room_loading_alert_title">"Vi kunne ikke vise forhåndsvisning av dette rommet"</string>
|
||||
<string name="screen_join_room_space_not_supported_description">"%1$s støtter ikke områder ennå. Du kan få tilgang til områder på nett."</string>
|
||||
<string name="screen_join_room_space_not_supported_title">"Områder støttes ikke ennå"</string>
|
||||
<string name="screen_join_room_subtitle_knock">"Klikk på knappen nedenfor, så vil en romadministrator bli varslet. Du vil kunne delta i samtalen når den er godkjent."</string>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_join_room_cancel_knock_action">"Verzoek annuleren"</string>
|
||||
<string name="screen_join_room_join_action">"Toetreden tot de kamer"</string>
|
||||
<string name="screen_join_room_knock_action">"Klop om deel te nemen"</string>
|
||||
<string name="screen_join_room_knock_message_description">"Bericht (optioneel)"</string>
|
||||
<string name="screen_join_room_knock_sent_description">"Je ontvangt een uitnodiging om deel te nemen aan de kamer als je aanvraag wordt geaccepteerd."</string>
|
||||
<string name="screen_join_room_knock_sent_title">"Verzoek om toe te treden verzonden"</string>
|
||||
<string name="screen_join_room_space_not_supported_description">"%1$s ondersteunt nog geen spaces. Je kunt spaces benaderen via de webbrowser."</string>
|
||||
<string name="screen_join_room_space_not_supported_title">"Spaces worden nog niet ondersteund"</string>
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ class JoinRoomPresenterTest {
|
|||
val presenter = createJoinRoomPresenter(
|
||||
roomDescription = Optional.of(roomDescription),
|
||||
joinRoomLambda = { _, _, _ ->
|
||||
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden"))
|
||||
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null))
|
||||
},
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -742,7 +742,7 @@ class JoinRoomPresenterTest {
|
|||
fun `present - when room is not known RoomPreview is loaded with error Forbidden`() = runTest {
|
||||
val client = FakeMatrixClient(
|
||||
getRoomPreviewResult = { _, _ ->
|
||||
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden"))
|
||||
Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null))
|
||||
}
|
||||
)
|
||||
val presenter = createJoinRoomPresenter(
|
||||
|
|
|
|||
|
|
@ -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_knock_requests_list_accept_all_alert_confirm_button_title">"Iawn, derbyn y cyfan"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_alert_description">"Ydych chi\'n siŵr eich bod am dderbyn pob cais i ymuno?"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_alert_title">"Derbyn pob cais"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_button_title">"Derbyn y cyfan"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_failed_alert_description">"Doedd dim modd derbyn pob cais. Hoffech chi roi cynnig arall arni?"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_failed_alert_title">"Wedi methu derbyn pob cais"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_loading_title">"Yn derbyn pob cais i ymuno"</string>
|
||||
<string name="screen_knock_requests_list_accept_failed_alert_description">"Doedd dim modd derbyn y cais hwn. Hoffech chi roi cynnig arall arni?"</string>
|
||||
<string name="screen_knock_requests_list_accept_failed_alert_title">"Wedi methu â derbyn y cais"</string>
|
||||
<string name="screen_knock_requests_list_accept_loading_title">"Yn derbyn cais i ymuno"</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Iawn, gwrthod a gwahardd"</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_description">"Ydych chi\'n siŵr eich bod am wrthod a gwahardd %1$s? Bydd y defnyddiwr hwn ddim yn gallu gofyn am fynediad i ymuno â\'r ystafell hon eto."</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_title">"Gwrthod a gwahardd mynediad"</string>
|
||||
<string name="screen_knock_requests_list_ban_loading_title">"Yn gwrthod a gwahardd mynediad"</string>
|
||||
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Iawn, gwrthod"</string>
|
||||
<string name="screen_knock_requests_list_decline_alert_description">"Ydych chi\'n siŵr eich bod am wrthod %1$s cais i ymuno â\'r ystafell hon?"</string>
|
||||
<string name="screen_knock_requests_list_decline_alert_title">"Gwrthod mynediad"</string>
|
||||
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Gwrthod a gwahardd"</string>
|
||||
<string name="screen_knock_requests_list_decline_failed_alert_description">"Doedd dim modd i ni wrthod y cais hwn. Hoffech chi roi cynnig arall arni?"</string>
|
||||
<string name="screen_knock_requests_list_decline_failed_alert_title">"Wedi methu â gwrthod y cais"</string>
|
||||
<string name="screen_knock_requests_list_decline_loading_title">"Yn gwrthod cais i ymuno"</string>
|
||||
<string name="screen_knock_requests_list_empty_state_description">"Pan fydd rhywun yn gofyn am gael ymuno â\'r ystafell, byddwch yn gallu gweld eu cais yma."</string>
|
||||
<string name="screen_knock_requests_list_empty_state_title">"Dim cais i ymuno yn disgwyl"</string>
|
||||
<string name="screen_knock_requests_list_initial_loading_title">"Yn llwytho ceisiadau i ymuno…"</string>
|
||||
<string name="screen_knock_requests_list_title">"Ceisiadau i ymuno"</string>
|
||||
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Gweld y cyfan"</string>
|
||||
<string name="screen_room_single_knock_request_accept_button_title">"Derbyn"</string>
|
||||
<string name="screen_room_single_knock_request_title">"Mae %1$s eisiau ymuno â\'r ystafell hon"</string>
|
||||
<string name="screen_room_single_knock_request_view_button_title">"Golwg"</string>
|
||||
</resources>
|
||||
|
|
@ -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">"Priimti"</string>
|
||||
</resources>
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
<?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, godta alle"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_alert_description">"Er du sikker på at du vil godta alle forespørsler om å bli med?"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_alert_title">"Godta alle forespørsler"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_button_title">"Godta alle"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_failed_alert_description">"Vi kunne ikke godta alle forespørsler. Vil du prøve igjen?"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_failed_alert_title">"Kunne ikke godta alle forespørsler"</string>
|
||||
<string name="screen_knock_requests_list_accept_all_loading_title">"Godtar alle forespørsler om å bli med"</string>
|
||||
<string name="screen_knock_requests_list_accept_failed_alert_description">"Vi kunne ikke godta denne forespørselen. Vil du prøve igjen?"</string>
|
||||
<string name="screen_knock_requests_list_accept_failed_alert_title">"Kunne ikke godta forespørselen"</string>
|
||||
<string name="screen_knock_requests_list_accept_loading_title">"Godtar forespørsel om å bli med"</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Ja, avslå og utesteng"</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_description">"Er du sikker på at du vil avvise og utestenge %1$s? Denne brukeren vil ikke kunne be om tilgang til dette rommet igjen."</string>
|
||||
<string name="screen_knock_requests_list_ban_alert_title">"Avslå og forby tilgang"</string>
|
||||
<string name="screen_knock_requests_list_ban_loading_title">"Avslår og forbyr tilgang"</string>
|
||||
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Ja, avslå"</string>
|
||||
<string name="screen_knock_requests_list_decline_alert_description">"Er du sikker på at du vil avslå %1$ss forespørsel om å bli med i dette rommet?"</string>
|
||||
|
|
@ -12,8 +21,14 @@
|
|||
<string name="screen_knock_requests_list_decline_failed_alert_description">"Vi kunne ikke avslå denne forespørselen. Vil du prøve igjen?"</string>
|
||||
<string name="screen_knock_requests_list_decline_failed_alert_title">"Kunne ikke avslå forespørselen"</string>
|
||||
<string name="screen_knock_requests_list_decline_loading_title">"Avslår forespørsel om å bli med"</string>
|
||||
<string name="screen_knock_requests_list_empty_state_description">"Når noen ber om å bli med i rommet, vil du kunne se forespørselen deres her."</string>
|
||||
<string name="screen_knock_requests_list_empty_state_title">"Ingen ventende forespørsel om å bli med"</string>
|
||||
<string name="screen_knock_requests_list_initial_loading_title">"Laster inn forespørsler om å bli med…"</string>
|
||||
<string name="screen_knock_requests_list_title">"Forespørsler om å bli med"</string>
|
||||
<plurals name="screen_room_multiple_knock_requests_title">
|
||||
<item quantity="one">"%1$s +%2$d andre ønsker å bli med i dette rommet"</item>
|
||||
<item quantity="other">"%1$s +%2$d andre ønsker å bli med i dette rommet"</item>
|
||||
</plurals>
|
||||
<string name="screen_room_multiple_knock_requests_view_all_button_title">"Vis alle"</string>
|
||||
<string name="screen_room_single_knock_request_accept_button_title">"Godta"</string>
|
||||
<string name="screen_room_single_knock_request_title">"%1$s ønsker å bli med i dette rommet"</string>
|
||||
|
|
|
|||
|
|
@ -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">"Ydych chi\'n siŵr eich bod am adael y sgwrs hon? Dyw\'r sgwrs hon ddim yn gyhoeddus a fyddwch chi ddim yn gallu ailymuno heb wahoddiad."</string>
|
||||
<string name="leave_room_alert_empty_subtitle">"Ydych chi\'n siŵr eich bod am adael yr ystafell hon? Chi yw\'r unig berson yma. Os byddwch yn gadael, fydd neb yn gallu ymuno yn y dyfodol, gan gynnwys chi."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Ydych chi\'n siŵr eich bod am adael yr ystafell hon? Dyw\'r ystafell hon ddim yn gyhoeddus a fyddwch chi ddim yn gallu ailymuno heb wahoddiad."</string>
|
||||
<string name="leave_room_alert_subtitle">"Ydych chi\'n siŵr eich bod am adael yr ystafell?"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_room_alert_empty_subtitle">"Ar tikrai norite išeiti iš šio kambario? Jūs esate vienintelis žmogus jame. Jei išeisite, niekas negalės prisijungti ateityje, įskaitant Jus."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Ar tikrai norite išeiti iš šio kambario? Šis kambarys nėra viešas ir negalėsite vėl prisijungti be kvietimo."</string>
|
||||
<string name="leave_room_alert_subtitle">"Ar tikrai norite išeiti iš kambario?"</string>
|
||||
</resources>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_conversation_alert_subtitle">"Tem certeza de que deseja sair dessa conversa? Essa conversa não é pública e você não poderá entrar novamente sem um convite."</string>
|
||||
<string name="leave_room_alert_empty_subtitle">"Tem certeza de que deseja sair desta sala? Você é a única pessoa aqui. Se você sair, ninguém poderá ingressar no futuro, inclusive você."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Tem certeza de que deseja sair desta sala? Esta sala não é pública e você não poderá entrar novamente sem um convite."</string>
|
||||
<string name="leave_room_alert_subtitle">"Tem certeza de que deseja sair da sala?"</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_app_lock_forgot_pin">"Wedi anghofio\'ch PIN?"</string>
|
||||
<string name="screen_app_lock_setup_confirm_pin">"Cadarnhau eich PIN"</string>
|
||||
</resources>
|
||||
|
|
@ -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_signout_in_progress_dialog_content">"Atsijungiama…"</string>
|
||||
</resources>
|
||||
|
|
@ -9,11 +9,11 @@ package io.element.android.features.login.impl.util
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import io.element.android.appconfig.AuthenticationConfig
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
|
||||
fun openLearnMorePage(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(AuthenticationConfig.SLIDING_SYNC_READ_MORE_URL))
|
||||
val intent = Intent(Intent.ACTION_VIEW, AuthenticationConfig.SLIDING_SYNC_READ_MORE_URL.toUri())
|
||||
tryOrNull { context.startActivity(intent) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
package io.element.android.features.login.impl.web
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.appconfig.AuthenticationConfig
|
||||
import io.element.android.features.login.impl.resolver.network.WellknownAPI
|
||||
|
|
@ -43,7 +43,7 @@ class DefaultWebClientUrlForAuthenticationRetriever @Inject constructor(
|
|||
}
|
||||
val registrationHelperUrl = result.registrationHelperUrl
|
||||
return if (registrationHelperUrl != null) {
|
||||
Uri.parse(registrationHelperUrl)
|
||||
registrationHelperUrl.toUri()
|
||||
.buildUpon()
|
||||
.appendQueryParameter("hs_url", homeServerUrl)
|
||||
.build()
|
||||
|
|
|
|||
15
features/login/impl/src/main/res/values-cy/translations.xml
Normal file
15
features/login/impl/src/main/res/values-cy/translations.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_change_account_provider_other">"Arall"</string>
|
||||
<string name="screen_create_account_title">"Creu cyfrif"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Mae\'r cyfrif hwn wedi\'i gau."</string>
|
||||
<string name="screen_login_title">"Croeso nôl!"</string>
|
||||
<string name="screen_qr_code_login_connection_note_secure_state_title">"Nid yw\'r cysylltiad yn ddiogel"</string>
|
||||
<string name="screen_qr_code_login_error_cancelled_subtitle">"Cafodd y mewngofnodi ei ddiddymu ar y ddyfais arall."</string>
|
||||
<string name="screen_qr_code_login_error_cancelled_title">"Cais mewngofnodi wedi\'i ddiddymu"</string>
|
||||
<string name="screen_qr_code_login_error_declined_title">"Gwrthodwyd y mewngofnodi"</string>
|
||||
<string name="screen_qr_code_login_error_expired_title">"Heb gwblhau\'r mewngofnodi mewn pryd"</string>
|
||||
<string name="screen_qr_code_login_error_linking_not_suported_title">"Nid yw\'r cod QR yn cael ei gefnogi"</string>
|
||||
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Ceisiwch eto"</string>
|
||||
<string name="screen_qr_code_login_unknown_error_description">"Digwyddodd gwall annisgwyl. Ceisiwch eto."</string>
|
||||
</resources>
|
||||
27
features/login/impl/src/main/res/values-lt/translations.xml
Normal file
27
features/login/impl/src/main/res/values-lt/translations.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_account_provider_change">"Keisti paskyros teikėją"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Čia bus saugomi Jūsų pokalbiai - panašiai kaip el. pašto paslaugų teikėjas saugo Jūsų el. laiškus."</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Čia bus saugomi Jūsų pokalbiai - panašiai kaip el. pašto paslaugų teikėjas saugo Jūsų el. laiškus."</string>
|
||||
<string name="screen_change_account_provider_title">"Keisti paskyros teikėją"</string>
|
||||
<string name="screen_change_server_error_invalid_homeserver">"Nepavyko pasiekti šio serverio. Patikrinkite, ar teisingai įvedėte serverio URL. Jei URL yra teisingas, susisiekite su serverio administracija dėl tolimesnės pagalbos."</string>
|
||||
<string name="screen_change_server_error_no_sliding_sync_message">"Šiuo metu šis serveris nepalaiko slenkančios sinchronizacijos (sliding sync)."</string>
|
||||
<string name="screen_change_server_form_header">"Serverio URL"</string>
|
||||
<string name="screen_change_server_form_notice">"Galite prisijungti tik prie serverio, palaikančio slenkančią sinchronizaciją (sliding sync). Jūsų serverio administracija turėtų ją sukonfigūruoti. %1$s"</string>
|
||||
<string name="screen_change_server_subtitle">"Koks yra Jūsų serverio adresas?"</string>
|
||||
<string name="screen_create_account_title">"Sukurti paskyrą"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Ši paskyra buvo išjungta."</string>
|
||||
<string name="screen_login_error_invalid_credentials">"Neteisingas vartotojo vardas ir (arba) slaptažodis"</string>
|
||||
<string name="screen_login_error_invalid_user_id">"Tai nėra tinkamas vartotojo vardas. Reikalingas formatas: \'@vartotojas:serveris.org\'"</string>
|
||||
<string name="screen_login_error_unsupported_authentication">"Pasirinktas serveris nepalaiko slaptažodžio ar OIDC prisijungimo. Susisiekite su serverio administracija arba pasirinkite kitą serverį."</string>
|
||||
<string name="screen_login_form_header">"Įveskite savo duomenis"</string>
|
||||
<string name="screen_login_subtitle">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string>
|
||||
<string name="screen_login_title">"Sveiki sugrįžę!"</string>
|
||||
<string name="screen_login_title_with_homeserver">"Prisijungti prie %1$s"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Keisti paskyros teikėją"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Privatus serveris “Element” darbuotojams."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix yra atviras tinklas, skirtas saugiam, decentralizuotam bendravimui."</string>
|
||||
<string name="screen_server_confirmation_message_register">"Čia bus saugomi Jūsų pokalbiai - panašiai kaip el. pašto paslaugų teikėjas saugo Jūsų el. laiškus."</string>
|
||||
<string name="screen_server_confirmation_title_login">"Jūs ruošiatės prisijungti prie %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"Jūs ruošiatės susikurti paskyrą %1$s"</string>
|
||||
</resources>
|
||||
|
|
@ -55,6 +55,7 @@ Prøv å logge på manuelt, eller skann QR-koden med en annen enhet."</string>
|
|||
<string name="screen_qr_code_login_error_sliding_sync_not_supported_subtitle">"Kontotilbyderen din støtter ikke %1$s."</string>
|
||||
<string name="screen_qr_code_login_error_sliding_sync_not_supported_title">"%1$s støttes ikke"</string>
|
||||
<string name="screen_qr_code_login_initial_state_button_title">"Klar til å skanne"</string>
|
||||
<string name="screen_qr_code_login_initial_state_item_1">"Åpne %1$s på en datamaskin"</string>
|
||||
<string name="screen_qr_code_login_initial_state_item_2">"Klikk på avataren din"</string>
|
||||
<string name="screen_qr_code_login_initial_state_item_3">"Velg %1$s"</string>
|
||||
<string name="screen_qr_code_login_initial_state_item_3_action">"«Koble til ny enhet»"</string>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
<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_user_id">"Esse não é um identificador de usuário válido. Formato esperado: \'@usuário:servidor.org\'"</string>
|
||||
<string name="screen_login_error_refresh_tokens">"Este servidor está configurado para usar tokens de atualização. Eles não são suportados ao usar login baseado em senha."</string>
|
||||
<string name="screen_login_error_unsupported_authentication">"O servidor selecionado não suporta senha ou login no OIDC. Entre em contato com o administrador ou escolha outro servidor."</string>
|
||||
<string name="screen_login_form_header">"Insira seus dados"</string>
|
||||
<string name="screen_login_subtitle">"A Matrix é uma rede aberta para comunicação segura e descentralizada."</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_signout_confirmation_dialog_submit">"Allgofnodi"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Allgofnodi"</string>
|
||||
<string name="screen_signout_preference_item">"Allgofnodi"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?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">"Ar tikrai norite atsijungti?"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Atsijungiama…"</string>
|
||||
</resources>
|
||||
|
|
@ -4,10 +4,15 @@
|
|||
<string name="screen_signout_confirmation_dialog_submit">"Sair"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Sair"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Saindo…"</string>
|
||||
<string name="screen_signout_key_backup_disabled_subtitle">"Você está prestes a sair da sua última sessão. Se você sair agora, perderá o acesso às suas mensagens criptografadas."</string>
|
||||
<string name="screen_signout_key_backup_disabled_title">"Você desativou o backup"</string>
|
||||
<string name="screen_signout_key_backup_offline_subtitle">"O backup das suas chaves ainda estava sendo feito quando você ficou off-line. Reconecte-se para que você possa fazer o backup de suas chaves antes de sair."</string>
|
||||
<string name="screen_signout_key_backup_offline_title">"O backup das suas chaves ainda está em andamento"</string>
|
||||
<string name="screen_signout_key_backup_ongoing_subtitle">"Aguarde até que isso seja concluído antes de sair."</string>
|
||||
<string name="screen_signout_key_backup_ongoing_title">"O backup das suas chaves ainda está em andamento"</string>
|
||||
<string name="screen_signout_preference_item">"Sair"</string>
|
||||
<string name="screen_signout_recovery_disabled_subtitle">"Você está prestes a sair da sua última sessão. Se você sair agora, perderá o acesso às suas mensagens criptografadas."</string>
|
||||
<string name="screen_signout_recovery_disabled_title">"A recuperação não está configurada"</string>
|
||||
<string name="screen_signout_save_recovery_key_subtitle">"Você está prestes a sair da sua última sessão. Se você sair agora, poderá perder o acesso às suas mensagens criptografadas."</string>
|
||||
<string name="screen_signout_save_recovery_key_title">"Você salvou sua chave de recuperação?"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -363,7 +363,9 @@ private fun MessagesViewContent(
|
|||
},
|
||||
content = { paddingValues ->
|
||||
Box(modifier = Modifier.padding(paddingValues)) {
|
||||
val scrollBehavior = PinnedMessagesBannerViewDefaults.rememberExitOnScrollBehavior()
|
||||
val scrollBehavior = PinnedMessagesBannerViewDefaults.rememberScrollBehavior(
|
||||
pinnedMessagesCount = state.pinnedMessagesBannerState.pinnedMessagesCount(),
|
||||
)
|
||||
TimelineView(
|
||||
state = state.timelineState,
|
||||
timelineProtectionState = state.timelineProtectionState,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.traversalIndex
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -188,6 +190,7 @@ private fun ActionListViewContent(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.clearAndSetSemantics {},
|
||||
)
|
||||
if (target.event.messageShield != null) {
|
||||
MessageShieldView(
|
||||
|
|
@ -347,12 +350,21 @@ private fun EmojiReactionsRow(
|
|||
)
|
||||
for (emoji in defaultEmojis) {
|
||||
val isHighlighted = highlightedEmojis.contains(emoji)
|
||||
EmojiButton(emoji, isHighlighted, onEmojiReactionClick)
|
||||
EmojiButton(
|
||||
modifier = Modifier
|
||||
// Make it appear after the more useful actions for the accessibility service
|
||||
.semantics {
|
||||
traversalIndex = 1f
|
||||
},
|
||||
emoji = emoji,
|
||||
isHighlighted = isHighlighted,
|
||||
onClick = onEmojiReactionClick
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.ReactionAdd(),
|
||||
|
|
@ -366,6 +378,10 @@ private fun EmojiReactionsRow(
|
|||
indication = ripple(bounded = false, radius = emojiRippleRadius),
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
// Make it appear after the more useful actions for the accessibility service
|
||||
.semantics {
|
||||
traversalIndex = 1f
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -413,6 +429,7 @@ private fun EmojiButton(
|
|||
emoji: String,
|
||||
isHighlighted: Boolean,
|
||||
onClick: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val backgroundColor = if (isHighlighted) {
|
||||
ElementTheme.colors.bgActionPrimaryRest
|
||||
|
|
@ -425,10 +442,16 @@ private fun EmojiButton(
|
|||
stringResource(id = CommonStrings.a11y_react_with, emoji)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.size(48.dp)
|
||||
.background(backgroundColor, CircleShape)
|
||||
.clearAndSetSemantics {
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = { onClick(emoji) },
|
||||
indication = ripple(bounded = false, radius = emojiRippleRadius),
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
.semantics {
|
||||
contentDescription = description
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
|
|
@ -436,13 +459,6 @@ private fun EmojiButton(
|
|||
Text(
|
||||
emoji,
|
||||
style = ElementTheme.typography.fontBodyLgRegular.copy(fontSize = 24.dp.toSp(), color = Color.White),
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = { onClick(emoji) },
|
||||
indication = ripple(bounded = false, radius = emojiRippleRadius),
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ internal fun DisabledComposerView(
|
|||
IconColorButton(
|
||||
onClick = {},
|
||||
imageVector = CompoundIcons.Plus(),
|
||||
contentDescription = null,
|
||||
iconColorButtonStyle = IconColorButtonStyle.Disabled,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ internal interface PinnedMessagesBannerViewScrollBehavior {
|
|||
|
||||
internal object PinnedMessagesBannerViewDefaults {
|
||||
@Composable
|
||||
fun rememberExitOnScrollBehavior(): PinnedMessagesBannerViewScrollBehavior = remember {
|
||||
fun rememberScrollBehavior(pinnedMessagesCount: Int): PinnedMessagesBannerViewScrollBehavior = remember(pinnedMessagesCount) {
|
||||
ExitOnScrollBehavior()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
package io.element.android.features.messages.impl.timeline
|
||||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
|
|
@ -75,6 +74,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline
|
|||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
|
|
@ -126,10 +126,7 @@ fun TimelineView(
|
|||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
// Disable reverse layout when TalkBack is enabled to avoid incorrect ordering issues seen in the current Compose UI version
|
||||
val useReverseLayout = remember {
|
||||
val accessibilityManager = context.getSystemService(AccessibilityManager::class.java)
|
||||
accessibilityManager.isTouchExplorationEnabled.not()
|
||||
}
|
||||
val useReverseLayout = !isTalkbackActive()
|
||||
|
||||
fun inReplyToClick(eventId: EventId) {
|
||||
state.eventSink(TimelineEvents.FocusOnEvent(eventId))
|
||||
|
|
@ -159,7 +156,7 @@ fun TimelineView(
|
|||
.testTag(TestTags.timeline),
|
||||
state = lazyListState,
|
||||
reverseLayout = useReverseLayout,
|
||||
contentPadding = PaddingValues(vertical = 8.dp),
|
||||
contentPadding = PaddingValues(top = 64.dp, bottom = 8.dp),
|
||||
) {
|
||||
items(
|
||||
items = state.timelineItems,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import io.element.android.libraries.designsystem.theme.messageFromMeBackground
|
|||
import io.element.android.libraries.designsystem.theme.messageFromOtherBackground
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
|
||||
private val BUBBLE_RADIUS = 12.dp
|
||||
private val avatarRadius = AvatarSize.TimelineSender.dp / 2
|
||||
|
|
@ -95,6 +96,17 @@ fun MessageEventBubble(
|
|||
}
|
||||
}
|
||||
|
||||
val clickableModifier = if (isTalkbackActive()) {
|
||||
Modifier
|
||||
} else {
|
||||
Modifier.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
indication = ripple(),
|
||||
interactionSource = interactionSource
|
||||
)
|
||||
}
|
||||
|
||||
// Ignore state.isHighlighted for now, we need a design decision on it.
|
||||
val backgroundBubbleColor = when {
|
||||
state.isMine -> ElementTheme.colors.messageFromMeBackground
|
||||
|
|
@ -137,12 +149,7 @@ fun MessageEventBubble(
|
|||
.toDp()
|
||||
)
|
||||
.clip(bubbleShape)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
indication = ripple(),
|
||||
interactionSource = interactionSource
|
||||
),
|
||||
.then(clickableModifier),
|
||||
color = backgroundBubbleColor,
|
||||
shape = bubbleShape,
|
||||
content = content
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.invisibleToUser
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -77,7 +79,8 @@ fun TimelineEventTimestampView(
|
|||
.size(15.dp, 18.dp)
|
||||
.clickable(isVerifiedUserSendFailure) {
|
||||
eventSink(TimelineEvents.ComputeVerifiedUserSendFailure(event))
|
||||
},
|
||||
}
|
||||
.semantics { invisibleToUser() }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +94,8 @@ fun TimelineEventTimestampView(
|
|||
.size(15.dp)
|
||||
.clickable {
|
||||
eventSink(TimelineEvents.ShowShieldDialog(shield))
|
||||
},
|
||||
}
|
||||
.semantics { invisibleToUser() },
|
||||
tint = shield.toIconColor(),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
|
|
|
|||
|
|
@ -37,13 +37,12 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||
import androidx.compose.ui.platform.ViewConfiguration
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.invisibleToUser
|
||||
import androidx.compose.ui.semantics.isTraversalGroup
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import androidx.compose.ui.semantics.traversalIndex
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -96,6 +95,7 @@ import io.element.android.libraries.matrix.ui.messages.sender.SenderNameMode
|
|||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.abs
|
||||
|
|
@ -245,7 +245,7 @@ fun TimelineItemEventRow(
|
|||
),
|
||||
renderReadReceipts = renderReadReceipts,
|
||||
onReadReceiptsClick = { onReadReceiptClick(event) },
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
modifier = Modifier.padding(top = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -595,7 +595,10 @@ private fun MessageEventBubbleContent(
|
|||
timestampPosition = timestampPosition,
|
||||
eventSink = eventSink,
|
||||
canShrinkContent = canShrinkContent,
|
||||
modifier = timestampLayoutModifier,
|
||||
modifier = timestampLayoutModifier.semantics(mergeDescendants = false) {
|
||||
isTraversalGroup = true
|
||||
traversalIndex = -1f
|
||||
},
|
||||
content = { onContentLayoutChange ->
|
||||
eventContentView(contentModifier, onContentLayoutChange)
|
||||
}
|
||||
|
|
@ -607,17 +610,23 @@ private fun MessageEventBubbleContent(
|
|||
val inReplyToModifier = Modifier
|
||||
.padding(top = topPadding, start = 8.dp, end = 8.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
// FIXME when a node is clickable, its contents won't be added to the semantics tree of its parent
|
||||
.clickable(onClick = inReplyToClick)
|
||||
|
||||
val talkbackCompatModifier = if (isTalkbackActive()) {
|
||||
// Use z-index to make the replied to text being read after the message
|
||||
// Usually, you'd use traversalIndex for that, but it's not working for some reason
|
||||
inReplyToModifier.zIndex(1f)
|
||||
} else {
|
||||
inReplyToModifier.clickable(onClick = inReplyToClick)
|
||||
}
|
||||
InReplyToView(
|
||||
inReplyTo = inReplyTo,
|
||||
hideImage = timelineProtectionState.hideMediaContent(inReplyTo.eventId()),
|
||||
modifier = inReplyToModifier,
|
||||
modifier = talkbackCompatModifier,
|
||||
)
|
||||
}
|
||||
if (inReplyToDetails != null) {
|
||||
// Use SubComposeLayout only if necessary as it can have consequences on the performance.
|
||||
EqualWidthColumn(modifier = modifier, spacing = 8.dp) {
|
||||
EqualWidthColumn(spacing = 8.dp) {
|
||||
threadDecoration()
|
||||
inReplyTo(inReplyToDetails)
|
||||
contentWithTimestamp()
|
||||
|
|
@ -651,9 +660,7 @@ private fun MessageEventBubbleContent(
|
|||
paddingBehaviour = paddingBehaviour,
|
||||
inReplyToDetails = event.inReplyTo,
|
||||
canShrinkContent = event.content is TimelineItemVoiceContent,
|
||||
modifier = bubbleModifier.semantics(mergeDescendants = true) {
|
||||
contentDescription = event.safeSenderName
|
||||
}
|
||||
modifier = bubbleModifier,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import io.element.android.features.messages.impl.R
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
|
|
@ -25,6 +27,7 @@ import io.element.android.features.messages.impl.timeline.components.layout.Cont
|
|||
import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
||||
import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState
|
||||
|
|
@ -140,7 +143,16 @@ private fun TimelineItemGroupedEventsRowContent(
|
|||
},
|
||||
) {
|
||||
Column(modifier = modifier.animateContentSize()) {
|
||||
val groupedEventsTitle = pluralStringResource(
|
||||
id = R.plurals.screen_room_timeline_state_changes,
|
||||
count = timelineItem.events.size,
|
||||
timelineItem.events.size
|
||||
)
|
||||
GroupHeaderView(
|
||||
modifier = Modifier.clearAndSetSemantics {
|
||||
val groupedEventsContent = timelineItem.events.reversed().joinToString(separator = "\n") { (it.content as TimelineItemStateContent).body }
|
||||
contentDescription = groupedEventsTitle + groupedEventsContent
|
||||
},
|
||||
text = pluralStringResource(
|
||||
id = R.plurals.screen_room_timeline_state_changes,
|
||||
count = timelineItem.events.size,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.invisibleToUser
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.features.messages.impl.R
|
||||
|
|
@ -40,7 +42,9 @@ fun TimelineItemReactionsView(
|
|||
) {
|
||||
var expanded: Boolean by rememberSaveable { mutableStateOf(false) }
|
||||
TimelineItemReactionsView(
|
||||
modifier = modifier,
|
||||
modifier = modifier.semantics {
|
||||
invisibleToUser()
|
||||
},
|
||||
reactions = reactionsState.reactions,
|
||||
userCanSendReaction = userCanSendReaction,
|
||||
expanded = expanded,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
|
|
@ -17,6 +19,9 @@ import androidx.compose.ui.draw.drawWithCache
|
|||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -28,6 +33,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
|
|
@ -37,8 +43,12 @@ import io.element.android.libraries.designsystem.theme.LocalBuildMeta
|
|||
import io.element.android.libraries.designsystem.theme.highlightedMessageBackgroundColor
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun TimelineItemRow(
|
||||
timelineItem: TimelineItem,
|
||||
|
|
@ -120,7 +130,28 @@ internal fun TimelineItemRow(
|
|||
)
|
||||
}
|
||||
else -> {
|
||||
val a11yVoiceMessage = stringResource(CommonStrings.a11y_voice_message)
|
||||
TimelineItemEventRow(
|
||||
modifier = Modifier
|
||||
.semantics(mergeDescendants = true) {
|
||||
contentDescription = if (timelineItem.content is TimelineItemVoiceContent) {
|
||||
val voiceMessageText = String.format(a11yVoiceMessage, timelineItem.content.duration.toString(DurationUnit.MINUTES))
|
||||
"${timelineItem.safeSenderName}, $voiceMessageText"
|
||||
} else {
|
||||
timelineItem.safeSenderName
|
||||
}
|
||||
}
|
||||
// Custom clickable that applies over the whole item for accessibility
|
||||
.then(
|
||||
if (isTalkbackActive()) {
|
||||
Modifier.combinedClickable(
|
||||
onClick = { onContentClick(timelineItem) },
|
||||
onLongClick = { onLongClick(timelineItem) }
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
event = timelineItem,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
renderReadReceipts = renderReadReceipts,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.size
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -21,6 +22,7 @@ import io.element.android.libraries.designsystem.icons.CompoundDrawables
|
|||
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.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun TimelineItemFileView(
|
||||
|
|
@ -37,7 +39,7 @@ fun TimelineItemFileView(
|
|||
icon = {
|
||||
Icon(
|
||||
resourceId = CompoundDrawables.ic_compound_attachment,
|
||||
contentDescription = null,
|
||||
contentDescription = stringResource(CommonStrings.common_file),
|
||||
tint = ElementTheme.colors.iconPrimary,
|
||||
modifier = Modifier
|
||||
.size(16.dp)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImage
|
||||
|
|
@ -55,6 +53,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
|||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.wysiwyg.compose.EditorStyledText
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
|
||||
|
|
@ -71,10 +70,9 @@ fun TimelineItemImageView(
|
|||
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val description = stringResource(CommonStrings.common_image)
|
||||
Column(
|
||||
modifier = modifier.semantics { contentDescription = description },
|
||||
) {
|
||||
val a11yLabel = stringResource(CommonStrings.common_image)
|
||||
val description = content.caption?.let { "$a11yLabel: $it" } ?: a11yLabel
|
||||
Column(modifier = modifier) {
|
||||
val containerModifier = if (content.showCaption) {
|
||||
Modifier.clip(RoundedCornerShape(10.dp))
|
||||
} else {
|
||||
|
|
@ -93,7 +91,16 @@ fun TimelineItemImageView(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.then(if (isLoaded) Modifier.background(Color.White) else Modifier)
|
||||
.then(if (onContentClick != null) Modifier.combinedClickable(onClick = onContentClick, onLongClick = onLongClick) else Modifier),
|
||||
.then(
|
||||
if (!isTalkbackActive() && onContentClick != null) {
|
||||
Modifier.combinedClickable(
|
||||
onClick = onContentClick,
|
||||
onLongClick = onLongClick
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
model = content.thumbnailMediaRequestData,
|
||||
contentScale = ContentScale.Fit,
|
||||
alignment = Alignment.Center,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import androidx.compose.ui.graphics.ColorFilter
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.invisibleToUser
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -63,6 +63,7 @@ import io.element.android.libraries.matrix.ui.media.MAX_THUMBNAIL_WIDTH
|
|||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.wysiwyg.compose.EditorStyledText
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
|
||||
|
|
@ -79,10 +80,10 @@ fun TimelineItemVideoView(
|
|||
onContentLayoutChange: (ContentAvoidingLayoutData) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val description = stringResource(CommonStrings.common_video)
|
||||
Column(
|
||||
modifier = modifier.semantics { contentDescription = description }
|
||||
) {
|
||||
val isTalkbackActive = isTalkbackActive()
|
||||
val a11yLabel = stringResource(CommonStrings.common_video)
|
||||
val description = content.caption?.let { "$a11yLabel: $it" } ?: a11yLabel
|
||||
Column(modifier = modifier) {
|
||||
val containerModifier = if (content.showCaption) {
|
||||
Modifier
|
||||
.padding(top = 6.dp)
|
||||
|
|
@ -104,7 +105,16 @@ fun TimelineItemVideoView(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.then(if (isLoaded) Modifier.background(Color.White) else Modifier)
|
||||
.then(if (onContentClick != null) Modifier.combinedClickable(onClick = onContentClick, onLongClick = onLongClick) else Modifier),
|
||||
.then(
|
||||
if (!isTalkbackActive && onContentClick != null) {
|
||||
Modifier.combinedClickable(
|
||||
onClick = onContentClick,
|
||||
onLongClick = onLongClick
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
model = MediaRequestData(
|
||||
source = content.thumbnailSource,
|
||||
kind = MediaRequestData.Kind.Thumbnail(
|
||||
|
|
@ -126,6 +136,7 @@ fun TimelineItemVideoView(
|
|||
imageVector = CompoundIcons.PlaySolid(),
|
||||
contentDescription = stringResource(id = CommonStrings.a11y_play),
|
||||
colorFilter = ColorFilter.tint(Color.White),
|
||||
modifier = Modifier.semantics { invisibleToUser() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.disabled
|
||||
import androidx.compose.ui.semantics.onClick
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
|
@ -40,7 +41,6 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
|||
import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContentProvider
|
||||
import io.element.android.libraries.androidutils.accessibility.isScreenReaderEnabled
|
||||
import io.element.android.libraries.designsystem.components.media.WaveformPlaybackView
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
|
@ -49,6 +49,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
|||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.libraries.ui.utils.time.isTalkbackActive
|
||||
import io.element.android.libraries.voiceplayer.api.VoiceMessageEvents
|
||||
import io.element.android.libraries.voiceplayer.api.VoiceMessageState
|
||||
import io.element.android.libraries.voiceplayer.api.VoiceMessageStateProvider
|
||||
|
|
@ -66,10 +67,27 @@ fun TimelineItemVoiceView(
|
|||
}
|
||||
|
||||
val a11y = stringResource(CommonStrings.common_voice_message)
|
||||
val a11yActionLabel = stringResource(
|
||||
when (state.button) {
|
||||
VoiceMessageState.Button.Play -> CommonStrings.a11y_play
|
||||
VoiceMessageState.Button.Pause -> CommonStrings.a11y_pause
|
||||
VoiceMessageState.Button.Downloading -> CommonStrings.common_downloading
|
||||
VoiceMessageState.Button.Retry -> CommonStrings.action_retry
|
||||
VoiceMessageState.Button.Disabled -> CommonStrings.error_unknown
|
||||
}
|
||||
)
|
||||
Row(
|
||||
modifier = modifier
|
||||
.semantics {
|
||||
.clearAndSetSemantics {
|
||||
contentDescription = a11y
|
||||
if (state.button == VoiceMessageState.Button.Disabled) {
|
||||
disabled()
|
||||
} else if (state.button in listOf(VoiceMessageState.Button.Play, VoiceMessageState.Button.Pause)) {
|
||||
onClick(label = a11yActionLabel) {
|
||||
playPause()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
.onSizeChanged {
|
||||
onContentLayoutChange(
|
||||
|
|
@ -81,12 +99,14 @@ fun TimelineItemVoiceView(
|
|||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
when (state.button) {
|
||||
VoiceMessageState.Button.Play -> PlayButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Pause -> PauseButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Downloading -> ProgressButton()
|
||||
VoiceMessageState.Button.Retry -> RetryButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Disabled -> PlayButton(onClick = {}, enabled = false)
|
||||
if (!isTalkbackActive()) {
|
||||
when (state.button) {
|
||||
VoiceMessageState.Button.Play -> PlayButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Pause -> PauseButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Downloading -> ProgressButton()
|
||||
VoiceMessageState.Button.Retry -> RetryButton(onClick = ::playPause)
|
||||
VoiceMessageState.Button.Disabled -> PlayButton(onClick = {}, enabled = false)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
|
|
@ -97,13 +117,12 @@ fun TimelineItemVoiceView(
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
val context = LocalContext.current
|
||||
WaveformPlaybackView(
|
||||
showCursor = state.showCursor,
|
||||
playbackProgress = state.progress,
|
||||
waveform = content.waveform,
|
||||
modifier = Modifier.height(34.dp),
|
||||
seekEnabled = !context.isScreenReaderEnabled(),
|
||||
seekEnabled = !isTalkbackActive(),
|
||||
onSeek = { state.eventSink(VoiceMessageEvents.Seek(it)) },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import androidx.compose.ui.res.pluralStringResource
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.invisibleToUser
|
||||
import androidx.compose.ui.semantics.testTag
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -56,7 +57,11 @@ fun TimelineItemReadReceiptView(
|
|||
) {
|
||||
if (state.receipts.isNotEmpty()) {
|
||||
if (renderReadReceipts) {
|
||||
ReadReceiptsRow(modifier = modifier) {
|
||||
ReadReceiptsRow(
|
||||
modifier = modifier.clearAndSetSemantics {
|
||||
invisibleToUser()
|
||||
}
|
||||
) {
|
||||
ReadReceiptsAvatars(
|
||||
receipts = state.receipts,
|
||||
modifier = Modifier
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="emoji_picker_category_activity">"Gweithgareddau"</string>
|
||||
<string name="emoji_picker_category_flags">"Baneri"</string>
|
||||
<string name="emoji_picker_category_foods">"Bwyd a Diod"</string>
|
||||
<string name="emoji_picker_category_nature">"Anifeiliaid a Natur"</string>
|
||||
<string name="emoji_picker_category_objects">"Gwrthrychau"</string>
|
||||
<string name="emoji_picker_category_people">"Wynebau Hapus a Phobl"</string>
|
||||
<string name="emoji_picker_category_places">"Teithio a Llefydd"</string>
|
||||
<string name="emoji_picker_category_symbols">"Symbolau"</string>
|
||||
<string name="screen_report_content_block_user">"Rhwystro defnyddiwr"</string>
|
||||
<string name="screen_room_attachment_source_camera">"Camera"</string>
|
||||
<string name="screen_room_attachment_source_camera_photo">"Cymryd llun"</string>
|
||||
<string name="screen_room_attachment_source_files">"Atodiad"</string>
|
||||
<string name="screen_room_attachment_source_location">"Lleoliad"</string>
|
||||
<string name="screen_room_attachment_source_poll">"Pôl"</string>
|
||||
<string name="screen_room_mentions_at_room_subtitle">"Rhowch wybod i\'r ystafell gyfan"</string>
|
||||
<string name="screen_room_mentions_at_room_title">"Pawb"</string>
|
||||
<string name="screen_room_timeline_less_reactions">"Dangos llai"</string>
|
||||
<string name="screen_room_timeline_reactions_show_less">"Dangos llai"</string>
|
||||
<string name="screen_room_timeline_reactions_show_more">"Dangos rhagor"</string>
|
||||
<string name="screen_room_timeline_read_marker_title">"Newydd"</string>
|
||||
<string name="screen_room_typing_two_members">"%1$s a %2$s"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="emoji_picker_category_activity">"Veikla"</string>
|
||||
<string name="emoji_picker_category_flags">"Vėliavos"</string>
|
||||
<string name="emoji_picker_category_foods">"Maistas ir Gėrimai"</string>
|
||||
<string name="emoji_picker_category_nature">"Gyvūnai ir Gamta"</string>
|
||||
<string name="emoji_picker_category_objects">"Objektai"</string>
|
||||
<string name="emoji_picker_category_people">"Šypsenėlės ir Žmonės"</string>
|
||||
<string name="emoji_picker_category_places">"Kelionės ir Vietovės"</string>
|
||||
<string name="emoji_picker_category_symbols">"Simboliai"</string>
|
||||
<string name="screen_report_content_block_user">"Blokuoti vartotoją"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Pažymėkite, jei norite paslėpti visas esamas ir būsimas šio vartotojo žinutes"</string>
|
||||
<string name="screen_report_content_explanation">"Apie šią žinutę bus pranešta Jūsų serverio administracijai. Jie negalės perskaityti jokių užšifruotų žinučių."</string>
|
||||
<string name="screen_report_content_hint">"Skundo dėl šio turinio priežastis"</string>
|
||||
<string name="screen_room_attachment_source_camera">"Kamera"</string>
|
||||
<string name="screen_room_attachment_source_camera_photo">"Fotografuoti"</string>
|
||||
<string name="screen_room_attachment_source_camera_video">"Įrašyti vaizdo įrašą"</string>
|
||||
<string name="screen_room_attachment_source_files">"Priedas"</string>
|
||||
<string name="screen_room_attachment_source_gallery">"Nuotraukų ir vaizdo įrašų biblioteka"</string>
|
||||
<string name="screen_room_timeline_beginning_of_room">"Tai yra %1$s pradžia."</string>
|
||||
<string name="screen_room_timeline_beginning_of_room_no_name">"Tai yra šio pokalbio pradžia."</string>
|
||||
<string name="screen_room_timeline_read_marker_title">"Naujų"</string>
|
||||
<plurals name="screen_room_timeline_state_changes">
|
||||
<item quantity="one">"%1$d kambario pakeitimas"</item>
|
||||
<item quantity="few">"%1$d kambario pakeitimai"</item>
|
||||
<item quantity="other">"%1$d kambario pakeitimų"</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
<string name="screen_room_attachment_source_poll">"Enquete"</string>
|
||||
<string name="screen_room_attachment_text_formatting">"Formatação de texto"</string>
|
||||
<string name="screen_room_encrypted_history_banner">"O histórico de mensagens não está disponível no momento."</string>
|
||||
<string name="screen_room_encrypted_history_banner_unverified">"O histórico de mensagens não está disponível nesta sala. Verifique este dispositivo para ver seu histórico de mensagens."</string>
|
||||
<string name="screen_room_invite_again_alert_message">"Gostaria de convidá-los de volta?"</string>
|
||||
<string name="screen_room_invite_again_alert_title">"Você está sozinho neste chat"</string>
|
||||
<string name="screen_room_mentions_at_room_subtitle">"Notificar a sala inteira"</string>
|
||||
|
|
|
|||
|
|
@ -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_onboarding_sign_up">"Creu cyfrif"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_onboarding_sign_in_manually">"Prisijunkite rankiniu būdu"</string>
|
||||
<string name="screen_onboarding_sign_in_with_qr_code">"Prisijunkite naudodami QR kodą"</string>
|
||||
<string name="screen_onboarding_sign_up">"Sukurti paskyrą"</string>
|
||||
<string name="screen_onboarding_welcome_subtitle">"Sveiki atvykę į %1$s. Įkrautas greitumui ir paprastumui."</string>
|
||||
<string name="screen_onboarding_welcome_title">"Būkite savo elemente"</string>
|
||||
</resources>
|
||||
10
features/poll/impl/src/main/res/values-cy/translations.xml
Normal file
10
features/poll/impl/src/main/res/values-cy/translations.xml
Normal 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_create_poll_add_option_btn">"Ychwanegu dewis"</string>
|
||||
<string name="screen_create_poll_cancel_confirmation_content_android">"Dyw eich newidiadau heb gael eu cadw. Ydych chi\'n siŵr eich bod am fynd nôl?"</string>
|
||||
<string name="screen_create_poll_title">"Creu Pôl"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation_title">"Dileu Pôl"</string>
|
||||
<string name="screen_edit_poll_title">"Golygu pôl"</string>
|
||||
<string name="screen_polls_history_filter_ongoing">"Parhaus"</string>
|
||||
<string name="screen_polls_history_title">"Polau"</string>
|
||||
</resources>
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
<string name="screen_edit_poll_delete_confirmation_title">"Umfrage löschen"</string>
|
||||
<string name="screen_edit_poll_title">"Umfrage bearbeiten"</string>
|
||||
<string name="screen_polls_history_empty_ongoing">"Keine laufenden Umfragen vorhanden."</string>
|
||||
<string name="screen_polls_history_empty_past">"Keine vergangenen Umfragen vorhanden."</string>
|
||||
<string name="screen_polls_history_empty_past">"Keine beendeten Umfragen vorhanden."</string>
|
||||
<string name="screen_polls_history_filter_ongoing">"Aktuell"</string>
|
||||
<string name="screen_polls_history_filter_past">"Vergangene"</string>
|
||||
<string name="screen_polls_history_filter_past">"Vergangenheit"</string>
|
||||
<string name="screen_polls_history_title">"Umfragen"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@
|
|||
<string name="screen_polls_history_empty_ongoing">"Finner ingen pågående avstemninger."</string>
|
||||
<string name="screen_polls_history_empty_past">"Kan ikke finne noen tidligere avstemninger."</string>
|
||||
<string name="screen_polls_history_filter_ongoing">"Pågående"</string>
|
||||
<string name="screen_polls_history_filter_past">"Fortid"</string>
|
||||
<string name="screen_polls_history_title">"Avstemninger"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -7,16 +7,13 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
|
||||
sealed interface AdvancedSettingsEvents {
|
||||
data class SetDeveloperModeEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
||||
data class SetSharePresenceEnabled(val enabled: Boolean) : AdvancedSettingsEvents
|
||||
data class SetCompressMedia(val compress: Boolean) : AdvancedSettingsEvents
|
||||
data object ChangeTheme : AdvancedSettingsEvents
|
||||
data object CancelChangeTheme : AdvancedSettingsEvents
|
||||
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
|
||||
data class SetTheme(val theme: ThemeOption) : AdvancedSettingsEvents
|
||||
data class SetTimelineMediaPreviewValue(val value: MediaPreviewValue) : AdvancedSettingsEvents
|
||||
data class SetHideInviteAvatars(val value: Boolean) : AdvancedSettingsEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@ package io.element.android.features.preferences.impl.advanced
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.compound.theme.mapToTheme
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
|
@ -39,11 +38,9 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
val doesCompressMedia by remember {
|
||||
sessionPreferencesStore.doesCompressMedia()
|
||||
}.collectAsState(initial = true)
|
||||
val theme by remember {
|
||||
val theme = remember {
|
||||
appPreferencesStore.getThemeFlow().mapToTheme()
|
||||
}.collectAsState(initial = Theme.System)
|
||||
var showChangeThemeDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val hideInviteAvatars by remember {
|
||||
appPreferencesStore.getHideInviteAvatarsFlow()
|
||||
}.collectAsState(false)
|
||||
|
|
@ -52,6 +49,16 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
appPreferencesStore.getTimelineMediaPreviewValueFlow()
|
||||
}.collectAsState(initial = MediaPreviewValue.On)
|
||||
|
||||
val themeOption by remember {
|
||||
derivedStateOf {
|
||||
when (theme.value) {
|
||||
Theme.System -> ThemeOption.System
|
||||
Theme.Dark -> ThemeOption.Dark
|
||||
Theme.Light -> ThemeOption.Light
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvents(event: AdvancedSettingsEvents) {
|
||||
when (event) {
|
||||
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
||||
|
|
@ -63,11 +70,12 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
is AdvancedSettingsEvents.SetCompressMedia -> localCoroutineScope.launch {
|
||||
sessionPreferencesStore.setCompressMedia(event.compress)
|
||||
}
|
||||
AdvancedSettingsEvents.CancelChangeTheme -> showChangeThemeDialog = false
|
||||
AdvancedSettingsEvents.ChangeTheme -> showChangeThemeDialog = true
|
||||
is AdvancedSettingsEvents.SetTheme -> localCoroutineScope.launch {
|
||||
appPreferencesStore.setTheme(event.theme.name)
|
||||
showChangeThemeDialog = false
|
||||
when (event.theme) {
|
||||
ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name)
|
||||
ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name)
|
||||
ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name)
|
||||
}
|
||||
}
|
||||
is AdvancedSettingsEvents.SetHideInviteAvatars -> localCoroutineScope.launch {
|
||||
appPreferencesStore.setHideInviteAvatars(event.value)
|
||||
|
|
@ -82,8 +90,7 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||
doesCompressMedia = doesCompressMedia,
|
||||
theme = theme,
|
||||
showChangeThemeDialog = showChangeThemeDialog,
|
||||
theme = themeOption,
|
||||
hideInviteAvatars = hideInviteAvatars,
|
||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||
eventSink = { handleEvents(it) }
|
||||
|
|
|
|||
|
|
@ -7,16 +7,33 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import io.element.android.compound.theme.Theme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import io.element.android.libraries.designsystem.components.preferences.DropdownOption
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
data class AdvancedSettingsState(
|
||||
val isDeveloperModeEnabled: Boolean,
|
||||
val isSharePresenceEnabled: Boolean,
|
||||
val doesCompressMedia: Boolean,
|
||||
val theme: Theme,
|
||||
val showChangeThemeDialog: Boolean,
|
||||
val theme: ThemeOption,
|
||||
val hideInviteAvatars: Boolean,
|
||||
val timelineMediaPreviewValue: MediaPreviewValue,
|
||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||
)
|
||||
|
||||
enum class ThemeOption : DropdownOption {
|
||||
System {
|
||||
@Composable
|
||||
override fun getText(): String = stringResource(CommonStrings.common_system)
|
||||
},
|
||||
Dark {
|
||||
@Composable
|
||||
override fun getText(): String = stringResource(CommonStrings.common_dark)
|
||||
},
|
||||
Light {
|
||||
@Composable
|
||||
override fun getText(): String = stringResource(CommonStrings.common_light)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
||||
|
||||
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
||||
|
|
@ -16,7 +15,6 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
|
|||
get() = sequenceOf(
|
||||
aAdvancedSettingsState(),
|
||||
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
||||
aAdvancedSettingsState(showChangeThemeDialog = true),
|
||||
aAdvancedSettingsState(isSharePresenceEnabled = true),
|
||||
aAdvancedSettingsState(doesCompressMedia = true),
|
||||
aAdvancedSettingsState(hideInviteAvatars = true),
|
||||
|
|
@ -28,16 +26,15 @@ fun aAdvancedSettingsState(
|
|||
isDeveloperModeEnabled: Boolean = false,
|
||||
isSharePresenceEnabled: Boolean = false,
|
||||
doesCompressMedia: Boolean = false,
|
||||
showChangeThemeDialog: Boolean = false,
|
||||
hideInviteAvatars: Boolean = false,
|
||||
theme: ThemeOption = ThemeOption.System,
|
||||
timelineMediaPreviewValue: MediaPreviewValue = MediaPreviewValue.On,
|
||||
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
||||
) = AdvancedSettingsState(
|
||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||
doesCompressMedia = doesCompressMedia,
|
||||
theme = Theme.System,
|
||||
showChangeThemeDialog = showChangeThemeDialog,
|
||||
theme = theme,
|
||||
hideInviteAvatars = hideInviteAvatars,
|
||||
timelineMediaPreviewValue = timelineMediaPreviewValue,
|
||||
eventSink = eventSink
|
||||
|
|
|
|||
|
|
@ -12,14 +12,11 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.compound.theme.themes
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ListOption
|
||||
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceDropdown
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
|
|
@ -34,8 +31,7 @@ import io.element.android.libraries.matrix.api.media.MediaPreviewValue
|
|||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
||||
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
@Composable
|
||||
fun AdvancedSettingsView(
|
||||
|
|
@ -49,15 +45,12 @@ fun AdvancedSettingsView(
|
|||
onBackClick = onBackClick,
|
||||
title = stringResource(id = CommonStrings.common_advanced_settings)
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(text = stringResource(id = CommonStrings.common_appearance))
|
||||
},
|
||||
trailingContent = ListItemContent.Text(
|
||||
state.theme.toHumanReadable()
|
||||
),
|
||||
onClick = {
|
||||
state.eventSink(AdvancedSettingsEvents.ChangeTheme)
|
||||
PreferenceDropdown(
|
||||
title = stringResource(id = CommonStrings.common_appearance),
|
||||
selectedOption = state.theme,
|
||||
options = ThemeOption.entries.toPersistentList(),
|
||||
onSelectOption = { logLevel ->
|
||||
state.eventSink(AdvancedSettingsEvents.SetTheme(logLevel))
|
||||
}
|
||||
)
|
||||
ListItem(
|
||||
|
|
@ -108,21 +101,6 @@ fun AdvancedSettingsView(
|
|||
)
|
||||
ModerationAndSafety(state)
|
||||
}
|
||||
|
||||
if (state.showChangeThemeDialog) {
|
||||
SingleSelectionDialog(
|
||||
options = getOptions(),
|
||||
initialSelection = themes.indexOf(state.theme),
|
||||
onSelectOption = {
|
||||
state.eventSink(
|
||||
AdvancedSettingsEvents.SetTheme(
|
||||
themes[it]
|
||||
)
|
||||
)
|
||||
},
|
||||
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -176,24 +154,6 @@ private fun ModerationAndSafety(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getOptions(): ImmutableList<ListOption> {
|
||||
return themes.map {
|
||||
ListOption(title = it.toHumanReadable())
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Theme.toHumanReadable(): String {
|
||||
return stringResource(
|
||||
id = when (this) {
|
||||
Theme.System -> CommonStrings.common_system
|
||||
Theme.Dark -> CommonStrings.common_dark
|
||||
Theme.Light -> CommonStrings.common_light
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewWithLargeHeight
|
||||
@Composable
|
||||
internal fun AdvancedSettingsViewLightPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) =
|
||||
|
|
|
|||
|
|
@ -7,22 +7,28 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.developer.tracing
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.libraries.designsystem.components.preferences.DropdownOption
|
||||
|
||||
enum class LogLevelItem : DropdownOption {
|
||||
ERROR {
|
||||
override val text: String = "Error"
|
||||
@Composable
|
||||
override fun getText(): String = "Error"
|
||||
},
|
||||
WARN {
|
||||
override val text: String = "Warn"
|
||||
@Composable
|
||||
override fun getText(): String = "Warn"
|
||||
},
|
||||
INFO {
|
||||
override val text: String = "Info"
|
||||
@Composable
|
||||
override fun getText(): String = "Info"
|
||||
},
|
||||
DEBUG {
|
||||
override val text: String = "Debug"
|
||||
@Composable
|
||||
override fun getText(): String = "Debug"
|
||||
},
|
||||
TRACE {
|
||||
override val text: String = "Trace"
|
||||
@Composable
|
||||
override fun getText(): String = "Trace"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class EditUserProfilePresenter @AssistedInject constructor(
|
|||
@Composable
|
||||
override fun present(): EditUserProfileState {
|
||||
val cameraPermissionState = cameraPermissionPresenter.present()
|
||||
var userAvatarUri by rememberSaveable { mutableStateOf(matrixUser.avatarUrl?.let { Uri.parse(it) }) }
|
||||
var userAvatarUri by rememberSaveable { mutableStateOf(matrixUser.avatarUrl?.toUri()) }
|
||||
var userDisplayName by rememberSaveable { mutableStateOf(matrixUser.displayName) }
|
||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
|
||||
onResult = { uri ->
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"Pokud je vypnuto, potvrzení o přečtení se nikomu neodesílají. Stále budete dostávat potvrzení o přečtení od ostatních uživatelů."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Sdílejte přítomnost"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Pokud je tato funkce vypnutá, nebudete moci odesílat ani přijímat potvrzení o přečtení ani upozornění o psaní."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Vždy skrýt"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Vždy zobrazit"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"V soukromých místnostech"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Skryté médium lze vždy zobrazit klepnutím na něj"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Zobrazit média na časové ose"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Povolit možnost zobrazení zdroje zprávy na časové ose."</string>
|
||||
<string name="screen_blocked_users_empty">"Nemáte žádné blokované uživatele"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Odblokovat"</string>
|
||||
|
|
@ -60,6 +65,7 @@ Pokud budete pokračovat, některá nastavení se mohou změnit."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"systémová nastavení"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Systémová oznámení byla vypnuta"</string>
|
||||
<string name="screen_notification_settings_title">"Oznámení"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Historie push oznámení"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Odstraňování problémů"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Odstraňování problémů s upozorněními"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="full_screen_intent_banner_message">"Er mwyn sicrhau fyddwch chi ddim yn colli galwad bwysig, newidiwch eich gosodiadau i ganiatáu hysbysiadau sgrin lawn pan fydd eich ffôn wedi\'i gloi."</string>
|
||||
<string name="full_screen_intent_banner_title">"Gwella profiad eich galwadau"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url">"URL sylfaen Galwad Element Cyfaddas"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Gosod URL sylfaen cyfaddas ar gyfer Galwad Element."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"URL annilys, gwnewch yn siŵr eich bod yn cynnwys y protocol (http/https) a\'r cyfeiriad cywir."</string>
|
||||
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Cuddio afatarau yn y ceisiadau gwahoddiad i ystafell"</string>
|
||||
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Cuddio rhagolygon cyfryngau yn y llinell amser"</string>
|
||||
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Cymedroli a Diogelwch"</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts">"Derbynebau darllen"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Cuddio bob tro"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Dangos bob tro"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"Mewn ystafelloedd preifat"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Mae modd dangos cyfrwng cudd trwy dapio arno"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Dangos cyfryngau mewn llinell amser"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Dad-rwystro"</string>
|
||||
<string name="screen_edit_profile_display_name">"Enw dangos"</string>
|
||||
<string name="screen_edit_profile_title">"Golygu proffil"</string>
|
||||
<string name="screen_notification_settings_additional_settings_section_title">"Gosodiadau ychwanegol"</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Crybwyll"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Y Cyfan"</string>
|
||||
<string name="screen_notification_settings_mode_mentions">"Crybwyll"</string>
|
||||
<string name="screen_notification_settings_title">"Hysbysiadau"</string>
|
||||
</resources>
|
||||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"Wenn diese Option deaktiviert ist, werden Ihre Lesebestätigungen an niemanden gesendet. Du erhältst weiterhin Lesebestätigungen von anderen Benutzern."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Präsenz teilen"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Wenn diese Option deaktiviert ist, kannst du keine Lesebestätigungen oder Tipp-Benachrichtigungen senden oder empfangen."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Immer verstecken"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Immer anzeigen"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"In privaten Chatrooms"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Ein verstecktes Medium kann jederzeit durch Antippen angezeigt werden"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Medien in der Zeitleiste anzeigen"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Option aktiveren, um Nachrichtenquelle in der Zeitleiste anzuzeigen."</string>
|
||||
<string name="screen_blocked_users_empty">"Du hast keine blockierten Nutzer"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Blockierung aufheben"</string>
|
||||
|
|
@ -58,6 +63,7 @@ Wenn du fortfährst, können sich einige deiner Einstellungen ändern."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"Systemeinstellungen"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Systembenachrichtigungen deaktiviert"</string>
|
||||
<string name="screen_notification_settings_title">"Benachrichtigungen"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Verlauf pushen"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Fehlerbehebung"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Fehlerbehebung für Benachrichtigungen"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"Kui lülitad selle valiku välja, siis mitte keegi enam ei saa sinult lugemisteatisi. Küll aga saad sina teiste kasutajate lugemisteatisi."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Jaga oma olekut"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Kui see eelistus on välja lülitatud, siis sa ei saa ega saada ei lugemisteatisi ega kirjutamise teavitusi."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Peida alati"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Näita alati"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"Privaatsetes jututubades"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Peidetud meediumi saad alati näha temal klõpsides"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Näita ajajoonel meediat"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Selle eelistuse sisselülitamisel on võimalik ajajoonel vaadata sõnumite lähtekoodi."</string>
|
||||
<string name="screen_blocked_users_empty">"Sa pole ühtegi kasutajat blokeerinud"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Eemalda blokeering"</string>
|
||||
|
|
@ -58,6 +63,7 @@ Kui sa jätkad muutmist, siis võivad muutuda ka need peidetud eelistused."</str
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"süsteemi seadistusi"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Süsteemi teavitused on välja lülitatud"</string>
|
||||
<string name="screen_notification_settings_title">"Teavitused"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Tõuketeadete ajalugu"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Veaotsing"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Teavituste veaotsing"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -8,14 +8,22 @@
|
|||
<string name="screen_advanced_settings_element_call_base_url">"Mukautettu Element Call URL-osoite"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Aseta mukautettu URL-osoite Element Callille."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"Virheellinen URL-osoite. Varmista, että sisällytät protokollan (http/https) ja oikean osoitteen."</string>
|
||||
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Piilota huoneiden avatarit kutsuista"</string>
|
||||
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Piilota median esikatselu aikajanalla"</string>
|
||||
<string name="screen_advanced_settings_media_compression_description">"Lähetä valokuvia ja videoita nopeammin ja vähennä datan käyttöä."</string>
|
||||
<string name="screen_advanced_settings_media_compression_title">"Optimoi median laatu"</string>
|
||||
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Moderointi ja Turvallisuus"</string>
|
||||
<string name="screen_advanced_settings_push_provider_android">"Push-ilmoitusten tarjoaja"</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Ota rikastettu tekstieditori pois käytöstä, jotta voit kirjoittaa Markdownia manuaalisesti."</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts">"Lukukuittaukset"</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts_description">"Jos tämä on poissa päältä, sinun lukukuittauksia ei lähetetä kenellekään. Vastaanotat silti lukukuittauksia muilta käyttäjiltä."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Jaa läsnäolo"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Jos tämä on poissa päältä, et lähetä tai vastaanota lukukuittauksia tai kirjoitusilmotuksia."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Piilota aina"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Näytä aina"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"Yksityisissä huoneissa"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Piilotetun median voi aina näyttää napauttamalla sitä"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Näytä media aikajanalla"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Ota käyttöön mahdollisuus tarkastella viestin lähdettä aikajanalla."</string>
|
||||
<string name="screen_blocked_users_empty">"Et ole estänyt ketään"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Poista esto"</string>
|
||||
|
|
@ -55,6 +63,7 @@ Jos jatkat, jotkin asetukset saattavat muuttua."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"järjestelmäsi asetuksia"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Järjestelmän ilmoitukset on poissa päältä"</string>
|
||||
<string name="screen_notification_settings_title">"Ilmoitukset"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Push-historia"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Vianmääritys"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Ilmoitusten vianmääritys"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"En cas de désactivation, vos accusés de lecture ne seront pas envoyés aux autres membres. Vous verrez toujours les accusés des autres membres."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Partager la présence"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Si cette option est désactivée, vous ne pourrez ni envoyer ni recevoir de confirmations de lecture ni de notifications de saisie."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Toujours cacher"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Toujours montrer"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"Dans les salons privés"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Un média caché peut toujours être affiché en cliquant dessus"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Afficher les médias dans les discussions."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Activer cette option pour pouvoir voir la source des messages dans la discussion."</string>
|
||||
<string name="screen_blocked_users_empty">"Vous n’avez bloqué personne"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Débloquer"</string>
|
||||
|
|
@ -58,6 +63,7 @@ Si vous continuez, il est possible que certains de vos paramètres soient modifi
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"paramètres du système"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Les notifications du système sont désactivées"</string>
|
||||
<string name="screen_notification_settings_title">"Notifications"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Historique des Push"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Dépannage"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Dépanner les notifications"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"Ha ki van kapcsolva, az olvasási visszaigazolások nem lesznek elküldve senkinek. A többi felhasználó olvasási visszaigazolását továbbra is meg fogja kapni."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Jelenlét megosztása"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Ha ki van kapcsolva, nem tud olvasási visszaigazolást vagy írási értesítést küldeni és fogadni"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Elrejtés mindig"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Megjelenítés mindig"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"Privát szobákban"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"A rejtett médiatartalmak koppintással jeleníthetők meg"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Média megjelenítése az idővonalon"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Engedélyezze a beállítást az üzenet forrásának megjelenítéséhez az idővonalon."</string>
|
||||
<string name="screen_blocked_users_empty">"Nincsenek letiltott felhasználók"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Letiltás feloldása"</string>
|
||||
|
|
@ -58,6 +63,7 @@ Ha folytatja, egyes beállítások megváltozhatnak."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"rendszerbeállításokat"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"A rendszerértesítések ki vannak kapcsolva"</string>
|
||||
<string name="screen_notification_settings_title">"Értesítések"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Leküldéses értesítés előzmények"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Hibaelhárítás"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Értesítések hibaelhárítása"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_advanced_settings_choose_distributor_dialog_title_android">"Pasirinkite, kaip gauti pranešimus"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Atblokuoti"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_description">"Vėl galėsite matyti visas iš jų gautas žinutes."</string>
|
||||
<string name="screen_blocked_users_unblock_alert_title">"Atblokuoti vartotoją"</string>
|
||||
</resources>
|
||||
|
|
@ -5,14 +5,25 @@
|
|||
<string name="screen_advanced_settings_choose_distributor_dialog_title_android">"Velg hvordan du vil motta varsler"</string>
|
||||
<string name="screen_advanced_settings_developer_mode">"Utviklermodus"</string>
|
||||
<string name="screen_advanced_settings_developer_mode_description">"Aktiver for å få tilgang til funksjoner og funksjonalitet for utviklere."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url">"Egendefinert Element Call base URL"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Angi en egendefinert base URL for Element Call."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"Ugyldig URL. Pass på at du inkluderer protokollen (http/https) og riktig adresse."</string>
|
||||
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Skjul avatarer i invitasjonsforespørsler til rom"</string>
|
||||
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Skjul forhåndsvisninger av medier på tidslinjen"</string>
|
||||
<string name="screen_advanced_settings_media_compression_description">"Last opp bilder og videoer raskere og reduser databruken"</string>
|
||||
<string name="screen_advanced_settings_media_compression_title">"Optimaliser mediekvaliteten"</string>
|
||||
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Moderasjon og sikkerhet"</string>
|
||||
<string name="screen_advanced_settings_push_provider_android">"Leverandør av pushvarsling"</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Deaktiver rik tekstredigering for å skrive Markdown manuelt."</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts">"Lesebekreftelser"</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts_description">"Hvis slått av, sendes ikke lesebekreftelsene dine til noen. Du vil fortsatt motta lesebekreftelser fra andre brukere."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Del tilstedeværelse"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Hvis slått av, kan du ikke sende eller motta lesebekreftelser eller skrivevarsler."</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Skjul alltid"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Vis alltid"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"I private rom"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Et skjult medium kan alltid vises ved å trykke på det"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Vis medier i tidslinjen"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Aktiver alternativet for å vise meldingskilden på tidslinjen."</string>
|
||||
<string name="screen_blocked_users_empty">"Du har ingen blokkerte brukere"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Fjern blokkering"</string>
|
||||
|
|
@ -52,6 +63,7 @@ Hvis du fortsetter, kan noen av innstillingene dine endres."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"systeminnstillinger"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Systemvarsler er slått av"</string>
|
||||
<string name="screen_notification_settings_title">"Varslinger"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Push-historikk"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Feilsøk"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Feilsøk varsler"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ Niektóre ustawienia mogą ulec zmianie, jeśli kontynuujesz."</string>
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"ustawienia systemowe"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Powiadomienia systemowe wyłączone"</string>
|
||||
<string name="screen_notification_settings_title">"Powiadomienia"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"Historia powiadomień Push"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Rozwiązywanie problemów"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Rozwiązywanie problemów powiadomień"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ Se você continuar, algumas de suas configurações poderão mudar."</string>
|
|||
<string name="screen_notification_settings_failed_fixing_configuration">"A configuração não foi corrigida, tente novamente."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Bate-papos em grupo"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Convites"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Seu servidor doméstico não suporta esta opção em salas criptografadas. Você pode não ser notificado em algumas salas."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Menções"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Todos"</string>
|
||||
<string name="screen_notification_settings_mode_mentions">"Menções"</string>
|
||||
|
|
|
|||
|
|
@ -8,14 +8,21 @@
|
|||
<string name="screen_advanced_settings_element_call_base_url">"Базовый URL сервера звонков Element"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Задайте свой сервер Element Call."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"Адрес указан неверно, удостоверьтесь, что вы указали протокол (http/https) и правильный адрес."</string>
|
||||
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Скрыть аватары в запросах на приглашение в комнату"</string>
|
||||
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Скрыть предварительный просмотр медиафайлов на временной шкале"</string>
|
||||
<string name="screen_advanced_settings_media_compression_description">"Загружайте фотографии и видео быстрее и сокращайте потребление трафика"</string>
|
||||
<string name="screen_advanced_settings_media_compression_title">"Оптимизировать качество мультимедиа"</string>
|
||||
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Модерация и безопасность"</string>
|
||||
<string name="screen_advanced_settings_push_provider_android">"Поставщик push-уведомлений"</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Отключить редактор форматированного текста и включить Markdown."</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts">"Уведомления о прочтении"</string>
|
||||
<string name="screen_advanced_settings_send_read_receipts_description">"Если этот параметр выключен, ваш статус о прочтении не будет отображаться. Вы по-прежнему будете видеть статус о прочтении от других пользователей."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Поделиться присутствием"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Если выключено, вы не сможете отправлять, получать уведомления о прочтении и наборе текста"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Всегда скрывать"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Всегда показывать"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"В личных комнатах"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Скрытый медиафайл всегда можно отобразить, нажав на него."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Включить опцию просмотра источника сообщения в ленте."</string>
|
||||
<string name="screen_blocked_users_empty">"У вас нет заблокированных пользователей"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Разблокировать"</string>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
<string name="screen_advanced_settings_send_read_receipts_description">"Ak je táto funkcia vypnutá, vaše potvrdenia o prečítaní sa nebudú nikomu odosielať. Stále budete dostávať potvrdenia o prečítaní od ostatných používateľov."</string>
|
||||
<string name="screen_advanced_settings_share_presence">"Zdieľať prítomnosť"</string>
|
||||
<string name="screen_advanced_settings_share_presence_description">"Ak je vypnuté, nebudete môcť odosielať ani prijímať potvrdenia o prečítaní alebo upozornenia o písaní"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_hide">"Vždy skryť"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_always_show">"Vždy zobraziť"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_private_rooms">"V súkromných miestnostiach"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_subtitle">"Skryté médium sa dá vždy zobraziť ťuknutím naň"</string>
|
||||
<string name="screen_advanced_settings_show_media_timeline_title">"Zobraziť médiá na časovej osi"</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Povoliť možnosť zobrazenia zdroja správy na časovej osi."</string>
|
||||
<string name="screen_blocked_users_empty">"Nemáte žiadnych blokovaných používateľov"</string>
|
||||
<string name="screen_blocked_users_unblock_alert_action">"Odblokovať"</string>
|
||||
|
|
@ -60,6 +65,7 @@ Ak budete pokračovať, niektoré z vašich nastavení sa môžu zmeniť."</stri
|
|||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"nastavenia systému"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"Systémové oznámenia sú vypnuté"</string>
|
||||
<string name="screen_notification_settings_title">"Oznámenia"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_push_history_title">"História push oznámení"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_section">"Riešenie problémov"</string>
|
||||
<string name="troubleshoot_notifications_entry_point_title">"Oznámenia riešení problémov"</string>
|
||||
</resources>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue