Merge branch 'develop' into feature/bma/focussedButton

This commit is contained in:
Benoit Marty
2026-07-15 15:58:01 +02:00
committed by GitHub
327 changed files with 3427 additions and 1625 deletions
+12 -1
View File
@@ -104,7 +104,18 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Compile release sources
if: ${{ matrix.variant == 'release' }}
run: ./gradlew bundleGplayRelease -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
run: |
./gradlew assembleGplayRelease -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
./gradlew bundleGplayRelease -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
- name: Run aapt dump
if: ${{ matrix.variant == 'release' }}
run: |
$ANDROID_HOME/build-tools/37.0.0/aapt dump badging \
./app/build/outputs/apk/gplay/release/app-gplay-universal-release.apk \
> /tmp/currentAaptDump.txt
- name: Check manifest has not changed
if: ${{ matrix.variant == 'release' }}
run: diff /tmp/currentAaptDump.txt ./tools/manifest/gplay/release/aaptDump.txt
- name: Compile nightly sources
if: ${{ matrix.variant == 'nightly' }}
run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
+1
View File
@@ -39,6 +39,7 @@ jobs:
./tools/localazy/downloadStrings.sh --all
./tools/localazy/importSupportedLocalesFromLocalazy.py
./tools/test/generateAllScreenshots.py
./tools/manifest/aaptDump.sh
- name: Create Pull Request for Strings
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
@@ -0,0 +1,21 @@
appId: ${MAESTRO_APP_ID}
---
# Clean up the room list if it was left in a bad state by previous tests
- runFlow:
when:
visible: 'aRoomName'
commands:
- longPressOn: 'aRoomName'
- tapOn:
text: "Leave room"
index: 0
- tapOn: "Leave"
- runFlow:
when:
visible: ${MAESTRO_INVITEE1_MXID}
commands:
- longPressOn: ${MAESTRO_INVITEE1_MXID}
- tapOn:
text: "Leave room"
index: 0
- tapOn: "Leave"
+10 -1
View File
@@ -7,7 +7,16 @@ appId: ${MAESTRO_APP_ID}
- tapOn:
text: ${MAESTRO_INVITEE1_MXID}
index: 1
- tapOn: "Continue"
- runFlow:
when:
visible: 'Start a chat with this new contact?'
commands:
- tapOn: 'Continue'
- runFlow:
when:
visible: 'Send invite?'
commands:
- tapOn: 'Send invite'
- takeScreenshot: build/maestro/330-createAndDeleteDM
- tapOn: "maestroelement2"
- scroll
@@ -15,6 +15,12 @@ appId: ${MAESTRO_APP_ID}
text: ${MAESTRO_INVITEE1_MXID}
index: 1
- tapOn: "Finish"
- runFlow:
when:
visible: 'Invite new contact to this room?'
commands:
- tapOn:
id: "confirm_invite_unknown"
- tapOn: "aRoomName"
- tapOn: "Invite"
# assert there's 1 member and 1 invitee
@@ -23,6 +29,10 @@ appId: ${MAESTRO_APP_ID}
- tapOn:
text: ${MAESTRO_INVITEE2_MXID}
index: 1
# Hide keyboard by tapping on an external element in case it's displayed, otherwise it will 'eat' the back button press
- tapOn:
# Navigation title
text: "Invite people"
- tapOn: "Invite"
- runFlow:
when:
@@ -30,10 +40,6 @@ appId: ${MAESTRO_APP_ID}
commands:
- tapOn:
id: "confirm_invite_unknown"
# Close the keyboard if it's still open
- tapOn: "Back"
# Go back to the room details screen
- tapOn: "Back"
- scrollUntilVisible:
direction: DOWN
element:
+1
View File
@@ -1,5 +1,6 @@
appId: ${MAESTRO_APP_ID}
---
- runFlow: cleanUpRoomList.yaml
- runFlow: searchRoomList.yaml
- takeScreenshot: build/maestro/300-RoomList
- runFlow: timeline/timeline.yaml
@@ -15,7 +15,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
@ContributesBinding(AppScope::class)
class DefaultSessionGraphFactory(
private val appGraph: AppGraph
private val appGraph: AppGraph,
) : SessionGraphFactory {
override fun create(client: MatrixClient): Any {
return appGraph.sessionGraphFactory.create(client)
@@ -22,7 +22,6 @@ import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.MobileScreen
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.data.WidgetMessage
import io.element.android.features.call.impl.utils.ActiveCallManager
@@ -84,7 +83,7 @@ class CallScreenPresenter(
var ignoreWebViewError by rememberSaveable { mutableStateOf(false) }
var webViewError by remember { mutableStateOf<String?>(null) }
val languageTag = languageTagProvider.provideLanguageTag()
val theme = if (ElementTheme.isLightTheme) "light" else "dark"
val theme = "dark"
DisposableEffect(Unit) {
coroutineScope.launch {
@@ -38,6 +38,7 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import dev.zacsweers.metro.Inject
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.compound.theme.ForcedDarkElementTheme
import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
import io.element.android.features.call.impl.di.CallBindings
@@ -143,24 +144,28 @@ class ElementCallActivity :
compoundDark = colors.dark,
buildMeta = buildMeta,
) {
val state = presenter.present()
eventSink = state.eventSink
LaunchedEffect(state.isCallActive) {
if (state.isCallActive) {
setCallIsActive()
ForcedDarkElementTheme(
colors = colors,
) {
val state = presenter.present()
eventSink = state.eventSink
LaunchedEffect(state.isCallActive) {
if (state.isCallActive) {
setCallIsActive()
}
}
CallScreenView(
state = state,
pipState = pipState,
onConsoleMessage = {
consoleMessageLogger.log("ElementCall", it)
},
requestPermissions = { permissions, callback ->
requestPermissionCallback = callback
requestPermissionsLauncher.launch(permissions)
}
)
}
CallScreenView(
state = state,
pipState = pipState,
onConsoleMessage = {
consoleMessageLogger.log("ElementCall", it)
},
requestPermissions = { permissions, callback ->
requestPermissionCallback = callback
requestPermissionsLauncher.launch(permissions)
}
)
}
}
}
@@ -43,6 +43,7 @@ dependencies {
implementation(libs.coil.compose)
implementation(projects.libraries.featureflag.api)
implementation(projects.features.invitepeople.api)
implementation(projects.features.enterprise.api)
api(projects.features.createroom.api)
testCommonDependencies(libs, true)
@@ -53,4 +54,5 @@ dependencies {
testImplementation(projects.libraries.permissions.test)
testImplementation(projects.features.startchat.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.features.enterprise.test)
}
@@ -24,6 +24,7 @@ import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.CreatedRoom
import io.element.android.features.enterprise.api.SessionEnterpriseService
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
@@ -73,6 +74,7 @@ class ConfigureRoomPresenter(
private val featureFlagService: FeatureFlagService,
private val roomAliasHelper: RoomAliasHelper,
private val mediaOptimizationConfigProvider: MediaOptimizationConfigProvider,
private val sessionEnterpriseService: SessionEnterpriseService,
) : Presenter<ConfigureRoomState> {
@AssistedFactory
interface Factory {
@@ -256,7 +258,7 @@ class ConfigureRoomPresenter(
CreateRoomParameters(
name = config.roomName,
topic = config.topic,
isEncrypted = true,
isEncrypted = !sessionEnterpriseService.isEncryptionDisabledByHomeserver(),
isDirect = false,
visibility = RoomVisibility.Private,
historyVisibilityOverride = RoomHistoryVisibility.Invited,
@@ -3,14 +3,34 @@
<string name="screen_create_room_action_create_room">"Ruangan baru"</string>
<string name="screen_create_room_add_people_title">"Undang orang-orang"</string>
<string name="screen_create_room_error_creating_room">"Terjadi kesalahan saat membuat ruangan"</string>
<string name="screen_create_room_error_creating_space">"Ruang tersebut tidak dapat dibuat karena kesalahan yang tidak diketahui. Coba lagi nanti."</string>
<string name="screen_create_room_name_placeholder">"Tambahkan nama…"</string>
<string name="screen_create_room_new_room_title">"Ruangan baru"</string>
<string name="screen_create_room_new_space_title">"Ruang baru"</string>
<string name="screen_create_room_private_option_description">"Hanya orang-orang yang diundang dapat mengakses ruangan ini. Semua pesan terenkripsi secara ujung ke ujung."</string>
<string name="screen_create_room_private_option_title">"Pribadi"</string>
<string name="screen_create_room_public_option_description">"Siapa pun dapat mencari ruangan ini.
Anda dapat mengubah ini kapan pun dalam pengaturan ruangan."</string>
<string name="screen_create_room_public_option_short_description">"Siapa pun bisa bergabung."</string>
<string name="screen_create_room_public_option_title">"Umum"</string>
<string name="screen_create_room_room_access_section_knocking_option_description">"Siapa pun dapat meminta untuk bergabung dengan ijin administrator atau moderator"</string>
<string name="screen_create_room_room_access_section_knocking_option_title">"Minta untuk bergabung"</string>
<string name="screen_create_room_room_access_section_knocking_restricted_option_description">"Siapa pun di %1$s dapat bergabung, tetapi semua orang lain harus meminta akses."</string>
<string name="screen_create_room_room_access_section_knocking_restricted_option_title">"Ajukan permohonan untuk bergabung"</string>
<string name="screen_create_room_room_access_section_private_option_description">"Hanya orang-orang yang diundang dapat mengakses ruangan ini. Semua pesan terenkripsi secara ujung ke ujung."</string>
<string name="screen_create_room_room_access_section_private_option_title">"Pribadi"</string>
<string name="screen_create_room_room_access_section_public_option_description">"Siapa pun dapat bergabung dengan ruangan ini"</string>
<string name="screen_create_room_room_access_section_public_option_title">"Umum"</string>
<string name="screen_create_room_room_access_section_restricted_option_description">"Siapa pun di %1$s dapat bergabung."</string>
<string name="screen_create_room_room_access_section_restricted_option_title">"Standar"</string>
<string name="screen_create_room_room_access_section_title">"Yang memiliki akses"</string>
<string name="screen_create_room_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_create_room_room_address_section_title">"Alamat ruangan"</string>
<string name="screen_create_room_room_visibility_section_title">"Keterlihatan ruangan"</string>
<string name="screen_create_room_space_selection_no_space_description">"(ruang sudah penuh)"</string>
<string name="screen_create_room_space_selection_no_space_option">"Jangan menambahkan sesuatu ke ruang yang sudah ada."</string>
<string name="screen_create_room_space_selection_no_space_title">"Tidak ada ruang yang dipilih"</string>
<string name="screen_create_room_space_selection_sheet_title">"Tambahkan ke ruang"</string>
<string name="screen_create_room_topic_label">"Topik (opsional)"</string>
<string name="screen_create_room_topic_placeholder">"Tambahkan deskripsi…"</string>
</resources>
@@ -23,7 +23,7 @@
<string name="screen_create_room_room_access_section_public_option_title">"公開"</string>
<string name="screen_create_room_room_access_section_restricted_option_description">"%1$s にいる全員が参加することができます。"</string>
<string name="screen_create_room_room_access_section_restricted_option_title">"スタンダード"</string>
<string name="screen_create_room_room_access_section_title">"参加できるユーザー"</string>
<string name="screen_create_room_room_access_section_title">"参加可能なユーザー"</string>
<string name="screen_create_room_room_address_section_footer">"公開ディレクトリで自分を見つけられるようにするには、アドレスが必要です。"</string>
<string name="screen_create_room_room_address_section_title">"アドレス"</string>
<string name="screen_create_room_room_visibility_section_title">"ルームの公開度"</string>
@@ -20,11 +20,13 @@ import io.element.android.features.createroom.impl.configureroom.CreateRoomConfi
import io.element.android.features.createroom.impl.configureroom.JoinRuleItem
import io.element.android.features.createroom.impl.configureroom.RoomAddress
import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
@@ -56,6 +58,7 @@ import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.matching
import io.element.android.tests.testutils.robolectric.RobolectricTest
import io.element.android.tests.testutils.test
import io.mockk.mockk
@@ -517,6 +520,30 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
}
}
@Test
fun `present - creating a private room when encryption is disabled by the HS creates it unencrypted`() = runTest {
val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true })
val createRoomLambda = lambdaRecorder<CreateRoomParameters, Result<RoomId>> { Result.success(A_ROOM_ID) }
val matrixClient = createMatrixClient().apply {
createRoomResult = createRoomLambda
}
val presenter = createConfigureRoomPresenter(
matrixClient = matrixClient,
sessionEnterpriseService = sessionEnterpriseService,
)
presenter.test {
val initialState = initialState()
initialState.eventSink(ConfigureRoomEvents.JoinRuleChanged(JoinRuleItem.PrivateVisibility.Private))
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
assertThat(awaitItem().createRoomAction.isLoading()).isTrue()
assertThat(awaitItem().createRoomAction.isSuccess()).isTrue()
createRoomLambda.assertions().isCalledOnce().with(matching<CreateRoomParameters> { !it.isEncrypted })
}
}
private suspend fun TurbineTestContext<ConfigureRoomState>.initialState(): ConfigureRoomState {
skipItems(1)
return awaitItem()
@@ -552,6 +579,7 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
isKnockFeatureEnabled: Boolean = true,
mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(),
sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { false }),
) = ConfigureRoomPresenter(
isSpace = isSpace,
initialParentSpaceId = initialParenSpaceId,
@@ -566,5 +594,6 @@ class ConfigureRoomPresenterTest : RobolectricTest() {
mapOf(FeatureFlags.Knock.key to isKnockFeatureEnabled)
),
mediaOptimizationConfigProvider = mediaOptimizationConfigProvider,
sessionEnterpriseService = sessionEnterpriseService,
)
}
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_deactivate_account_confirmation_dialog_content">"Bekreft at du vil deaktivere kontoen din. Denne handlingen kan ikke angres."</string>
<string name="screen_deactivate_account_confirmation_dialog_content">"Bekreft at du vil slette kontoen din. Denne handlingen kan ikke angres."</string>
<string name="screen_deactivate_account_delete_all_messages">"Slett alle meldingene mine"</string>
<string name="screen_deactivate_account_delete_all_messages_notice">"Advarsel: Fremtidige brukere vil kunne se ufullstendige samtaler."</string>
<string name="screen_deactivate_account_description">"Deaktivering av kontoen din er %1$s , det vil:"</string>
<string name="screen_deactivate_account_description">"Hvis %1$s sletter kontoen din, vil følgende skje:"</string>
<string name="screen_deactivate_account_description_bold_part">"irreversibel"</string>
<string name="screen_deactivate_account_list_item_1">"%1$s kontoen din (du kan ikke logge på igjen, og ID-en din kan ikke brukes på nytt)."</string>
<string name="screen_deactivate_account_list_item_1_bold_part">"Deaktiver permanent"</string>
<string name="screen_deactivate_account_list_item_2">"Fjern deg fra alle chatterom."</string>
<string name="screen_deactivate_account_list_item_3">"Slett kontoinformasjonen din fra vår identitetsserver."</string>
<string name="screen_deactivate_account_list_item_4">"Meldingene dine vil fortsatt være synlige for registrerte brukere, men vil ikke være tilgjengelige for nye eller uregistrerte brukere hvis du velger å slette dem."</string>
<string name="screen_deactivate_account_title">"Deaktiver kontoen"</string>
<string name="screen_deactivate_account_title">"Slett kontoen"</string>
</resources>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_deactivate_account_confirmation_dialog_content">"Iltimos, hisobingizni o‘chirishni xohlayotganingizni tasdiqlang. Bu amalni qaytarib bo‘lmaydi."</string>
<string name="screen_deactivate_account_confirmation_dialog_content">"Iltimos, hisobingizni oʻchirishni xohlayotganingizni tasdiqlang. Bu amalni qaytarib boʻlmaydi."</string>
<string name="screen_deactivate_account_delete_all_messages">"Barcha xabarlarimni o‘chirib tashlang"</string>
<string name="screen_deactivate_account_delete_all_messages_notice">"Ogohlantirish: Kelgusi foydalanuvchilar chala suhbatlarni ko‘rishi mumkin."</string>
<string name="screen_deactivate_account_description">"Hisobingiz %1$s faolsizlantirilmoqda, u quyidagilarni bajaradi:"</string>
@@ -12,5 +12,7 @@ interface SessionEnterpriseService {
suspend fun isElementCallAvailable(): Boolean
suspend fun tweakMasUrl(url: String): String
suspend fun isEncryptionDisabledByHomeserver(): Boolean
suspend fun init()
}
@@ -17,4 +17,5 @@ class DefaultSessionEnterpriseService : SessionEnterpriseService {
override suspend fun init() = Unit
override suspend fun tweakMasUrl(url: String): String = url
override suspend fun isElementCallAvailable(): Boolean = true
override suspend fun isEncryptionDisabledByHomeserver(): Boolean = false
}
@@ -15,6 +15,7 @@ import io.element.android.tests.testutils.simulateLongTask
class FakeSessionEnterpriseService(
private val isElementCallAvailableResult: () -> Boolean = { lambdaError() },
private val tweakMasUrlResult: (String) -> String = { lambdaError() },
private val isEncryptionDisabledResult: () -> Boolean = { lambdaError() },
) : SessionEnterpriseService {
override suspend fun init() {
}
@@ -26,4 +27,8 @@ class FakeSessionEnterpriseService(
override suspend fun isElementCallAvailable(): Boolean = simulateLongTask {
isElementCallAvailableResult()
}
override suspend fun isEncryptionDisabledByHomeserver(): Boolean {
return isEncryptionDisabledResult()
}
}
@@ -2,8 +2,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_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>
@@ -2,7 +2,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Kan du ikke bekrefte?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Opprett en ny gjenopprettingsnøkkel"</string>
<string name="screen_identity_confirmation_subtitle">"Verifiser denne enheten for å sette opp sikker meldingsutveksling."</string>
<string name="screen_identity_confirmation_subtitle">"Velg hvordan du vil verifisere deg for å sette opp sikker meldingsutveksling."</string>
<string name="screen_identity_confirmation_title">"Bekreft din digitale identitet"</string>
<string name="screen_identity_confirmation_use_another_device">"Bruk en annen enhet"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Bruk gjenopprettingsnøkkel"</string>
@@ -3,6 +3,8 @@
<string name="banner_battery_optimization_content_android">"Nonaktifkan pengoptimalan baterai untuk aplikasi ini, untuk memastikan semua notifikasi diterima."</string>
<string name="banner_battery_optimization_submit_android">"Nonaktifkan optimasi"</string>
<string name="banner_battery_optimization_title_android">"Notifikasi tidak masuk?"</string>
<string name="banner_new_sound_message">"Pemberitahuan Anda telah diperbarui—lebih jelas, lebih cepat, dan tidak mengganggu."</string>
<string name="banner_new_sound_title">"Kami telah memperbarui suara Anda."</string>
<string name="banner_set_up_recovery_content">"Buat kunci pemulihan baru yang dapat digunakan untuk memulihkan riwayat pesan terenkripsi Anda jika Anda kehilangan akses ke perangkat Anda."</string>
<string name="banner_set_up_recovery_submit">"Siapkan Kunci pemulihan"</string>
<string name="banner_set_up_recovery_title">"Cadangkan obrolan Anda"</string>
@@ -48,6 +50,7 @@ Anda tidak memiliki pesan yang belum dibaca!"</string>
<string name="screen_roomlist_mark_as_read">"Tandai sebagai dibaca"</string>
<string name="screen_roomlist_mark_as_unread">"Tandai sebagai belum dibaca"</string>
<string name="screen_roomlist_tombstoned_room_description">"Ruangan ini telah ditingkatkan"</string>
<string name="screen_roomlist_your_spaces">"Ruang Anda"</string>
<string name="session_verification_banner_message">"Sepertinya Anda menggunakan perangkat baru. Verifikasi dengan perangkat lain untuk mengakses pesan terenkripsi Anda selanjutnya."</string>
<string name="session_verification_banner_title">"Verifikasi bahwa ini Anda"</string>
</resources>
@@ -5,9 +5,9 @@
<string name="banner_battery_optimization_title_android">"Kommer ikke varslene frem?"</string>
<string name="banner_new_sound_message">"Varslingssignalet ditt er oppdatert – tydeligere, raskere og mindre forstyrrende."</string>
<string name="banner_new_sound_title">"Vi har oppdatert lydene dine"</string>
<string name="banner_set_up_recovery_content">"Gjenopprett din kryptografiske identitet og meldingshistorikk med en gjenopprettingsnøkkel hvis du har mistet alle dine brukte enheter."</string>
<string name="banner_set_up_recovery_content">"Chattene dine sikkerhetskopieres automatisk med ende-til-ende-kryptering. For å gjenopprette denne sikkerhetskopien og beholde din digitale identitet når du mister tilgang til alle enhetene dine, trenger du gjenopprettingsnøkkelen din."</string>
<string name="banner_set_up_recovery_submit">"Hent gjenopprettingsnøkkel"</string>
<string name="banner_set_up_recovery_title">"Konfigurer gjenoppretting for å beskytte kontoen din"</string>
<string name="banner_set_up_recovery_title">"Sikkerhetskopier chattene dine"</string>
<string name="confirm_recovery_key_banner_message">"Verifiser gjenopprettingsnøkkelen for å opprettholde tilgangen til nøkkellageret og meldingshistorikken."</string>
<string name="confirm_recovery_key_banner_primary_button_title">"Skriv inn gjenopprettingsnøkkelen din"</string>
<string name="confirm_recovery_key_banner_secondary_button_title">"Har du glemt din gjenopprettingsnøkkel?"</string>
@@ -302,13 +302,13 @@ private fun InvitePeopleConfirmModal(
text = stringResource(CommonStrings.action_remove),
onClick = onRemove,
leadingIcon = IconSource.Vector(CompoundIcons.Close()),
modifier = Modifier.weight(1f).testTag(TestTags.confirmInviteUnknown),
modifier = Modifier.weight(1f),
)
Button(
text = stringResource(CommonStrings.action_invite),
onClick = onInvite,
leadingIcon = IconSource.Vector(CompoundIcons.Check()),
modifier = Modifier.weight(1f)
modifier = Modifier.weight(1f).testTag(TestTags.confirmInviteUnknown),
)
}
}
@@ -2,4 +2,8 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_invite_users_already_a_member">"Sudah menjadi anggota"</string>
<string name="screen_invite_users_already_invited">"Sudah diundang"</string>
<string name="screen_invite_users_confirm_dialog_subtitle_multiple_users">"Saat ini Anda belum memiliki obrolan dengan kontak-kontak ini. Konfirmasikan undangan untuk mengundang mereka ke ruang obrolan ini sebelum melanjutkan."</string>
<string name="screen_invite_users_confirm_dialog_subtitle_one_user">"Saat ini Anda belum memiliki obrolan apa pun dengan kontak ini. Konfirmasikan undangan ke ruang obrolan ini sebelum melanjutkan."</string>
<string name="screen_invite_users_confirm_dialog_title_mutiple_users">"Ingin mengundang kontak baru ke ruang ini?"</string>
<string name="screen_invite_users_confirm_dialog_title_one_user">"Ingin mengundang kontak baru ke ruang ini?"</string>
</resources>
@@ -2,4 +2,8 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_invite_users_already_a_member">"Allaqachon a\'zo"</string>
<string name="screen_invite_users_already_invited">"Allaqachon taklif qilingan"</string>
<string name="screen_invite_users_confirm_dialog_subtitle_multiple_users">"Hozirda ushbu kontaktlar bilan hech qanday chatingiz yoʻq. Davom etishdan oldin ularni ushbu xonaga taklif qilishni tasdiqlang."</string>
<string name="screen_invite_users_confirm_dialog_subtitle_one_user">"Hozirda bu kontakt bilan hech qanday chatingiz yoʻq. Davom etishdan oldin ularni ushbu xonaga taklif qilishni tasdiqlang."</string>
<string name="screen_invite_users_confirm_dialog_title_mutiple_users">"Bu xonaga yangi kontaktlar taklif qilinsinmi?"</string>
<string name="screen_invite_users_confirm_dialog_title_one_user">"Bu xonaga yangi kontakt taklif qilinsinmi?"</string>
</resources>
@@ -13,6 +13,8 @@
<string name="screen_link_new_device_mobile_step2">"گزینش %1$s"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"نتوانست اتّصالی امن به افزارهٔ جدید بسازد. افزاره‌های موجودتان هنوز امنند و نیازی نیست نگرانشان باشید."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"اکنون چه؟"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"آزمودن ورود دوباره با کد پاس در صورت مشکل شبکه"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"آزمون شبکهٔ وای‌فایی دیگر یا استفاده از دادهٔ همراهتان به جای وای‌فای در صورت مواجه دوباره با مشکل"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"ورود دستی در صورت کار نکردنش"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"اتّصال ناامن"</string>
<string name="screen_qr_code_login_device_code_subtitle">"از شما خواسته خواهد شد که دو رقم نشان داده روی این افزاره را وارد کنید."</string>
@@ -1,16 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_link_new_device_desktop_scanning_title">"Pindai kode QR"</string>
<string name="screen_link_new_device_desktop_step1">"Buka %1$s di laptop atau komputer desktop."</string>
<string name="screen_link_new_device_desktop_step3">"Pindai kode QR dengan perangkat ini"</string>
<string name="screen_link_new_device_desktop_submit">"Siap untuk memindai"</string>
<string name="screen_link_new_device_desktop_title">"Buka %1$s di komputer desktop untuk mendapatkan kode QR."</string>
<string name="screen_link_new_device_enter_number_error_numbers_do_not_match">"Angkanya tidak cocok"</string>
<string name="screen_link_new_device_enter_number_notice">"Masukkan kode 2 digit"</string>
<string name="screen_link_new_device_enter_number_subtitle">"Ini akan memverifikasi bahwa koneksi ke perangkat Anda yang lain aman."</string>
<string name="screen_link_new_device_enter_number_title">"Masukkan nomor yang ditampilkan di perangkat Anda yang lain"</string>
<string name="screen_link_new_device_error_app_not_supported_subtitle">"Penyedia akun Anda tidak mendukung %1$s."</string>
<string name="screen_link_new_device_error_app_not_supported_title">"%1$s tidak didukung"</string>
<string name="screen_link_new_device_error_not_supported_subtitle">"Penyedia akun Anda tidak mendukung masuk ke perangkat baru menggunakan kode QR."</string>
<string name="screen_link_new_device_error_not_supported_title">"Kode QR tidak didukung"</string>
<string name="screen_link_new_device_error_request_cancelled_subtitle">"Proses masuk dibatalkan di perangkat lain."</string>
<string name="screen_link_new_device_error_request_cancelled_title">"Permintaan masuk dibatalkan"</string>
<string name="screen_link_new_device_error_request_timeout_subtitle">"Masa masuk kedaluwarsa. Silakan coba lagi."</string>
<string name="screen_link_new_device_error_request_timeout_title">"Proses masuk tidak selesai tepat waktu"</string>
<string name="screen_link_new_device_mobile_step1">"Buka %1$s di perangkat lain."</string>
<string name="screen_link_new_device_mobile_step2">"Pilih %1$s"</string>
<string name="screen_link_new_device_mobile_step2_action">"Masuk dengan kode QR"</string>
<string name="screen_link_new_device_mobile_step3">"Pindai kode QR yang ditampilkan di sini dengan perangkat lain."</string>
<string name="screen_link_new_device_mobile_title">"Buka %1$s di perangkat lain."</string>
<string name="screen_link_new_device_root_desktop_computer">"Komputer desktop"</string>
<string name="screen_link_new_device_root_loading_qr_code">"Memuat kode QR…"</string>
<string name="screen_link_new_device_root_mobile_device">"Perangkat seluler"</string>
<string name="screen_link_new_device_root_title">"Jenis perangkat apa yang ingin Anda tautkan?"</string>
<string name="screen_link_new_device_wrong_number_subtitle">"Silakan coba lagi dan pastikan Anda telah memasukkan kode 2 digit dengan benar. Jika angka-angka tersebut masih tidak cocok, hubungi penyedia akun Anda."</string>
<string name="screen_link_new_device_wrong_number_title">"Angkanya tidak cocok"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Koneksi aman tidak dapat dibuat ke perangkat baru. Perangkat Anda yang ada masih aman dan Anda tidak perlu khawatir tentang mereka."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Apa sekarang?"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"Coba masuk lagi dengan kode QR jika ini adalah masalah jaringan"</string>
@@ -23,6 +40,8 @@
<string name="screen_qr_code_login_error_cancelled_title">"Permintaan masuk dibatalkan"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Proses masuk ditolak di perangkat lain."</string>
<string name="screen_qr_code_login_error_declined_title">"Proses masuk ditolak"</string>
<string name="screen_qr_code_login_error_device_already_signed_in_subtitle">"Anda tidak perlu melakukan hal lain."</string>
<string name="screen_qr_code_login_error_device_already_signed_in_title">"Perangkat Anda yang lain sudah masuk"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Masa masuk kedaluwarsa. Silakan coba lagi."</string>
<string name="screen_qr_code_login_error_expired_title">"Proses masuk tidak selesai tepat waktu"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Perangkat Anda yang lain tidak mendukung masuk ke %s dengan kode QR.
@@ -2,4 +2,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_share_location_live_location_disclaimer_title">"Vaša povijest lokacije uživo bit će pohranjena u sobi i vidljiva članovima nakon završetka sesije."</string>
<string name="screen_share_location_live_location_duration_picker_title">"Odaberite koliko dugo želite dijeliti svoju lokaciju uživo."</string>
<string name="screen_share_location_live_location_missing_permissions">"Nemate dopuštenja za dijeljenje svoje lokacije uživo u ovoj sobi"</string>
</resources>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_share_location_live_location_disclaimer_title">"Riwayat lokasi langsung Anda akan disimpan di ruang obrolan dan dapat dilihat oleh anggota setelah sesi berakhir."</string>
<string name="screen_share_location_live_location_duration_picker_title">"Pilih berapa lama Anda ingin membagikan lokasi langsung Anda."</string>
<string name="screen_share_location_live_location_missing_permissions">"Anda tidak memiliki izin untuk membagikan lokasi real-time Anda di ruang ini"</string>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_share_location_live_location_duration_picker_title">"Velg hvor lenge du vil dele din sanntidslokasjon."</string>
</resources>
@@ -2,4 +2,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_share_location_live_location_disclaimer_title">"Jonli joylashuv tarixingiz chat-xonada saqlanadi va sessiya tugaganidan keyin homiylarga ko‘rinadi."</string>
<string name="screen_share_location_live_location_duration_picker_title">"Jonli joylashuvingiz qancha vaqt ulashilishini tanlang."</string>
<string name="screen_share_location_live_location_missing_permissions">"Bu xonada jonli joylashuvingizni ulashish uchun sizda ruxsat yoʻq"</string>
</resources>
@@ -41,6 +41,8 @@
<string name="screen_qr_code_login_connecting_subtitle">"برقرار کدن اتّصالی امن"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"نتوانست اتّصالی امن به افزارهٔ جدید بسازد. افزاره‌های موجودتان هنوز امنند و نیازی نیست نگرانشان باشید."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"اکنون چه؟"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_1">"آزمودن ورود دوباره با کد پاس در صورت مشکل شبکه"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_2">"آزمون شبکهٔ وای‌فایی دیگر یا استفاده از دادهٔ همراهتان به جای وای‌فای در صورت مواجه دوباره با مشکل"</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_item_3">"ورود دستی در صورت کار نکردنش"</string>
<string name="screen_qr_code_login_connection_note_secure_state_title">"اتّصال ناامن"</string>
<string name="screen_qr_code_login_device_code_subtitle">"از شما خواسته خواهد شد که دو رقم نشان داده روی این افزاره را وارد کنید."</string>
@@ -37,11 +37,20 @@
<string name="screen_login_subtitle">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string>
<string name="screen_login_title">"Selamat datang kembali!"</string>
<string name="screen_login_title_with_homeserver">"Masuk ke %1$s"</string>
<string name="screen_missing_key_backup_open_element_classic">"Buka Element Classic"</string>
<string name="screen_missing_key_backup_step_1">"Buka Element Classic di perangkat Anda"</string>
<string name="screen_missing_key_backup_step_2_android">"Buka Pengaturan &gt; Keamanan &amp;amp; Privasi"</string>
<string name="screen_missing_key_backup_step_3_android">"Dalam pengelolaan kunci kriptografi, pilih Pemulihan pesan terenkripsi"</string>
<string name="screen_missing_key_backup_step_4">"Ikuti petunjuk berikut untuk mengaktifkan penyimpanan kunci Anda"</string>
<string name="screen_missing_key_backup_step_5">"Kembali ke %1$s"</string>
<string name="screen_missing_key_backup_title">"Aktifkan penyimpanan kunci Anda sebelum melanjutkan ke %1$s"</string>
<string name="screen_onboarding_app_version">"Versi %1$s"</string>
<string name="screen_onboarding_checking_account">"Memeriksa akun…"</string>
<string name="screen_onboarding_sign_in_manually">"Masuk secara manual"</string>
<string name="screen_onboarding_sign_in_to">"Masuk ke %1$s"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Masuk dengan kode QR"</string>
<string name="screen_onboarding_sign_up">"Buat akun"</string>
<string name="screen_onboarding_welcome_back">"Selamat datang kembali!"</string>
<string name="screen_onboarding_welcome_message">"Selamat datang di %1$s tercepat yang pernah ada. Berdaya besar untuk kecepatan dan kesederhanaan."</string>
<string name="screen_onboarding_welcome_subtitle">"Selamat datang di %1$s. Berdaya penuh, untuk kecepatan dan kesederhanaan."</string>
<string name="screen_onboarding_welcome_title">"Berada di elemen Anda"</string>
@@ -60,6 +69,8 @@
<string name="screen_qr_code_login_error_cancelled_title">"Permintaan masuk dibatalkan"</string>
<string name="screen_qr_code_login_error_declined_subtitle">"Proses masuk ditolak di perangkat lain."</string>
<string name="screen_qr_code_login_error_declined_title">"Proses masuk ditolak"</string>
<string name="screen_qr_code_login_error_device_already_signed_in_subtitle">"Anda tidak perlu melakukan hal lain."</string>
<string name="screen_qr_code_login_error_device_already_signed_in_title">"Perangkat Anda yang lain sudah masuk"</string>
<string name="screen_qr_code_login_error_expired_subtitle">"Masa masuk kedaluwarsa. Silakan coba lagi."</string>
<string name="screen_qr_code_login_error_expired_title">"Proses masuk tidak selesai tepat waktu"</string>
<string name="screen_qr_code_login_error_linking_not_suported_subtitle">"Perangkat Anda yang lain tidak mendukung masuk ke %s dengan kode QR.
@@ -28,7 +28,7 @@
<string name="screen_change_server_subtitle">"Hva er adressen til serveren din?"</string>
<string name="screen_change_server_title">"Velg din server"</string>
<string name="screen_create_account_title">"Opprett konto"</string>
<string name="screen_login_error_deactivated_account">"Denne kontoen er deaktivert."</string>
<string name="screen_login_error_deactivated_account">"Denne kontoen er slettet."</string>
<string name="screen_login_error_invalid_credentials">"Feil brukernavn og/eller passord"</string>
<string name="screen_login_error_invalid_user_id">"Dette er ikke en gyldig brukeridentifikator. Forventet format: \'@bruker:homeserver.org\'"</string>
<string name="screen_login_error_refresh_tokens">"Denne serveren er konfigurert til å bruke oppdateringstokener. Disse støttes ikke når du bruker passordbasert pålogging."</string>
@@ -27,7 +27,7 @@
<string name="screen_change_server_subtitle">"Địa chỉ máy chủ của bạn là gì?"</string>
<string name="screen_change_server_title">"Chọn máy chủ của bạn"</string>
<string name="screen_create_account_title">"Tạo tài khoản"</string>
<string name="screen_login_error_deactivated_account">"Tài khoản này đã bị vô hiệu hóa."</string>
<string name="screen_login_error_deactivated_account">"Tài khoản này đã bị xóa."</string>
<string name="screen_login_error_invalid_credentials">"Tên người dùng và/hoặc mật khẩu không chính xác"</string>
<string name="screen_login_error_invalid_user_id">"Đây không phải là mã nhận dạng người dùng hợp lệ. Định dạng mong đợi: ‘@user:homeserver.org’"</string>
<string name="screen_login_error_refresh_tokens">"Máy chủ này được cấu hình sử dụng refresh token. Điều này không được hỗ trợ khi đăng nhập bằng mật khẩu."</string>
@@ -4,15 +4,15 @@
<string name="screen_signout_confirmation_dialog_submit">"Fjern denne enheten"</string>
<string name="screen_signout_confirmation_dialog_title">"Fjern denne enheten"</string>
<string name="screen_signout_in_progress_dialog_content">"Fjerner enheten …"</string>
<string name="screen_signout_key_backup_disabled_subtitle">"Du er i ferd med å logge av din siste sesjon. Hvis du logger av nå, mister du tilgangen til de krypterte meldingene dine."</string>
<string name="screen_signout_key_backup_disabled_subtitle">"Dette er din eneste enhet. Hvis du fjerner den, trenger du en gjenopprettingsnøkkel for å bekrefte din digitale identitet og gjenopprette de krypterte chattene dine neste gang du logger på."</string>
<string name="screen_signout_key_backup_disabled_title">"Du er i ferd med å miste tilgangen til dine krypterte chatter"</string>
<string name="screen_signout_key_backup_offline_subtitle">"Nøklene dine ble fortsatt sikkerhetskopiert da du koblet fra. Koble til igjen, slik at nøklene dine kan sikkerhetskopieres før du logger av."</string>
<string name="screen_signout_key_backup_offline_title">"Nøklene dine blir fortsatt sikkerhetskopiert"</string>
<string name="screen_signout_key_backup_ongoing_subtitle">"Vennligst vent til dette er fullført før du fjerner denne enheten."</string>
<string name="screen_signout_key_backup_ongoing_title">"Nøklene dine blir fortsatt sikkerhetskopiert"</string>
<string name="screen_signout_preference_item">"Fjern denne enheten"</string>
<string name="screen_signout_recovery_disabled_subtitle">"Du er i ferd med å logge ut av din siste sesjon. Hvis du logger ut nå, mister du tilgangen til de krypterte meldingene dine."</string>
<string name="screen_signout_recovery_disabled_subtitle">"Dette er din eneste enhet. Hvis du fjerner den, trenger du en gjenopprettingsnøkkel for å bekrefte din digitale identitet og gjenopprette de krypterte chattene dine neste gang du logger på."</string>
<string name="screen_signout_recovery_disabled_title">"Du er i ferd med å miste tilgangen til dine krypterte chatter"</string>
<string name="screen_signout_save_recovery_key_subtitle">"Du er i ferd med å logge av din siste sesjon. Hvis du logger av nå, kan du miste tilgangen til de krypterte meldingene dine."</string>
<string name="screen_signout_save_recovery_key_subtitle">"Dette er din eneste enhet. Hvis du fjerner den, trenger du en gjenopprettingsnøkkel for å bekrefte din digitale identitet og gjenopprette de krypterte chattene dine neste gang du logger på."</string>
<string name="screen_signout_save_recovery_key_title">"Sørg for at du har tilgang til gjenopprettingsnøkkelen din før du fjerner denne enheten"</string>
</resources>
@@ -21,6 +21,7 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItemRead
import io.element.android.features.messages.impl.timeline.model.TimelineItemThreadInfo
import io.element.android.features.messages.impl.timeline.model.anAggregatedReaction
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
@@ -255,6 +256,23 @@ internal fun aGroupedEvents(
)
}
internal fun aRedactedMessagesGroupedEvents(
id: UniqueId = UniqueId("redacted_group"),
count: Int = 4,
): TimelineItem.GroupedEvents {
val events = (0 until count).map { index ->
aTimelineItemEvent(
eventId = EventId("\$redacted_$index"),
content = TimelineItemRedactedContent,
)
}
return TimelineItem.GroupedEvents(
id = id,
events = events.toImmutableList(),
aggregatedReadReceipts = persistentListOf(),
)
}
internal fun aTimelineRoomInfo(
name: String = ROOM_NAME,
isDm: Boolean = false,
@@ -19,12 +19,14 @@ import io.element.android.features.messages.impl.R
import io.element.android.features.messages.impl.timeline.TimelineEvent
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
import io.element.android.features.messages.impl.timeline.aGroupedEvents
import io.element.android.features.messages.impl.timeline.aRedactedMessagesGroupedEvents
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView
import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData
import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState
import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView
import io.element.android.features.messages.impl.timeline.groups.isRedactedMessagesGroup
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
@@ -147,12 +149,18 @@ private fun TimelineItemGroupedEventsRowContent(
},
) {
Column(modifier = modifier.animateContentSize()) {
val count = timelineItem.events.size
// A group made entirely of redacted events is a collapsed run of deleted messages
// (element-web style); anything else is the regular run of room state changes. For the
// redacted case we show only the count: the SDK does not expose who performed the redaction,
// and showing the original authors would be misleading.
val headerText = if (timelineItem.isRedactedMessagesGroup()) {
pluralStringResource(R.plurals.screen_room_timeline_redacted_messages, count, count)
} else {
pluralStringResource(R.plurals.screen_room_timeline_state_changes, count, count)
}
GroupHeaderView(
text = pluralStringResource(
id = R.plurals.screen_room_timeline_state_changes,
count = timelineItem.events.size,
timelineItem.events.size
),
text = headerText,
isExpanded = isExpanded,
isHighlighted = !isExpanded && timelineItem.events.any { it.isEvent(focusedEventId) },
onClick = onExpandGroupClick,
@@ -252,3 +260,31 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi
eventSink = {},
)
}
@PreviewsDayNight
@Composable
internal fun TimelineItemRedactedMessagesGroupPreview() = ElementPreview {
// A collapsed run of deleted messages, shown as a single "N removed messages" header.
TimelineItemGroupedEventsRowContent(
isExpanded = false,
onExpandGroupClick = {},
timelineItem = aRedactedMessagesGroupedEvents(count = 11),
timelineMode = Timeline.Mode.Live,
timelineRoomInfo = aTimelineRoomInfo(),
timelineProtectionState = aTimelineProtectionState(),
focusedEventId = null,
isLastOutgoingMessage = false,
displayThreadSummaries = false,
onClick = {},
onLongClick = {},
onLinkLongClick = {},
inReplyToClick = {},
onUserDataClick = {},
onLinkClick = {},
onReactionClick = { _, _ -> },
onReactionLongClick = { _, _ -> },
onMoreReactionsClick = {},
onReadReceiptClick = {},
eventSink = {},
)
}
@@ -44,6 +44,14 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StickerConten
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
/**
* Return true when every event in the group is a redacted (deleted) message, i.e. the group is a
* collapsed run of deleted messages rather than the usual run of room state changes. Used to pick
* the group header label. An empty group is not considered a redacted group.
*/
internal fun TimelineItem.GroupedEvents.isRedactedMessagesGroup(): Boolean =
events.isNotEmpty() && events.all { it.content is TimelineItemRedactedContent }
/**
* Return true if the Event can be grouped in a collapse/expand block
* When [canBeGrouped] returns a value, [canBeDisplayedInBubbleBlock] MUST return the opposite value.
@@ -12,6 +12,7 @@ import androidx.annotation.VisibleForTesting
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.UniqueId
import kotlinx.collections.immutable.toImmutableList
@@ -47,7 +48,8 @@ class TimelineItemGrouper {
if (currentGroup.isNotEmpty()) {
result.addGroup(groupIds, currentGroup)
}
return result
// Finally, fold runs of consecutive deleted messages into a single group (element-web style).
return result.collapseRedactedRuns(groupIds)
}
}
@@ -89,3 +91,56 @@ private fun MutableMap<String, String>.getOrPutGroupId(timelineItems: List<Timel
@VisibleForTesting
internal fun computeGroupIdWith(timelineItem: TimelineItem): UniqueId = UniqueId("${timelineItem.identifier()}_group")
// Runs shorter than this are left as individual "Message removed" tiles, like element-web.
internal const val MIN_REDACTED_RUN_SIZE = 3
/**
* Fold runs of [MIN_REDACTED_RUN_SIZE] or more consecutive deleted (redacted) messages into a single
* [TimelineItem.GroupedEvents], so a long stretch of "Message removed" tiles shows as one expandable
* "N removed messages" line, like element-web. Shorter runs, and anything that is not a redacted event
* (day dividers included), are left untouched.
*
* This runs as the final step of [TimelineItemGrouper.group], after the state and membership events
* have been grouped. It is deliberately kept out of the normal grouping: a run needs a higher minimum
* than an ordinary group, and a redacted group has to stay entirely redacted so its header can show a
* plain count rather than being mixed in with the surrounding state changes.
*
* Events are kept oldest-first to match the other groups, and the group id is resolved through the
* grouper's [getOrPutGroupId] registry, also like the other groups, so it stays stable however the
* run grows: older history loading in, or a new adjacent message being redacted. A stable id keeps
* the user's expand/collapse state across timeline updates.
*/
internal fun List<TimelineItem>.collapseRedactedRuns(groupIds: MutableMap<String, String>): List<TimelineItem> {
val result = mutableListOf<TimelineItem>()
val run = mutableListOf<TimelineItem.Event>()
fun flushRun() {
when {
run.isEmpty() -> Unit
run.size < MIN_REDACTED_RUN_SIZE -> result.addAll(run)
else -> {
val events = run.reversed()
result.add(
TimelineItem.GroupedEvents(
id = UniqueId(groupIds.getOrPutGroupId(events)),
events = events.toImmutableList(),
aggregatedReadReceipts = events.flatMap { it.readReceiptState.receipts }.toImmutableList(),
)
)
}
}
run.clear()
}
for (item in this) {
if (item is TimelineItem.Event && item.content is TimelineItemRedactedContent) {
run.add(item)
} else {
flushRun()
result.add(item)
}
}
flushRun()
return result
}
@@ -16,6 +16,18 @@
<string name="emoji_picker_category_places">"Putovanja i mjesta"</string>
<string name="emoji_picker_category_recent">"Nedavni emotikoni"</string>
<string name="emoji_picker_category_symbols">"Simboli"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally">"Okreni sliku vodoravno"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_flipped">"Okrenuto vodoravno"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_original">"Izvornik"</string>
<string name="screen_image_edition_a11y_flip_image_vertically">"Okreni sliku okomito"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_flipped">"Okrenuto okomito"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_original">"Izvornik"</string>
<string name="screen_image_edition_a11y_rotate_to_the_left">"Okrenite sliku ulijevo"</string>
<plurals name="screen_image_edition_a11y_rotation_state">
<item quantity="one">"%1$d stupanj"</item>
<item quantity="other">"%1$d stupnjevi"</item>
</plurals>
<string name="screen_image_edition_title">"Uredi fotografiju"</string>
<string name="screen_media_upload_preview_caption_warning">"Opisi možda neće biti vidljivi osobama koji se služe starijim aplikacijama."</string>
<string name="screen_media_upload_preview_change_video_quality_prompt">"Dodirnite za promjenu kvalitete prijenosa videozapisa"</string>
<string name="screen_media_upload_preview_error_could_not_be_uploaded">"Datoteka se nije mogla prenijeti."</string>
@@ -26,6 +38,7 @@
<string name="screen_media_upload_preview_item_count">"Stavka %1$d od %2$d"</string>
<string name="screen_media_upload_preview_optimize_image_quality_title">"Optimiziraj kvalitetu slike"</string>
<string name="screen_media_upload_preview_processing">"Obrada…"</string>
<string name="screen_media_upload_preview_title">"Dodaj medij"</string>
<string name="screen_report_content_block_user">"Blokiraj korisnika"</string>
<string name="screen_report_content_block_user_hint">"Označite ako želite sakriti sve trenutačne i buduće poruke od ovog korisnika"</string>
<string name="screen_report_content_explanation">"Ova poruka bit će prijavljena administratoru vašeg matičnog poslužitelja. On neće moći pročitati nijednu šifriranu poruku."</string>
@@ -16,6 +16,11 @@
<string name="emoji_picker_category_places">"Wisata &amp; Tempat"</string>
<string name="emoji_picker_category_recent">"Emojis Sebelumnya"</string>
<string name="emoji_picker_category_symbols">"Simbol"</string>
<string name="screen_image_edition_a11y_rotate_to_the_left">"Putar gambar ke kiri"</string>
<plurals name="screen_image_edition_a11y_rotation_state">
<item quantity="other">"%1$d derajat"</item>
</plurals>
<string name="screen_image_edition_title">"Sunting Foto"</string>
<string name="screen_media_upload_preview_caption_warning">"Keterangan mungkin tidak terlihat oleh orang yang menggunakan aplikasi lama."</string>
<string name="screen_media_upload_preview_change_video_quality_prompt">"Ketuk untuk mengubah kualitas unggahan video"</string>
<string name="screen_media_upload_preview_error_could_not_be_uploaded">"Dokumen tidak dapat diunggah."</string>
@@ -26,6 +31,7 @@
<string name="screen_media_upload_preview_item_count">"Item %1$d dari %2$d"</string>
<string name="screen_media_upload_preview_optimize_image_quality_title">"Optimalkan kualitas gambar"</string>
<string name="screen_media_upload_preview_processing">"Memproses…"</string>
<string name="screen_media_upload_preview_title">"Tambahkan media"</string>
<string name="screen_report_content_block_user">"Blokir pengguna"</string>
<string name="screen_report_content_block_user_hint">"Centang jika Anda ingin menyembunyikan semua pesan saat ini dan yang akan datang dari pengguna ini"</string>
<string name="screen_report_content_explanation">"Pesan ini akan dilaporkan ke administrator homeserver Anda. Mereka tidak akan dapat membaca pesan terenkripsi apa pun."</string>
@@ -16,6 +16,18 @@
<string name="emoji_picker_category_places">"Viaggi &amp; Luoghi"</string>
<string name="emoji_picker_category_recent">"Emoji recenti"</string>
<string name="emoji_picker_category_symbols">"Simboli"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally">"Capovolgi l\'immagine orizzontalmente"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_flipped">"Capovolto orizzontalmente"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_original">"Originale"</string>
<string name="screen_image_edition_a11y_flip_image_vertically">"Capovolgi l\'immagine verticalmente"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_flipped">"Capovolto verticalmente"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_original">"Originale"</string>
<string name="screen_image_edition_a11y_rotate_to_the_left">"Ruota l\'immagine verso sinistra"</string>
<plurals name="screen_image_edition_a11y_rotation_state">
<item quantity="one">"%1$d grado"</item>
<item quantity="other">"%1$d gradi"</item>
</plurals>
<string name="screen_image_edition_title">"Modifica foto"</string>
<string name="screen_media_upload_preview_caption_warning">"Le didascalie potrebbero non essere visibili agli utenti di app meno recenti."</string>
<string name="screen_media_upload_preview_change_video_quality_prompt">"Tocca per modificare la qualità di caricamento del video"</string>
<string name="screen_media_upload_preview_error_could_not_be_uploaded">"Impossibile caricare il file."</string>
@@ -26,6 +38,7 @@
<string name="screen_media_upload_preview_item_count">"Elemento %1$d di %2$d"</string>
<string name="screen_media_upload_preview_optimize_image_quality_title">"Ottimizza la qualità delle immagini"</string>
<string name="screen_media_upload_preview_processing">"Elaborazione…"</string>
<string name="screen_media_upload_preview_title">"Aggiungi contenuti multimediali"</string>
<string name="screen_report_content_block_user">"Blocca utente"</string>
<string name="screen_report_content_block_user_hint">"Seleziona se vuoi nascondere tutti i messaggi attuali e futuri di questo utente"</string>
<string name="screen_report_content_explanation">"Questo messaggio verrà segnalato all\'amministratore dell\'homeserver. Questi non sarà in grado di leggere i messaggi cifrati."</string>
@@ -16,6 +16,12 @@
<string name="emoji_picker_category_places">"旅・場所"</string>
<string name="emoji_picker_category_recent">"最近使用"</string>
<string name="emoji_picker_category_symbols">"記号"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally">"水平に反転"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_flipped">"垂直に反転"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_original">"元画像"</string>
<string name="screen_image_edition_a11y_flip_image_vertically">"垂直に反転"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_flipped">"水平に反転"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_original">"編集前"</string>
<string name="screen_image_edition_a11y_rotate_to_the_left">"画像を左に回転"</string>
<plurals name="screen_image_edition_a11y_rotation_state">
<item quantity="other">"%1$d°"</item>
@@ -16,6 +16,18 @@
<string name="emoji_picker_category_places">"Sayohat va Joylar"</string>
<string name="emoji_picker_category_recent">"Oxirgi kulgichlar"</string>
<string name="emoji_picker_category_symbols">"Belgilar"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally">"Rasmni gorizontal ravishda aylantiring"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_flipped">"Gorizontal ravishda aylantirildi"</string>
<string name="screen_image_edition_a11y_flip_image_horizontally_state_original">"Asl nusxasi"</string>
<string name="screen_image_edition_a11y_flip_image_vertically">"Rasmni vertikal ravishda aylantirish"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_flipped">"Vertikal ravishda aylantirildi"</string>
<string name="screen_image_edition_a11y_flip_image_vertically_state_original">"Asl nusxasi"</string>
<string name="screen_image_edition_a11y_rotate_to_the_left">"Rasmni chapga aylantiring"</string>
<plurals name="screen_image_edition_a11y_rotation_state">
<item quantity="one">"%1$d daraja"</item>
<item quantity="other">"%1$d daraja"</item>
</plurals>
<string name="screen_image_edition_title">"Suratni tahrirlash"</string>
<string name="screen_media_upload_preview_caption_warning">"Taglavhalar eski ilovalardan foydalanuvchilarga ko‘rinmasligi mumkin."</string>
<string name="screen_media_upload_preview_change_video_quality_prompt">"Video yuklash sifatini oʻzgartirish uchun bosing"</string>
<string name="screen_media_upload_preview_error_could_not_be_uploaded">"Faylni yuklab boʻlmadi."</string>
@@ -26,6 +38,7 @@
<string name="screen_media_upload_preview_item_count">"Element%1$d ning %2$d"</string>
<string name="screen_media_upload_preview_optimize_image_quality_title">"Tasvir sifatini optimallashtirish"</string>
<string name="screen_media_upload_preview_processing">"Qayta ishlanmoqda…"</string>
<string name="screen_media_upload_preview_title">"Media qoʻshish"</string>
<string name="screen_report_content_block_user">"Foydalanuvchini bloklash"</string>
<string name="screen_report_content_block_user_hint">"Ushbu foydalanuvchidan barcha joriy va kelajakdagi xabarlarni yashirishni xohlayotganingizni tekshiring"</string>
<string name="screen_report_content_explanation">"Bu xabar uy serveringiz administratoriga xabar qilinadi. Ular hech qanday shifrlangan xabarlarni o\'qiy olmaydi."</string>
@@ -79,6 +79,10 @@
<string name="screen_room_timeline_reactions_show_more">"Show more"</string>
<string name="screen_room_timeline_reactions_show_reactions_summary">"Show reactions summary"</string>
<string name="screen_room_timeline_read_marker_title">"New"</string>
<plurals name="screen_room_timeline_redacted_messages">
<item quantity="one">"%1$d removed message"</item>
<item quantity="other">"%1$d removed messages"</item>
</plurals>
<plurals name="screen_room_timeline_state_changes">
<item quantity="one">"%1$d room change"</item>
<item quantity="other">"%1$d room changes"</item>
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.messages.impl.timeline
import com.google.common.truth.Truth.assertThat
import io.element.android.features.messages.impl.timeline.components.receipt.aReadReceiptData
import io.element.android.features.messages.impl.timeline.groups.collapseRedactedRuns
import io.element.android.features.messages.impl.timeline.groups.computeGroupIdWith
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UniqueId
import kotlinx.collections.immutable.toImmutableList
import org.junit.Test
class CollapseRedactedRunsTest {
private val groupIds = mutableMapOf<String, String>()
private fun redacted(id: String) = aTimelineItemEvent(
eventId = EventId(id),
content = TimelineItemRedactedContent,
)
@Test
fun `collapses a run of three or more redacted events into a single group`() {
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val r3 = redacted("\$R3")
val result = listOf<TimelineItem>(r1, r2, r3).collapseRedactedRuns(groupIds)
assertThat(result).hasSize(1)
val group = result.single() as TimelineItem.GroupedEvents
// Stored oldest-first (the input is newest-first), like the existing grouper.
assertThat(group.events.map { it.eventId }).containsExactly(
EventId("\$R3"),
EventId("\$R2"),
EventId("\$R1"),
).inOrder()
// Group id comes from the shared registry, keyed like the other groups (oldest member).
assertThat(group.id).isEqualTo(computeGroupIdWith(r3))
}
@Test
fun `leaves a run shorter than three as individual tiles`() {
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val result = listOf<TimelineItem>(r1, r2).collapseRedactedRuns(groupIds)
assertThat(result).containsExactly(r1, r2).inOrder()
}
@Test
fun `keeps surrounding events and only collapses the redacted run between them`() {
val newest = aTimelineItemEvent(eventId = EventId("\$NEW"))
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val r3 = redacted("\$R3")
val oldest = aTimelineItemEvent(eventId = EventId("\$OLD"))
val result = listOf<TimelineItem>(newest, r1, r2, r3, oldest).collapseRedactedRuns(groupIds)
assertThat(result).hasSize(3)
assertThat(result.first()).isEqualTo(newest)
assertThat(result.last()).isEqualTo(oldest)
assertThat(result[1]).isInstanceOf(TimelineItem.GroupedEvents::class.java)
assertThat((result[1] as TimelineItem.GroupedEvents).events).hasSize(3)
}
@Test
fun `a day separator breaks a run so each side is evaluated on its own`() {
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val r3 = redacted("\$R3")
val sep = aTimelineItemDaySeparator()
val r4 = redacted("\$R4")
val r5 = redacted("\$R5")
val result = listOf<TimelineItem>(r1, r2, r3, sep, r4, r5).collapseRedactedRuns(groupIds)
// First run (3) collapses, the separator passes through, the second run (2) stays as tiles.
assertThat(result).hasSize(4)
assertThat(result.first()).isInstanceOf(TimelineItem.GroupedEvents::class.java)
assertThat(result[1]).isEqualTo(sep)
assertThat(result[2]).isEqualTo(r4)
assertThat(result[3]).isEqualTo(r5)
}
@Test
fun `does not collapse a run interrupted by a non-redacted event`() {
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val between = aTimelineItemEvent(eventId = EventId("\$MID"))
val r3 = redacted("\$R3")
val result = listOf<TimelineItem>(r1, r2, between, r3).collapseRedactedRuns(groupIds)
assertThat(result).containsExactly(r1, r2, between, r3).inOrder()
}
@Test
fun `collapses a long run into a single group keeping every event`() {
val run = (1..5).map { redacted("\$R$it") }
val result = run.collapseRedactedRuns(groupIds)
assertThat(result).hasSize(1)
assertThat((result.single() as TimelineItem.GroupedEvents).events).hasSize(5)
}
@Test
fun `collapses each qualifying run independently`() {
val firstRun = (1..3).map { redacted("\$A$it") }
val separator = aTimelineItemEvent(eventId = EventId("\$SEP"))
val secondRun = (1..3).map { redacted("\$B$it") }
val result = (firstRun + separator + secondRun).collapseRedactedRuns(groupIds)
assertThat(result).hasSize(3)
assertThat(result[0]).isInstanceOf(TimelineItem.GroupedEvents::class.java)
assertThat(result[1]).isEqualTo(separator)
assertThat(result[2]).isInstanceOf(TimelineItem.GroupedEvents::class.java)
// The two groups get distinct ids so their expand state does not bleed into one another.
assertThat((result[0] as TimelineItem.GroupedEvents).id)
.isNotEqualTo((result[2] as TimelineItem.GroupedEvents).id)
}
@Test
fun `collapses a run that sits at the very end of the list`() {
val newest = aTimelineItemEvent(eventId = EventId("\$NEW"))
val run = (1..3).map { redacted("\$R$it") }
val result = (listOf<TimelineItem>(newest) + run).collapseRedactedRuns(groupIds)
assertThat(result).hasSize(2)
assertThat(result.first()).isEqualTo(newest)
assertThat(result.last()).isInstanceOf(TimelineItem.GroupedEvents::class.java)
}
@Test
fun `leaves a single redacted event untouched`() {
val r1 = redacted("\$R1")
assertThat(listOf<TimelineItem>(r1).collapseRedactedRuns(groupIds)).containsExactly(r1)
}
@Test
fun `aggregates the read receipts of every event in the collapsed group`() {
fun redactedWithReceipt(id: String, receiptIndex: Int) = aTimelineItemEvent(
eventId = EventId(id),
content = TimelineItemRedactedContent,
readReceiptState = TimelineItemReadReceipts(
receipts = listOf(aReadReceiptData(receiptIndex)).toImmutableList(),
),
)
val run = listOf<TimelineItem>(
redactedWithReceipt("\$R1", 0),
redactedWithReceipt("\$R2", 1),
redactedWithReceipt("\$R3", 2),
)
val group = run.collapseRedactedRuns(groupIds).single() as TimelineItem.GroupedEvents
assertThat(group.aggregatedReadReceipts).hasSize(3)
}
@Test
fun `an existing grouped item breaks the run and is passed through untouched`() {
val stateGroup = aGroupedEvents(id = UniqueId("state"))
val run = (1..3).map { redacted("\$R$it") }
val result = (run + stateGroup).collapseRedactedRuns(groupIds)
assertThat(result).hasSize(2)
assertThat(result.first()).isInstanceOf(TimelineItem.GroupedEvents::class.java)
assertThat(result.last()).isEqualTo(stateGroup)
}
@Test
fun `is a no-op on an empty list`() {
assertThat(emptyList<TimelineItem>().collapseRedactedRuns(groupIds)).isEmpty()
}
@Test
fun `the group id survives the run growing at either end`() {
val r1 = redacted("\$R1")
val r2 = redacted("\$R2")
val r3 = redacted("\$R3")
val first = listOf<TimelineItem>(r1, r2, r3).collapseRedactedRuns(groupIds).single() as TimelineItem.GroupedEvents
// A newer adjacent message gets redacted and older history loads in: the id must not move,
// or the user's expanded group would snap shut on the update.
val grown = listOf<TimelineItem>(redacted("\$R0"), r1, r2, r3, redacted("\$R4"))
.collapseRedactedRuns(groupIds)
.single() as TimelineItem.GroupedEvents
assertThat(grown.id).isEqualTo(first.id)
}
}
@@ -44,6 +44,7 @@ import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
import io.element.android.libraries.matrix.test.AN_EVENT_ID
@@ -865,6 +866,28 @@ class TimelinePresenterTest {
}
}
@Test
fun `present - collapses a run of three or more redacted events into a single group`() = runTest {
val timeline = FakeTimeline(
timelineItems = flowOf(
(0 until 3).map { index ->
MatrixTimelineItem.Event(
uniqueId = UniqueId("redacted_$index"),
event = anEventTimelineItem(eventId = EventId("\$R$index"), content = RedactedContent),
)
}
),
)
val presenter = createTimelinePresenter(timeline = timeline)
presenter.test {
val state = consumeItemsUntilPredicate { it.timelineItems.size == 1 }.last()
val group = state.timelineItems.single()
assertThat(group).isInstanceOf(TimelineItem.GroupedEvents::class.java)
assertThat((group as TimelineItem.GroupedEvents).events).hasSize(3)
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - reaction ordering`() = runTest {
val timelineItems = MutableStateFlow(emptyList<MatrixTimelineItem>())
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.messages.impl.timeline.groups
import com.google.common.truth.Truth.assertThat
import io.element.android.features.messages.impl.timeline.aGroupedEvents
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UniqueId
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import org.junit.Test
class GroupabilityTest {
private fun redacted(id: String) = aTimelineItemEvent(
eventId = EventId(id),
content = TimelineItemRedactedContent,
)
private fun groupOf(vararg events: TimelineItem.Event) = TimelineItem.GroupedEvents(
id = UniqueId("group"),
events = events.toList().toImmutableList(),
aggregatedReadReceipts = persistentListOf(),
)
@Test
fun `a group made only of redacted events is a redacted messages group`() {
val group = groupOf(redacted("\$R1"), redacted("\$R2"), redacted("\$R3"))
assertThat(group.isRedactedMessagesGroup()).isTrue()
}
@Test
fun `a group of state changes is not a redacted messages group`() {
// aGroupedEvents builds a run of state events.
assertThat(aGroupedEvents().isRedactedMessagesGroup()).isFalse()
}
@Test
fun `a group mixing redacted and non-redacted events is not a redacted messages group`() {
val group = groupOf(redacted("\$R1"), aTimelineItemEvent(eventId = EventId("\$E")), redacted("\$R2"))
assertThat(group.isRedactedMessagesGroup()).isFalse()
}
@Test
fun `an empty group is not a redacted messages group`() {
val group = TimelineItem.GroupedEvents(
id = UniqueId("group"),
events = persistentListOf(),
aggregatedReadReceipts = persistentListOf(),
)
assertThat(group.isRedactedMessagesGroup()).isFalse()
}
}
@@ -15,6 +15,7 @@ import io.element.android.features.messages.impl.timeline.aTimelineItemReactions
import io.element.android.features.messages.impl.timeline.model.ReadReceiptData
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
@@ -169,4 +170,31 @@ class TimelineItemGrouperTest {
// Then
assertThat(actualGroupId).isEqualTo(expectedGroupId)
}
@Test
fun `a run of three or more redacted events is collapsed into a single group as a final step`() {
val r0 = aGroupableItem.copy(id = UniqueId("r0"), content = TimelineItemRedactedContent)
val r1 = aGroupableItem.copy(id = UniqueId("r1"), content = TimelineItemRedactedContent)
val r2 = aGroupableItem.copy(id = UniqueId("r2"), content = TimelineItemRedactedContent)
val result = sut.group(listOf(r0, r1, r2))
assertThat(result).isEqualTo(
listOf(
TimelineItem.GroupedEvents(
id = computeGroupIdWith(r2),
// Stored oldest-first (the input is newest-first) with the id keyed by the
// oldest member through the shared registry, like the other groups.
events = listOf(r2, r1, r0).toImmutableList(),
aggregatedReadReceipts = emptyList<ReadReceiptData>().toImmutableList(),
)
)
)
}
@Test
fun `a run of fewer than three redacted events is left untouched`() {
val r0 = aGroupableItem.copy(id = UniqueId("r0"), content = TimelineItemRedactedContent)
val r1 = aGroupableItem.copy(id = UniqueId("r1"), content = TimelineItemRedactedContent)
val result = sut.group(listOf(r0, r1))
assertThat(result).isEqualTo(listOf(r0, r1))
}
}
@@ -59,6 +59,7 @@
<string name="screen_labs_header_title">"Jeste li spremni za eksperimentiranje?"</string>
<string name="screen_labs_title">"Laboratoriji"</string>
<string name="screen_notification_settings_additional_settings_section_title">"Dodatne postavke"</string>
<string name="screen_notification_settings_call_ringtone_label">"Ton zvona"</string>
<string name="screen_notification_settings_calls_label">"Audiopozivi i videopozivi"</string>
<string name="screen_notification_settings_configuration_mismatch">"Neusklađenost konfiguracije"</string>
<string name="screen_notification_settings_configuration_mismatch_description">"Pojednostavili smo postavke obavijesti kako bismo olakšali pronalaženje mogućnosti. Neke prilagođene postavke koje ste odabrali u prošlosti nisu ovdje prikazane, ali su i dalje aktivne.
@@ -77,14 +78,31 @@ Ako nastavite, neke od vaših postavki mogu se promijeniti."</string>
<string name="screen_notification_settings_invite_for_me_label">"Pozivnice"</string>
<string name="screen_notification_settings_mentions_only_disclaimer">"Vaš matični poslužitelj ne podržava ovu mogućnost u šifriranim sobama; možda nećete dobiti obavijesti u nekim sobama."</string>
<string name="screen_notification_settings_mentions_section_title">"Spominjanja"</string>
<string name="screen_notification_settings_message_sound_dialog_choose_other">"Odaberite drugi zvuk…"</string>
<string name="screen_notification_settings_message_sound_dialog_current_subtitle">"Trenutačno upotrebljavate %1$s"</string>
<string name="screen_notification_settings_message_sound_dialog_title">"Zvuk poruke"</string>
<string name="screen_notification_settings_message_sound_label">"Zvuk poruke"</string>
<string name="screen_notification_settings_mode_all">"Sve"</string>
<string name="screen_notification_settings_mode_mentions">"Spominjanja"</string>
<string name="screen_notification_settings_notification_section_title">"Obavijesti me za"</string>
<string name="screen_notification_settings_room_mention_label">"Obavijesti me o sobi @soba"</string>
<string name="screen_notification_settings_sound_custom_fallback">"Prilagođeno"</string>
<string name="screen_notification_settings_sound_custom_sound_button_title">"Personalizirano zvono"</string>
<string name="screen_notification_settings_sound_delete_sound_error_title">"Pogreška pri brisanju datoteke"</string>
<string name="screen_notification_settings_sound_element_default">"Zadano za element"</string>
<string name="screen_notification_settings_sound_element_fade">"Blijeđenje elementa"</string>
<string name="screen_notification_settings_sound_import_sound_error_title">"Pogreška pri uvozu datoteke"</string>
<string name="screen_notification_settings_sound_preview_sound_error_title">"Problem s pregledom zvuka upozorenja"</string>
<string name="screen_notification_settings_sound_section_title">"Zvuk"</string>
<string name="screen_notification_settings_sound_set_sound_error_dismiss_a11y">"Pogreška zvuka odbacivanja upozorenja"</string>
<string name="screen_notification_settings_sound_set_sound_error_title">"Problem s postavljanjem zvuka upozorenja"</string>
<string name="screen_notification_settings_sound_silent">"Stišano"</string>
<string name="screen_notification_settings_sound_system_default">"Zadano sustavom"</string>
<string name="screen_notification_settings_system_notifications_action_required">"Kako biste primali obavijesti, promijenite %1$s."</string>
<string name="screen_notification_settings_system_notifications_action_required_content_link">"postavke sustava"</string>
<string name="screen_notification_settings_system_notifications_turned_off">"Obavijesti sustava su isključene"</string>
<string name="screen_notification_settings_title">"Obavijesti"</string>
<string name="theme_black">"Crna"</string>
<string name="theme_dark">"Tamno"</string>
<string name="theme_light">"Svijetlo"</string>
<string name="theme_system">"Sustav"</string>
@@ -10,6 +10,14 @@
<string name="screen_advanced_settings_element_call_base_url_validation_error">"URL tidak valid, pastikan Anda menyertakan protokol (http/https) dan alamat yang benar."</string>
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Sembunyikan avatar dalam permintaan undangan ruangan"</string>
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Sembunyikan pratinjau media pada lini masa"</string>
<string name="screen_advanced_settings_labs">"Uji Coba"</string>
<string name="screen_advanced_settings_live_location_section_description">"Jarak yang harus Anda tempuh untuk memicu pembaruan."</string>
<string name="screen_advanced_settings_live_location_section_footer">"Pastikan \"Lokasi Tepat\" diaktifkan untuk aplikasi ini. Untuk mengubah izin tersebut, buka %1$s."</string>
<string name="screen_advanced_settings_live_location_section_footer_link">"Pengaturan aplikasi"</string>
<string name="screen_advanced_settings_live_location_section_title">"Pembaruan lokasi secara langsung"</string>
<plurals name="screen_advanced_settings_live_location_update_distance">
<item quantity="other">"Setiap %1$d meter"</item>
</plurals>
<string name="screen_advanced_settings_media_compression_description">"Unggah foto dan video lebih cepat dan kurangi penggunaan data"</string>
<string name="screen_advanced_settings_media_compression_title">"Optimalkan kualitas media"</string>
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Moderasi dan Keamanan"</string>
@@ -43,6 +51,11 @@
<string name="screen_edit_profile_error_title">"Tidak dapat memperbarui profil"</string>
<string name="screen_edit_profile_title">"Edit profil"</string>
<string name="screen_edit_profile_updating_details">"Memperbarui profil…"</string>
<string name="screen_labs_enable_threads">"Aktifkan balasan utas"</string>
<string name="screen_labs_enable_threads_description">"Aplikasi akan dimulai ulang untuk menerapkan perubahan ini."</string>
<string name="screen_labs_header_description">"Cobalah ide-ide terbaru kami yang sedang dikembangkan. Fitur-fitur ini belum final; mungkin masih tidak stabil dan dapat berubah."</string>
<string name="screen_labs_header_title">"Merasa ingin bereksperimen?"</string>
<string name="screen_labs_title">"Uji Coba"</string>
<string name="screen_notification_settings_additional_settings_section_title">"Pengaturan tambahan"</string>
<string name="screen_notification_settings_calls_label">"Panggilan audio dan video"</string>
<string name="screen_notification_settings_configuration_mismatch">"Ketidakcocokan pengaturan"</string>
@@ -68,10 +81,12 @@ Jika Anda melanjutkan, beberapa pengaturan Anda dapat berubah."</string>
<string name="screen_notification_settings_mode_mentions">"Sebutan"</string>
<string name="screen_notification_settings_notification_section_title">"Beri tahu saya tentang"</string>
<string name="screen_notification_settings_room_mention_label">"Beri tahu saya pada @room"</string>
<string name="screen_notification_settings_sound_element_default">"Pengaturan Default Element"</string>
<string name="screen_notification_settings_system_notifications_action_required">"Untuk menerima pemberitahuan, silakan ubah %1$s Anda."</string>
<string name="screen_notification_settings_system_notifications_action_required_content_link">"pengaturan sistem"</string>
<string name="screen_notification_settings_system_notifications_turned_off">"Pemberitahuan sistem dimatikan"</string>
<string name="screen_notification_settings_title">"Notifikasi"</string>
<string name="theme_black">"Hitam"</string>
<string name="theme_dark">"Gelap"</string>
<string name="theme_light">"Terang"</string>
<string name="theme_system">"Sistem"</string>
@@ -31,7 +31,7 @@
<string name="screen_advanced_settings_optimise_video_upload_quality_title">"Qualità del caricamento video"</string>
<string name="screen_advanced_settings_push_provider_android">"Fornitore di notifiche push"</string>
<string name="screen_advanced_settings_rich_text_editor_description">"Disattiva l\'editor di testo avanzato per scrivere manualmente in Markdown"</string>
<string name="screen_advanced_settings_send_read_receipts">"Conferme di visualizzazione"</string>
<string name="screen_advanced_settings_send_read_receipts">"Conferme di lettura"</string>
<string name="screen_advanced_settings_send_read_receipts_description">"Se disattivato, le tue conferme di visualizzazione non verranno inviate a nessuno. Riceverai comunque conferme di visualizzazione da altri utenti."</string>
<string name="screen_advanced_settings_share_presence">"Condividi presenza online"</string>
<string name="screen_advanced_settings_share_presence_description">"Se disattivato, non potrai né inviare né ricevere conferme di lettura o notifiche di scrittura."</string>
@@ -58,6 +58,7 @@
<string name="screen_labs_header_title">"Hai voglia di sperimentare?"</string>
<string name="screen_labs_title">"Labs"</string>
<string name="screen_notification_settings_additional_settings_section_title">"Impostazioni aggiuntive"</string>
<string name="screen_notification_settings_call_ringtone_label">"Suoneria di chiamata"</string>
<string name="screen_notification_settings_calls_label">"Chiamate audio e video"</string>
<string name="screen_notification_settings_configuration_mismatch">"Mancata corrispondenza di configurazione"</string>
<string name="screen_notification_settings_configuration_mismatch_description">"Abbiamo semplificato le impostazioni di notifica per rendere le opzioni più facili da trovare. Alcune impostazioni personalizzate che hai scelto in passato non sono mostrate qui, ma sono ancora attive.
@@ -76,14 +77,31 @@ Se procedi, alcune delle tue impostazioni potrebbero cambiare."</string>
<string name="screen_notification_settings_invite_for_me_label">"Inviti"</string>
<string name="screen_notification_settings_mentions_only_disclaimer">"Il tuo homeserver non supporta questa opzione nelle stanze crifrate, quindi potresti non ricevere notifiche in alcune stanze."</string>
<string name="screen_notification_settings_mentions_section_title">"Menzioni"</string>
<string name="screen_notification_settings_message_sound_dialog_choose_other">"Scegli un altro suono…"</string>
<string name="screen_notification_settings_message_sound_dialog_current_subtitle">"Attualmente si utilizza %1$s"</string>
<string name="screen_notification_settings_message_sound_dialog_title">"Suono messaggi"</string>
<string name="screen_notification_settings_message_sound_label">"Suono messaggi"</string>
<string name="screen_notification_settings_mode_all">"Tutto"</string>
<string name="screen_notification_settings_mode_mentions">"Menzioni"</string>
<string name="screen_notification_settings_notification_section_title">"Avvisami per"</string>
<string name="screen_notification_settings_room_mention_label">"Avvisami con @room"</string>
<string name="screen_notification_settings_sound_custom_fallback">"Personalizzato"</string>
<string name="screen_notification_settings_sound_custom_sound_button_title">"Suono personalizzato…"</string>
<string name="screen_notification_settings_sound_delete_sound_error_title">"Errore durante l\'eliminazione del file"</string>
<string name="screen_notification_settings_sound_element_default">"Predefinito di Element"</string>
<string name="screen_notification_settings_sound_element_fade">"Dissolvenza di Element"</string>
<string name="screen_notification_settings_sound_import_sound_error_title">"Errore durante l\'importazione del file"</string>
<string name="screen_notification_settings_sound_preview_sound_error_title">"Problema durante l\'anteprima del suono di avviso"</string>
<string name="screen_notification_settings_sound_section_title">"Suono"</string>
<string name="screen_notification_settings_sound_set_sound_error_dismiss_a11y">"Ignora l\'errore relativo al suono di avviso"</string>
<string name="screen_notification_settings_sound_set_sound_error_title">"Problema con l\'impostazione del suono di avviso"</string>
<string name="screen_notification_settings_sound_silent">"Silenzioso"</string>
<string name="screen_notification_settings_sound_system_default">"Predefinito"</string>
<string name="screen_notification_settings_system_notifications_action_required">"Per ricevere notifiche, modifica le tue %1$s."</string>
<string name="screen_notification_settings_system_notifications_action_required_content_link">"impostazioni di sistema"</string>
<string name="screen_notification_settings_system_notifications_turned_off">"Notifiche di sistema disattivate"</string>
<string name="screen_notification_settings_title">"Notifiche"</string>
<string name="theme_black">"Nero"</string>
<string name="theme_dark">"Scuro"</string>
<string name="theme_light">"Chiaro"</string>
<string name="theme_system">"Sistema"</string>
@@ -11,6 +11,14 @@
<string name="screen_advanced_settings_hide_invite_avatars_toggle_title">"Xonaga taklif so‘rovlarida avatarlarni berkitish"</string>
<string name="screen_advanced_settings_hide_timeline_media_toggle_title">"Vaqt jadvalida mediaga razm solishlarni berkitish"</string>
<string name="screen_advanced_settings_labs">"Laboratoriyalar"</string>
<string name="screen_advanced_settings_live_location_section_description">"Yangilanishni ishga tushirish uchun harakat qilishingiz kerak boʻlgan masofa"</string>
<string name="screen_advanced_settings_live_location_section_footer">"Ushbu ilova uchun “Aniq joylashuv” yoqilganligiga ishonch hosil qiling. Ruxsatni oʻzgartirish uchun %1$s ga oʻting."</string>
<string name="screen_advanced_settings_live_location_section_footer_link">"Ilova sozlamalari"</string>
<string name="screen_advanced_settings_live_location_section_title">"Jonli joylashuv yangilanishlari"</string>
<plurals name="screen_advanced_settings_live_location_update_distance">
<item quantity="one">"Har %1$d metr"</item>
<item quantity="other">"Har %1$d metr"</item>
</plurals>
<string name="screen_advanced_settings_media_compression_description">"Rasm va videolarni tezroq yuklang va trafik sarfini kamaytiring"</string>
<string name="screen_advanced_settings_media_compression_title">"Media sifatini yaxshilash"</string>
<string name="screen_advanced_settings_moderation_and_safety_section_title">"Moderatsiya va xavfsizlik"</string>
@@ -50,6 +58,7 @@
<string name="screen_labs_header_title">"Tajribani his qilyapsizmi?"</string>
<string name="screen_labs_title">"Laboratoriyalar"</string>
<string name="screen_notification_settings_additional_settings_section_title">"Qo\'shimcha sozlamalar"</string>
<string name="screen_notification_settings_call_ringtone_label">"Qoʻngʻroq ohangi"</string>
<string name="screen_notification_settings_calls_label">"Audio va video qo\'ng\'iroqlar"</string>
<string name="screen_notification_settings_configuration_mismatch">"Konfiguratsiya mos kelmasligi"</string>
<string name="screen_notification_settings_configuration_mismatch_description">"Variantlarni topishni osonlashtirish uchun bildirishnomalar sozlamalarini soddalashtirdik. Ilgari siz tanlagan baʼzi shaxsiy sozlamalar bu yerda koʻrsatilmaydi, lekin ular hali ham faol.
@@ -68,14 +77,31 @@ Davom ettirsangiz, baʼzi sozlamalaringiz oʻzgarishi mumkin."</string>
<string name="screen_notification_settings_invite_for_me_label">"Taklifnomalar"</string>
<string name="screen_notification_settings_mentions_only_disclaimer">"Uy serveringiz shifrlangan xonalarda ushbu imkoniyatni qoʻllab-quvvatlamaydi, shuning uchun baʼzi xonalardagi xabarlarni olmasligingiz mumkin."</string>
<string name="screen_notification_settings_mentions_section_title">"Eslatmalar"</string>
<string name="screen_notification_settings_message_sound_dialog_choose_other">"Boshqa tovushni tanlang…"</string>
<string name="screen_notification_settings_message_sound_dialog_current_subtitle">"Hozir foydalanilmoqda: %1$s"</string>
<string name="screen_notification_settings_message_sound_dialog_title">"Xabar ovozi"</string>
<string name="screen_notification_settings_message_sound_label">"Xabar ovozi"</string>
<string name="screen_notification_settings_mode_all">"Hammasi"</string>
<string name="screen_notification_settings_mode_mentions">"Eslatmalar"</string>
<string name="screen_notification_settings_notification_section_title">"Menga xabar bering"</string>
<string name="screen_notification_settings_room_mention_label">"Menga @room orqali xabar bering"</string>
<string name="screen_notification_settings_sound_custom_fallback">"Maxsus"</string>
<string name="screen_notification_settings_sound_custom_sound_button_title">"Maxsus ovoz…"</string>
<string name="screen_notification_settings_sound_delete_sound_error_title">"Faylni oʻchirishda xatolik yuz berdi"</string>
<string name="screen_notification_settings_sound_element_default">"Element standarti"</string>
<string name="screen_notification_settings_sound_element_fade">"Elementlarning yoʻqolishi"</string>
<string name="screen_notification_settings_sound_import_sound_error_title">"Faylni import qilishda xatolik yuz berdi"</string>
<string name="screen_notification_settings_sound_preview_sound_error_title">"Ogohlantirish ovozini oldindan koʻrishda muammo"</string>
<string name="screen_notification_settings_sound_section_title">"Ovoz"</string>
<string name="screen_notification_settings_sound_set_sound_error_dismiss_a11y">"Ogohlantirish ovozi xatosini yopish"</string>
<string name="screen_notification_settings_sound_set_sound_error_title">"Ogohlantirish ovozini sozlashda muammo"</string>
<string name="screen_notification_settings_sound_silent">"Ovozsiz"</string>
<string name="screen_notification_settings_sound_system_default">"Tizim standarti"</string>
<string name="screen_notification_settings_system_notifications_action_required">"Bildirishnomalarni olish uchun, iltimos, o\'zingizni %1$singizni o\'zgartiring."</string>
<string name="screen_notification_settings_system_notifications_action_required_content_link">"tizim sozlamalari"</string>
<string name="screen_notification_settings_system_notifications_turned_off">"Tizim bildirishnomalari o\'chirilgan"</string>
<string name="screen_notification_settings_title">"Bildirishnomalar"</string>
<string name="theme_black">"Qora"</string>
<string name="theme_dark">"Tungi"</string>
<string name="theme_light">"Nur"</string>
<string name="theme_system">"Tizim"</string>
@@ -68,7 +68,7 @@ If you proceed, some of your settings may change."</string>
<string name="screen_notification_settings_edit_custom_settings_section_title">"Custom setting per chat"</string>
<string name="screen_notification_settings_edit_failed_updating_default_mode">"An error occurred while updating the notification setting."</string>
<string name="screen_notification_settings_edit_mode_all_messages">"All messages"</string>
<string name="screen_notification_settings_edit_mode_mentions_and_keywords">"Mentions and Keywords only"</string>
<string name="screen_notification_settings_edit_mode_mentions_and_keywords">"Mentions and replies only"</string>
<string name="screen_notification_settings_edit_screen_direct_section_header">"On direct chats, notify me for"</string>
<string name="screen_notification_settings_edit_screen_group_section_header">"On group chats, notify me for"</string>
<string name="screen_notification_settings_enable_notifications">"Enable notifications on this device"</string>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="crash_detection_dialog_content">"%1$soxirgi marta ishlatilganda qulab tushdi. Biz bilan nosozlik hisobotini baham ko\'rmoqchimisiz?"</string>
<string name="crash_detection_dialog_content">"%1$s oxirgi marta ishlatilganda xatolik berdi. Biz bilan nosozlik hisobotini ulashmoqchimisiz?"</string>
<string name="rageshake_detection_dialog_content">"Siz hafsalasi pir bo\'lib telefonni silkitayotganga o\'xshaysiz. Xatolar haqida hisobot ekranini ochmoqchimisiz?"</string>
<string name="settings_rageshake">"G\'azablanish"</string>
<string name="settings_rageshake_detection_threshold">"Aniqlash chegarasi"</string>
@@ -8,6 +8,8 @@
<string name="screen_bug_report_editor_placeholder">"Opišite problem…"</string>
<string name="screen_bug_report_editor_supporting">"Ako je moguće, molimo vas da opis bude na engleskom jeziku."</string>
<string name="screen_bug_report_error_description_too_short">"Opis je prekratak; navedite više pojedinosti o tome što se dogodilo. Hvala!"</string>
<string name="screen_bug_report_github_issue_description">"Možete unijeti broj povezanog GitHub problema, ako postoji."</string>
<string name="screen_bug_report_github_issue_label">"Problem s GitHubom"</string>
<string name="screen_bug_report_include_crash_logs">"Pošalji zapisnike o padu aplikacije"</string>
<string name="screen_bug_report_include_logs">"Dopusti zapisnike"</string>
<string name="screen_bug_report_include_logs_error">"Vaši su zapisnici preopširni pa ih nije moguće uključiti u ovo izvješće. Molimo vas da nam ih pošaljete na drugi način."</string>
@@ -14,5 +14,7 @@
<string name="screen_bug_report_include_screenshot">"Kirim tangkapan layar"</string>
<string name="screen_bug_report_logs_description">"Log akan disertakan dengan pesan Anda untuk memastikan bahwa semuanya berfungsi dengan baik. Untuk mengirimkan pesan Anda tanpa log, matikan pengaturan ini."</string>
<string name="screen_bug_report_rash_logs_alert_title">"%1$s mengalami kemogokan saat terakhir kali digunakan. Apakah Anda ingin berbagi laporan kerusakan dengan kami?"</string>
<string name="screen_bug_report_send_notification_settings_description">"Jika Anda mengalami masalah dengan notifikasi, mengunggah aturan push notifikasi dapat membantu kami menemukan penyebab utamanya. Perlu diingat bahwa aturan ini dapat berisi informasi pribadi, seperti nama tampilan Anda atau kata kunci yang ingin Anda terima notifikasinya."</string>
<string name="screen_bug_report_send_notification_settings_title">"Pengaturan notifikasi pengiriman"</string>
<string name="screen_bug_report_view_logs">"Tampilkan catatan"</string>
</resources>
@@ -8,6 +8,8 @@
<string name="screen_bug_report_editor_placeholder">"Descrivi il problema…"</string>
<string name="screen_bug_report_editor_supporting">"Se possibile, scrivere la descrizione in inglese."</string>
<string name="screen_bug_report_error_description_too_short">"La descrizione è troppo breve, ti preghiamo di fornire maggiori dettagli sull\'accaduto. Grazie!"</string>
<string name="screen_bug_report_github_issue_description">"Puoi inserire il numero di una segnalazione GitHub associata, se presente."</string>
<string name="screen_bug_report_github_issue_label">"Segnalazione GitHub"</string>
<string name="screen_bug_report_include_crash_logs">"Invia i log degli arresti anomali"</string>
<string name="screen_bug_report_include_logs">"Consenti i log"</string>
<string name="screen_bug_report_include_logs_error">"I tuoi log sono troppo grandi, quindi non possono essere inclusi in questo rapporto, inviaceli in un altro modo."</string>
@@ -8,12 +8,14 @@
<string name="screen_bug_report_editor_placeholder">"Muammoni tasvirlab bering…"</string>
<string name="screen_bug_report_editor_supporting">"Iloji bo\'lsa, tavsifni ingliz tilida yozing."</string>
<string name="screen_bug_report_error_description_too_short">"Tavsif juda qisqa, nima boʻlganligi haqida batafsilroq maʼlumot bering. Rahmat!"</string>
<string name="screen_bug_report_github_issue_description">"Agar mavjud boʻlsa, bogʻliq GitHub muammosining raqamini kiritishingiz mumkin."</string>
<string name="screen_bug_report_github_issue_label">"GitHub muammosi"</string>
<string name="screen_bug_report_include_crash_logs">"Buzilish jurnallarini yuboring"</string>
<string name="screen_bug_report_include_logs">"Jurnallarga ruxsat bering"</string>
<string name="screen_bug_report_include_logs_error">"Sizning jurnallaringiz juda katta, shuning uchun bu hisobotga kiritilmaydi, iltimos ularni bizga boshqa usulda yuboring."</string>
<string name="screen_bug_report_include_screenshot">"Ekran tasvirini yuboring"</string>
<string name="screen_bug_report_logs_description">"Har bir narsa to\'ri ishlayotganiga ishonch hosil qilish uchun xabaringizga jurnallar kiritiladi. Xabarni jurnallarsiz yuborish uchun ushbu sozlamani oʻchiring."</string>
<string name="screen_bug_report_rash_logs_alert_title">"%1$soxirgi marta ishlatilganda qulab tushdi. Biz bilan nosozlik hisobotini baham ko\'rmoqchimisiz?"</string>
<string name="screen_bug_report_rash_logs_alert_title">"%1$s oxirgi marta ishlatilganda xatolik berdi. Biz bilan nosozlik hisobotini ulashmoqchimisiz?"</string>
<string name="screen_bug_report_send_notification_settings_description">"Agar bildirishnomalar bilan bog‘liq muammolarga duch kelayotgan bo‘lsangiz, bildirishnomalarni yetkazish qoidalarini yuklash bizga asosiy sababni aniqlashda yordam beradi. Shuni yodda tutingki, bu qoidalarda shaxsiy ma’lumotlar, masalan, ko‘rsatiladigan ismingiz yoki bildirishnoma olishingiz kerak bo‘lgan kalit so‘zlar kabi ma’lumotlar bo‘lishi mumkin."</string>
<string name="screen_bug_report_send_notification_settings_title">"Bildirishnoma sozlamalarini yuborish"</string>
<string name="screen_bug_report_view_logs">"Jurnallarni ko'rish"</string>
@@ -32,7 +32,7 @@
<string name="screen_room_change_role_section_users">"اعضا"</string>
<string name="screen_room_change_role_unsaved_changes_description">"تغییراتی ذخیره نشده دارید."</string>
<string name="screen_room_change_role_unsaved_changes_title">"ذخیرهٔ تغییرات؟"</string>
<string name="screen_room_member_list_banned_empty">"هیچ کاربر محرومی در این اتاق نیست."</string>
<string name="screen_room_member_list_banned_empty">"هیچ کاربری محروم نشده."</string>
<plurals name="screen_room_member_list_header_title">
<item quantity="one">"%1$d نفر"</item>
<item quantity="other">"%1$d نفر"</item>
@@ -59,6 +59,7 @@
<string name="screen_room_roles_and_permissions_moderators">"ناظم‌ها"</string>
<string name="screen_room_roles_and_permissions_owners">"مالکان"</string>
<string name="screen_room_roles_and_permissions_reset">"بازنشانی اجازه‌ها"</string>
<string name="screen_room_roles_and_permissions_reset_confirm_description">"پس از بازنشانی اجازه‌ها تنظیمات فعلی را از دست خواهید داد."</string>
<string name="screen_room_roles_and_permissions_reset_confirm_title">"بازنشانی اجازه‌ها؟"</string>
<string name="screen_room_roles_and_permissions_roles_header">"نقش‌ها"</string>
<string name="screen_room_roles_and_permissions_room_details">"جزییات اتاق"</string>
@@ -6,6 +6,7 @@
<string name="screen_room_change_permissions_delete_messages">"Uklanjanje poruka"</string>
<string name="screen_room_change_permissions_everyone">"Član"</string>
<string name="screen_room_change_permissions_invite_people">"Pozivanje osoba"</string>
<string name="screen_room_change_permissions_live_location">"Dijeljenje lokacije uživo"</string>
<string name="screen_room_change_permissions_manage_space">"Upravljaj prostorom"</string>
<string name="screen_room_change_permissions_manage_space_rooms">"Upravljaj sobama"</string>
<string name="screen_room_change_permissions_member_moderation">"Upravljanje članovima"</string>
@@ -2,9 +2,13 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_change_permissions_administrators">"Hanya admin"</string>
<string name="screen_room_change_permissions_ban_people">"Cekal orang-orang"</string>
<string name="screen_room_change_permissions_change_settings">"Ubah pengaturan"</string>
<string name="screen_room_change_permissions_delete_messages">"Hilangkan pesan"</string>
<string name="screen_room_change_permissions_everyone">"Semua Anggota"</string>
<string name="screen_room_change_permissions_invite_people">"Boleh mungundang"</string>
<string name="screen_room_change_permissions_live_location">"Bagikan lokasi secara langsung"</string>
<string name="screen_room_change_permissions_manage_space">"Kelola ruang"</string>
<string name="screen_room_change_permissions_manage_space_rooms">"Kelola ruangan"</string>
<string name="screen_room_change_permissions_member_moderation">"Kelola anggota"</string>
<string name="screen_room_change_permissions_messages_and_content">"Pesan dan konten"</string>
<string name="screen_room_change_permissions_moderators">"Admin dan moderator"</string>
@@ -14,6 +18,7 @@
<string name="screen_room_change_permissions_room_name">"Ubah nama ruangan"</string>
<string name="screen_room_change_permissions_room_topic">"Ubah topik ruangan"</string>
<string name="screen_room_change_permissions_send_messages">"Kirim pesan"</string>
<string name="screen_room_change_permissions_title">"Permission"</string>
<string name="screen_room_change_role_administrators_title">"Edit Admin"</string>
<string name="screen_room_change_role_confirm_add_admin_description">"Anda tidak akan dapat mengurungkan tindakan ini. Anda mempromosikan pengguna untuk memiliki tingkat daya yang sama seperti Anda."</string>
<string name="screen_room_change_role_confirm_add_admin_title">"Tambahkan Admin?"</string>
@@ -34,6 +39,11 @@
<string name="screen_room_change_role_unsaved_changes_description">"Anda memiliki perubahan yang belum disimpan."</string>
<string name="screen_room_change_role_unsaved_changes_title">"Simpan perubahan?"</string>
<string name="screen_room_member_list_banned_empty">"Tidak ada pengguna yang dicekal dalam ruangan ini."</string>
<plurals name="screen_room_member_list_banned_header_title">
<item quantity="other">"%1$d Dilarang"</item>
</plurals>
<string name="screen_room_member_list_empty_search_subtitle">"Periksa ejaannya atau coba pencarian baru"</string>
<string name="screen_room_member_list_empty_search_title">"Tidak ada hasil untuk%1$s"</string>
<plurals name="screen_room_member_list_header_title">
<item quantity="other">"%1$d orang"</item>
</plurals>
@@ -44,6 +54,10 @@
<string name="screen_room_member_list_manage_member_unban_title">"Batalkan cekalan dari ruangan"</string>
<string name="screen_room_member_list_mode_banned">"Tercekal"</string>
<string name="screen_room_member_list_mode_members">"Anggota"</string>
<plurals name="screen_room_member_list_pending_header_title">
<item quantity="other">"%1$d Diundang"</item>
</plurals>
<string name="screen_room_member_list_pending_status">"Tertunda"</string>
<string name="screen_room_member_list_role_administrator">"Hanya admin"</string>
<string name="screen_room_member_list_role_moderator">"Admin dan moderator"</string>
<string name="screen_room_member_list_role_owner">"Pemilik"</string>
@@ -58,10 +72,12 @@
<string name="screen_room_roles_and_permissions_messages_and_content">"Pesan dan konten"</string>
<string name="screen_room_roles_and_permissions_moderators">"Moderator"</string>
<string name="screen_room_roles_and_permissions_owners">"Pemilik"</string>
<string name="screen_room_roles_and_permissions_permissions_header">"Permission"</string>
<string name="screen_room_roles_and_permissions_reset">"Atur ulang perizinan"</string>
<string name="screen_room_roles_and_permissions_reset_confirm_description">"Setelah Anda mengatur ulang perizinan, Anda akan kehilangan pengaturan Anda saat ini."</string>
<string name="screen_room_roles_and_permissions_reset_confirm_title">"Atur ulang perizinan?"</string>
<string name="screen_room_roles_and_permissions_roles_header">"Peran"</string>
<string name="screen_room_roles_and_permissions_room_details">"Detail ruangan"</string>
<string name="screen_room_roles_and_permissions_space_details">"Detail ruang"</string>
<string name="screen_room_roles_and_permissions_title">"Peran dan perizinan"</string>
</resources>
@@ -6,6 +6,7 @@
<string name="screen_room_change_permissions_delete_messages">"Xabarlarni olib tashlash"</string>
<string name="screen_room_change_permissions_everyone">"A\'zo"</string>
<string name="screen_room_change_permissions_invite_people">"Odamlarni taklif qiling"</string>
<string name="screen_room_change_permissions_live_location">"Jonli joylashuvni ulashish"</string>
<string name="screen_room_change_permissions_manage_space">"Maydonni boshqarish"</string>
<string name="screen_room_change_permissions_manage_space_rooms">"Xonalarni boshqarish"</string>
<string name="screen_room_change_permissions_member_moderation">"A’zolarni boshqarish"</string>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_room_alias_resolver_resolve_alias_failure">"شکست در دریافت نام مستعار اتاق."</string>
</resources>
@@ -68,7 +68,7 @@
<string name="screen_room_details_title">"اطّلاعات اتاق"</string>
<string name="screen_room_details_topic_title">"موضوع"</string>
<string name="screen_room_details_updating_room">"به‌روز کردن اتاق…"</string>
<string name="screen_room_member_list_banned_empty">"هیچ کاربر محرومی در این اتاق نیست."</string>
<string name="screen_room_member_list_banned_empty">"هیچ کاربری محروم نشده."</string>
<plurals name="screen_room_member_list_header_title">
<item quantity="one">"%1$d نفر"</item>
<item quantity="other">"%1$d نفر"</item>
@@ -109,6 +109,7 @@
<string name="screen_room_roles_and_permissions_moderators">"ناظم‌ها"</string>
<string name="screen_room_roles_and_permissions_owners">"مالکان"</string>
<string name="screen_room_roles_and_permissions_reset">"بازنشانی اجازه‌ها"</string>
<string name="screen_room_roles_and_permissions_reset_confirm_description">"پس از بازنشانی اجازه‌ها تنظیمات فعلی را از دست خواهید داد."</string>
<string name="screen_room_roles_and_permissions_reset_confirm_title">"بازنشانی اجازه‌ها؟"</string>
<string name="screen_room_roles_and_permissions_roles_header">"نقش‌ها"</string>
<string name="screen_room_roles_and_permissions_room_details">"جزییات اتاق"</string>
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="crypto_history_sharing_room_info_hidden_badge_content">"Anggota baru tidak dapat melihat riwayat"</string>
<string name="crypto_history_sharing_room_info_shared_badge_content">"Anggota baru dapat melihat riwayat"</string>
<string name="crypto_history_sharing_room_info_world_readable_badge_content">"Siapa pun dapat melihat riwayat"</string>
<string name="screen_edit_room_address_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_edit_room_address_title">"Edit alamat"</string>
<string name="screen_notification_settings_edit_failed_updating_default_mode">"Terjadi kesalahan saat memperbarui pengaturan pemberitahuan."</string>
@@ -64,6 +67,7 @@
<string name="screen_room_details_profile_row_title">"Profil"</string>
<string name="screen_room_details_requests_to_join_title">"Permintaan untuk bergabung"</string>
<string name="screen_room_details_roles_and_permissions">"Peran dan perizinan"</string>
<string name="screen_room_details_room_name_label">"Nama"</string>
<string name="screen_room_details_security_and_privacy_title">"Keamanan &amp; privasi"</string>
<string name="screen_room_details_security_title">"Keamanan"</string>
<string name="screen_room_details_share_room_title">"Bagikan ruangan"</string>
@@ -71,6 +75,11 @@
<string name="screen_room_details_topic_title">"Topik"</string>
<string name="screen_room_details_updating_room">"Memperbarui ruangan…"</string>
<string name="screen_room_member_list_banned_empty">"Tidak ada pengguna yang dicekal dalam ruangan ini."</string>
<plurals name="screen_room_member_list_banned_header_title">
<item quantity="other">"%1$d Dilarang"</item>
</plurals>
<string name="screen_room_member_list_empty_search_subtitle">"Periksa ejaannya atau coba pencarian baru"</string>
<string name="screen_room_member_list_empty_search_title">"Tidak ada hasil untuk%1$s"</string>
<plurals name="screen_room_member_list_header_title">
<item quantity="other">"%1$d orang"</item>
</plurals>
@@ -81,6 +90,10 @@
<string name="screen_room_member_list_manage_member_unban_title">"Batalkan cekalan dari ruangan"</string>
<string name="screen_room_member_list_mode_banned">"Tercekal"</string>
<string name="screen_room_member_list_mode_members">"Anggota"</string>
<plurals name="screen_room_member_list_pending_header_title">
<item quantity="other">"%1$d Diundang"</item>
</plurals>
<string name="screen_room_member_list_pending_status">"Tertunda"</string>
<string name="screen_room_member_list_role_administrator">"Hanya admin"</string>
<string name="screen_room_member_list_role_moderator">"Admin dan moderator"</string>
<string name="screen_room_member_list_role_owner">"Pemilik"</string>
@@ -109,6 +122,7 @@
<string name="screen_room_roles_and_permissions_messages_and_content">"Pesan dan konten"</string>
<string name="screen_room_roles_and_permissions_moderators">"Moderator"</string>
<string name="screen_room_roles_and_permissions_owners">"Pemilik"</string>
<string name="screen_room_roles_and_permissions_permissions_header">"Permission"</string>
<string name="screen_room_roles_and_permissions_reset">"Atur ulang perizinan"</string>
<string name="screen_room_roles_and_permissions_reset_confirm_description">"Setelah Anda mengatur ulang perizinan, Anda akan kehilangan pengaturan Anda saat ini."</string>
<string name="screen_room_roles_and_permissions_reset_confirm_title">"Atur ulang perizinan?"</string>
@@ -118,8 +132,10 @@
<string name="screen_roomlist_mark_as_read">"Tandai sebagai dibaca"</string>
<string name="screen_roomlist_mark_as_unread">"Tandai sebagai belum dibaca"</string>
<string name="screen_security_and_privacy_add_room_address_action">"Tambahkan alamat"</string>
<string name="screen_security_and_privacy_ask_to_join_multiple_spaces_members_option_description">"Siapa pun yang berada di ruang yang diizinkan dapat bergabung, tetapi semua orang lain harus meminta akses."</string>
<string name="screen_security_and_privacy_ask_to_join_option_description">"Meminta hak akses pada administrator atau moderator."</string>
<string name="screen_security_and_privacy_ask_to_join_option_title">"Ijin bergabung"</string>
<string name="screen_security_and_privacy_ask_to_join_single_space_members_option_description">"Siapa pun di %1$s dapat bergabung, tetapi semua orang lain harus meminta akses."</string>
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Ya, aktifkan enkripsi"</string>
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Setelah diaktifkan, encryption untuk sebuah ruangan tidak dapat dinonaktifkan, Riwayat pesan hanya akan terlihat oleh anggota ruangan sejak mereka diundang atau sejak mereka bergabung dengan ruangan tersebut.
Tidak ada orang lain selain anggota ruangan yang dapat membaca pesan. Hal ini dapat mencegah bot dan jembatan bekerja dengan benar.
@@ -130,20 +146,28 @@ Kami tidak menyarankan untuk mengaktifkan enkripsi untuk ruangan yang dapat dite
<string name="screen_security_and_privacy_encryption_toggle_title">"Aktifkan enkripsi ujung ke ujung"</string>
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Siapa pun dapat menemukan dan bergabung"</string>
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Semua orang"</string>
<string name="screen_security_and_privacy_room_access_footer">"Pilih ruang mana yang anggotanya dapat bergabung ke ruangan ini tanpa undangan. %1$s"</string>
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Kelola ruang"</string>
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Orang hanya dapat bergabung jika mereka diundang"</string>
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Hanya undangan"</string>
<string name="screen_security_and_privacy_room_access_section_header">"Akses ruangan"</string>
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Siapa pun yang berada di area yang diizinkan dapat bergabung."</string>
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Siapa pun di %1$s dapat bergabung."</string>
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Anggota space"</string>
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Space saat ini tidak didukung"</string>
<string name="screen_security_and_privacy_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_security_and_privacy_room_address_section_header">"Alamat"</string>
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Izinkan ruangan ini ditemukan dengan mencari direktori ruangan %1$s publik"</string>
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Izinkan agar dapat ditemukan melalui pencarian di direktori publik."</string>
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Tersedia di direktori publik"</string>
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Siapa saja (riwayat publik)"</string>
<string name="screen_security_and_privacy_room_history_section_footer">"Perubahan tidak akan memengaruhi pesan lama, hanya pesan baru. %1$s"</string>
<string name="screen_security_and_privacy_room_history_section_header">"Siapa yang bisa membaca riwayat"</string>
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Hanya sejak anggota diundang"</string>
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Anggota dapat melihat rekaman percakapan sejak memilih opsi ini"</string>
<string name="screen_security_and_privacy_room_publishing_section_footer">"Alamat ruangan adalah cara untuk menemukan dan mengakses ruangan. Ini juga memastikan Anda dapat dengan mudah berbagi ruangan dengan orang lain. Anda dapat memilih untuk menerbitkan ruangan Anda di direktori ruangan publik homeserver Anda."</string>
<string name="screen_security_and_privacy_room_publishing_section_header">"Penerbitan ruangan"</string>
<string name="screen_security_and_privacy_room_visibility_section_footer">"Alamat adalah cara untuk menemukan dan mengakses ruangan dan ruang. Ini juga memastikan Anda dapat dengan mudah membagikannya dengan orang lain."</string>
<string name="screen_security_and_privacy_room_visibility_section_header">"Visibilitas"</string>
<string name="screen_security_and_privacy_title">"Keamanan &amp; privasi"</string>
</resources>
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="crypto_history_sharing_room_info_hidden_badge_content">"新しいメンバーは過去の内容を確認できない"</string>
<string name="crypto_history_sharing_room_info_shared_badge_content">"新しいメンバーは過去の内容を確認できる"</string>
<string name="crypto_history_sharing_room_info_world_readable_badge_content">"すべてのユーザーが過去の内容を確認できる"</string>
<string name="crypto_history_sharing_room_info_shared_badge_content">"新規メンバーも過去の内容を確認できます"</string>
<string name="crypto_history_sharing_room_info_world_readable_badge_content">"すべてのユーザーが過去の内容を確認できます"</string>
<string name="screen_edit_room_address_room_address_section_footer">"公開ディレクトリで自分を見つけられるようにするには、アドレスが必要です。"</string>
<string name="screen_edit_room_address_title">"アドレスの編集"</string>
<string name="screen_notification_settings_edit_failed_updating_default_mode">"通知設定の更新中に問題が発生しました。"</string>
@@ -114,7 +114,7 @@
<string name="screen_room_notification_settings_error_setting_mode">"Failed setting the mode, please try again."</string>
<string name="screen_room_notification_settings_mentions_only_disclaimer">"Your homeserver does not support this option in encrypted rooms, you won\'t get notified in this room."</string>
<string name="screen_room_notification_settings_mode_all_messages">"All messages"</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Mentions and Keywords only"</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Mentions and replies only"</string>
<string name="screen_room_notification_settings_room_custom_settings_title">"In this room, notify me for"</string>
<string name="screen_room_roles_and_permissions_admins">"Admins"</string>
<string name="screen_room_roles_and_permissions_admins_and_owners">"Admins and owners"</string>
@@ -4,10 +4,12 @@
<string name="screen_bottom_sheet_manage_room_member_ban_member_confirmation_action">"Cekal"</string>
<string name="screen_bottom_sheet_manage_room_member_ban_member_confirmation_description">"Mereka tidak akan dapat bergabung ke ruangan ini lagi jika diundang."</string>
<string name="screen_bottom_sheet_manage_room_member_ban_member_confirmation_title">"Apakah Anda yakin ingin mencekal anggota ini?"</string>
<string name="screen_bottom_sheet_manage_room_member_ban_member_from_space_confirmation_description">"Mereka tidak akan dapat bergabung kembali ke space ini meskipun diundang, tetapi mereka tetap akan mempertahankan keanggotaan mereka di room atau subruang mana pun."</string>
<string name="screen_bottom_sheet_manage_room_member_banning_user">"Mencekal %1$s"</string>
<string name="screen_bottom_sheet_manage_room_member_kick_member_confirmation_action">"Hapus"</string>
<string name="screen_bottom_sheet_manage_room_member_kick_member_confirmation_description">"Pengguna dapat bergabung ke ruangan ini lagi jika diundang."</string>
<string name="screen_bottom_sheet_manage_room_member_kick_member_confirmation_title">"Apakah Anda yakin ingin menghapus anggota ini?"</string>
<string name="screen_bottom_sheet_manage_room_member_kick_member_from_space_confirmation_description">"Mereka akan dapat bergabung kembali ke Space ini jika diundang, dan mereka tetap akan mempertahankan keanggotaan mereka di room atau subruang mana pun."</string>
<string name="screen_bottom_sheet_manage_room_member_member_user_info">"Tampilkan profil"</string>
<string name="screen_bottom_sheet_manage_room_member_remove">"Keluarkan dari ruangan"</string>
<string name="screen_bottom_sheet_manage_room_member_remove_confirmation_title">"Keluarkan pengguna dan cekal pengguna bergabung lagi di masa mendatang?"</string>
@@ -20,6 +20,27 @@
<string name="screen_create_new_recovery_key_list_item_4">"Seuraa ohjeita uuden palautusavaimen luomiseksi"</string>
<string name="screen_create_new_recovery_key_list_item_5">"Tallenna uusi palautusavaimesi salasanojen hallintaohjelmaan tai salattuun muistiinpanoon"</string>
<string name="screen_create_new_recovery_key_title">"Nollaa tilisi salaus toisella laitteella"</string>
<string name="screen_custom_recovery_key_confirm_error_mismatch">"Antamasi palautusavain ei täsmää"</string>
<string name="screen_custom_recovery_key_confirm_submit">"Viimeistele määritys"</string>
<string name="screen_custom_recovery_key_confirm_subtitle">"Anna palautusavaimesi uudelleen."</string>
<string name="screen_custom_recovery_key_confirm_title">"Vahvista palautusavaimesi"</string>
<plurals name="screen_custom_recovery_key_input_notice">
<item quantity="one">"Vähintään %1$d merkki. Älä käytä tilisi salasanaa"</item>
<item quantity="other">"Vähintään %1$d merkkiä. Älä käytä tilisi salasanaa"</item>
</plurals>
<string name="screen_custom_recovery_key_input_strength">"Vahvuus"</string>
<string name="screen_custom_recovery_key_input_strength_a11y">"Salasanan vahvuus: %1$s"</string>
<string name="screen_custom_recovery_key_input_strength_moderate">"Kohtalainen"</string>
<string name="screen_custom_recovery_key_input_strength_strong">"Vahva"</string>
<string name="screen_custom_recovery_key_input_strength_very_strong">"Erittäin vahva"</string>
<string name="screen_custom_recovery_key_input_strength_very_weak">"Erittäin heikko"</string>
<string name="screen_custom_recovery_key_input_strength_weak">"Heikko"</string>
<string name="screen_custom_recovery_key_input_subtitle">"Valitse palautusavain, jonka osaat muistaa."</string>
<string name="screen_custom_recovery_key_input_title">"Anna palautusavain"</string>
<string name="screen_custom_recovery_key_loading_a11y">"Palautusavaimen vaatimuksia ladataan"</string>
<string name="screen_custom_recovery_key_success_notice">"Jos haluat vaihtaa palautusavaimesi, mene kohtaan Asetukset → Salaus"</string>
<string name="screen_custom_recovery_key_success_subtitle">"Voit käyttää palautusavainta uusien laitteiden vahvistamiseen tai salattujen keskustelujen palauttamiseen, jos menetät pääsyn kaikkiin laitteisiisi."</string>
<string name="screen_custom_recovery_key_success_title">"Varmuuskopiointi on nyt täysin määritetty"</string>
<string name="screen_encryption_reset_action_continue_reset">"Jatka nollausta"</string>
<string name="screen_encryption_reset_bullet_1">"Tilitietosi, yhteystiedot, asetukset ja keskustelulista säilytetään"</string>
<string name="screen_encryption_reset_bullet_2">"Menetät kaiken viestihistorian, joka on tallella vain palvelimella"</string>
@@ -20,6 +20,27 @@
<string name="screen_create_new_recovery_key_list_item_4">"Pridržavajte se uputa za izradu novog ključa za oporavak"</string>
<string name="screen_create_new_recovery_key_list_item_5">"Spremite svoj novi ključ za oporavak u upravitelj zaporki ili šifriranu bilješku"</string>
<string name="screen_create_new_recovery_key_title">"Resetirajte šifriranje za svoj račun pomoću drugog uređaja"</string>
<string name="screen_custom_recovery_key_confirm_error_mismatch">"Ključ za oporavak koji ste unijeli ne odgovara"</string>
<string name="screen_custom_recovery_key_confirm_submit">"Završi postavljanje"</string>
<string name="screen_custom_recovery_key_confirm_subtitle">"Ponovno unesite svoj ključ za oporavak."</string>
<string name="screen_custom_recovery_key_confirm_title">"Potvrdite svoj ključ za oporavak"</string>
<plurals name="screen_custom_recovery_key_input_notice">
<item quantity="one">"Minimalno %1$d znakova. Nemojte koristiti lozinku računa."</item>
<item quantity="other">"Minimalno %1$d znakova. Nemojte koristiti lozinku računa."</item>
</plurals>
<string name="screen_custom_recovery_key_input_strength">"Snaga"</string>
<string name="screen_custom_recovery_key_input_strength_a11y">"Jačina lozinke: %1$s"</string>
<string name="screen_custom_recovery_key_input_strength_moderate">"Umjereno"</string>
<string name="screen_custom_recovery_key_input_strength_strong">"Jak"</string>
<string name="screen_custom_recovery_key_input_strength_very_strong">"Vrlo jaka"</string>
<string name="screen_custom_recovery_key_input_strength_very_weak">"Vrlo slaba"</string>
<string name="screen_custom_recovery_key_input_strength_weak">"Slaba"</string>
<string name="screen_custom_recovery_key_input_subtitle">"Odaberite ključ za oporavak koji možete zapamtiti."</string>
<string name="screen_custom_recovery_key_input_title">"Unesite ključ za oporavak"</string>
<string name="screen_custom_recovery_key_loading_a11y">"Učitavanje zahtjeva za ključ za oporavak"</string>
<string name="screen_custom_recovery_key_success_notice">"Za promjenu ključa za oporavak, idite na Postavke → Šifriranje → Sigurnosna kopija"</string>
<string name="screen_custom_recovery_key_success_subtitle">"Ključ za oporavak možete koristiti za potvrdu novih uređaja ili vraćanje šifriranih razgovora ako izgubite pristup svim svojim uređajima."</string>
<string name="screen_custom_recovery_key_success_title">"Vaša sigurnosna kopija je sada potpuno postavljena"</string>
<string name="screen_encryption_reset_action_continue_reset">"Nastavi s poništavanjem"</string>
<string name="screen_encryption_reset_bullet_1">"Sačuvat će se podatci o vašem računu, kontakti, postavke i popis razgovora"</string>
<string name="screen_encryption_reset_bullet_2">"Izgubit ćete svu povijest poruka koja je pohranjena samo na poslužitelju"</string>
@@ -12,6 +12,7 @@
<string name="screen_chat_backup_recovery_action_confirm">"Masukkan kunci pemulihan"</string>
<string name="screen_chat_backup_recovery_action_confirm_description">"Penyimpanan kunci Anda saat ini tidak sinkron."</string>
<string name="screen_chat_backup_recovery_action_setup">"Siapkan Kunci pemulihan"</string>
<string name="screen_chat_backup_recovery_action_setup_description">"Pulihkan identitas kriptografi dan riwayat pesan Anda dengan kunci pemulihan jika Anda kehilangan semua perangkat yang ada."</string>
<string name="screen_create_new_recovery_key_list_item_1">"Buka %1$s di perangkat desktop"</string>
<string name="screen_create_new_recovery_key_list_item_2">"Masuk ke akun Anda lagi"</string>
<string name="screen_create_new_recovery_key_list_item_3">"Saat diminta untuk memverifikasi perangkat Anda, pilih %1$s"</string>
@@ -20,6 +20,27 @@
<string name="screen_create_new_recovery_key_list_item_4">"Segui le istruzioni per creare una nuova chiave di recupero"</string>
<string name="screen_create_new_recovery_key_list_item_5">"Salva la tua nuova chiave di recupero in un gestore di password o in una nota criptata"</string>
<string name="screen_create_new_recovery_key_title">"Reimposta la crittografia del tuo account utilizzando un altro dispositivo"</string>
<string name="screen_custom_recovery_key_confirm_error_mismatch">"La chiave di recupero che hai inserito non corrisponde"</string>
<string name="screen_custom_recovery_key_confirm_submit">"Completa la configurazione"</string>
<string name="screen_custom_recovery_key_confirm_subtitle">"Inserisci nuovamente la tua chiave di recupero."</string>
<string name="screen_custom_recovery_key_confirm_title">"Conferma la tua chiave di recupero"</string>
<plurals name="screen_custom_recovery_key_input_notice">
<item quantity="one">"Minimo %1$d carattere. Non usare la password del tuo account"</item>
<item quantity="other">"Minimo %1$d caratteri. Non usare la password del tuo account"</item>
</plurals>
<string name="screen_custom_recovery_key_input_strength">"Complessità"</string>
<string name="screen_custom_recovery_key_input_strength_a11y">"Complessità della passphrase: %1$s"</string>
<string name="screen_custom_recovery_key_input_strength_moderate">"Moderata"</string>
<string name="screen_custom_recovery_key_input_strength_strong">"Sicura"</string>
<string name="screen_custom_recovery_key_input_strength_very_strong">"Molto sicura"</string>
<string name="screen_custom_recovery_key_input_strength_very_weak">"Molto debole"</string>
<string name="screen_custom_recovery_key_input_strength_weak">"Debole"</string>
<string name="screen_custom_recovery_key_input_subtitle">"Scegli una chiave di recupero che puoi ricordare."</string>
<string name="screen_custom_recovery_key_input_title">"Inserisci una chiave di recupero"</string>
<string name="screen_custom_recovery_key_loading_a11y">"Caricamento dei requisiti per la chiave di recupero"</string>
<string name="screen_custom_recovery_key_success_notice">"Per modificare la chiave di recupero, vai su Impostazioni → Crittografia → Backup"</string>
<string name="screen_custom_recovery_key_success_subtitle">"Puoi utilizzare la tua chiave di recupero per confermare nuovi dispositivi o ripristinare le tue chat crittografate se perdi l\'accesso a tutti i tuoi dispositivi."</string>
<string name="screen_custom_recovery_key_success_title">"Il tuo backup è ora completamente configurato."</string>
<string name="screen_encryption_reset_action_continue_reset">"Continua il ripristino"</string>
<string name="screen_encryption_reset_bullet_1">"I dettagli del tuo account, i contatti, le preferenze e l\'elenco delle conversazioni verranno conservati"</string>
<string name="screen_encryption_reset_bullet_2">"Perderai la cronologia dei messaggi esistente"</string>
@@ -20,6 +20,26 @@
<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_custom_recovery_key_confirm_error_mismatch">"入力した回復鍵が一致しません"</string>
<string name="screen_custom_recovery_key_confirm_submit">"設定完了"</string>
<string name="screen_custom_recovery_key_confirm_subtitle">"回復鍵を再度入力してください。"</string>
<string name="screen_custom_recovery_key_confirm_title">"回復鍵の確認"</string>
<plurals name="screen_custom_recovery_key_input_notice">
<item quantity="other">"%1$d字以上でアカウントのパスワードとは異なるものを設定してください。"</item>
</plurals>
<string name="screen_custom_recovery_key_input_strength">"強度"</string>
<string name="screen_custom_recovery_key_input_strength_a11y">"パスフレーズの強度: %1$s"</string>
<string name="screen_custom_recovery_key_input_strength_moderate">"中程度"</string>
<string name="screen_custom_recovery_key_input_strength_strong">"強い"</string>
<string name="screen_custom_recovery_key_input_strength_very_strong">"とても強い"</string>
<string name="screen_custom_recovery_key_input_strength_very_weak">"とても弱い"</string>
<string name="screen_custom_recovery_key_input_strength_weak">"弱い"</string>
<string name="screen_custom_recovery_key_input_subtitle">"思い出せる回復鍵を作成してください。"</string>
<string name="screen_custom_recovery_key_input_title">"回復鍵の入力"</string>
<string name="screen_custom_recovery_key_loading_a11y">"回復鍵の要件を読み込み中"</string>
<string name="screen_custom_recovery_key_success_notice">"回復鍵を変更するには、「設定 - 暗号化 - バックアップ」を開いてください。"</string>
<string name="screen_custom_recovery_key_success_subtitle">"回復鍵は他の端末をすべて使用できない場合に、新しい端末を承認したり暗号化された会話を復元したりするために使用します。"</string>
<string name="screen_custom_recovery_key_success_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>
@@ -2,13 +2,13 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_chat_backup_key_backup_action_disable">"Slett nøkkellagring"</string>
<string name="screen_chat_backup_key_backup_action_enable">"Slå på sikkerhetskopiering"</string>
<string name="screen_chat_backup_key_backup_description">"Lagre din kryptografiske identitet og meldingsnøkler sikkert på serveren. Dette gjør at du kan se meldingshistorikken din på alle nye enheter. %1$s."</string>
<string name="screen_chat_backup_key_backup_description">"Dette lar deg se chatloggen din på alle nye enheter, og det er nødvendig for sikkerhetskopiering av chatter og digital identitet. %1$s."</string>
<string name="screen_chat_backup_key_backup_title">"Nøkkellagring"</string>
<string name="screen_chat_backup_key_storage_disabled_error">"Nøkkellagring må være slått på for å konfigurere gjenoppretting."</string>
<string name="screen_chat_backup_key_storage_disabled_error">"Nøkkellagring må være aktivert for å sikkerhetskopiere chattene dine."</string>
<string name="screen_chat_backup_key_storage_toggle_description">"Last opp nøkler fra denne enheten"</string>
<string name="screen_chat_backup_key_storage_toggle_title">"Tillat nøkkellagring"</string>
<string name="screen_chat_backup_recovery_action_change">"Endre gjenopprettingsnøkkel"</string>
<string name="screen_chat_backup_recovery_action_change_description">"Gjenopprett din kryptografiske identitet og meldingshistorikk med en gjenopprettingsnøkkel hvis du har mistet alle dine brukte enheter."</string>
<string name="screen_chat_backup_recovery_action_change_description">"Chattene dine sikkerhetskopieres automatisk med ende-til-ende-kryptering. For å gjenopprette denne sikkerhetskopien og beholde din digitale identitet når du mister tilgang til alle enhetene dine, trenger du gjenopprettingsnøkkelen din."</string>
<string name="screen_chat_backup_recovery_action_confirm">"Skriv inn gjenopprettingsnøkkel"</string>
<string name="screen_chat_backup_recovery_action_confirm_description">"Nøkkellagringen din er for øyeblikket ikke synkronisert."</string>
<string name="screen_chat_backup_recovery_action_setup">"Hent gjenopprettingsnøkkel"</string>
@@ -23,10 +23,10 @@
<string name="screen_encryption_reset_bullet_1">"Dine kontodetaljer, kontakter, innstillinger og chatteliste vil bli beholdt"</string>
<string name="screen_encryption_reset_bullet_2">"Du mister all meldingshistorikk som bare er lagret på serveren"</string>
<string name="screen_encryption_reset_bullet_3">"Du må verifisere alle eksisterende enheter og kontakter på nytt"</string>
<string name="screen_encryption_reset_footer">"Tilbakestill identiteten din bare hvis du ikke har tilgang til en annen pålogget enhet og du har mistet gjenopprettingsnøkkelen."</string>
<string name="screen_encryption_reset_title">"Kan du ikke bekrefte? Du må tilbakestille identiteten din."</string>
<string name="screen_encryption_reset_footer">"Tilbakestill bare den digitale identiteten din hvis du ikke har tilgang til en annen bekreftet enhet og du ikke har gjenopprettingsnøkkelen din."</string>
<string name="screen_encryption_reset_title">"Kan du ikke bekrefte? Du må tilbakestille den digitale identiteten din."</string>
<string name="screen_key_backup_disable_confirmation_action_turn_off">"Slett"</string>
<string name="screen_key_backup_disable_confirmation_description">"Du mister de krypterte meldingene dine hvis du er logget ut av alle enheter."</string>
<string name="screen_key_backup_disable_confirmation_description">"Du vil miste den krypterte chatloggen din og må tilbakestille den digitale identiteten din hvis du fjerner alle enhetene dine."</string>
<string name="screen_key_backup_disable_confirmation_title">"Er du sikker på at du vil slette nøkkellagringen?"</string>
<string name="screen_key_backup_disable_description">"Sletting av nøkkellagring vil fjerne din kryptografiske identitet og meldingsnøkler fra serveren og deaktivere følgende sikkerhetsfunksjoner:"</string>
<string name="screen_key_backup_disable_description_point_1">"Du vil ikke ha kryptert meldingshistorikk på nye enheter"</string>
@@ -61,9 +61,9 @@
<string name="screen_recovery_key_setup_title">"Hent gjenopprettingsnøkkel"</string>
<string name="screen_reset_encryption_confirmation_alert_action">"Ja, tilbakestill nå"</string>
<string name="screen_reset_encryption_confirmation_alert_subtitle">"Denne prosessen kan ikke angres."</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Er du sikker på at du vil tilbakestille identiteten din?"</string>
<string name="screen_reset_encryption_confirmation_alert_title">"Er du sikker på at du vil tilbakestille den digitale identiteten din?"</string>
<string name="screen_reset_encryption_password_error">"En ukjent feil har oppstått. Vennligst sjekk at passordet ditt er riktig og prøv igjen."</string>
<string name="screen_reset_encryption_password_placeholder">"Angi…"</string>
<string name="screen_reset_encryption_password_subtitle">"Bekreft at du vil tilbakestille identiteten din."</string>
<string name="screen_reset_encryption_password_subtitle">"Bekreft at du vil tilbakestille din digitale identitet."</string>
<string name="screen_reset_encryption_password_title">"Skriv inn passordet til kontoen din for å fortsette"</string>
</resources>
@@ -20,6 +20,28 @@
<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_custom_recovery_key_confirm_error_mismatch">"Введенный вами ключ восстановления не совпадает."</string>
<string name="screen_custom_recovery_key_confirm_submit">"Завершить настройку"</string>
<string name="screen_custom_recovery_key_confirm_subtitle">"Введите ваш ключ восстановления еще раз."</string>
<string name="screen_custom_recovery_key_confirm_title">"Подтвердите ваш ключ восстановления."</string>
<plurals name="screen_custom_recovery_key_input_notice">
<item quantity="one">"Минимальное количество символов: %1$d. Не используйте пароль от своей учетной записи."</item>
<item quantity="few">"Минимальное количество символов: %1$d. Не используйте пароль от своей учетной записи."</item>
<item quantity="many">"Минимальное количество символов: %1$d. Не используйте пароль от своей учетной записи."</item>
</plurals>
<string name="screen_custom_recovery_key_input_strength">"Прочность"</string>
<string name="screen_custom_recovery_key_input_strength_a11y">"Надежность парольной фразы: %1$s"</string>
<string name="screen_custom_recovery_key_input_strength_moderate">"Умеренный"</string>
<string name="screen_custom_recovery_key_input_strength_strong">"Сильный"</string>
<string name="screen_custom_recovery_key_input_strength_very_strong">"Очень сильный"</string>
<string name="screen_custom_recovery_key_input_strength_very_weak">"Очень слабый"</string>
<string name="screen_custom_recovery_key_input_strength_weak">"Слабый"</string>
<string name="screen_custom_recovery_key_input_subtitle">"Выберите ключ восстановления, который вы сможете запомнить."</string>
<string name="screen_custom_recovery_key_input_title">"Введите ключ восстановления"</string>
<string name="screen_custom_recovery_key_loading_a11y">"Загрузка требований к ключу восстановления"</string>
<string name="screen_custom_recovery_key_success_notice">"Чтобы изменить ключ восстановления, перейдите в Настройки → Шифрование → Резервное копирование"</string>
<string name="screen_custom_recovery_key_success_subtitle">"Вы можете использовать свой ключ восстановления для подтверждения новых устройств или восстановления зашифрованных чатов, если потеряете доступ ко всем своим устройствам."</string>
<string name="screen_custom_recovery_key_success_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>
@@ -41,10 +41,12 @@ dependencies {
implementation(projects.libraries.uiStrings)
implementation(projects.services.analytics.api)
implementation(projects.libraries.featureflag.api)
implementation(projects.features.enterprise.api)
testCommonDependencies(libs, true)
testImplementation(projects.services.analytics.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.testtags)
testImplementation(projects.features.enterprise.test)
}
@@ -22,6 +22,7 @@ import androidx.compose.runtime.setValue
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import io.element.android.features.enterprise.api.SessionEnterpriseService
import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyPermissions
import io.element.android.features.securityandprivacy.api.securityAndPrivacyPermissions
import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator
@@ -63,6 +64,7 @@ class SecurityAndPrivacyPresenter(
private val matrixClient: MatrixClient,
private val room: JoinedRoom,
private val featureFlagService: FeatureFlagService,
private val sessionEnterpriseService: SessionEnterpriseService,
) : Presenter<SecurityAndPrivacyState> {
@AssistedFactory
interface Factory {
@@ -83,6 +85,10 @@ class SecurityAndPrivacyPresenter(
val homeserverName = remember { matrixClient.userIdServerName() }
val roomInfo by room.roomInfoFlow.collectAsState()
val isEncryptionDisabledByHomeserver by produceState(false) {
value = sessionEnterpriseService.isEncryptionDisabledByHomeserver()
}
val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }
LaunchedEffect(Unit) {
isRoomVisibleInRoomDirectory(savedIsVisibleInRoomDirectory)
@@ -247,6 +253,7 @@ class SecurityAndPrivacyPresenter(
isSpace = roomInfo.isSpace,
selectableJoinedSpaces = selectableJoinedSpaces,
spaceSelectionMode = spaceSelectionMode,
isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver,
eventSink = ::handleEvent,
)
@@ -27,6 +27,7 @@ data class SecurityAndPrivacyState(
// the settings the user wants to apply.
val editedSettings: SecurityAndPrivacySettings,
val homeserverName: String,
val isEncryptionDisabledByHomeserver: Boolean,
val showEnableEncryptionConfirmation: Boolean,
private val isKnockEnabled: Boolean,
val saveAction: AsyncAction<Unit>,
@@ -84,7 +85,7 @@ data class SecurityAndPrivacyState(
editedSettings.roomAccess.canConfigureRoomVisibility()
val showHistoryVisibilitySection = permissions.canChangeHistoryVisibility && !isSpace
val showEncryptionSection = permissions.canChangeEncryption && !isSpace
val showEncryptionSection = !isEncryptionDisabledByHomeserver && permissions.canChangeEncryption && !isSpace
@Composable
fun spaceMemberDescription(): String {
@@ -138,6 +138,7 @@ fun aSecurityAndPrivacyState(
isSpace: Boolean = false,
selectableJoinedSpaces: Set<SpaceRoom> = emptySet(),
spaceSelectionMode: SpaceSelectionMode = SpaceSelectionMode.None,
isEncryptionDisabledByHomeserver: Boolean = false,
eventSink: (SecurityAndPrivacyEvent) -> Unit = {}
) = SecurityAndPrivacyState(
editedSettings = editedSettings,
@@ -150,5 +151,6 @@ fun aSecurityAndPrivacyState(
isSpace = isSpace,
selectableJoinedSpaces = selectableJoinedSpaces.toImmutableSet(),
spaceSelectionMode = spaceSelectionMode,
isEncryptionDisabledByHomeserver = isEncryptionDisabledByHomeserver,
eventSink = eventSink,
)
@@ -2,9 +2,16 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_edit_room_address_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_edit_room_address_title">"Edit alamat"</string>
<string name="screen_manage_authorized_spaces_header">"Ruang di mana anggota dapat bergabung ke ruangan tanpa undangan."</string>
<string name="screen_manage_authorized_spaces_title">"Kelola ruang"</string>
<string name="screen_manage_authorized_spaces_unknown_space">"(Ruang tak dikenal)"</string>
<string name="screen_manage_authorized_spaces_unknown_spaces_section_title">"Ruang lain yang bukan merupakan keanggotaan Anda"</string>
<string name="screen_manage_authorized_spaces_your_spaces_section_title">"Ruang Anda"</string>
<string name="screen_security_and_privacy_add_room_address_action">"Tambahkan alamat"</string>
<string name="screen_security_and_privacy_ask_to_join_multiple_spaces_members_option_description">"Siapa pun yang berada di ruang yang diizinkan dapat bergabung, tetapi semua orang lain harus meminta akses."</string>
<string name="screen_security_and_privacy_ask_to_join_option_description">"Meminta hak akses pada administrator atau moderator."</string>
<string name="screen_security_and_privacy_ask_to_join_option_title">"Ijin bergabung"</string>
<string name="screen_security_and_privacy_ask_to_join_single_space_members_option_description">"Siapa pun di %1$s dapat bergabung, tetapi semua orang lain harus meminta akses."</string>
<string name="screen_security_and_privacy_enable_encryption_alert_confirm_button_title">"Ya, aktifkan enkripsi"</string>
<string name="screen_security_and_privacy_enable_encryption_alert_description">"Setelah diaktifkan, encryption untuk sebuah ruangan tidak dapat dinonaktifkan, Riwayat pesan hanya akan terlihat oleh anggota ruangan sejak mereka diundang atau sejak mereka bergabung dengan ruangan tersebut.
Tidak ada orang lain selain anggota ruangan yang dapat membaca pesan. Hal ini dapat mencegah bot dan jembatan bekerja dengan benar.
@@ -15,20 +22,28 @@ Kami tidak menyarankan untuk mengaktifkan enkripsi untuk ruangan yang dapat dite
<string name="screen_security_and_privacy_encryption_toggle_title">"Aktifkan enkripsi ujung ke ujung"</string>
<string name="screen_security_and_privacy_room_access_anyone_option_description">"Siapa pun dapat menemukan dan bergabung"</string>
<string name="screen_security_and_privacy_room_access_anyone_option_title">"Semua orang"</string>
<string name="screen_security_and_privacy_room_access_footer">"Pilih ruang mana yang anggotanya dapat bergabung ke ruangan ini tanpa undangan. %1$s"</string>
<string name="screen_security_and_privacy_room_access_footer_manage_spaces_action">"Kelola ruang"</string>
<string name="screen_security_and_privacy_room_access_invite_only_option_description">"Orang hanya dapat bergabung jika mereka diundang"</string>
<string name="screen_security_and_privacy_room_access_invite_only_option_title">"Hanya undangan"</string>
<string name="screen_security_and_privacy_room_access_section_header">"Akses ruangan"</string>
<string name="screen_security_and_privacy_room_access_space_members_option_multiple_parents_description">"Siapa pun yang berada di area yang diizinkan dapat bergabung."</string>
<string name="screen_security_and_privacy_room_access_space_members_option_single_parent_description">"Siapa pun di %1$s dapat bergabung."</string>
<string name="screen_security_and_privacy_room_access_space_members_option_title">"Anggota space"</string>
<string name="screen_security_and_privacy_room_access_space_members_option_unavailable_description">"Space saat ini tidak didukung"</string>
<string name="screen_security_and_privacy_room_address_section_footer">"Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan."</string>
<string name="screen_security_and_privacy_room_address_section_header">"Alamat"</string>
<string name="screen_security_and_privacy_room_directory_visibility_section_footer">"Izinkan ruangan ini ditemukan dengan mencari direktori ruangan %1$s publik"</string>
<string name="screen_security_and_privacy_room_directory_visibility_toggle_description">"Izinkan agar dapat ditemukan melalui pencarian di direktori publik."</string>
<string name="screen_security_and_privacy_room_directory_visibility_toggle_title">"Tersedia di direktori publik"</string>
<string name="screen_security_and_privacy_room_history_anyone_option_title">"Siapa saja (riwayat publik)"</string>
<string name="screen_security_and_privacy_room_history_section_footer">"Perubahan tidak akan memengaruhi pesan lama, hanya pesan baru. %1$s"</string>
<string name="screen_security_and_privacy_room_history_section_header">"Siapa yang bisa membaca riwayat"</string>
<string name="screen_security_and_privacy_room_history_since_invite_option_title">"Hanya sejak anggota diundang"</string>
<string name="screen_security_and_privacy_room_history_since_selecting_option_title">"Anggota dapat melihat rekaman percakapan sejak memilih opsi ini"</string>
<string name="screen_security_and_privacy_room_publishing_section_footer">"Alamat ruangan adalah cara untuk menemukan dan mengakses ruangan. Ini juga memastikan Anda dapat dengan mudah berbagi ruangan dengan orang lain. Anda dapat memilih untuk menerbitkan ruangan Anda di direktori ruangan publik homeserver Anda."</string>
<string name="screen_security_and_privacy_room_publishing_section_header">"Penerbitan ruangan"</string>
<string name="screen_security_and_privacy_room_visibility_section_footer">"Alamat adalah cara untuk menemukan dan mengakses ruangan dan ruang. Ini juga memastikan Anda dapat dengan mudah membagikannya dengan orang lain."</string>
<string name="screen_security_and_privacy_room_visibility_section_header">"Visibilitas"</string>
<string name="screen_security_and_privacy_title">"Keamanan &amp; privasi"</string>
</resources>
@@ -8,6 +8,7 @@
package io.element.android.features.securityandprivacy.impl.root
import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
import io.element.android.features.securityandprivacy.impl.FakeSecurityAndPrivacyNavigator
import io.element.android.features.securityandprivacy.impl.SecurityAndPrivacyNavigator
import io.element.android.features.securityandprivacy.impl.manageauthorizedspaces.SpaceSelectionStateHolder
@@ -1046,6 +1047,20 @@ class SecurityAndPrivacyPresenterTest {
}
}
@Test
fun `present - showEncryptionSection is false if the HS disabled encryption`() = runTest {
val sessionEnterpriseService = FakeSessionEnterpriseService(isEncryptionDisabledResult = { true })
val presenter = createSecurityAndPrivacyPresenter(
sessionEnterpriseService = sessionEnterpriseService,
)
presenter.test {
skipItems(1)
// The HS has disabled encryption, so the encryption section should not be shown
assertThat(awaitItem().showEncryptionSection).isFalse()
}
}
private fun roomPermissions(
canChangeRoomAccess: Boolean = true,
canChangeHistoryVisibility: Boolean = true,
@@ -1084,6 +1099,9 @@ class SecurityAndPrivacyPresenterTest {
),
),
spaceSelectionStateHolder: SpaceSelectionStateHolder = SpaceSelectionStateHolder(),
sessionEnterpriseService: FakeSessionEnterpriseService = FakeSessionEnterpriseService(
isEncryptionDisabledResult = { false },
)
): SecurityAndPrivacyPresenter {
return SecurityAndPrivacyPresenter(
room = room,
@@ -1091,6 +1109,7 @@ class SecurityAndPrivacyPresenterTest {
navigator = navigator,
featureFlagService = featureFlagService,
spaceSelectionStateHolder = spaceSelectionStateHolder,
sessionEnterpriseService = sessionEnterpriseService,
)
}
}
@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_leave_space_choose_owners_action">"Pilih Pemilik"</string>
<string name="screen_leave_space_last_admin_info">"%1$s (Admin)"</string>
<plurals name="screen_leave_space_submit">
<item quantity="other">"Tinggalkan ruangan dan ruang %1$d"</item>
</plurals>
<string name="screen_leave_space_subtitle">"Pilih room yang ingin Anda tinggalkan di mana Anda bukan satu-satunya administrator:"</string>
<string name="screen_leave_space_subtitle_last_admin">"Anda perlu menunjuk admin lain untuk ruang ini sebelum Anda dapat keluar."</string>
<string name="screen_leave_space_subtitle_last_owner">"Anda adalah satu-satunya pemilik dari %1$s. Anda harus mengalihkan kepemilikan kepada orang lain sebelum Anda pergi."</string>
<string name="screen_leave_space_subtitle_only_last_admin">"Anda tidak akan dikeluarkan dari ruangan berikut karena Anda adalah satu-satunya administrator:"</string>
<string name="screen_leave_space_title">"Keluar dari %1$s?"</string>
<string name="screen_leave_space_title_last_admin">"Anda adalah satu-satunya admin untuk %1$s"</string>
<string name="screen_leave_space_title_last_owner">"Transfer kepemilikan"</string>
<string name="screen_space_add_room_action">"Ruangan"</string>
<string name="screen_space_add_rooms_room_access_description">"Menambahkan ruangan tidak akan memengaruhi akses ruangan. Untuk mengubah akses, buka Pengaturan ruangan &gt; Keamanan &amp;amp; privasi."</string>
<string name="screen_space_empty_state_title">"Tambahkan ruang pertama Anda"</string>
<string name="screen_space_menu_action_members">"Lihat anggota"</string>
<string name="screen_space_remove_rooms_confirmation_content">"Menghapus ruangan tidak akan memengaruhi akses ruangan. Untuk mengubah akses, buka Info ruangan &gt; Privasi &amp;amp; keamanan."</string>
<plurals name="screen_space_remove_rooms_confirmation_title">
<item quantity="other">"Hapus ruangan %1$d dari %2$s"</item>
</plurals>
<string name="screen_space_settings_leave_space">"Tinggalkan space"</string>
<string name="screen_space_settings_roles_and_permissions">"Peran dan perizinan"</string>
<string name="screen_space_settings_security_and_privacy">"Keamanan &amp; privasi"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Keskustelun aloituksessa tapahtui virhe"</string>
<string name="screen_start_chat_join_room_by_address_action">"Liity huoneeseen osoitteella"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Osoite ei ole kelvollinen"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Kirjoita…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Kirjoita osoite…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Täsmäävä huone löytyi"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Huonetta ei löytynyt"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"esim. #huoneen-nimi:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Došlo je do pogreške prilikom pokretanja razgovora"</string>
<string name="screen_start_chat_join_room_by_address_action">"Pridruži se sobi putem adrese"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Adresa nije valjana"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Unos…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Unesite adresu…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Pronađena je odgovarajuća soba"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Soba nije pronađena"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"npr. #naziv-sobe:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Hiba történt a csevegés indításakor"</string>
<string name="screen_start_chat_join_room_by_address_action">"Csatlakozás a szobához cím szerint"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Nem érvényes cím"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Írja be…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Cím megadása…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Megfelelő szoba található"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Szoba nem található"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"pl. #szoba-neve:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Si è verificato un errore durante il tentativo di avviare una chat"</string>
<string name="screen_start_chat_join_room_by_address_action">"Accedi alla stanza tramite indirizzo"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Indirizzo non valido"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Inserisci…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Inserisci l\'indirizzo…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Stanza trovata"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Stanza non trovata"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"ad esempio #room -name:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"新しい会話を開始する際に問題が発生しました。"</string>
<string name="screen_start_chat_join_room_by_address_action">"アドレスからルームに参加"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"有効なアドレスではありません"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"入力してください…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"アドレスを入力…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"ルームが見つかりました"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"ルームが見つかりません"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"例) #room-name:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Det oppstod en feil når du prøvde å starte en chat"</string>
<string name="screen_start_chat_join_room_by_address_action">"Bli med i rommet med adresse"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Ikke en gyldig adresse"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Gå inn…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Skriv inn adresse…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Matchende rom funnet"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Rom ikke funnet"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"f.eks. #rom-navn:matrix.org"</string>
@@ -5,7 +5,7 @@
<string name="screen_start_chat_error_starting_chat">"Произошла ошибка при попытке начать чат"</string>
<string name="screen_start_chat_join_room_by_address_action">"Присоединиться к комнате по адресу"</string>
<string name="screen_start_chat_join_room_by_address_invalid_address">"Недействительный адрес"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Ввести…"</string>
<string name="screen_start_chat_join_room_by_address_placeholder">"Введите адрес…"</string>
<string name="screen_start_chat_join_room_by_address_room_found">"Комната найдена"</string>
<string name="screen_start_chat_join_room_by_address_room_not_found">"Комната не найдена"</string>
<string name="screen_start_chat_join_room_by_address_supporting_text">"прим. #room-name:matrix.org"</string>
@@ -2,8 +2,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_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>
@@ -2,7 +2,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_identity_confirmation_cannot_confirm">"Kan du ikke bekrefte?"</string>
<string name="screen_identity_confirmation_create_new_recovery_key">"Opprett en ny gjenopprettingsnøkkel"</string>
<string name="screen_identity_confirmation_subtitle">"Verifiser denne enheten for å sette opp sikker meldingsutveksling."</string>
<string name="screen_identity_confirmation_subtitle">"Velg hvordan du vil verifisere deg for å sette opp sikker meldingsutveksling."</string>
<string name="screen_identity_confirmation_title">"Bekreft din digitale identitet"</string>
<string name="screen_identity_confirmation_use_another_device">"Bruk en annen enhet"</string>
<string name="screen_identity_confirmation_use_recovery_key">"Bruk gjenopprettingsnøkkel"</string>
@@ -17,7 +17,7 @@
<string name="screen_session_verification_compare_numbers_subtitle">"Kontroller at tallene nedenfor stemmer overens med dem som vises på den andre sesjonen."</string>
<string name="screen_session_verification_compare_numbers_title">"Sammenlign tallene"</string>
<string name="screen_session_verification_complete_subtitle">"Nå kan du lese eller sende meldinger sikkert på den andre enheten din."</string>
<string name="screen_session_verification_complete_user_subtitle">"Nå kan du stole på identiteten til denne brukeren når du sender eller mottar meldinger."</string>
<string name="screen_session_verification_complete_user_subtitle">"Nå kan du stole på den digitale identiteten til denne brukeren når du sender eller mottar meldinger."</string>
<string name="screen_session_verification_device_verified">"Enhet verifisert"</string>
<string name="screen_session_verification_enter_recovery_key">"Skriv inn gjenopprettingsnøkkel"</string>
<string name="screen_session_verification_failed_subtitle">"Enten ble forespørselen tidsavbrutt, forespørselen ble avslått eller det var en feil i verifiseringen."</string>
+8 -8
View File
@@ -22,7 +22,7 @@ camera = "1.6.1"
work = "2.11.2"
# Compose
compose_bom = "2026.06.00"
compose_bom = "2026.06.01"
# Coroutines
coroutines = "1.11.0"
@@ -32,7 +32,7 @@ accompanist = "0.37.3"
# Test
test_core = "1.7.0"
roborazzi = "1.64.0"
roborazzi = "1.67.0"
# Jetbrain
datetime = "0.8.0"
@@ -175,7 +175,7 @@ test_truth = "com.google.truth:truth:1.4.5"
test_parameter_injector = "com.google.testparameterinjector:test-parameter-injector:1.22"
test_robolectric = "org.robolectric:robolectric:4.16.1"
test_appyx_junit = { module = "com.bumble.appyx:testing-junit4", version.ref = "appyx" }
test_composable_preview_scanner = "io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.0"
test_composable_preview_scanner = "io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.1"
test_detekt_api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" }
test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version.ref = "detekt" }
@@ -185,7 +185,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version
# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
# All new features should not be implemented in the pull request that upgrades the version, developers should
# only fix API breaks and may add some TODOs.
matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.06.30"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.07.15"
# Others
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
@@ -196,7 +196,7 @@ coil_svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil" }
coil_test = { module = "io.coil-kt.coil3:coil-test", version.ref = "coil" }
datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" }
kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.5.0"
kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.5.1"
showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
jsoup = "org.jsoup:jsoup:1.22.2"
@@ -209,7 +209,7 @@ sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", ver
sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
sqlcipher = "net.zetetic:sqlcipher-android:4.16.0"
sqlite = "androidx.sqlite:sqlite-ktx:2.6.2"
sqlite = "androidx.sqlite:sqlite-ktx:2.7.0"
unifiedpush = "org.unifiedpush.android:connector:3.3.3"
vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0"
telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil3", version.ref = "telephoto" }
@@ -220,7 +220,7 @@ maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2"
maplibre_compose = "org.maplibre.compose:maplibre-compose:0.13.0"
maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2"
opusencoder = "io.element.android:opusencoder:1.2.0"
zxing_cpp = "io.github.zxing-cpp:android:3.0.2"
zxing_cpp = "io.github.zxing-cpp:android:3.1.0"
google_zxing = "com.google.zxing:core:3.5.4"
google_guava = "com.google.guava:guava:33.6.0-android"
@@ -230,7 +230,7 @@ color_picker = "io.mhssn:colorpicker:1.0.0"
# Analytics
posthog = "com.posthog:posthog-android:3.51.1"
sentry = "io.sentry:sentry-android:8.46.0"
sentry = "io.sentry:sentry-android:8.47.0"
# main branch can be tested replacing the version with main-SNAPSHOT
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.37.0"
@@ -47,7 +47,7 @@
<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">"%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>
@@ -89,6 +89,8 @@ sealed interface NotificationContent {
val senderId: UserId,
val question: String,
) : MessageLike
data object Beacon : MessageLike
}
sealed interface StateEvent : NotificationContent {
@@ -116,6 +118,7 @@ sealed interface NotificationContent {
data class RoomTopic(val topic: String) : StateEvent
data object SpaceChild : StateEvent
data object SpaceParent : StateEvent
data object BeaconInfo : StateEvent
}
data class Invite(
@@ -71,6 +71,7 @@ private fun StateEventContent.toContent(): NotificationContent.StateEvent {
is StateEventContent.RoomTopic -> NotificationContent.StateEvent.RoomTopic(topic)
StateEventContent.SpaceChild -> NotificationContent.StateEvent.SpaceChild
StateEventContent.SpaceParent -> NotificationContent.StateEvent.SpaceParent
StateEventContent.BeaconInfo -> NotificationContent.StateEvent.BeaconInfo
}
}
@@ -108,6 +109,7 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
)
MessageLikeEventContent.Sticker -> NotificationContent.MessageLike.Sticker
is MessageLikeEventContent.Poll -> NotificationContent.MessageLike.Poll(senderId, question)
MessageLikeEventContent.Beacon -> NotificationContent.MessageLike.Beacon
}
}
}
@@ -90,6 +90,8 @@ class RustMatrixClientTest {
userId = userId,
displayName = A_USER_NAME,
avatarUrl = AN_AVATAR_URL,
status = null,
call = null,
)
},
),

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