Merge branch 'develop' into feature/fga/pinned_messages_actions

This commit is contained in:
ganfra 2024-09-16 15:24:22 +02:00 committed by GitHub
commit f6c6943ef0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
138 changed files with 1578 additions and 1021 deletions

View file

@ -1,6 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="shared">
<words>
<w>agpl</w>
<w>backstack</w>
<w>blurhash</w>
<w>fdroid</w>
@ -17,6 +18,7 @@
<w>securebackup</w>
<w>showkase</w>
<w>snackbar</w>
<w>spdx</w>
<w>swipeable</w>
<w>textfields</w>
<w>tombstoned</w>

View file

@ -1,3 +1,22 @@
Changes in Element X v0.6.0 (2024-09-12)
========================================
### 🙌 Improvements
* Enables pinned messages feature by default. by @ganfra in https://github.com/element-hq/element-x-android/pull/3439
* Pinned messages list : hide reactions by @ganfra in https://github.com/element-hq/element-x-android/pull/3430
### 🐛 Bugfixes
* Feature/fga/pinned messages fix timeline provider by @ganfra in https://github.com/element-hq/element-x-android/pull/3432
### Dependency upgrades
* Update activity to v1.9.2 by @renovate in https://github.com/element-hq/element-x-android/pull/3397
* Update peter-evans/create-pull-request action to v7 by @renovate in https://github.com/element-hq/element-x-android/pull/3383
* Rust sdk upgrade to 0.2.43 by @bmarty in https://github.com/element-hq/element-x-android/pull/3446
### Others
* DeviceId and cleanup. by @bmarty in https://github.com/element-hq/element-x-android/pull/3442
* Update application store assets by @bmarty in https://github.com/element-hq/element-x-android/pull/3441
Changes in Element X v0.5.3 (2024-09-10)
========================================

View file

@ -59,6 +59,7 @@ dependencies {
testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.oidc.impl)
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.push.test)
testImplementation(projects.libraries.pushproviders.test)
testImplementation(projects.features.networkmonitor.test)

View file

@ -9,4 +9,6 @@ package io.element.android.appnav.loggedin
sealed interface LoggedInEvents {
data class CloseErrorDialog(val doNotShowAgain: Boolean) : LoggedInEvents
data object CheckSlidingSyncProxyAvailability : LoggedInEvents
data object LogoutAndMigrateToNativeSlidingSync : LoggedInEvents
}

View file

@ -16,6 +16,7 @@ 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 im.vector.app.features.analytics.plan.CryptoSessionStateChange
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.features.networkmonitor.api.NetworkMonitor
@ -29,6 +30,7 @@ import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.pushproviders.api.RegistrationFailure
import io.element.android.services.analytics.api.AnalyticsService
@ -48,6 +50,7 @@ class LoggedInPresenter @Inject constructor(
private val sessionVerificationService: SessionVerificationService,
private val analyticsService: AnalyticsService,
private val encryptionService: EncryptionService,
private val enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase,
) : Presenter<LoggedInState> {
@Composable
override fun present(): LoggedInState {
@ -78,6 +81,7 @@ class LoggedInPresenter @Inject constructor(
networkStatus == NetworkStatus.Online && syncIndicator == RoomListService.SyncIndicator.Show
}
}
var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
combine(
sessionVerificationService.sessionVerifiedStatus,
@ -97,6 +101,18 @@ class LoggedInPresenter @Inject constructor(
}
}
}
LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch {
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is.
forceNativeSlidingSyncMigration = !matrixClient.isUsingNativeSlidingSync() &&
matrixClient.isNativeSlidingSyncSupported() &&
!matrixClient.isSlidingSyncProxySupported()
}
LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch {
// Enable native sliding sync if it wasn't already the case
enableNativeSlidingSyncUseCase()
// Then force the logout
matrixClient.logout(userInitiated = true, ignoreSdkError = true)
}
}
}
@ -104,6 +120,7 @@ class LoggedInPresenter @Inject constructor(
showSyncSpinner = showSyncSpinner,
pusherRegistrationState = pusherRegistrationState.value,
ignoreRegistrationError = ignoreRegistrationError,
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,
eventSink = ::handleEvent
)
}

View file

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

View file

@ -16,15 +16,18 @@ open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
aLoggedInState(),
aLoggedInState(showSyncSpinner = true),
aLoggedInState(pusherRegistrationState = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable())),
aLoggedInState(forceNativeSlidingSyncMigration = true),
)
}
fun aLoggedInState(
showSyncSpinner: Boolean = false,
pusherRegistrationState: AsyncData<Unit> = AsyncData.Uninitialized,
forceNativeSlidingSyncMigration: Boolean = false,
) = LoggedInState(
showSyncSpinner = showSyncSpinner,
pusherRegistrationState = pusherRegistrationState,
ignoreRegistrationError = false,
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,
eventSink = {},
)

View file

@ -15,10 +15,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.lifecycle.Lifecycle
import io.element.android.appnav.R
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialogWithDoNotShowAgain
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.matrix.api.exception.isNetworkError
import io.element.android.libraries.ui.strings.CommonStrings
@ -28,6 +32,11 @@ fun LoggedInView(
navigateToNotificationTroubleshoot: () -> Unit,
modifier: Modifier = Modifier
) {
OnLifecycleEvent { _, event ->
if (event == Lifecycle.Event.ON_RESUME) {
state.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability)
}
}
Box(
modifier = modifier
.fillMaxSize()
@ -61,6 +70,13 @@ fun LoggedInView(
}
}
}
// Set the force migration dialog here so it's always displayed over every screen
if (state.forceNativeSlidingSyncMigration) {
ForceNativeSlidingSyncMigrationDialog(onSubmit = {
state.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
})
}
}
private fun Throwable.getReason(): String? {
@ -80,6 +96,19 @@ private fun Throwable.getReason(): String? {
}
}
@Composable
private fun ForceNativeSlidingSyncMigrationDialog(
onSubmit: () -> Unit,
) {
ErrorDialog(
title = null,
content = stringResource(R.string.banner_migrate_to_native_sliding_sync_force_logout_title),
submitText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action),
onSubmit = onSubmit,
canDismiss = false,
)
}
@PreviewsDayNight
@Composable
internal fun LoggedInViewPreview(@PreviewParameter(LoggedInStateProvider::class) state: LoggedInState) = ElementPreview {

View file

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

View file

@ -29,6 +29,8 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.push.test.FakePushService
import io.element.android.libraries.pushproviders.api.Distributor
@ -42,6 +44,10 @@ import io.element.android.tests.testutils.lambda.any
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@ -91,7 +97,8 @@ class LoggedInPresenterTest {
pushService = FakePushService(),
sessionVerificationService = verificationService,
analyticsService = analyticsService,
encryptionService = encryptionService
encryptionService = encryptionService,
enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this),
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -487,26 +494,103 @@ class LoggedInPresenterTest {
)
}
@Test
fun `present - CheckSlidingSyncProxyAvailability forces the sliding sync migration under the right circumstances`() = runTest {
// The migration will be forced if:
// - The user is not using the native sliding sync
// - The sliding sync proxy is no longer supported
// - The native sliding sync is supported
val matrixClient = FakeMatrixClient(
isUsingNativeSlidingSyncLambda = { false },
isSlidingSyncProxySupportedLambda = { false },
isNativeSlidingSyncSupportedLambda = { true },
)
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability)
assertThat(awaitItem().forceNativeSlidingSyncMigration).isTrue()
}
}
@Test
fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest {
val matrixClient = FakeMatrixClient(
isUsingNativeSlidingSyncLambda = { false },
isSlidingSyncProxySupportedLambda = { false },
isNativeSlidingSyncSupportedLambda = { false },
)
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability)
expectNoEvents()
}
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `present - LogoutAndMigrateToNativeSlidingSync enables native sliding sync and logs out the user`() = runTest {
val logoutLambda = lambdaRecorder<Boolean, Boolean, String?> { userInitiated, ignoreSdkError ->
assertThat(userInitiated).isTrue()
assertThat(ignoreSdkError).isTrue()
null
}
val matrixClient = FakeMatrixClient().apply {
this.logoutLambda = logoutLambda
}
val appPreferencesStore = InMemoryAppPreferencesStore()
val enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(appPreferencesStore, this)
val presenter = createLoggedInPresenter(matrixClient = matrixClient, enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse()
initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
advanceUntilIdle()
assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue()
assertThat(logoutLambda.assertions().isCalledOnce())
}
}
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
skipItems(1)
return awaitItem()
}
private fun createLoggedInPresenter(
private fun TestScope.createLoggedInPresenter(
roomListService: RoomListService = FakeRoomListService(),
networkStatus: NetworkStatus = NetworkStatus.Offline,
analyticsService: AnalyticsService = FakeAnalyticsService(),
sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
encryptionService: EncryptionService = FakeEncryptionService(),
pushService: PushService = FakePushService(),
enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this),
matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService),
): LoggedInPresenter {
return LoggedInPresenter(
matrixClient = FakeMatrixClient(roomListService = roomListService),
matrixClient = matrixClient,
networkMonitor = FakeNetworkMonitor(networkStatus),
pushService = pushService,
sessionVerificationService = sessionVerificationService,
analyticsService = analyticsService,
encryptionService = encryptionService
encryptionService = encryptionService,
enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase,
)
}
}

View file

@ -0,0 +1,2 @@
Element X is the new generation of Element for professional and personal use on mobile. Its the fastest Matrix client with a seamless & intuitive user interface.
Full changelog: https://github.com/element-hq/element-x-android/releases

View file

@ -1,23 +1,35 @@
Element X is the future Element.
Element X brings you both sovereign & seamless collaboration built on Matrix.
It is the brand new, and fastest ever, Matrix client. It is for personal and community use, and will support enterprise functionality later this year.
The collaboration capabilities include chat & video calls with the modern set of features such as:
• public & private channels
• room moderation & access conUpdatetrol
• replies, reactions, polls, read receipts, pinned messages, etc.
• simultaneous chat & calls (picture in picture)
• decentralized & federated communication across organizations
A complete new build, Element X transforms performance. Its not just the fastest Matrix client, its also fresher and more reliable.
All this comes in a secure & sovereign fashion without compromising responsiveness or overall usability of the app:
• enterprise-grade single sign-on
• easy & secure login & device verification via QR-code
• end to end encryption & zero trust
• protection against MITM & other cyber attacks
Its so fast for a number of reasons, but in particular weve introduced a completely new syncing service (sliding sync). So even in big end-to-end encrypted chat rooms it operates incredibly quickly.
If youre a new user, use the new Element X app from the start. Compared to the current Element app you will get:
• greatly enhanced performance, sleek user interface and overall better user experience
• enterprise-grade support for single sign-on (OIDC)
• QR-code based login & device verification
• natively integrated Element Call for video calls
• continuous improvements, bug fixes and new features
Its fresher because weve rebuilt the entire user experience. All the power of Matrix - and the complexity of decentralized end-to-end encryption - is now hidden under a beautiful and intuitive user interface using the very latest frameworks and accessibility features.
Element X delivers speed, usability and reliability on the decentralized Matrix open standard.
If youre an existing user, using the current Element app - check out the new Element X and start planning your transition. The current Element app will be phased out and will only get critical security updates.
<b>Own your data</b>
Matrix-based, Element X lets you self-host your data or choose from any free public server (the default is matrix.org, but there are plenty of others to choose from). However you host, you have ownership; its your data. Youre not the product. Youre in control.
<b>Interoperate natively</b>
Enjoy the freedom of the Matrix open standard! You have native interoperability with any other Matrix-based app. So just like email, it doesn't matter if your friends are on a different Matrix-based app you can still connect and chat.
Enjoy the freedom of the Matrix open standard! You have native interoperability with any other Matrix-based app. So just like email, it doesn't matter if your friends, partners or customers are on a different Matrix-based app - you can still connect.
<b>Encrypt your data</b>
Enjoy your right to private conversations - free from data mining, ads and all the rest of it - and stay secure. Only the people in your conversation can read your messages. And Element X E2EE applies to voice and video calls too.
Enjoy your right to private conversations - free from data mining, ads and all the rest of it - and stay secure. Only the people in your conversation can read your messages.
<b>Chat across multiple devices</b>
Stay in touch wherever you are with fully synchronized message history across all your devices, even those running traditional Element, and on the web at https://app.element.io
Stay in touch wherever you are with fully synchronized message history across all your devices, even those running Element legacy app, and on the web at https://app.element.io

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -1 +1 @@
Fastest ever Matrix client
Sovereign. Seamless. On Matrix

View file

@ -1 +1 @@
Element X - Secure messenger
Element X - Secure Chat & Call

View file

@ -111,7 +111,7 @@ internal fun CallScreenView(
is AsyncData.Failure ->
ErrorDialog(
content = state.urlState.error.message.orEmpty(),
onDismiss = { state.eventSink(CallScreenEvents.Hangup) },
onSubmit = { state.eventSink(CallScreenEvents.Hangup) },
)
is AsyncData.Success -> Unit
}

View file

@ -112,8 +112,8 @@ class AcceptDeclineInvitePresenter @Inject constructor(
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<AsyncAction<RoomId>>) = launch {
suspend {
client.getRoom(roomId)?.use {
it.leave().getOrThrow()
client.getInvitedRoom(roomId)?.use {
it.declineInvite().getOrThrow()
notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId)
}
roomId

View file

@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.FakeInvitedRoom
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
import io.element.android.libraries.push.api.notifications.NotificationCleaner
import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner
@ -83,12 +83,7 @@ class AcceptDeclineInvitePresenterTest {
Result.failure<Unit>(RuntimeException("Failed to leave room"))
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom(
leaveRoomLambda = declineInviteFailure
)
)
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteFailure)
}
val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test {
@ -133,12 +128,7 @@ class AcceptDeclineInvitePresenterTest {
Result.success(Unit)
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom(
leaveRoomLambda = declineInviteSuccess
)
)
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteSuccess)
}
val presenter = createAcceptDeclineInvitePresenter(
client = client,

View file

@ -105,7 +105,7 @@ private fun LeaveRoomErrorDialog(
is LeaveRoomState.Error.Hidden -> {}
is LeaveRoomState.Error.Shown -> ErrorDialog(
content = stringResource(CommonStrings.error_unknown),
onDismiss = { state.eventSink(LeaveRoomEvent.HideError) }
onSubmit = { state.eventSink(LeaveRoomEvent.HideError) }
)
}
}

View file

@ -116,7 +116,7 @@ private fun SetupPinContent(
ErrorDialog(
title = state.setupPinFailure.title(),
content = state.setupPinFailure.content(),
onDismiss = {
onSubmit = {
state.eventSink(SetupPinEvents.ClearFailure)
}
)

View file

@ -104,7 +104,7 @@ fun PinUnlockView(
if (state.showBiometricUnlockError) {
ErrorDialog(
content = state.biometricUnlockErrorMessage ?: "",
onDismiss = { state.eventSink(PinUnlockEvents.ClearBiometricError) }
onSubmit = { state.eventSink(PinUnlockEvents.ClearBiometricError) }
)
}
}
@ -206,7 +206,7 @@ private fun SignOutPrompt(
ErrorDialog(
title = stringResource(id = R.string.screen_app_lock_signout_alert_title),
content = stringResource(id = R.string.screen_app_lock_signout_alert_message),
onDismiss = onSignOut,
onSubmit = onSignOut,
)
}
}

View file

@ -36,7 +36,7 @@ fun ChangeServerView(
ErrorDialog(
modifier = modifier,
content = error.message(),
onDismiss = {
onSubmit = {
eventSink.invoke(ChangeServerEvents.ClearError)
}
)

View file

@ -103,7 +103,7 @@ fun ConfirmAccountProviderView(
is ChangeServerError.Error -> {
ErrorDialog(
content = error.message(),
onDismiss = {
onSubmit = {
eventSink.invoke(ConfirmAccountProviderEvents.ClearError)
}
)

View file

@ -283,7 +283,7 @@ private fun LoginErrorDialog(error: Throwable, onDismiss: () -> Unit) {
ErrorDialog(
title = stringResource(id = CommonStrings.dialog_title_error),
content = stringResource(loginError(error)),
onDismiss = onDismiss
onSubmit = onDismiss
)
}

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў."</string>
<string name="screen_server_confirmation_title_login">"Вы збіраецеся ўвайсці ў %1$s"</string>
<string name="screen_server_confirmation_title_register">"Вы збіраецеся стварыць уліковы запіс на %1$s"</string>
<string name="screen_waitlist_message">"Зараз існуе высокі попыт на %1$s на %2$s. Калі ласка, вярніцеся ў праграму праз некалькі дзён і паспрабуйце зноў.
Дзякуй за цярпенне!"</string>
<string name="screen_waitlist_message_success">"Вітаем у %1$s!"</string>
<string name="screen_waitlist_title">"Амаль гатова."</string>
<string name="screen_waitlist_title_success">"Вы зарэгістраваны."</string>
</resources>

View file

@ -24,5 +24,4 @@
<string name="screen_server_confirmation_message_register">"Това е мястото, където ще живеят вашите разговори — точно както бихте използвали имейл доставчик, за да съхранявате вашите имейли."</string>
<string name="screen_server_confirmation_title_login">"На път сте да влезете в %1$s"</string>
<string name="screen_server_confirmation_title_register">"На път сте да създадете акаунт в %1$s"</string>
<string name="screen_waitlist_message_success">"Добре дошли в %1$s!"</string>
</resources>

View file

@ -78,10 +78,4 @@ Zkuste se přihlásit ručně nebo naskenujte QR kód pomocí jiného zařízen
<string name="screen_server_confirmation_message_register">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
<string name="screen_server_confirmation_title_login">"Chystáte se přihlásit do služby %1$s"</string>
<string name="screen_server_confirmation_title_register">"Chystáte se vytvořit účet na %1$s"</string>
<string name="screen_waitlist_message">"Na %2$s je momentálně vysoká poptávka po %1$s. Vraťte se do aplikace za pár dní a zkuste to znovu.
Díky za trpělivost!"</string>
<string name="screen_waitlist_message_success">"Vítá vás %1$s!"</string>
<string name="screen_waitlist_title">"Jste v pořadníku!"</string>
<string name="screen_waitlist_title_success">"Jdete do toho!"</string>
</resources>

View file

@ -78,10 +78,4 @@ Versuche, dich manuell anzumelden, oder scanne den QR-Code mit einem anderen Ger
<string name="screen_server_confirmation_message_register">"Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden."</string>
<string name="screen_server_confirmation_title_login">"Du bist dabei, dich bei %1$s anzumelden"</string>
<string name="screen_server_confirmation_title_register">"Du bist dabei, ein Konto auf %1$s zu erstellen"</string>
<string name="screen_waitlist_message">"Derzeit besteht eine hohe Nachfrage nach %1$s auf %2$s. Kehre in ein paar Tagen zur App zurück und versuche es erneut.
Danke für deine Geduld!"</string>
<string name="screen_waitlist_message_success">"Willkommen bei %1$s!"</string>
<string name="screen_waitlist_title">"Du bist fast am Ziel."</string>
<string name="screen_waitlist_title_success">"Du bist dabei."</string>
</resources>

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"Εδώ θα ζουν οι συνομιλίες σου - όπως θα χρησιμοποιούσες έναν πάροχο email για να διατηρήσεις τα email σου."</string>
<string name="screen_server_confirmation_title_login">"Πρόκειται να συνδεθείς στο %1$s"</string>
<string name="screen_server_confirmation_title_register">"Πρόκειται να δημιουργήσεις έναν λογαριασμό στο %1$s"</string>
<string name="screen_waitlist_message">"Υπάρχει μεγάλη ζήτηση για το %1$s στον %2$s αυτή τη στιγμή. Επέστρεψε στην εφαρμογή σε λίγες μέρες και δοκίμασε ξανά.
Ευχαριστώ για την υπομονή σου!"</string>
<string name="screen_waitlist_message_success">"Καλώς ήρθες στο %1$s!"</string>
<string name="screen_waitlist_title">"Σχεδόν τα κατάφερες."</string>
<string name="screen_waitlist_title_success">"Είσαι μέσα."</string>
</resources>

View file

@ -37,10 +37,4 @@
<string name="screen_server_confirmation_message_register">"Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos."</string>
<string name="screen_server_confirmation_title_login">"Estás a punto de iniciar sesión en %1$s"</string>
<string name="screen_server_confirmation_title_register">"Estás a punto de crear una cuenta en %1$s"</string>
<string name="screen_waitlist_message">"Hay una gran demanda para %1$s en %2$s en este momento. Vuelve a la aplicación en unos días e inténtalo de nuevo.
¡Gracias por tu paciencia!"</string>
<string name="screen_waitlist_message_success">"¡Bienvenido a %1$s!"</string>
<string name="screen_waitlist_title">"Ya casi has terminado."</string>
<string name="screen_waitlist_title_success">"Estás dentro."</string>
</resources>

View file

@ -78,10 +78,4 @@ Proovi käsitsi sisselogimist või skaneeri QR-koodi mõne muu seadmega."</strin
<string name="screen_server_confirmation_message_register">"See on koht, kus sinu vestlused elavad just nagu kasutaksid oma e-kirjade säilitamiseks e-postitenuse pakkujat."</string>
<string name="screen_server_confirmation_title_login">"Sa oled sisselogimas koduserverisse %1$s"</string>
<string name="screen_server_confirmation_title_register">"Sa oled loomas kasutajakontot koduserveris %1$s"</string>
<string name="screen_waitlist_message">"%1$s kasutamiseks %2$s koduserveris on hetkel palju huvilisi. Proovi seda samast rakendusest mõne päeva pärast.
Täname kannatlikkuse eest!"</string>
<string name="screen_waitlist_message_success">"Tere tulemast rakendusse %1$s!"</string>
<string name="screen_waitlist_title">"Peaaegu olemas."</string>
<string name="screen_waitlist_title_success">"Oled nüüd jututoas."</string>
</resources>

View file

@ -76,10 +76,4 @@
<string name="screen_server_confirmation_message_register">"Cest ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails."</string>
<string name="screen_server_confirmation_title_login">"Vous êtes sur le point de vous connecter à %1$s"</string>
<string name="screen_server_confirmation_title_register">"Vous êtes sur le point de créer un compte sur %1$s"</string>
<string name="screen_waitlist_message">"Il y a une forte demande pour %1$s sur %2$s à lheure actuelle. Revenez sur lapplication dans quelques jours et réessayez.
Merci pour votre patience !"</string>
<string name="screen_waitlist_message_success">"Bienvenue dans %1$s !"</string>
<string name="screen_waitlist_title">"Vous y êtes presque."</string>
<string name="screen_waitlist_title_success">"Vous y êtes."</string>
</resources>

View file

@ -78,10 +78,4 @@ Próbáljon meg kézileg bejelentkezni, vagy olvassa be a QR-kódot egy másik e
<string name="screen_server_confirmation_message_register">"Itt lesznek a beszélgetései ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
<string name="screen_server_confirmation_title_login">"Hamarosan bejelentkezik ebbe: %1$s"</string>
<string name="screen_server_confirmation_title_register">"Hamarosan létrehoz egy fiókot ezen: %1$s"</string>
<string name="screen_waitlist_message">"Jelenleg nagy a kereslet a(z) %2$s oldalon futó %1$s iránt. Térjen vissza néhány nap múlva az alkalmazáshoz, és próbálja újra.
Köszönjük a türelmét!"</string>
<string name="screen_waitlist_message_success">"Üdvözli az %1$s!"</string>
<string name="screen_waitlist_title">"Már majdnem kész van."</string>
<string name="screen_waitlist_title_success">"Bent van."</string>
</resources>

View file

@ -78,10 +78,4 @@ Coba masuk secara manual, atau pindai kode QR dengan perangkat lain."</string>
<string name="screen_server_confirmation_message_register">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
<string name="screen_server_confirmation_title_login">"Anda akan masuk ke %1$s"</string>
<string name="screen_server_confirmation_title_register">"Anda akan membuat akun di %1$s"</string>
<string name="screen_waitlist_message">"Ada permintaan tinggi untuk %1$s di %2$s saat ini. Kembalilah ke aplikasi dalam beberapa hari dan coba lagi.
Terima kasih atas kesabaran Anda!"</string>
<string name="screen_waitlist_message_success">"Selamat datang di %1$s!"</string>
<string name="screen_waitlist_title">"Anda hampir selesai."</string>
<string name="screen_waitlist_title_success">"Anda sudah masuk."</string>
</resources>

View file

@ -78,10 +78,4 @@ Prova ad accedere manualmente o scansiona il codice QR con un altro dispositivo.
<string name="screen_server_confirmation_message_register">"Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email."</string>
<string name="screen_server_confirmation_title_login">"Stai per accedere a %1$s"</string>
<string name="screen_server_confirmation_title_register">"Stai per creare un account su %1$s"</string>
<string name="screen_waitlist_message">"Al momento c\'è una grande richiesta per %1$s su %2$s. Torna a visitare l\'app tra qualche giorno e riprova.
Grazie per la pazienza!"</string>
<string name="screen_waitlist_message_success">"Benvenuti in %1$s!"</string>
<string name="screen_waitlist_title">"Ci sei quasi."</string>
<string name="screen_waitlist_title_success">"Sei dentro."</string>
</resources>

View file

@ -34,10 +34,4 @@
<string name="screen_server_confirmation_message_register">"აქ იქნება თქვენი საუბრები - ისევე, როგორც თქვენ ელ. ფოსტაში ინახება თქვენი ელ.წერილები."</string>
<string name="screen_server_confirmation_title_login">"თქვენ აპირებთ შესვლას %1$s-ში"</string>
<string name="screen_server_confirmation_title_register">"თქვენ აპირებთ ანგარიშის შექმნას %1$s-ში"</string>
<string name="screen_waitlist_message">"ახლა დიდი მოთხოვნაა %1$s-ზე %2$s-ში. დაბრუნდით რამდენიმე დღეში და სცადეთ ერთხელაც.
მადლობა მოთმენისათვის!"</string>
<string name="screen_waitlist_message_success">"კეთილი იყოს თქვენი მობრძანება %1$s-ში!"</string>
<string name="screen_waitlist_title">"თითქმის მზადაა."</string>
<string name="screen_waitlist_title_success">"თქვენ შეხვედით."</string>
</resources>

View file

@ -35,10 +35,4 @@
<string name="screen_server_confirmation_message_register">"Dit is waar je gesprekken zullen worden bewaard — net zoals je een e-mailprovider zou gebruiken om je e-mails te bewaren."</string>
<string name="screen_server_confirmation_title_login">"Je staat op het punt je aan te melden bij %1$s"</string>
<string name="screen_server_confirmation_title_register">"Je staat op het punt een account aan te maken op %1$s"</string>
<string name="screen_waitlist_message">"Er is momenteel veel vraag naar %1$s op %2$s. Kom over een paar dagen terug naar de app en probeer het opnieuw.
Bedankt voor je geduld!"</string>
<string name="screen_waitlist_message_success">"Welkom bij %1$s!"</string>
<string name="screen_waitlist_title">"Je bent er bijna."</string>
<string name="screen_waitlist_title_success">"Je bent binnen."</string>
</resources>

View file

@ -78,10 +78,4 @@ Spróbuj zalogować się ręcznie lub zeskanuj kod QR na innym urządzeniu."</st
<string name="screen_server_confirmation_message_register">"Tutaj będą przechowywane Twoje konwersacje - w podobnej formie jak wiadomości widnieją na skrzynce e-mail."</string>
<string name="screen_server_confirmation_title_login">"Zamierzasz się zalogować do %1$s"</string>
<string name="screen_server_confirmation_title_register">"Zamierzasz utworzyć konto na %1$s"</string>
<string name="screen_waitlist_message">"Obecnie istnieje duże zapotrzebowanie na %1$s na %2$s. Wróć do aplikacji za kilka dni i spróbuj ponownie.
Dziękujemy za Twoją cierpliwość!"</string>
<string name="screen_waitlist_message_success">"Witamy w %1$s!"</string>
<string name="screen_waitlist_title">"Już prawie gotowe!"</string>
<string name="screen_waitlist_title_success">"Witamy!"</string>
</resources>

View file

@ -34,10 +34,4 @@
<string name="screen_server_confirmation_message_register">"Aqui é onde suas conversas vão ficar — assim como você usa um provedor de e-mails para manter seus e-mails."</string>
<string name="screen_server_confirmation_title_login">"Você está prestes a fazer login em %1$s"</string>
<string name="screen_server_confirmation_title_register">"Você está prestes a criar uma conta em %1$s"</string>
<string name="screen_waitlist_message">"Há uma grande demanda por %1$s sobre %2$s no momento. Volte ao aplicativo em alguns dias e tente novamente.
Obrigado pela sua paciência!"</string>
<string name="screen_waitlist_message_success">"Bem-vindo ao %1$s!"</string>
<string name="screen_waitlist_title">"Você está quase lá."</string>
<string name="screen_waitlist_title_success">"Você está dentro."</string>
</resources>

View file

@ -78,10 +78,4 @@ Tenta iniciar a sessão manualmente ou digitaliza o código QR com outro disposi
<string name="screen_server_confirmation_message_register">"É aqui que as tuas conversas vão ficar — tal como num serviço de e-mail."</string>
<string name="screen_server_confirmation_title_login">"Irás iniciar sessão em %1$s"</string>
<string name="screen_server_confirmation_title_register">"Irás criar uma conta em %1$s"</string>
<string name="screen_waitlist_message">"Há uma grande procura pela %1$s no %2$s, de momento. Volta à aplicação daqui a uns dias e tenta novamente.
Obrigado!"</string>
<string name="screen_waitlist_message_success">"Bem-vindo à %1$s!"</string>
<string name="screen_waitlist_title">"Estás quase lá."</string>
<string name="screen_waitlist_title_success">"Estás dentro."</string>
</resources>

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile."</string>
<string name="screen_server_confirmation_title_login">"Sunteți pe cale să vă conectați la %1$s"</string>
<string name="screen_server_confirmation_title_register">"Sunteți pe cale să creați un cont pe %1$s"</string>
<string name="screen_waitlist_message">"Există o cerere mare pentru %1$s pentru %2$s în acest moment. Reveniți la aplicație în câteva zile și încercați din nou.
Vă mulțumim pentru răbdare!"</string>
<string name="screen_waitlist_message_success">"Bun venit la%1$s!"</string>
<string name="screen_waitlist_title">"Sunteți pe lista de așteptare"</string>
<string name="screen_waitlist_title_success">"Sunteți conectat!"</string>
</resources>

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем."</string>
<string name="screen_server_confirmation_title_login">"Вы собираетесь войти в %1$s"</string>
<string name="screen_server_confirmation_title_register">"Вы собираетесь создать учетную запись на %1$s"</string>
<string name="screen_waitlist_message">"В настоящее время существует высокий спрос на %1$s на %2$s. Вернитесь в приложение через несколько дней и попробуйте снова.
Спасибо за терпение!"</string>
<string name="screen_waitlist_message_success">"Добро пожаловать в %1$s!"</string>
<string name="screen_waitlist_title">"Почти готово."</string>
<string name="screen_waitlist_title_success">"Вы зарегистрированы."</string>
</resources>

View file

@ -78,10 +78,4 @@ Skúste sa prihlásiť manuálne alebo naskenujte QR kód pomocou iného zariade
<string name="screen_server_confirmation_message_register">"Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov."</string>
<string name="screen_server_confirmation_title_login">"Chystáte sa prihlásiť do %1$s"</string>
<string name="screen_server_confirmation_title_register">"Chystáte sa vytvoriť účet na %1$s"</string>
<string name="screen_waitlist_message">"Momentálne je veľký dopyt po %1$s na %2$s. Vráťte sa do aplikácie za pár dní a skúste to znova.
Ďakujeme za trpezlivosť!"</string>
<string name="screen_waitlist_message_success">"Vitajte v %1$s!"</string>
<string name="screen_waitlist_title">"Ste na čakanej listine!"</string>
<string name="screen_waitlist_title_success">"Ste dnu!"</string>
</resources>

View file

@ -78,10 +78,4 @@ Prova att logga in manuellt eller skanna QR-koden med en annan enhet."</string>
<string name="screen_server_confirmation_message_register">"Det är här dina konversationer kommer att sparas - precis som du skulle använda en e-postleverantör för att spara dina e-brev."</string>
<string name="screen_server_confirmation_title_login">"Du är på väg att logga in på %1$s"</string>
<string name="screen_server_confirmation_title_register">"Du är på väg att skapa ett konto på %1$s"</string>
<string name="screen_waitlist_message">"Det finns en stor efterfrågan på %1$s på %2$s just nu. Kom tillbaka till appen om några dagar och försök igen.
Tack för ditt tålamod!"</string>
<string name="screen_waitlist_message_success">"Välkommen till %1$s!"</string>
<string name="screen_waitlist_title">"Du är nästan framme."</string>
<string name="screen_waitlist_title_success">"Du är inne."</string>
</resources>

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"Тут будуть зберігатися Ваші розмови - так само, як Ви використовуєте поштову скриньку для зберігання своїх електронних листів."</string>
<string name="screen_server_confirmation_title_login">"Ви збираєтесь увійти в %1$s"</string>
<string name="screen_server_confirmation_title_register">"Ви збираєтеся створити обліковий запис на %1$s"</string>
<string name="screen_waitlist_message">"На цей момент існує високий попит на %1$s в %2$s. Поверніться до застосунку через кілька днів і спробуйте ще раз.
Дякуємо за терпіння!"</string>
<string name="screen_waitlist_message_success">"Ласкаво просимо до %1$s!"</string>
<string name="screen_waitlist_title">"Майже готово."</string>
<string name="screen_waitlist_title_success">"Готово."</string>
</resources>

View file

@ -33,10 +33,4 @@
<string name="screen_server_confirmation_message_register">"Bu sizning suhbatlaringiz yashaydigan joy - xuddi siz elektron pochta xabarlaringizni saqlash uchun elektron pochta provayderidan foydalanganingiz kabi."</string>
<string name="screen_server_confirmation_title_login">"Siz tizimga kirmoqchisiz%1$s"</string>
<string name="screen_server_confirmation_title_register">"Hisob yaratmoqchisiz%1$s"</string>
<string name="screen_waitlist_message">"Hozirgi paytda %2$sga %1$sda talab yuqori. Bir necha kundan keyin ilovaga qayting va qaytadan urining.
Sabr-toqatingiz uchun rahmat!"</string>
<string name="screen_waitlist_message_success">"%1$sga Xush kelibsiz!"</string>
<string name="screen_waitlist_title">"Siz deyarli keldingiz."</string>
<string name="screen_waitlist_title_success">"Siz kirdingiz."</string>
</resources>

View file

@ -29,5 +29,4 @@
<string name="screen_server_confirmation_message_register">"您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。"</string>
<string name="screen_server_confirmation_title_login">"您即將登入 %1$s"</string>
<string name="screen_server_confirmation_title_register">"您即將在 %1$s 建立帳號"</string>
<string name="screen_waitlist_message_success">"歡迎使用 %1$s"</string>
</resources>

View file

@ -78,10 +78,4 @@
<string name="screen_server_confirmation_message_register">"这是您的对话将进行的地方,就像您使用电子邮件提供商来保存电子邮件一样。"</string>
<string name="screen_server_confirmation_title_login">"即将登录 %1$s"</string>
<string name="screen_server_confirmation_title_register">"即将在 %1$s 上创建一个账户"</string>
<string name="screen_waitlist_message">"目前 %1$s 上 %2$s 的负载很大。过几天再回来试试吧。
感谢您的耐心!"</string>
<string name="screen_waitlist_message_success">"欢迎使用 %1$s"</string>
<string name="screen_waitlist_title">"马上就好。"</string>
<string name="screen_waitlist_title_success">"您已加入。"</string>
</resources>

View file

@ -78,10 +78,4 @@ Try signing in manually, or scan the QR code with another device."</string>
<string name="screen_server_confirmation_message_register">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
<string name="screen_server_confirmation_title_login">"Youre about to sign in to %1$s"</string>
<string name="screen_server_confirmation_title_register">"Youre about to create an account on %1$s"</string>
<string name="screen_waitlist_message">"There\'s a high demand for %1$s on %2$s at the moment. Come back to the app in a few days and try again.
Thanks for your patience!"</string>
<string name="screen_waitlist_message_success">"Welcome to %1$s!"</string>
<string name="screen_waitlist_title">"Youre almost there."</string>
<string name="screen_waitlist_title_success">"You\'re in."</string>
</resources>

View file

@ -26,6 +26,7 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
@ -54,7 +55,7 @@ import kotlin.time.Duration.Companion.milliseconds
class PinnedMessagesListPresenter @AssistedInject constructor(
@Assisted private val navigator: PinnedMessagesListNavigator,
private val room: MatrixRoom,
private val timelineItemsFactory: TimelineItemsFactory,
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,
private val timelineProvider: PinnedEventsTimelineProvider,
private val snackbarDispatcher: SnackbarDispatcher,
actionListPresenterFactory: ActionListPresenter.Factory,
@ -65,6 +66,12 @@ class PinnedMessagesListPresenter @AssistedInject constructor(
fun create(navigator: PinnedMessagesListNavigator): PinnedMessagesListPresenter
}
private val timelineItemsFactory: TimelineItemsFactory = timelineItemsFactoryCreator.create(
config = TimelineItemsFactoryConfig(
computeReadReceipts = false,
computeReactions = false,
)
)
private val actionListPresenter = actionListPresenterFactory.create(PinnedMessagesListTimelineActionPostProcessor())
@Composable

View file

@ -108,7 +108,7 @@ private fun PinnedMessagesListContent(
ErrorDialog(
title = stringResource(id = CommonStrings.error_unknown),
content = stringResource(id = CommonStrings.error_failed_loading_messages),
onDismiss = onErrorDismiss
onSubmit = onErrorDismiss
)
}
PinnedMessagesListState.Empty -> PinnedMessagesListEmpty()

View file

@ -22,6 +22,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.features.messages.impl.MessagesNavigator
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.model.NewEventState
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager
@ -54,7 +55,7 @@ import kotlinx.coroutines.withContext
const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L
class TimelinePresenter @AssistedInject constructor(
private val timelineItemsFactory: TimelineItemsFactory,
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,
private val timelineItemIndexer: TimelineItemIndexer,
private val room: MatrixRoom,
private val dispatchers: CoroutineDispatchers,
@ -71,6 +72,13 @@ class TimelinePresenter @AssistedInject constructor(
fun create(navigator: MessagesNavigator): TimelinePresenter
}
private val timelineItemsFactory: TimelineItemsFactory = timelineItemsFactoryCreator.create(
config = TimelineItemsFactoryConfig(
computeReadReceipts = true,
computeReactions = true,
)
)
@Composable
override fun present(): TimelineState {
val localScope = rememberCoroutineScope()

View file

@ -7,6 +7,9 @@
package io.element.android.features.messages.impl.timeline.factories
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.features.messages.impl.timeline.TimelineItemIndexer
import io.element.android.features.messages.impl.timeline.diff.TimelineItemsCacheInvalidator
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemEventFactory
@ -26,15 +29,21 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import javax.inject.Inject
class TimelineItemsFactory @Inject constructor(
class TimelineItemsFactory @AssistedInject constructor(
@Assisted config: TimelineItemsFactoryConfig,
eventItemFactoryCreator: TimelineItemEventFactory.Creator,
private val dispatchers: CoroutineDispatchers,
private val eventItemFactory: TimelineItemEventFactory,
private val virtualItemFactory: TimelineItemVirtualFactory,
private val timelineItemGrouper: TimelineItemGrouper,
private val timelineItemIndexer: TimelineItemIndexer,
) {
@AssistedFactory
interface Creator {
fun create(config: TimelineItemsFactoryConfig): TimelineItemsFactory
}
private val eventItemFactory = eventItemFactoryCreator.create(config)
private val _timelineItems = MutableSharedFlow<ImmutableList<TimelineItem>>(replay = 1)
private val lock = Mutex()
private val diffCache = MutableListDiffCache<TimelineItem>()

View file

@ -0,0 +1,18 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.features.messages.impl.timeline.factories
/**
* Some data used to configure the creation of timeline items.
* @param computeReadReceipts when false, read receipts will be empty.
* @param computeReactions when false, reactions will be empty.
*/
data class TimelineItemsFactoryConfig(
val computeReadReceipts: Boolean,
val computeReactions: Boolean,
)

View file

@ -7,6 +7,10 @@
package io.element.android.features.messages.impl.timeline.factories.event
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.groups.canBeDisplayedInBubbleBlock
import io.element.android.features.messages.impl.timeline.model.AggregatedReaction
import io.element.android.features.messages.impl.timeline.model.AggregatedReactionSender
@ -26,17 +30,23 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.getAvatarUrl
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
import io.element.android.libraries.matrix.ui.messages.reply.map
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import java.text.DateFormat
import java.util.Date
import javax.inject.Inject
class TimelineItemEventFactory @Inject constructor(
class TimelineItemEventFactory @AssistedInject constructor(
@Assisted private val config: TimelineItemsFactoryConfig,
private val contentFactory: TimelineItemContentFactory,
private val matrixClient: MatrixClient,
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
private val permalinkParser: PermalinkParser,
) {
@AssistedFactory
interface Creator {
fun create(config: TimelineItemsFactoryConfig): TimelineItemEventFactory
}
suspend fun create(
currentTimelineItem: MatrixTimelineItem.Event,
index: Int,
@ -92,8 +102,11 @@ class TimelineItemEventFactory @Inject constructor(
}
private fun MatrixTimelineItem.Event.computeReactionsState(): TimelineItemReactions {
if (!config.computeReactions) {
return TimelineItemReactions(reactions = persistentListOf())
}
val timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT)
var aggregatedReactions = event.reactions.map { reaction ->
var aggregatedReactions = this.event.reactions.map { reaction ->
// Sort reactions within an aggregation by timestamp descending.
// This puts the most recent at the top, useful in cases like the
// reaction summary view or getting the most recent reaction.
@ -129,6 +142,9 @@ class TimelineItemEventFactory @Inject constructor(
private fun MatrixTimelineItem.Event.computeReadReceiptState(
roomMembers: List<RoomMember>,
): TimelineItemReadReceipts {
if (!config.computeReadReceipts) {
return TimelineItemReadReceipts(receipts = persistentListOf())
}
return TimelineItemReadReceipts(
receipts = event.receipts
.map { receipt ->

View file

@ -36,7 +36,7 @@ fun FocusRequestStateView(
}
ErrorDialog(
content = errorMessage,
onDismiss = onClearFocusRequestState,
onSubmit = onClearFocusRequestState,
modifier = modifier,
)
}

View file

@ -19,7 +19,7 @@ internal fun VoiceMessageSendingFailedDialog(
ErrorDialog(
title = stringResource(CommonStrings.common_error),
content = stringResource(CommonStrings.error_failed_uploading_voice_message),
onDismiss = onDismiss,
onSubmit = onDismiss,
submitText = stringResource(CommonStrings.action_ok),
)
}

View file

@ -18,7 +18,7 @@ import io.element.android.features.messages.impl.actionlist.FakeActionListPresen
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.draft.FakeComposerDraftService
import io.element.android.features.messages.impl.fixtures.aMessageEvent
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator
import io.element.android.features.messages.impl.messagecomposer.DefaultMessageComposerContext
import io.element.android.features.messages.impl.messagecomposer.FakeRoomAliasSuggestionsDataSource
import io.element.android.features.messages.impl.messagecomposer.MessageComposerPresenter
@ -1024,7 +1024,7 @@ class MessagesPresenterTest {
permissionsPresenterFactory,
)
val timelinePresenter = TimelinePresenter(
timelineItemsFactory = aTimelineItemsFactory(),
timelineItemsFactoryCreator = aTimelineItemsFactoryCreator(),
room = matrixRoom,
dispatchers = coroutineDispatchers,
appScope = this,

View file

@ -9,6 +9,7 @@ package io.element.android.features.messages.impl.fixtures
import io.element.android.features.messages.impl.timeline.TimelineItemIndexer
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemContentFactory
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemContentFailedToParseMessageFactory
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemContentFailedToParseStateFactory
@ -39,40 +40,56 @@ import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorW
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope
internal fun TestScope.aTimelineItemsFactoryCreator(
timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer(),
): TimelineItemsFactory.Creator {
return object : TimelineItemsFactory.Creator {
override fun create(config: TimelineItemsFactoryConfig): TimelineItemsFactory {
return aTimelineItemsFactory(config, timelineItemIndexer)
}
}
}
internal fun TestScope.aTimelineItemsFactory(
timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer()
config: TimelineItemsFactoryConfig,
timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer(),
): TimelineItemsFactory {
val timelineEventFormatter = aTimelineEventFormatter()
val matrixClient = FakeMatrixClient()
return TimelineItemsFactory(
dispatchers = testCoroutineDispatchers(),
eventItemFactory = TimelineItemEventFactory(
contentFactory = TimelineItemContentFactory(
messageFactory = TimelineItemContentMessageFactory(
fileSizeFormatter = FakeFileSizeFormatter(),
fileExtensionExtractor = FileExtensionExtractorWithoutValidation(),
featureFlagService = FakeFeatureFlagService(),
htmlConverterProvider = FakeHtmlConverterProvider(),
eventItemFactoryCreator = object : TimelineItemEventFactory.Creator {
override fun create(config: TimelineItemsFactoryConfig): TimelineItemEventFactory {
return TimelineItemEventFactory(
contentFactory = TimelineItemContentFactory(
messageFactory = TimelineItemContentMessageFactory(
fileSizeFormatter = FakeFileSizeFormatter(),
fileExtensionExtractor = FileExtensionExtractorWithoutValidation(),
featureFlagService = FakeFeatureFlagService(),
htmlConverterProvider = FakeHtmlConverterProvider(),
permalinkParser = FakePermalinkParser(),
textPillificationHelper = FakeTextPillificationHelper(),
),
redactedMessageFactory = TimelineItemContentRedactedFactory(),
stickerFactory = TimelineItemContentStickerFactory(
fileSizeFormatter = FakeFileSizeFormatter(),
fileExtensionExtractor = FileExtensionExtractorWithoutValidation()
),
pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()),
utdFactory = TimelineItemContentUTDFactory(),
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
profileChangeFactory = TimelineItemContentProfileChangeFactory(timelineEventFormatter),
stateFactory = TimelineItemContentStateFactory(timelineEventFormatter),
failedToParseMessageFactory = TimelineItemContentFailedToParseMessageFactory(),
failedToParseStateFactory = TimelineItemContentFailedToParseStateFactory(),
),
matrixClient = matrixClient,
lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter(),
permalinkParser = FakePermalinkParser(),
textPillificationHelper = FakeTextPillificationHelper(),
),
redactedMessageFactory = TimelineItemContentRedactedFactory(),
stickerFactory = TimelineItemContentStickerFactory(
fileSizeFormatter = FakeFileSizeFormatter(),
fileExtensionExtractor = FileExtensionExtractorWithoutValidation()
),
pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()),
utdFactory = TimelineItemContentUTDFactory(),
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
profileChangeFactory = TimelineItemContentProfileChangeFactory(timelineEventFormatter),
stateFactory = TimelineItemContentStateFactory(timelineEventFormatter),
failedToParseMessageFactory = TimelineItemContentFailedToParseMessageFactory(),
failedToParseStateFactory = TimelineItemContentFailedToParseStateFactory(),
),
matrixClient = matrixClient,
lastMessageTimestampFormatter = FakeLastMessageTimestampFormatter(),
permalinkParser = FakePermalinkParser(),
),
config = config
)
}
},
virtualItemFactory = TimelineItemVirtualFactory(
daySeparatorFactory = TimelineItemDaySeparatorFactory(
FakeDaySeparatorFormatter()
@ -80,6 +97,7 @@ internal fun TestScope.aTimelineItemsFactory(
),
timelineItemGrouper = TimelineItemGrouper(),
timelineItemIndexer = timelineItemIndexer,
config = config
)
}

View file

@ -10,7 +10,7 @@ package io.element.android.features.messages.impl.pinned.list
import com.google.common.truth.Truth.assertThat
import io.element.android.features.messages.impl.actionlist.FakeActionListPresenter
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.networkmonitor.api.NetworkMonitor
@ -298,7 +298,7 @@ class PinnedMessagesListPresenterTest {
return PinnedMessagesListPresenter(
navigator = navigator,
room = room,
timelineItemsFactory = aTimelineItemsFactory(),
timelineItemsFactoryCreator = aTimelineItemsFactoryCreator(),
timelineProvider = timelineProvider,
snackbarDispatcher = SnackbarDispatcher(),
actionListPresenterFactory = FakeActionListPresenter.Factory,

View file

@ -14,9 +14,8 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.messages.impl.FakeMessagesNavigator
import io.element.android.features.messages.impl.fixtures.aMessageEvent
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory
import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactoryCreator
import io.element.android.features.messages.impl.timeline.components.aCriticalShield
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.model.NewEventState
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager
@ -662,7 +661,6 @@ import kotlin.time.Duration.Companion.seconds
liveTimeline = timeline,
canUserSendMessageResult = { _, _ -> Result.success(true) }
),
timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory(),
redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(),
endPollAction: EndPollAction = FakeEndPollAction(),
@ -671,7 +669,7 @@ import kotlin.time.Duration.Companion.seconds
timelineItemIndexer: TimelineItemIndexer = TimelineItemIndexer(),
): TimelinePresenter {
return TimelinePresenter(
timelineItemsFactory = timelineItemsFactory,
timelineItemsFactoryCreator = aTimelineItemsFactoryCreator(),
room = room,
dispatchers = testCoroutineDispatchers(),
appScope = this,

View file

@ -259,7 +259,7 @@ private fun InvalidNotificationSettingsView(
ErrorDialog(
title = stringResource(id = CommonStrings.dialog_title_error),
content = stringResource(id = R.string.screen_notification_settings_failed_fixing_configuration),
onDismiss = onDismissError
onSubmit = onDismissError
)
}
}

View file

@ -9,12 +9,13 @@ package io.element.android.features.preferences.impl.root
import io.element.android.features.logout.api.direct.DirectLogoutState
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
import io.element.android.libraries.matrix.api.core.DeviceId
import io.element.android.libraries.matrix.api.user.MatrixUser
data class PreferencesRootState(
val myUser: MatrixUser,
val version: String,
val deviceId: String?,
val deviceId: DeviceId?,
val showSecureBackup: Boolean,
val showSecureBackupBadge: Boolean,
val accountManagementUrl: String?,

View file

@ -9,6 +9,7 @@ package io.element.android.features.preferences.impl.root
import io.element.android.features.logout.api.direct.aDirectLogoutState
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
import io.element.android.libraries.matrix.api.core.DeviceId
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.ui.strings.CommonStrings
@ -18,7 +19,7 @@ fun aPreferencesRootState(
) = PreferencesRootState(
myUser = myUser,
version = "Version 1.1 (1)",
deviceId = "ILAKNDNASDLK",
deviceId = DeviceId("ILAKNDNASDLK"),
showSecureBackup = true,
showSecureBackupBadge = true,
accountManagementUrl = "aUrl",

View file

@ -36,6 +36,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
import io.element.android.libraries.matrix.api.core.DeviceId
import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
import io.element.android.libraries.ui.strings.CommonStrings
@ -229,7 +230,7 @@ private fun ColumnScope.GeneralSection(
@Composable
private fun ColumnScope.Footer(
version: String,
deviceId: String?,
deviceId: DeviceId?,
onClick: (() -> Unit)?,
) {
val text = remember(version, deviceId) {

View file

@ -124,7 +124,7 @@ fun RolesAndPermissionsView(
is AsyncAction.Failure -> {
ErrorDialog(
content = stringResource(CommonStrings.error_unknown),
onDismiss = { state.eventSink(RolesAndPermissionsEvents.CancelPendingAction) }
onSubmit = { state.eventSink(RolesAndPermissionsEvents.CancelPendingAction) }
)
}
else -> Unit

View file

@ -210,7 +210,7 @@ fun ChangeRolesView(
is AsyncAction.Failure -> {
ErrorDialog(
content = stringResource(CommonStrings.error_unknown),
onDismiss = { state.eventSink(ChangeRolesEvent.ClearError) }
onSubmit = { state.eventSink(ChangeRolesEvent.ClearError) }
)
}
is AsyncAction.Success -> {

View file

@ -1,5 +1,9 @@
<?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">"Odhlásit se a upgradovat"</string>
<string name="banner_migrate_to_native_sliding_sync_description">"Váš server nyní podporuje nový, rychlejší protokol. Chcete-li upgradovat, odhlaste se a znovu se přihlaste. Pokud to uděláte nyní, pomůže vám vyhnout se nucenému odhlášení, když bude starý protokol později odstraněn."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Váš domovský server již nepodporuje starý protokol. Chcete-li pokračovat v používání aplikace, odhlaste se a znovu se přihlaste."</string>
<string name="banner_migrate_to_native_sliding_sync_title">"Upgrade k dispozici"</string>
<string name="banner_set_up_recovery_content">"Vygenerujte nový klíč pro obnovení, který lze použít k obnovení historie šifrovaných zpráv v případě, že ztratíte přístup ke svým zařízením."</string>
<string name="banner_set_up_recovery_title">"Nastavení obnovy"</string>
<string name="confirm_recovery_key_banner_message">"Vaše záloha chatu není aktuálně synchronizována. Abyste si zachovali přístup k záloze chatu, musíte potvrdit klíč pro obnovení."</string>

View file

@ -1,5 +1,11 @@
<?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">"Αποσύνδεση &amp;amp; Αναβάθμιση"</string>
<string name="banner_migrate_to_native_sliding_sync_description">"Ο διακομιστής σου υποστηρίζει τώρα ένα νέο, ταχύτερο πρωτόκολλο. Αποσυνδέσου και συνδέσου ξανά για αναβάθμιση τώρα. Κάνοντας αυτό τώρα θα σε βοηθήσει να αποφύγεις μια αναγκαστική αποσύνδεση όταν το παλιό πρωτόκολλο καταργηθεί αργότερα."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Ο οικιακός διακομιστής σου δεν υποστηρίζει πλέον το παλιό πρωτόκολλο. Αποσυνδέσου και συνδέσου ξανά για να συνεχίσεις να χρησιμοποιείς την εφαρμογή."</string>
<string name="banner_migrate_to_native_sliding_sync_title">"Διαθέσιμη αναβάθμιση"</string>
<string name="banner_set_up_recovery_content">"Δημιούργησε ένα νέο κλειδί ανάκτησης που μπορεί να χρησιμοποιηθεί για την επαναφορά του ιστορικού των κρυπτογραφημένων μηνυμάτων σου σε περίπτωση που χάσεις την πρόσβαση στις συσκευές σου."</string>
<string name="banner_set_up_recovery_title">"Ρύθμιση ανάκτησης"</string>
<string name="confirm_recovery_key_banner_message">"Το αντίγραφο ασφαλείας της συνομιλίας σου δεν είναι συγχρονισμένο αυτήν τη στιγμή. Πρέπει να εισαγάγεις το κλειδί ανάκτησης για να διατηρήσεις την πρόσβαση στο αντίγραφο ασφαλείας της συνομιλίας σου."</string>
<string name="confirm_recovery_key_banner_title">"Εισήγαγε το κλειδί ανάκτησης"</string>
<string name="full_screen_intent_banner_message">"Για να διασφαλίσεις ότι δεν θα χάσεις ποτέ μια σημαντική κλήση, άλλαξε τις ρυθμίσεις σου για να επιτρέψεις τις ειδοποιήσεις πλήρους οθόνης όταν το τηλέφωνό σου είναι κλειδωμένο."</string>

View file

@ -1,5 +1,9 @@
<?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">"Logi välja ja uuenda"</string>
<string name="banner_migrate_to_native_sliding_sync_description">"Sinu koduserver toetab uut ja kiiremat protokolli. Uuendamiseks logi korraks rakendusest välja ja siis tagasi. Mingil hetkel tulevikus vana protokoll eemaldatakse kasutusest ja tehes uuenduse nüüd väldid hilisemat sundkorras uuendust."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Sinu koduserver enam ei toeta vana protokolli. Jätkamaks rakenduse kasutamist palun logi välja ning seejärel tagasi."</string>
<string name="banner_migrate_to_native_sliding_sync_title">"Saadaval on uuendus"</string>
<string name="banner_set_up_recovery_content">"Loo uus taastevõti, mida saad kasutada oma krüptitud sõnumite ajaloo taastamisel olukorras, kus kaotad ligipääsu oma seadmetele."</string>
<string name="banner_set_up_recovery_title">"Seadista taastamine"</string>
<string name="confirm_recovery_key_banner_message">"Sinu vestluste varukoopia pole hetkel sünkroonis. Säilitamaks ligipääsu vestluse varukoopiale palun sisesta oma taastevõti."</string>

View file

@ -1,5 +1,9 @@
<?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">"Odhlásiť sa a aktualizovať"</string>
<string name="banner_migrate_to_native_sliding_sync_description">"Váš server teraz podporuje nový, rýchlejší protokol. Odhláste sa a prihláste sa znova, aby ste mohli aktualizovať. Ak to urobíte teraz, pomôže vám vyhnúť sa nútenému odhláseniu, keď sa starý protokol neskôr odstráni."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Váš domovský server už nepodporuje starý protokol. Ak chcete pokračovať v používaní aplikácie, odhláste sa a znova sa prihláste."</string>
<string name="banner_migrate_to_native_sliding_sync_title">"Aktualizácia je k dispozícii"</string>
<string name="banner_set_up_recovery_content">"Vytvorte nový kľúč na obnovenie, ktorý môžete použiť na obnovenie vašej histórie šifrovaných správ v prípade straty prístupu k vašim zariadeniam."</string>
<string name="banner_set_up_recovery_title">"Nastaviť obnovenie"</string>
<string name="confirm_recovery_key_banner_message">"Vaša záloha konverzácie nie je momentálne synchronizovaná. Na zachovanie prístupu k zálohe konverzácie musíte potvrdiť svoj kľúč na obnovu."</string>

View file

@ -2,6 +2,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="banner_migrate_to_native_sliding_sync_action">"Log Out &amp; Upgrade"</string>
<string name="banner_migrate_to_native_sliding_sync_description">"Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later."</string>
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app."</string>
<string name="banner_migrate_to_native_sliding_sync_title">"Upgrade available"</string>
<string name="banner_set_up_recovery_content">"Generate a new recovery key that can be used to restore your encrypted message history in case you lose access to your devices."</string>
<string name="banner_set_up_recovery_title">"Set up recovery"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"Паўтарыце спробу, каб пацвердзіць доступ да рэзервовай копіі чата."</string>
<string name="screen_recovery_key_confirm_error_title">"Няправільны ключ аднаўлення"</string>
<string name="screen_recovery_key_confirm_key_description">"Калі ў вас ёсць ключ аднаўлення або парольная фраза, гэта таксама будзе працаваць."</string>
<string name="screen_recovery_key_confirm_key_label">"Ключ аднаўлення або код доступу"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Увесці…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Страцілі ключ аднаўлення?"</string>
<string name="screen_recovery_key_confirm_success">"Ключ аднаўлення пацверджаны"</string>

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Zkuste prosím znovu potvrdit přístup k záloze chatu."</string>
<string name="screen_recovery_key_confirm_error_title">"Nesprávný klíč pro obnovení"</string>
<string name="screen_recovery_key_confirm_key_description">"Pokud máte bezpečnostní klíč nebo bezpečnostní frázi, bude to fungovat také."</string>
<string name="screen_recovery_key_confirm_key_label">"Klíč pro obnovení nebo přístupový kód"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Zadejte…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Ztratili jste klíč pro obnovení?"</string>
<string name="screen_recovery_key_confirm_success">"Klíč pro obnovení potvrzen"</string>

View file

@ -51,10 +51,6 @@ Das bedeutet:"</string>
<string name="screen_recovery_key_confirm_error_content">"Bitte versuche es noch einmal, um den Zugriff auf dein Chat-Backup zu bestätigen."</string>
<string name="screen_recovery_key_confirm_error_title">"Falscher Wiederherstellungsschlüssel"</string>
<string name="screen_recovery_key_confirm_key_description">"Dies funktioniert auch mit einem Sicherheitsschlüssel oder Sicherheitsphrase."</string>
<string name="screen_recovery_key_confirm_key_label">
<b>"Wiederherstellungsschlüssel"</b>
" oder Passcode"
</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Eingeben…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Hast du deinen Wiederherstellungschlüssel vergessen?"</string>
<string name="screen_recovery_key_confirm_success">"Wiederherstellungsschlüssel bestätigt"</string>

View file

@ -16,6 +16,12 @@
<string name="screen_create_new_recovery_key_list_item_4">"Ακολούθησε τις οδηγίες για να δημιουργήσεις ένα νέο κλειδί ανάκτησης"</string>
<string name="screen_create_new_recovery_key_list_item_5">"Αποθήκευσε το νέο κλειδί ανάκτησης σε έναν διαχειριστή κωδικών πρόσβασης ή σε κρυπτογραφημένη σημείωση"</string>
<string name="screen_create_new_recovery_key_title">"Επανάφερε την κρυπτογράφηση για το λογαριασμό σου χρησιμοποιώντας άλλη συσκευή"</string>
<string name="screen_encryption_reset_action_continue_reset">"Συνέχιση επαναφοράς"</string>
<string name="screen_encryption_reset_bullet_1">"Τα στοιχεία του λογαριασμού σου, οι επαφές, οι προτιμήσεις και η λίστα συνομιλιών θα διατηρηθούν"</string>
<string name="screen_encryption_reset_bullet_2">"Θα χάσεις το υπάρχον ιστορικό μηνυμάτων σου"</string>
<string name="screen_encryption_reset_bullet_3">"Θα χρειαστεί να επαληθεύσεις ξανά όλες τις υπάρχουσες συσκευές και επαφές σου"</string>
<string name="screen_encryption_reset_footer">"Επανάφερε την ταυτότητά σου μόνο εάν δεν έχεις πρόσβαση σε άλλη συνδεδεμένη συσκευή και έχεις χάσει το κλειδί ανάκτησης."</string>
<string name="screen_encryption_reset_title">"Δεν μπορείς να επιβεβαιώσεις; Θα χρειαστεί να επαναφέρεις την ταυτότητά σου."</string>
<string name="screen_key_backup_disable_confirmation_action_turn_off">"Απενεργοποίηση"</string>
<string name="screen_key_backup_disable_confirmation_description">"Θα χάσεις τα κρυπτογραφημένα μηνύματά σου εάν αποσυνδεθείς από όλες τις συσκευές."</string>
<string name="screen_key_backup_disable_confirmation_title">"Σίγουρα θες να απενεργοποιήσεις τα αντίγραφα ασφαλείας;"</string>
@ -33,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Προσπάθησε ξανά για να επιβεβαιώσεις την πρόσβαση στο αντίγραφο ασφαλείας της συνομιλίας σου."</string>
<string name="screen_recovery_key_confirm_error_title">"Λανθασμένο κλειδί ανάκτησης"</string>
<string name="screen_recovery_key_confirm_key_description">"Εάν έχεις ένα κλειδί ασφαλείας ή μια φράση ασφαλείας, θα λειτουργήσει επίσης."</string>
<string name="screen_recovery_key_confirm_key_label">"Κλειδί ανάκτησης ή κωδικός πρόσβασης"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Εισαγωγή…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Έχασες το κλειδί ανάκτησης;"</string>
<string name="screen_recovery_key_confirm_success">"Επιβεβαιώθηκε το κλειδί ανάκτησης"</string>
@ -51,4 +56,11 @@
<string name="screen_recovery_key_setup_generate_key_description">"Βεβαιώσου ότι μπορείς να αποθηκεύσεις το κλειδί ανάκτησης κάπου ασφαλές"</string>
<string name="screen_recovery_key_setup_success">"Επιτυχής ρύθμιση ανάκτησης"</string>
<string name="screen_recovery_key_setup_title">"Ρύθμιση ανάκτησης"</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Ναι, επαναφορά τώρα"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"Η διαδικασία είναι μη αναστρέψιμη."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Σίγουρα θες να επαναφέρεις την ταυτότητά σου;"</string>
<string name="screen_reset_encryption_password_error">"Συνέβη ένα άγνωστο σφάλμα. Έλεγξε ότι ο κωδικός πρόσβασης του λογαριασμού σου είναι σωστός και δοκίμασε ξανά."</string>
<string name="screen_reset_encryption_password_placeholder">"Εισαγωγή…"</string>
<string name="screen_reset_encryption_password_subtitle">"Επιβεβαίωσε ότι θες να επαναφέρεις την ταυτότητά σου."</string>
<string name="screen_reset_encryption_password_title">"Εισήγαγε τον κωδικό πρόσβασης του λογαριασμού σου για να συνεχίσεις"</string>
</resources>

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Kinnitamaks ligipääsu sinu vestluse varukoopiale, palun proovi uuesti"</string>
<string name="screen_recovery_key_confirm_error_title">"Vigane taastevõti"</string>
<string name="screen_recovery_key_confirm_key_description">"Kui sul on turvavõti või turvafraas, siis need toimivad ka."</string>
<string name="screen_recovery_key_confirm_key_label">"Taastevõti või turvafraas"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Sisesta…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Kas sa oled taastevõtme kaotanud?"</string>
<string name="screen_recovery_key_confirm_success">"Taastevõti on kinnitatud"</string>

View file

@ -37,7 +37,6 @@
<string name="screen_recovery_key_confirm_error_content">"Veuillez réessayer afin de pouvoir accéder à vos anciens messages."</string>
<string name="screen_recovery_key_confirm_error_title">"Clé de récupération incorrecte"</string>
<string name="screen_recovery_key_confirm_key_description">"Si vous avez une clé de sécurité ou une phrase de sécurité, cela fonctionnera également."</string>
<string name="screen_recovery_key_confirm_key_label">"Clé de récupération"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Saisissez la clé ici…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Clé de récupération perdue?"</string>
<string name="screen_recovery_key_confirm_success">"Clé de récupération confirmée"</string>

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Próbálja meg újra megerősíteni a csevegés biztonsági mentéséhez való hozzáférését."</string>
<string name="screen_recovery_key_confirm_error_title">"Helytelen helyreállítási kulcs"</string>
<string name="screen_recovery_key_confirm_key_description">"Ha van biztonsági kulcsa vagy biztonsági jelmondata, akkor ez is fog működni."</string>
<string name="screen_recovery_key_confirm_key_label">"Helyreállítási kulcs vagy jelkód"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Megadás…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Elvesztette a helyreállítási kulcsát?"</string>
<string name="screen_recovery_key_confirm_success">"Helyreállítási kulcs megerősítve"</string>

View file

@ -33,7 +33,6 @@
<string name="screen_recovery_key_confirm_error_content">"Silakan coba lagi untuk mengonfirmasi akses ke cadangan percakapan Anda."</string>
<string name="screen_recovery_key_confirm_error_title">"Kunci pemulihan salah"</string>
<string name="screen_recovery_key_confirm_key_description">"Jika Anda memiliki kunci keamanan atau frasa keamanan, ini juga bisa digunakan."</string>
<string name="screen_recovery_key_confirm_key_label">"Kunci pemulihan atau kode sandi"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Masukkan…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Kehilangan kunci pemulihan Anda?"</string>
<string name="screen_recovery_key_confirm_success">"Kunci pemulihan dikonfirmasi"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"Riprova per confermare l\'accesso al backup della chat."</string>
<string name="screen_recovery_key_confirm_error_title">"Chiave di recupero errata"</string>
<string name="screen_recovery_key_confirm_key_description">"Se hai una chiave di sicurezza o una password, andrà bene anche questo."</string>
<string name="screen_recovery_key_confirm_key_label">"Chiave di recupero o codice di accesso"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Inserisci…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Hai perso la chiave di recupero?"</string>
<string name="screen_recovery_key_confirm_success">"Chiave di recupero confermata"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"Spróbuj ponownie, aby potwierdzić dostęp do backupu czatu."</string>
<string name="screen_recovery_key_confirm_error_title">"Nieprawidłowy klucz przywracania"</string>
<string name="screen_recovery_key_confirm_key_description">"To też zadziała, jeśli posiadasz klucz lub frazę bezpieczeństwa."</string>
<string name="screen_recovery_key_confirm_key_label">"Klucz przywracania lub hasło"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Wprowadź…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Zgubiłeś swój kod przywracania?"</string>
<string name="screen_recovery_key_confirm_success">"Potwierdzono klucz przywracania"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"Por favor, tenta novamente para confirmar o acesso à tua cópia de segurança das conversas."</string>
<string name="screen_recovery_key_confirm_error_title">"Chave de recuperação incorreta"</string>
<string name="screen_recovery_key_confirm_key_description">"Também funciona se tiveres uma chave ou frase de segurança."</string>
<string name="screen_recovery_key_confirm_key_label">"Chave ou código de recuperação"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Inserir…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Perdeste a tua chave?"</string>
<string name="screen_recovery_key_confirm_success">"Chave de recuperação confirmada"</string>

View file

@ -33,7 +33,6 @@
<string name="screen_recovery_key_confirm_error_content">"Vă rugăm să încercați din nou să confirmați accesul la backup."</string>
<string name="screen_recovery_key_confirm_error_title">"Cheie de recuperare incorectă"</string>
<string name="screen_recovery_key_confirm_key_description">"Dacă aveți o cheie de securitate sau o frază de securitate, aceasta va funcționa și ea."</string>
<string name="screen_recovery_key_confirm_key_label">"Cheie de recuperare sau cod de acces"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Introduceți…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Ați pierdut cheia de recuperare?"</string>
<string name="screen_recovery_key_confirm_success">"Cheia de recuperare confirmată"</string>

View file

@ -60,10 +60,6 @@
<b>"ключ восстановления"</b>
</string>
<string name="screen_recovery_key_confirm_key_description">"Если у вас есть пароль для восстановления или секретный пароль/ключ, это тоже сработает."</string>
<string name="screen_recovery_key_confirm_key_label">
<b>"Ключ восстановления"</b>
" или пароль"
</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Вход…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Потеряли ключ восстановления?"</string>
<string name="screen_recovery_key_confirm_success">

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Skúste prosím znova potvrdiť prístup k vašej zálohe konverzácie."</string>
<string name="screen_recovery_key_confirm_error_title">"Nesprávny kľúč na obnovenie"</string>
<string name="screen_recovery_key_confirm_key_description">"Ak máte bezpečnostný kľúč alebo bezpečnostnú frázu, bude to fungovať tiež."</string>
<string name="screen_recovery_key_confirm_key_label">"Kľúč na obnovenie alebo prístupový kód"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Zadať…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Stratili ste kľúč na obnovenie?"</string>
<string name="screen_recovery_key_confirm_success">"Kľúč na obnovu potvrdený"</string>

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Vänligen pröva igen för att bekräfta åtkomsten till din chattsäkerhetskopia."</string>
<string name="screen_recovery_key_confirm_error_title">"Felaktig återställningsnyckel"</string>
<string name="screen_recovery_key_confirm_key_description">"Om du har en säkerhetsnyckel eller säkerhetsfras så funkar den också."</string>
<string name="screen_recovery_key_confirm_key_label">"Återställningsnyckel eller lösenkod"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Ange …"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Blivit av med din återställningsnyckel?"</string>
<string name="screen_recovery_key_confirm_success">"Återställningsnyckel bekräftad"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"Будь ласка, спробуйте ще раз, щоб підтвердити доступ до резервної копії чату."</string>
<string name="screen_recovery_key_confirm_error_title">"Неправильний ключ відновлення"</string>
<string name="screen_recovery_key_confirm_key_description">"Якщо у вас є ключ безпеки або фраза безпеки, це теж спрацює."</string>
<string name="screen_recovery_key_confirm_key_label">"Ключ відновлення або код допуску"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Ввести…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Загубили ключ відновлення?"</string>
<string name="screen_recovery_key_confirm_success">"Ключ відновлення підтверджено"</string>

View file

@ -38,7 +38,6 @@
<string name="screen_recovery_key_confirm_error_content">"请重试以访问您的聊天备份。"</string>
<string name="screen_recovery_key_confirm_error_title">"恢复密钥不正确"</string>
<string name="screen_recovery_key_confirm_key_description">"如果您有安全密钥或安全短语,也可以用。"</string>
<string name="screen_recovery_key_confirm_key_label">"恢复密钥或密码"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"输入……"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"丢失了恢复密钥?"</string>
<string name="screen_recovery_key_confirm_success">"恢复密钥已确认"</string>

View file

@ -39,7 +39,6 @@
<string name="screen_recovery_key_confirm_error_content">"Please try again to confirm access to your chat backup."</string>
<string name="screen_recovery_key_confirm_error_title">"Incorrect recovery key"</string>
<string name="screen_recovery_key_confirm_key_description">"If you have a security key or security phrase, this will work too."</string>
<string name="screen_recovery_key_confirm_key_label">"Recovery key or passcode"</string>
<string name="screen_recovery_key_confirm_key_placeholder">"Enter…"</string>
<string name="screen_recovery_key_confirm_lost_recovery_key">"Lost your recovery key?"</string>
<string name="screen_recovery_key_confirm_success">"Recovery key confirmed"</string>

View file

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Δεν μπορείς να επιβεβαιώσεις;"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Δημιουργία νέου κλειδιού ανάκτησης"</string>
<string name="screen_identity_confirmation_subtitle">"Επαλήθευσε αυτήν τη συσκευή για να ρυθμίσεις την ασφαλή επικοινωνία."</string>
<string name="screen_identity_confirmation_title">"Επιβεβαίωσε ότι είσαι εσύ"</string>
<string name="screen_identity_confirmation_use_another_device">"Χρήση άλλης συσκευής"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Χρήση κλειδιού ανάκτησης"</string>
<string name="screen_identity_confirmed_subtitle">"Τώρα μπορείς να διαβάζεις ή να στέλνεις μηνύματα με ασφάλεια και επίσης μπορεί να εμπιστευτεί αυτήν τη συσκευή οποιοσδήποτε με τον οποίο συνομιλείς."</string>
<string name="screen_identity_confirmed_title">"Επαληθευμένη συσκευή"</string>
<string name="screen_identity_use_another_device">"Χρήση άλλης συσκευής"</string>

View file

@ -162,7 +162,7 @@ jsoup = "org.jsoup:jsoup:1.18.1"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.42"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.44"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }

View file

@ -48,7 +48,7 @@ fun <T> AsyncActionView(
ErrorDialog(
title = errorTitle(async.error),
content = errorMessage(async.error),
onDismiss = onErrorDismiss
onSubmit = onErrorDismiss
)
} else {
RetryDialog(

View file

@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@ -25,17 +26,23 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun ErrorDialog(
content: String,
onDismiss: () -> Unit,
onSubmit: () -> Unit,
modifier: Modifier = Modifier,
title: String = ErrorDialogDefaults.title,
title: String? = ErrorDialogDefaults.title,
submitText: String = ErrorDialogDefaults.submitText,
onDismiss: () -> Unit = onSubmit,
canDismiss: Boolean = true,
) {
BasicAlertDialog(modifier = modifier, onDismissRequest = onDismiss) {
BasicAlertDialog(
modifier = modifier,
onDismissRequest = onDismiss,
properties = DialogProperties(dismissOnClickOutside = canDismiss, dismissOnBackPress = canDismiss)
) {
ErrorDialogContent(
title = title,
content = content,
submitText = submitText,
onSubmitClick = onDismiss,
onSubmitClick = onSubmit,
)
}
}
@ -44,7 +51,7 @@ fun ErrorDialog(
private fun ErrorDialogContent(
content: String,
onSubmitClick: () -> Unit,
title: String = ErrorDialogDefaults.title,
title: String? = ErrorDialogDefaults.title,
submitText: String = ErrorDialogDefaults.submitText,
) {
SimpleAlertDialogContent(
@ -78,6 +85,6 @@ internal fun ErrorDialogContentPreview() {
internal fun ErrorDialogPreview() = ElementPreview {
ErrorDialog(
content = "Content",
onDismiss = {},
onSubmit = {},
)
}

View file

@ -45,6 +45,12 @@
<string name="state_event_room_name_removed_by_you">"Αφαίρεσες το όνομα του δωματίου"</string>
<string name="state_event_room_none">"Ο χρήστης %1$s δεν έκανε καμία αλλαγή"</string>
<string name="state_event_room_none_by_you">"Δεν έκανες καμία αλλαγή"</string>
<string name="state_event_room_pinned_events_changed">"Ο χρήστης %1$s άλλαξε τα καρφιτσωμένα μηνύματα"</string>
<string name="state_event_room_pinned_events_changed_by_you">"Άλλαξες τα καρφιτσωμένα μηνύματα"</string>
<string name="state_event_room_pinned_events_pinned">"Ο χρήστης %1$s καρφίτσωσε ένα μήνυμα"</string>
<string name="state_event_room_pinned_events_pinned_by_you">"Καρφίτσωσες ένα μήνυμα"</string>
<string name="state_event_room_pinned_events_unpinned">"Ο χρήστης %1$s ξεκαρφίτσωσε ένα μήνυμα"</string>
<string name="state_event_room_pinned_events_unpinned_by_you">"Ξεκαρφίτσωσες ένα μήνυμα"</string>
<string name="state_event_room_reject">"Ο χρήστης %1$s απέρριψε την πρόσκληση"</string>
<string name="state_event_room_reject_by_you">"Απέρριψες την πρόσκληση"</string>
<string name="state_event_room_remove">"Ο χρήστης %1$s αφαίρεσε τον χρήστη %2$s"</string>

View file

@ -13,8 +13,6 @@ import io.element.android.libraries.core.meta.BuildType
/**
* To enable or disable a FeatureFlags, change the `defaultValue` value.
* Warning: to enable a flag for the release app, you MUST update the file
* [io.element.android.libraries.featureflag.impl.StaticFeatureFlagProvider]
*/
enum class FeatureFlags(
override val key: String,
@ -115,7 +113,7 @@ enum class FeatureFlags(
key = "feature.pinnedEvents",
title = "Pinned Events",
description = "Allow user to pin events in a room",
defaultValue = { false },
defaultValue = { true },
isFinished = false,
),
SyncOnPush(
@ -125,4 +123,13 @@ enum class FeatureFlags(
defaultValue = { true },
isFinished = false,
),
InvisibleCrypto(
key = "feature.invisibleCrypto",
title = "Invisible Crypto",
description = "This setting controls how end-to-end encryption (E2E) keys are shared." +
" Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners." +
" You'll have to stop and re-open the app manually for that setting to take effect.",
defaultValue = { false },
isFinished = false,
),
}

View file

@ -7,6 +7,7 @@
package io.element.android.libraries.matrix.api
import io.element.android.libraries.matrix.api.core.DeviceId
import io.element.android.libraries.matrix.api.core.ProgressCallback
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
@ -20,6 +21,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.InvitedRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
@ -41,13 +43,14 @@ import java.util.Optional
interface MatrixClient : Closeable {
val sessionId: SessionId
val deviceId: String
val deviceId: DeviceId
val userProfile: StateFlow<MatrixUser>
val roomListService: RoomListService
val mediaLoader: MatrixMediaLoader
val sessionCoroutineScope: CoroutineScope
val ignoredUsersFlow: StateFlow<ImmutableList<UserId>>
suspend fun getRoom(roomId: RoomId): MatrixRoom?
suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom?
suspend fun findDM(userId: UserId): RoomId?
suspend fun ignoreUser(userId: UserId): Result<Unit>
suspend fun unignoreUser(userId: UserId): Result<Unit>
@ -130,6 +133,9 @@ interface MatrixClient : Closeable {
/** Returns `true` if the home server supports native sliding sync. */
suspend fun isNativeSlidingSyncSupported(): Boolean
/** Returns `true` if the current session is using native sliding sync. */
/** Returns `true` if the home server supports sliding sync using a proxy. */
suspend fun isSlidingSyncProxySupported(): Boolean
/** Returns `true` if the current session is using native sliding sync, `false` if it's using a proxy. */
fun isUsingNativeSlidingSync(): Boolean
}

View file

@ -0,0 +1,15 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.core
import java.io.Serializable
@JvmInline
value class DeviceId(val value: String) : Serializable {
override fun toString(): String = value
}

View file

@ -7,9 +7,11 @@
package io.element.android.libraries.matrix.api.oidc
import io.element.android.libraries.matrix.api.core.DeviceId
sealed interface AccountManagementAction {
data object Profile : AccountManagementAction
data object SessionsList : AccountManagementAction
data class SessionView(val deviceId: String) : AccountManagementAction
data class SessionEnd(val deviceId: String) : AccountManagementAction
data class SessionView(val deviceId: DeviceId) : AccountManagementAction
data class SessionEnd(val deviceId: DeviceId) : AccountManagementAction
}

View file

@ -0,0 +1,20 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.api.room
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
/** A reference to a room the current user has been invited to, with the ability to decline the invite. */
interface InvitedRoom : AutoCloseable {
val sessionId: SessionId
val roomId: RoomId
/** Decline the invite to this room. */
suspend fun declineInvite(): Result<Unit>
}

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