Merge branch 'develop' into julioromano/poll_history_entry_point
This commit is contained in:
commit
863d156e4d
738 changed files with 9387 additions and 1581 deletions
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_share_data">"Elemzési adatok megosztása"</string>
|
||||
<string name="screen_analytics_settings_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"%1$s olvashatja el a feltételeinket."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"Itt"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_share_data">"Bagikan data analitik"</string>
|
||||
<string name="screen_analytics_settings_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"di sini"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"Nem rögzítünk vagy profilozunk személyes adatokat"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Anonim használati adatok megosztása a problémák azonosítása érdekében."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"%1$s olvashatja el a feltételeinket."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"Itt"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Ezt bármikor kikapcsolhatja"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"Adatait nem osztjuk meg harmadik felekkel"</string>
|
||||
<string name="screen_analytics_prompt_title">"Segítsen az %1$s fejlesztésében"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"Kami tidak akan merekam atau memprofil data pribadi apa pun"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Bagikan data penggunaan anonim untuk membantu kami mengidentifikasi masalah."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Anda dapat membaca semua persyaratan kami %1$s."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"di sini"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Anda dapat mematikan ini kapan saja"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"Kami tidak akan membagikan data Anda dengan pihak ketiga"</string>
|
||||
<string name="screen_analytics_prompt_title">"Bantu sempurnakan %1$s"</string>
|
||||
</resources>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package io.element.android.features.cachecleaner.impl
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -46,9 +46,9 @@ class DefaultCacheCleanerTest {
|
|||
// Check the files are gone but the sub dirs are not.
|
||||
DefaultCacheCleaner.SUBDIRS_TO_CLEANUP.forEach {
|
||||
File(temporaryFolder.root, it).apply {
|
||||
Truth.assertThat(exists()).isTrue()
|
||||
Truth.assertThat(isDirectory).isTrue()
|
||||
Truth.assertThat(listFiles()).isEmpty()
|
||||
assertThat(exists()).isTrue()
|
||||
assertThat(isDirectory).isTrue()
|
||||
assertThat(listFiles()).isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
features/call/src/main/res/values-hu/translations.xml
Normal file
6
features/call/src/main/res/values-hu/translations.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="call_foreground_service_channel_title_android">"Folyamatban lévő hívás"</string>
|
||||
<string name="call_foreground_service_message_android">"Koppintson a híváshoz való visszatéréshez"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ Hívás folyamatban"</string>
|
||||
</resources>
|
||||
6
features/call/src/main/res/values-in/translations.xml
Normal file
6
features/call/src/main/res/values-in/translations.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="call_foreground_service_channel_title_android">"Panggilan berlangsung"</string>
|
||||
<string name="call_foreground_service_message_android">"Ketuk untuk kembali ke panggilan"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ Panggilan sedang berlangsung"</string>
|
||||
</resources>
|
||||
|
|
@ -39,7 +39,6 @@ class MapWebkitPermissionsTest {
|
|||
@Test
|
||||
fun `given any other permission, it returns nothing`() {
|
||||
val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID))
|
||||
assertThat(permission).isEqualTo(emptyList<String>())
|
||||
assertThat(permission).isEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.api
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
||||
interface StartDMAction {
|
||||
/**
|
||||
* Try to find an existing DM with the given user, or create one if none exists.
|
||||
* @param userId The user to start a DM with.
|
||||
* @param actionState The state to update with the result of the action.
|
||||
*/
|
||||
suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>)
|
||||
}
|
||||
|
|
@ -67,6 +67,7 @@ dependencies {
|
|||
testImplementation(projects.libraries.mediaupload.test)
|
||||
testImplementation(projects.libraries.permissions.test)
|
||||
testImplementation(projects.libraries.usersearch.test)
|
||||
testImplementation(projects.features.createroom.test)
|
||||
testImplementation(projects.tests.testutils)
|
||||
|
||||
ksp(libs.showkase.processor)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.StartDMResult
|
||||
import io.element.android.libraries.matrix.api.room.startDM
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultStartDMAction @Inject constructor(
|
||||
private val matrixClient: MatrixClient,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) : StartDMAction {
|
||||
|
||||
override suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>) {
|
||||
actionState.value = Async.Loading()
|
||||
when (val result = matrixClient.startDM(userId)) {
|
||||
is StartDMResult.Success -> {
|
||||
if (result.isNew) {
|
||||
analyticsService.capture(CreatedRoom(isDM = true))
|
||||
}
|
||||
actionState.value = Async.Success(result.roomId)
|
||||
}
|
||||
is StartDMResult.Failure -> {
|
||||
actionState.value = Async.Failure(result.throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,21 +21,16 @@ import androidx.compose.runtime.MutableState
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.features.createroom.impl.userlist.SelectionMode
|
||||
import io.element.android.features.createroom.impl.userlist.UserListDataStore
|
||||
import io.element.android.features.createroom.impl.userlist.UserListPresenter
|
||||
import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.usersearch.api.UserRepository
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -43,8 +38,7 @@ class CreateRoomRootPresenter @Inject constructor(
|
|||
presenterFactory: UserListPresenter.Factory,
|
||||
userRepository: UserRepository,
|
||||
userListDataStore: UserListDataStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val startDMAction: StartDMAction,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : Presenter<CreateRoomRootState> {
|
||||
|
||||
|
|
@ -61,37 +55,22 @@ class CreateRoomRootPresenter @Inject constructor(
|
|||
val userListState = presenter.present()
|
||||
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
val startDmAction: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
|
||||
val startDmActionState: MutableState<Async<RoomId>> = remember { mutableStateOf(Async.Uninitialized) }
|
||||
|
||||
fun handleEvents(event: CreateRoomRootEvents) {
|
||||
when (event) {
|
||||
is CreateRoomRootEvents.StartDM -> localCoroutineScope.startDm(event.matrixUser, startDmAction)
|
||||
CreateRoomRootEvents.CancelStartDM -> startDmAction.value = Async.Uninitialized
|
||||
is CreateRoomRootEvents.StartDM -> localCoroutineScope.launch {
|
||||
startDMAction.execute(event.matrixUser.userId, startDmActionState)
|
||||
}
|
||||
CreateRoomRootEvents.CancelStartDM -> startDmActionState.value = Async.Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
return CreateRoomRootState(
|
||||
applicationName = buildMeta.applicationName,
|
||||
userListState = userListState,
|
||||
startDmAction = startDmAction.value,
|
||||
startDmAction = startDmActionState.value,
|
||||
eventSink = ::handleEvents,
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.startDm(matrixUser: MatrixUser, startDmAction: MutableState<Async<RoomId>>) = launch {
|
||||
suspend {
|
||||
matrixClient.findDM(matrixUser.userId).use { existingDM ->
|
||||
existingDM?.roomId ?: createDM(matrixUser)
|
||||
}
|
||||
}.runCatchingUpdatingState(startDmAction)
|
||||
}
|
||||
|
||||
private suspend fun createDM(user: MatrixUser): RoomId {
|
||||
return matrixClient
|
||||
.createDM(user.userId)
|
||||
.onSuccess {
|
||||
analyticsService.capture(CreatedRoom(isDM = true))
|
||||
}
|
||||
.getOrThrow()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Új szoba"</string>
|
||||
<string name="screen_create_room_action_invite_people">"Hívja meg ismerőseit az Elementbe"</string>
|
||||
<string name="screen_create_room_add_people_title">"Emberek meghívása"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Hiba történt a szoba létrehozásakor"</string>
|
||||
<string name="screen_create_room_private_option_description">"A szobában lévő üzenetek titkosítottak. A titkosítást utólag nem lehet kikapcsolni."</string>
|
||||
<string name="screen_create_room_private_option_title">"Privát szoba (csak meghívással)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Az üzenetek nincsenek titkosítva, és bárki elolvashatja őket. A titkosítást később is engedélyezheti."</string>
|
||||
<string name="screen_create_room_public_option_title">"Nyilvános szoba (bárki)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Szoba neve"</string>
|
||||
<string name="screen_create_room_topic_label">"Téma (nem kötelező)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Hiba történt a csevegés indításakor"</string>
|
||||
<string name="screen_create_room_title">"Szoba létrehozása"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_room_action_create_room">"Ruangan baru"</string>
|
||||
<string name="screen_create_room_action_invite_people">"Undang teman ke Element"</string>
|
||||
<string name="screen_create_room_add_people_title">"Undang seseorang"</string>
|
||||
<string name="screen_create_room_error_creating_room">"Terjadi kesalahan saat membuat ruangan"</string>
|
||||
<string name="screen_create_room_private_option_description">"Pesan di ruangan ini dienkripsi. Enkripsi tidak dapat dinonaktifkan setelahnya."</string>
|
||||
<string name="screen_create_room_private_option_title">"Ruangan pribadi (hanya undangan)"</string>
|
||||
<string name="screen_create_room_public_option_description">"Pesan tidak dienkripsi dan siapa pun dapat membacanya. Anda dapat mengaktifkan enkripsi di kemudian hari."</string>
|
||||
<string name="screen_create_room_public_option_title">"Ruang publik (siapa saja)"</string>
|
||||
<string name="screen_create_room_room_name_label">"Nama ruangan"</string>
|
||||
<string name="screen_create_room_topic_label">"Topik (opsional)"</string>
|
||||
<string name="screen_start_chat_error_starting_chat">"Terjadi kesalahan saat mencoba memulai obrolan"</string>
|
||||
<string name="screen_create_room_title">"Buat ruangan"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.impl
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultStartDMActionTests {
|
||||
|
||||
@Test
|
||||
fun `when dm is found, assert state is updated with given room id`() = runTest {
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
givenFindDmResult(A_ROOM_ID)
|
||||
}
|
||||
val action = createStartDMAction(matrixClient)
|
||||
val state = mutableStateOf<Async<RoomId>>(Async.Uninitialized)
|
||||
action.execute(A_USER_ID, state)
|
||||
assertThat(state.value).isEqualTo(Async.Success(A_ROOM_ID))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when dm is not found, assert dm is created, state is updated with given room id and analytics get called`() = runTest {
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
givenFindDmResult(null)
|
||||
givenCreateDmResult(Result.success(A_ROOM_ID))
|
||||
}
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val action = createStartDMAction(matrixClient, analyticsService)
|
||||
val state = mutableStateOf<Async<RoomId>>(Async.Uninitialized)
|
||||
action.execute(A_USER_ID, state)
|
||||
assertThat(state.value).isEqualTo(Async.Success(A_ROOM_ID))
|
||||
assertThat(analyticsService.capturedEvents).containsExactly(CreatedRoom(isDM = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when dm creation fails, assert state is updated with given error`() = runTest {
|
||||
val matrixClient = FakeMatrixClient().apply {
|
||||
givenFindDmResult(null)
|
||||
givenCreateDmResult(Result.failure(A_THROWABLE))
|
||||
}
|
||||
val action = createStartDMAction(matrixClient)
|
||||
val state = mutableStateOf<Async<RoomId>>(Async.Uninitialized)
|
||||
action.execute(A_USER_ID, state)
|
||||
assertThat(state.value).isEqualTo(Async.Failure<RoomId>(A_THROWABLE))
|
||||
}
|
||||
|
||||
private fun createStartDMAction(
|
||||
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||
): DefaultStartDMAction {
|
||||
return DefaultStartDMAction(
|
||||
matrixClient = matrixClient,
|
||||
analyticsService = analyticsService,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -20,25 +20,21 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.features.createroom.impl.userlist.FakeUserListPresenter
|
||||
import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory
|
||||
import io.element.android.features.createroom.impl.userlist.UserListDataStore
|
||||
import io.element.android.features.createroom.impl.userlist.aUserListState
|
||||
import io.element.android.features.createroom.test.FakeStartDMAction
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.usersearch.test.FakeUserRepository
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
|
|
@ -47,142 +43,57 @@ class CreateRoomRootPresenterTests {
|
|||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
private lateinit var userRepository: FakeUserRepository
|
||||
private lateinit var presenter: CreateRoomRootPresenter
|
||||
private lateinit var fakeUserListPresenter: FakeUserListPresenter
|
||||
private lateinit var fakeMatrixClient: FakeMatrixClient
|
||||
private lateinit var fakeAnalyticsService: FakeAnalyticsService
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
fakeUserListPresenter = FakeUserListPresenter()
|
||||
fakeMatrixClient = FakeMatrixClient()
|
||||
fakeAnalyticsService = FakeAnalyticsService()
|
||||
userRepository = FakeUserRepository()
|
||||
presenter = CreateRoomRootPresenter(
|
||||
presenterFactory = FakeUserListPresenterFactory(fakeUserListPresenter),
|
||||
userRepository = userRepository,
|
||||
userListDataStore = UserListDataStore(),
|
||||
matrixClient = fakeMatrixClient,
|
||||
analyticsService = fakeAnalyticsService,
|
||||
buildMeta = aBuildMeta(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
fun `present - start DM action complete scenario`() = runTest {
|
||||
val startDMAction = FakeStartDMAction()
|
||||
val presenter = createCreateRoomRootPresenter(startDMAction)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
|
||||
assertThat(initialState.startDmAction).isInstanceOf(Async.Uninitialized::class.java)
|
||||
assertThat(initialState.applicationName).isEqualTo(aBuildMeta().applicationName)
|
||||
assertThat(initialState.userListState.selectedUsers).isEmpty()
|
||||
assertThat(initialState.userListState.isSearchActive).isFalse()
|
||||
assertThat(initialState.userListState.isMultiSelectionEnabled).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger create DM action`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixUser = MatrixUser(UserId("@name:domain"))
|
||||
val createDmResult = Result.success(RoomId("!createDmResult:domain"))
|
||||
|
||||
fakeMatrixClient.givenFindDmResult(null)
|
||||
fakeMatrixClient.givenCreateDmResult(createDmResult)
|
||||
|
||||
initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterStartDM = awaitItem()
|
||||
assertThat(stateAfterStartDM.startDmAction).isInstanceOf(Async.Success::class.java)
|
||||
assertThat(stateAfterStartDM.startDmAction.dataOrNull()).isEqualTo(createDmResult.getOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - creating a DM records analytics event`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixUser = MatrixUser(UserId("@name:domain"))
|
||||
val createDmResult = Result.success(RoomId("!createDmResult:domain"))
|
||||
|
||||
fakeMatrixClient.givenFindDmResult(null)
|
||||
fakeMatrixClient.givenCreateDmResult(createDmResult)
|
||||
|
||||
initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
skipItems(2)
|
||||
|
||||
val analyticsEvent = fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>().firstOrNull()
|
||||
assertThat(analyticsEvent).isNotNull()
|
||||
assertThat(analyticsEvent?.isDM).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger retrieve DM action`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixUser = MatrixUser(UserId("@name:domain"))
|
||||
val fakeDmResult = FakeMatrixRoom(roomId = RoomId("!fakeDmResult:domain"))
|
||||
|
||||
fakeMatrixClient.givenFindDmResult(fakeDmResult)
|
||||
|
||||
initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
val stateAfterStartDM = awaitItem()
|
||||
assertThat(stateAfterStartDM.startDmAction).isInstanceOf(Async.Success::class.java)
|
||||
assertThat(stateAfterStartDM.startDmAction.dataOrNull()).isEqualTo(fakeDmResult.roomId)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - trigger retry create DM action`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixUser = MatrixUser(UserId("@name:domain"))
|
||||
val createDmResult = Result.success(RoomId("!createDmResult:domain"))
|
||||
fakeUserListPresenter.givenState(aUserListState().copy(selectedUsers = persistentListOf(matrixUser)))
|
||||
|
||||
fakeMatrixClient.givenFindDmResult(null)
|
||||
fakeMatrixClient.givenCreateDmError(A_THROWABLE)
|
||||
fakeMatrixClient.givenCreateDmResult(createDmResult)
|
||||
val startDMSuccessResult = Async.Success(A_ROOM_ID)
|
||||
val startDMFailureResult = Async.Failure<RoomId>(A_THROWABLE)
|
||||
|
||||
// Failure
|
||||
startDMAction.givenExecuteResult(startDMFailureResult)
|
||||
initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterStartDM = awaitItem()
|
||||
assertThat(stateAfterStartDM.startDmAction).isInstanceOf(Async.Failure::class.java)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.startDmAction).isEqualTo(startDMFailureResult)
|
||||
state.eventSink(CreateRoomRootEvents.CancelStartDM)
|
||||
}
|
||||
|
||||
// Cancel
|
||||
stateAfterStartDM.eventSink(CreateRoomRootEvents.CancelStartDM)
|
||||
val stateAfterCancel = awaitItem()
|
||||
assertThat(stateAfterCancel.startDmAction).isInstanceOf(Async.Uninitialized::class.java)
|
||||
|
||||
// Failure
|
||||
stateAfterCancel.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
// Success
|
||||
startDMAction.givenExecuteResult(startDMSuccessResult)
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.startDmAction).isEqualTo(Async.Uninitialized)
|
||||
state.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
}
|
||||
assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterSecondAttempt = awaitItem()
|
||||
assertThat(stateAfterSecondAttempt.startDmAction).isInstanceOf(Async.Failure::class.java)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.startDmAction).isEqualTo(startDMSuccessResult)
|
||||
}
|
||||
|
||||
// Retry with success
|
||||
fakeMatrixClient.givenCreateDmError(null)
|
||||
stateAfterSecondAttempt.eventSink(CreateRoomRootEvents.StartDM(matrixUser))
|
||||
assertThat(awaitItem().startDmAction).isInstanceOf(Async.Loading::class.java)
|
||||
val stateAfterRetryStartDM = awaitItem()
|
||||
assertThat(stateAfterRetryStartDM.startDmAction).isInstanceOf(Async.Success::class.java)
|
||||
assertThat(stateAfterRetryStartDM.startDmAction.dataOrNull()).isEqualTo(createDmResult.getOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCreateRoomRootPresenter(
|
||||
startDMAction: StartDMAction = FakeStartDMAction(),
|
||||
): CreateRoomRootPresenter {
|
||||
return CreateRoomRootPresenter(
|
||||
presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()),
|
||||
userRepository = FakeUserRepository(),
|
||||
userListDataStore = UserListDataStore(),
|
||||
startDMAction = startDMAction,
|
||||
buildMeta = aBuildMeta(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
features/createroom/test/build.gradle.kts
Normal file
31
features/createroom/test/build.gradle.kts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.features.createroom.test"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.coroutines.core)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.matrix.test)
|
||||
implementation(projects.libraries.architecture)
|
||||
api(projects.features.createroom.api)
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.createroom.test
|
||||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
class FakeStartDMAction : StartDMAction {
|
||||
|
||||
private var executeResult: Async<RoomId> = Async.Success(A_ROOM_ID)
|
||||
|
||||
fun givenExecuteResult(result: Async<RoomId>) {
|
||||
executeResult = result
|
||||
}
|
||||
|
||||
override suspend fun execute(userId: UserId, actionState: MutableState<Async<RoomId>>) {
|
||||
actionState.value = Async.Loading()
|
||||
delay(1)
|
||||
actionState.value = executeResult
|
||||
}
|
||||
}
|
||||
13
features/ftue/impl/src/main/res/values-hu/translations.xml
Normal file
13
features/ftue/impl/src/main/res/values-hu/translations.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Ez egy egyszeri folyamat, köszönjük a türelmét."</string>
|
||||
<string name="screen_migration_title">"A fiók beállítása."</string>
|
||||
<string name="screen_notification_optin_subtitle">"A beállításokat később is módosíthatja."</string>
|
||||
<string name="screen_notification_optin_title">"Értesítések engedélyezése, hogy soha ne maradjon le egyetlen üzenetről sem"</string>
|
||||
<string name="screen_welcome_bullet_1">"A hívások, szavazások, keresések és egyebek az év további részében kerülnek hozzáadásra."</string>
|
||||
<string name="screen_welcome_bullet_2">"A titkosított szobák üzenetelőzményei nem lesznek elérhetők ebben a frissítésben."</string>
|
||||
<string name="screen_welcome_bullet_3">"Szeretnénk hallani a véleményét, ossza meg velünk a beállítások oldalon."</string>
|
||||
<string name="screen_welcome_button">"Lássunk neki!"</string>
|
||||
<string name="screen_welcome_subtitle">"A következőket kell tudnia:"</string>
|
||||
<string name="screen_welcome_title">"Üdvözli az %1$s!"</string>
|
||||
</resources>
|
||||
13
features/ftue/impl/src/main/res/values-in/translations.xml
Normal file
13
features/ftue/impl/src/main/res/values-in/translations.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_migration_message">"Ini adalah proses satu kali, terima kasih telah menunggu."</string>
|
||||
<string name="screen_migration_title">"Menyiapkan akun Anda."</string>
|
||||
<string name="screen_notification_optin_subtitle">"Anda dapat mengubah pengaturan Anda nanti."</string>
|
||||
<string name="screen_notification_optin_title">"Izinkan pemberitahuan dan jangan pernah melewatkan pesan"</string>
|
||||
<string name="screen_welcome_bullet_1">"Panggilan, pemungutan suara, pencarian, dan lainnya akan ditambahkan di tahun ini."</string>
|
||||
<string name="screen_welcome_bullet_2">"Riwayat pesan untuk ruangan terenkripsi tidak akan tersedia dalam pembaruan ini."</string>
|
||||
<string name="screen_welcome_bullet_3">"Kami ingin mendengar dari Anda, beri tahu kami pendapat Anda melalui halaman pengaturan."</string>
|
||||
<string name="screen_welcome_button">"Ayo!"</string>
|
||||
<string name="screen_welcome_subtitle">"Berikut adalah yang perlu Anda ketahui:"</string>
|
||||
<string name="screen_welcome_title">"Selamat datang di %1$s!"</string>
|
||||
</resources>
|
||||
|
|
@ -20,7 +20,7 @@ import android.os.Build
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
|
||||
|
|
@ -52,7 +52,7 @@ class NotificationsOptInPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.notificationsPermissionState.showDialog).isFalse()
|
||||
assertThat(initialState.notificationsPermissionState.showDialog).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ class NotificationsOptInPresenterTests {
|
|||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(NotificationsOptInEvents.ContinueClicked)
|
||||
Truth.assertThat(awaitItem().notificationsPermissionState.showDialog).isTrue()
|
||||
assertThat(awaitItem().notificationsPermissionState.showDialog).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ class NotificationsOptInPresenterTests {
|
|||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(NotificationsOptInEvents.ContinueClicked)
|
||||
Truth.assertThat(isFinished).isTrue()
|
||||
assertThat(isFinished).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ class NotificationsOptInPresenterTests {
|
|||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(NotificationsOptInEvents.NotNowClicked)
|
||||
Truth.assertThat(isFinished).isTrue()
|
||||
assertThat(isFinished).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ class NotificationsOptInPresenterTests {
|
|||
val isPermissionDenied = runBlocking {
|
||||
permissionStateProvider.isPermissionDenied("notifications").first()
|
||||
}
|
||||
Truth.assertThat(isPermissionDenied).isTrue()
|
||||
assertThat(isPermissionDenied).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ data class InviteListInviteSummary(
|
|||
val isNew: Boolean = false,
|
||||
)
|
||||
|
||||
data class InviteSender constructor(
|
||||
data class InviteSender(
|
||||
val userId: UserId,
|
||||
val displayName: String,
|
||||
val avatarData: AvatarData = AvatarData(userId.value, displayName, size = AvatarSize.InviteSender),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_invites_decline_chat_message">"Biztos, hogy elutasítja a meghívást, hogy csatlakozzon ehhez: %1$s?"</string>
|
||||
<string name="screen_invites_decline_chat_title">"Meghívás elutasítása"</string>
|
||||
<string name="screen_invites_decline_direct_chat_message">"Biztos, hogy elutasítja ezt a privát csevegést vele: %1$s?"</string>
|
||||
<string name="screen_invites_decline_direct_chat_title">"Csevegés elutasítása"</string>
|
||||
<string name="screen_invites_empty_list">"Nincsenek meghívások"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) meghívta"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_invites_decline_chat_message">"Apakah Anda yakin ingin menolak undangan untuk bergabung ke %1$s?"</string>
|
||||
<string name="screen_invites_decline_chat_title">"Tolak undangan"</string>
|
||||
<string name="screen_invites_decline_direct_chat_message">"Apakah Anda yakin ingin menolak obrolan pribadi dengan %1$s?"</string>
|
||||
<string name="screen_invites_decline_direct_chat_title">"Tolak obrolan"</string>
|
||||
<string name="screen_invites_empty_list">"Tidak ada undangan"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) mengundang Anda"</string>
|
||||
</resources>
|
||||
|
|
@ -19,7 +19,7 @@ package io.element.android.features.invitelist.impl
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.invitelist.api.SeenInvitesStore
|
||||
import io.element.android.features.invitelist.test.FakeSeenInvitesStore
|
||||
import io.element.android.libraries.architecture.Async
|
||||
|
|
@ -63,14 +63,14 @@ class InviteListPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.inviteList).isEmpty()
|
||||
assertThat(initialState.inviteList).isEmpty()
|
||||
|
||||
roomListService.postInviteRooms(listOf(aRoomSummary()))
|
||||
|
||||
val withInviteState = awaitItem()
|
||||
Truth.assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomName).isEqualTo(A_ROOM_NAME)
|
||||
assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
assertThat(withInviteState.inviteList[0].roomName).isEqualTo(A_ROOM_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,11 +84,11 @@ class InviteListPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val withInviteState = awaitItem()
|
||||
Truth.assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomAlias).isEqualTo(A_USER_ID.value)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomName).isEqualTo(A_ROOM_NAME)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomAvatarData).isEqualTo(
|
||||
assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
assertThat(withInviteState.inviteList[0].roomAlias).isEqualTo(A_USER_ID.value)
|
||||
assertThat(withInviteState.inviteList[0].roomName).isEqualTo(A_ROOM_NAME)
|
||||
assertThat(withInviteState.inviteList[0].roomAvatarData).isEqualTo(
|
||||
AvatarData(
|
||||
id = A_USER_ID.value,
|
||||
name = A_USER_NAME,
|
||||
|
|
@ -96,7 +96,7 @@ class InviteListPresenterTests {
|
|||
size = AvatarSize.RoomInviteItem,
|
||||
)
|
||||
)
|
||||
Truth.assertThat(withInviteState.inviteList[0].sender).isNull()
|
||||
assertThat(withInviteState.inviteList[0].sender).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,10 +110,10 @@ class InviteListPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val withInviteState = awaitItem()
|
||||
Truth.assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
Truth.assertThat(withInviteState.inviteList[0].sender?.displayName).isEqualTo(A_USER_NAME)
|
||||
Truth.assertThat(withInviteState.inviteList[0].sender?.userId).isEqualTo(A_USER_ID)
|
||||
Truth.assertThat(withInviteState.inviteList[0].sender?.avatarData).isEqualTo(
|
||||
assertThat(withInviteState.inviteList.size).isEqualTo(1)
|
||||
assertThat(withInviteState.inviteList[0].sender?.displayName).isEqualTo(A_USER_NAME)
|
||||
assertThat(withInviteState.inviteList[0].sender?.userId).isEqualTo(A_USER_ID)
|
||||
assertThat(withInviteState.inviteList[0].sender?.avatarData).isEqualTo(
|
||||
AvatarData(
|
||||
id = A_USER_ID.value,
|
||||
name = A_USER_NAME,
|
||||
|
|
@ -142,11 +142,11 @@ class InviteListPresenterTests {
|
|||
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
|
||||
|
||||
val newState = awaitItem()
|
||||
Truth.assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
|
||||
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
|
||||
|
||||
val confirmDialog = newState.declineConfirmationDialog as InviteDeclineConfirmationDialog.Visible
|
||||
Truth.assertThat(confirmDialog.isDirect).isTrue()
|
||||
Truth.assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
|
||||
assertThat(confirmDialog.isDirect).isTrue()
|
||||
assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +163,11 @@ class InviteListPresenterTests {
|
|||
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
|
||||
|
||||
val newState = awaitItem()
|
||||
Truth.assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
|
||||
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
|
||||
|
||||
val confirmDialog = newState.declineConfirmationDialog as InviteDeclineConfirmationDialog.Visible
|
||||
Truth.assertThat(confirmDialog.isDirect).isFalse()
|
||||
Truth.assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
|
||||
assertThat(confirmDialog.isDirect).isFalse()
|
||||
assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ class InviteListPresenterTests {
|
|||
originalState.eventSink(InviteListEvents.CancelDeclineInvite)
|
||||
|
||||
val newState = awaitItem()
|
||||
Truth.assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Hidden::class.java)
|
||||
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Hidden::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ class InviteListPresenterTests {
|
|||
|
||||
skipItems(2)
|
||||
|
||||
Truth.assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ class InviteListPresenterTests {
|
|||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(newState.declinedAction).isEqualTo(Async.Failure<Unit>(ex))
|
||||
assertThat(newState.declinedAction).isEqualTo(Async.Failure<Unit>(ex))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ class InviteListPresenterTests {
|
|||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(newState.declinedAction).isEqualTo(Async.Uninitialized)
|
||||
assertThat(newState.declinedAction).isEqualTo(Async.Uninitialized)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,8 +300,8 @@ class InviteListPresenterTests {
|
|||
|
||||
val newState = awaitItem()
|
||||
|
||||
Truth.assertThat(newState.acceptedAction).isEqualTo(Async.Success(A_ROOM_ID))
|
||||
Truth.assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
assertThat(newState.acceptedAction).isEqualTo(Async.Success(A_ROOM_ID))
|
||||
assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ class InviteListPresenterTests {
|
|||
val originalState = awaitItem()
|
||||
originalState.eventSink(InviteListEvents.AcceptInvite(originalState.inviteList[0]))
|
||||
|
||||
Truth.assertThat(awaitItem().acceptedAction).isEqualTo(Async.Failure<RoomId>(ex))
|
||||
assertThat(awaitItem().acceptedAction).isEqualTo(Async.Failure<RoomId>(ex))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ class InviteListPresenterTests {
|
|||
originalState.eventSink(InviteListEvents.DismissAcceptError)
|
||||
|
||||
val newState = awaitItem()
|
||||
Truth.assertThat(newState.acceptedAction).isEqualTo(Async.Uninitialized)
|
||||
assertThat(newState.acceptedAction).isEqualTo(Async.Uninitialized)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,19 +375,19 @@ class InviteListPresenterTests {
|
|||
roomListService.postInviteRooms(listOf(aRoomSummary()))
|
||||
|
||||
awaitItem()
|
||||
Truth.assertThat(store.getProvidedRoomIds()).isEqualTo(setOf(A_ROOM_ID))
|
||||
assertThat(store.getProvidedRoomIds()).isEqualTo(setOf(A_ROOM_ID))
|
||||
|
||||
// When a second is added, both are saved
|
||||
roomListService.postInviteRooms(listOf(aRoomSummary(), aRoomSummary(A_ROOM_ID_2)))
|
||||
|
||||
awaitItem()
|
||||
Truth.assertThat(store.getProvidedRoomIds()).isEqualTo(setOf(A_ROOM_ID, A_ROOM_ID_2))
|
||||
assertThat(store.getProvidedRoomIds()).isEqualTo(setOf(A_ROOM_ID, A_ROOM_ID_2))
|
||||
|
||||
// When they're both dismissed, an empty set is saved
|
||||
roomListService.postInviteRooms(listOf())
|
||||
|
||||
awaitItem()
|
||||
Truth.assertThat(store.getProvidedRoomIds()).isEmpty()
|
||||
assertThat(store.getProvidedRoomIds()).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -413,11 +413,11 @@ class InviteListPresenterTests {
|
|||
skipItems(1)
|
||||
|
||||
val withInviteState = awaitItem()
|
||||
Truth.assertThat(withInviteState.inviteList.size).isEqualTo(2)
|
||||
Truth.assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
Truth.assertThat(withInviteState.inviteList[0].isNew).isFalse()
|
||||
Truth.assertThat(withInviteState.inviteList[1].roomId).isEqualTo(A_ROOM_ID_2)
|
||||
Truth.assertThat(withInviteState.inviteList[1].isNew).isTrue()
|
||||
assertThat(withInviteState.inviteList.size).isEqualTo(2)
|
||||
assertThat(withInviteState.inviteList[0].roomId).isEqualTo(A_ROOM_ID)
|
||||
assertThat(withInviteState.inviteList[0].isNew).isFalse()
|
||||
assertThat(withInviteState.inviteList[1].roomId).isEqualTo(A_ROOM_ID_2)
|
||||
assertThat(withInviteState.inviteList[1].isNew).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_room_alert_empty_subtitle">"Biztos, hogy elhagyja ezt a szobát? Ön az egyedüli ember itt. Ha kilép, akkor senki sem fog tudni csatlakozni a jövőben, Önt is beleértve."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Biztos, hogy elhagyja ezt a szobát? Ez a szoba nem nyilvános, és meghívó nélkül nem fog tudni újra belépni."</string>
|
||||
<string name="leave_room_alert_subtitle">"Biztos, hogy elhagyja a szobát?"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="leave_room_alert_empty_subtitle">"Apakah Anda yakin ingin meninggalkan ruangan ini? Anda adalah orang satu-satunya di sini. Jika Anda pergi, tidak akan ada yang bisa bergabung di masa depan, termasuk Anda."</string>
|
||||
<string name="leave_room_alert_private_subtitle">"Apakah Anda yakin ingin meninggalkan ruangan ini? Ruangan ini tidak umum dan Anda tidak akan dapat bergabung kembali tanpa undangan."</string>
|
||||
<string name="leave_room_alert_subtitle">"Apakah Anda yakin ingin meninggalkan ruangan?"</string>
|
||||
</resources>
|
||||
|
|
@ -19,7 +19,7 @@ package io.element.android.features.location.impl.send
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.impl.aPermissionsState
|
||||
|
|
@ -77,16 +77,16 @@ class SendLocationPresenterTest {
|
|||
}.test {
|
||||
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(true)
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
assertThat(initialState.hasLocationPermission).isTrue()
|
||||
|
||||
// Swipe the map to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToPinLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(true)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,16 +104,16 @@ class SendLocationPresenterTest {
|
|||
}.test {
|
||||
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(true)
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.SenderLocation)
|
||||
assertThat(initialState.hasLocationPermission).isTrue()
|
||||
|
||||
// Swipe the map to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToPinLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(true)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,16 +130,16 @@ class SendLocationPresenterTest {
|
|||
sendLocationPresenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(initialState.hasLocationPermission).isFalse()
|
||||
|
||||
// Click on the button to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToMyLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionDenied)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionDenied)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,16 +156,16 @@ class SendLocationPresenterTest {
|
|||
sendLocationPresenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(initialState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(initialState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(initialState.hasLocationPermission).isFalse()
|
||||
|
||||
// Click on the button to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToMyLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,16 +187,16 @@ class SendLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToMyLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Dismiss the dialog
|
||||
myLocationState.eventSink(SendLocationEvents.DismissDialog)
|
||||
val dialogDismissedState = awaitItem()
|
||||
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(dialogDismissedState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(dialogDismissedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(dialogDismissedState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(dialogDismissedState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,13 +218,13 @@ class SendLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToMyLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionRationale)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Continue the dialog sends permission request to the permissions presenter
|
||||
myLocationState.eventSink(SendLocationEvents.RequestPermissions)
|
||||
Truth.assertThat(permissionsPresenterFake.events.last()).isEqualTo(PermissionsEvents.RequestPermissions)
|
||||
assertThat(permissionsPresenterFake.events.last()).isEqualTo(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,16 +246,16 @@ class SendLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(SendLocationEvents.SwitchToMyLocationMode)
|
||||
val myLocationState = awaitItem()
|
||||
Truth.assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionDenied)
|
||||
Truth.assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(myLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(myLocationState.permissionDialog).isEqualTo(SendLocationState.Dialog.PermissionDenied)
|
||||
assertThat(myLocationState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(myLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Dismiss the dialog
|
||||
myLocationState.eventSink(SendLocationEvents.DismissDialog)
|
||||
val dialogDismissedState = awaitItem()
|
||||
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(dialogDismissedState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(dialogDismissedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(dialogDismissedState.mode).isEqualTo(SendLocationState.Mode.PinLocation)
|
||||
assertThat(dialogDismissedState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -292,8 +292,8 @@ class SendLocationPresenterTest {
|
|||
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
|
||||
Truth.assertThat(fakeMatrixRoom.sentLocations.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeMatrixRoom.sentLocations.last()).isEqualTo(
|
||||
assertThat(fakeMatrixRoom.sentLocations.size).isEqualTo(1)
|
||||
assertThat(fakeMatrixRoom.sentLocations.last()).isEqualTo(
|
||||
SendLocationInvocation(
|
||||
body = "Location was shared at geo:3.0,4.0;u=5.0",
|
||||
geoUri = "geo:3.0,4.0;u=5.0",
|
||||
|
|
@ -303,8 +303,8 @@ class SendLocationPresenterTest {
|
|||
)
|
||||
)
|
||||
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
Composer(
|
||||
inThread = false,
|
||||
isEditing = false,
|
||||
|
|
@ -348,8 +348,8 @@ class SendLocationPresenterTest {
|
|||
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
|
||||
Truth.assertThat(fakeMatrixRoom.sentLocations.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeMatrixRoom.sentLocations.last()).isEqualTo(
|
||||
assertThat(fakeMatrixRoom.sentLocations.size).isEqualTo(1)
|
||||
assertThat(fakeMatrixRoom.sentLocations.last()).isEqualTo(
|
||||
SendLocationInvocation(
|
||||
body = "Location was shared at geo:0.0,1.0",
|
||||
geoUri = "geo:0.0,1.0",
|
||||
|
|
@ -359,8 +359,8 @@ class SendLocationPresenterTest {
|
|||
)
|
||||
)
|
||||
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
Composer(
|
||||
inThread = false,
|
||||
isEditing = false,
|
||||
|
|
@ -405,8 +405,8 @@ class SendLocationPresenterTest {
|
|||
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(1)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.last()).isEqualTo(
|
||||
Composer(
|
||||
inThread = false,
|
||||
isEditing = true,
|
||||
|
|
@ -444,8 +444,8 @@ class SendLocationPresenterTest {
|
|||
dialogShownState.eventSink(SendLocationEvents.OpenAppSettings)
|
||||
val settingsOpenedState = awaitItem()
|
||||
|
||||
Truth.assertThat(settingsOpenedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
Truth.assertThat(fakeLocationActions.openSettingsInvocationsCount).isEqualTo(1)
|
||||
assertThat(settingsOpenedState.permissionDialog).isEqualTo(SendLocationState.Dialog.None)
|
||||
assertThat(fakeLocationActions.openSettingsInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -455,7 +455,7 @@ class SendLocationPresenterTest {
|
|||
sendLocationPresenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.appName).isEqualTo("app name")
|
||||
assertThat(initialState.appName).isEqualTo("app name")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package io.element.android.features.location.impl.show
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.location.api.Location
|
||||
import io.element.android.features.location.impl.aPermissionsState
|
||||
import io.element.android.features.location.impl.common.actions.FakeLocationActions
|
||||
|
|
@ -66,10 +66,10 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.location).isEqualTo(location)
|
||||
Truth.assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(false)
|
||||
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false)
|
||||
assertThat(initialState.location).isEqualTo(location)
|
||||
assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
assertThat(initialState.hasLocationPermission).isFalse()
|
||||
assertThat(initialState.isTrackMyLocation).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,10 +86,10 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.location).isEqualTo(location)
|
||||
Truth.assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(false)
|
||||
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false)
|
||||
assertThat(initialState.location).isEqualTo(location)
|
||||
assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
assertThat(initialState.hasLocationPermission).isFalse()
|
||||
assertThat(initialState.isTrackMyLocation).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,10 +101,10 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.location).isEqualTo(location)
|
||||
Truth.assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(true)
|
||||
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false)
|
||||
assertThat(initialState.location).isEqualTo(location)
|
||||
assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
assertThat(initialState.hasLocationPermission).isTrue()
|
||||
assertThat(initialState.isTrackMyLocation).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,10 +116,10 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.location).isEqualTo(location)
|
||||
Truth.assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(true)
|
||||
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false)
|
||||
assertThat(initialState.location).isEqualTo(location)
|
||||
assertThat(initialState.description).isEqualTo(A_DESCRIPTION)
|
||||
assertThat(initialState.hasLocationPermission).isTrue()
|
||||
assertThat(initialState.isTrackMyLocation).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,8 +131,8 @@ class ShowLocationPresenterTest {
|
|||
val initialState = awaitItem()
|
||||
initialState.eventSink(ShowLocationEvents.Share)
|
||||
|
||||
Truth.assertThat(fakeLocationActions.sharedLocation).isEqualTo(location)
|
||||
Truth.assertThat(fakeLocationActions.sharedLabel).isEqualTo(A_DESCRIPTION)
|
||||
assertThat(fakeLocationActions.sharedLocation).isEqualTo(location)
|
||||
assertThat(fakeLocationActions.sharedLabel).isEqualTo(A_DESCRIPTION)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,23 +144,23 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.hasLocationPermission).isEqualTo(true)
|
||||
Truth.assertThat(initialState.isTrackMyLocation).isEqualTo(false)
|
||||
assertThat(initialState.hasLocationPermission).isTrue()
|
||||
assertThat(initialState.isTrackMyLocation).isFalse()
|
||||
|
||||
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true))
|
||||
val trackMyLocationState = awaitItem()
|
||||
|
||||
delay(1)
|
||||
|
||||
Truth.assertThat(trackMyLocationState.hasLocationPermission).isEqualTo(true)
|
||||
Truth.assertThat(trackMyLocationState.isTrackMyLocation).isEqualTo(true)
|
||||
assertThat(trackMyLocationState.hasLocationPermission).isTrue()
|
||||
assertThat(trackMyLocationState.isTrackMyLocation).isTrue()
|
||||
|
||||
// Swipe the map to switch mode
|
||||
initialState.eventSink(ShowLocationEvents.TrackMyLocation(false))
|
||||
val trackLocationDisabledState = awaitItem()
|
||||
Truth.assertThat(trackLocationDisabledState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
Truth.assertThat(trackLocationDisabledState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(trackLocationDisabledState.hasLocationPermission).isEqualTo(true)
|
||||
assertThat(trackLocationDisabledState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
assertThat(trackLocationDisabledState.isTrackMyLocation).isFalse()
|
||||
assertThat(trackLocationDisabledState.hasLocationPermission).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,16 +182,16 @@ class ShowLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true))
|
||||
val trackLocationState = awaitItem()
|
||||
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale)
|
||||
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale)
|
||||
assertThat(trackLocationState.isTrackMyLocation).isFalse()
|
||||
assertThat(trackLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Dismiss the dialog
|
||||
initialState.eventSink(ShowLocationEvents.DismissDialog)
|
||||
val dialogDismissedState = awaitItem()
|
||||
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
Truth.assertThat(dialogDismissedState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
assertThat(dialogDismissedState.isTrackMyLocation).isFalse()
|
||||
assertThat(dialogDismissedState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,13 +213,13 @@ class ShowLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true))
|
||||
val trackLocationState = awaitItem()
|
||||
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale)
|
||||
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionRationale)
|
||||
assertThat(trackLocationState.isTrackMyLocation).isFalse()
|
||||
assertThat(trackLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Continue the dialog sends permission request to the permissions presenter
|
||||
trackLocationState.eventSink(ShowLocationEvents.RequestPermissions)
|
||||
Truth.assertThat(permissionsPresenterFake.events.last()).isEqualTo(PermissionsEvents.RequestPermissions)
|
||||
assertThat(permissionsPresenterFake.events.last()).isEqualTo(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,16 +241,16 @@ class ShowLocationPresenterTest {
|
|||
// Click on the button to switch mode
|
||||
initialState.eventSink(ShowLocationEvents.TrackMyLocation(true))
|
||||
val trackLocationState = awaitItem()
|
||||
Truth.assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionDenied)
|
||||
Truth.assertThat(trackLocationState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(trackLocationState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(trackLocationState.permissionDialog).isEqualTo(ShowLocationState.Dialog.PermissionDenied)
|
||||
assertThat(trackLocationState.isTrackMyLocation).isFalse()
|
||||
assertThat(trackLocationState.hasLocationPermission).isFalse()
|
||||
|
||||
// Dismiss the dialog
|
||||
initialState.eventSink(ShowLocationEvents.DismissDialog)
|
||||
val dialogDismissedState = awaitItem()
|
||||
Truth.assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
Truth.assertThat(dialogDismissedState.isTrackMyLocation).isEqualTo(false)
|
||||
Truth.assertThat(dialogDismissedState.hasLocationPermission).isEqualTo(false)
|
||||
assertThat(dialogDismissedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
assertThat(dialogDismissedState.isTrackMyLocation).isFalse()
|
||||
assertThat(dialogDismissedState.hasLocationPermission).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,8 +276,8 @@ class ShowLocationPresenterTest {
|
|||
dialogShownState.eventSink(ShowLocationEvents.OpenAppSettings)
|
||||
val settingsOpenedState = awaitItem()
|
||||
|
||||
Truth.assertThat(settingsOpenedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
Truth.assertThat(fakeLocationActions.openSettingsInvocationsCount).isEqualTo(1)
|
||||
assertThat(settingsOpenedState.permissionDialog).isEqualTo(ShowLocationState.Dialog.None)
|
||||
assertThat(fakeLocationActions.openSettingsInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ class ShowLocationPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.appName).isEqualTo("app name")
|
||||
assertThat(initialState.appName).isEqualTo("app name")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<plurals name="screen_app_lock_subtitle">
|
||||
<item quantity="one">"Du hast %1$d Versuch zu entsperren"</item>
|
||||
<item quantity="other">"Du hast %1$d Versuche zum Entsperren"</item>
|
||||
</plurals>
|
||||
<plurals name="screen_app_lock_subtitle_wrong_pin">
|
||||
<item quantity="one">"Falsche PIN. Du hast %1$d weitere Chance"</item>
|
||||
<item quantity="other">"Falsche PIN. Du hast %1$d weitere Chancen"</item>
|
||||
</plurals>
|
||||
<string name="screen_app_lock_biometric_authentication">"biometrische Authentifizierung"</string>
|
||||
<string name="screen_app_lock_biometric_unlock">"biometrisches Entsperren"</string>
|
||||
<string name="screen_app_lock_biometric_unlock_title_android">"Mit Biometrie entsperren"</string>
|
||||
<string name="screen_app_lock_forgot_pin">"PIN vergessen?"</string>
|
||||
<string name="screen_app_lock_settings_change_pin">"PIN-Code ändern"</string>
|
||||
<string name="screen_app_lock_settings_enable_biometric_unlock">"Biometrisches Entsperren zulassen"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin">"Pin entfernen"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_message">"Bist du sicher, dass du die PIN entfernen willst?"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_title">"PIN entfernen?"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_allow_title">"%1$s zulassen"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_skip">"Ich verwende lieber die PIN"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Spare dir etwas Zeit und benutze %1$s, um die App jedes Mal zu entsperren"</string>
|
||||
<string name="screen_app_lock_setup_choose_pin">"PIN wählen"</string>
|
||||
<string name="screen_app_lock_setup_confirm_pin">"PIN bestätigen"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Aus Sicherheitsgründen kannst du das nicht als deinen PIN-Code wählen"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Wähle eine andere PIN"</string>
|
||||
<string name="screen_app_lock_setup_pin_context">"Sperre %1$s, um deine Chats noch sicherer zu machen.
|
||||
|
||||
Wähle etwas Einprägsames. Wenn du diese PIN vergisst, wirst du aus der App ausgeloggt."</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Bitte gib die gleiche PIN zweimal ein"</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"Die PINs stimmen nicht überein"</string>
|
||||
<string name="screen_app_lock_signout_alert_message">"Um fortzufahren, musst du dich erneut anmelden und eine neue PIN erstellen"</string>
|
||||
<string name="screen_app_lock_signout_alert_title">"Du wirst abgemeldet"</string>
|
||||
<string name="screen_app_lock_use_biometric_android">"Biometrie verwenden"</string>
|
||||
<string name="screen_app_lock_use_pin_android">"PIN verwenden"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Abmelden…"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<plurals name="screen_app_lock_subtitle">
|
||||
<item quantity="one">"%1$d próbálkozása van a feloldáshoz"</item>
|
||||
<item quantity="other">"%1$d próbálkozása van a feloldáshoz"</item>
|
||||
</plurals>
|
||||
<plurals name="screen_app_lock_subtitle_wrong_pin">
|
||||
<item quantity="one">"Hibás PIN-kód. Még %1$d próbálkozási lehetősége maradt."</item>
|
||||
<item quantity="other">"Hibás PIN-kód. Még %1$d próbálkozási lehetősége maradt."</item>
|
||||
</plurals>
|
||||
<string name="screen_app_lock_biometric_authentication">"biometrikus hitelesítés"</string>
|
||||
<string name="screen_app_lock_biometric_unlock">"biometrikus feloldás"</string>
|
||||
<string name="screen_app_lock_biometric_unlock_title_android">"Feloldás biometrikus adatokkal"</string>
|
||||
<string name="screen_app_lock_forgot_pin">"Elfelejtette a PIN-kódot?"</string>
|
||||
<string name="screen_app_lock_settings_change_pin">"PIN-kód módosítása"</string>
|
||||
<string name="screen_app_lock_settings_enable_biometric_unlock">"Biometrikus feloldás engedélyezése"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin">"PIN-kód eltávolítása"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_message">"Biztos, hogy eltávolítja a PIN-kódot?"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_title">"PIN-kód eltávolítása?"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_allow_title">"A %1$s engedélyezése"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_skip">"Inkább PIN-kód használata"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Spóroljon meg némi időt, és használja a %1$st az alkalmazás feloldásához"</string>
|
||||
<string name="screen_app_lock_setup_choose_pin">"PIN-kód kiválasztása"</string>
|
||||
<string name="screen_app_lock_setup_confirm_pin">"PIN-kód megerősítése"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Ezt biztonsági okokból nem választhatja PIN-kódként"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Válasszon egy másik PIN-kódot"</string>
|
||||
<string name="screen_app_lock_setup_pin_context">"Az %1$s zárolása a csevegései nagyobb biztonsága érdekében.
|
||||
|
||||
Válasszon valami megjegyezhetőt. Ha elfelejti a PIN-kódot, akkor ki lesz jelentkeztetve az alkalmazásból."</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Adja meg a PIN-kódját kétszer"</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"A PIN-kódok nem egyeznek"</string>
|
||||
<string name="screen_app_lock_signout_alert_message">"A folytatáshoz újra be kell jelentkeznie, és létre kell hoznia egy új PIN-kódot"</string>
|
||||
<string name="screen_app_lock_signout_alert_title">"Kijelentkeztetésre kerül"</string>
|
||||
<string name="screen_app_lock_use_biometric_android">"Biometrikus adatok használata"</string>
|
||||
<string name="screen_app_lock_use_pin_android">"PIN-kód használata"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Kijelentkezés…"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<plurals name="screen_app_lock_subtitle">
|
||||
<item quantity="other">"Anda memiliki %1$d percobaan lagi untuk membuka kunci"</item>
|
||||
</plurals>
|
||||
<plurals name="screen_app_lock_subtitle_wrong_pin">
|
||||
<item quantity="other">"PIN salah. Anda memiliki %1$d percobaan lagi"</item>
|
||||
</plurals>
|
||||
<string name="screen_app_lock_biometric_authentication">"autentikasi biometrik"</string>
|
||||
<string name="screen_app_lock_biometric_unlock">"pembukaan biometrik"</string>
|
||||
<string name="screen_app_lock_biometric_unlock_title_android">"Buka kunci dengan biometrik"</string>
|
||||
<string name="screen_app_lock_forgot_pin">"Lupa PIN?"</string>
|
||||
<string name="screen_app_lock_settings_change_pin">"Ubah kode PIN"</string>
|
||||
<string name="screen_app_lock_settings_enable_biometric_unlock">"Perbolehkan pembukaan biometrik"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin">"Hapus PIN"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_message">"Apakah Anda yakin ingin menghapus PIN?"</string>
|
||||
<string name="screen_app_lock_settings_remove_pin_alert_title">"Hapus PIN?"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_allow_title">"Perbolehkan %1$s"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_skip">"Saya lebih suka menggunakan PIN"</string>
|
||||
<string name="screen_app_lock_setup_biometric_unlock_subtitle">"Hemat waktu Anda dan gunakan %1$s untuk membuka kunci aplikasi setiap kalinya"</string>
|
||||
<string name="screen_app_lock_setup_choose_pin">"Pilih PIN"</string>
|
||||
<string name="screen_app_lock_setup_confirm_pin">"Konfirmasi PIN"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_content">"Anda tidak dapat memilih PIN ini demi keamanan"</string>
|
||||
<string name="screen_app_lock_setup_pin_blacklisted_dialog_title">"Pilih PIN yang lain"</string>
|
||||
<string name="screen_app_lock_setup_pin_context">"Kunci %1$s untuk menambahkan keamanan tambahan pada percakapan Anda.
|
||||
|
||||
Pilih sesuatu yang mudah untuk diingat. Jika Anda lupa PIN ini, Anda akan dikeluarkan dari aplikasi."</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_content">"Silakan masukkan PIN yang sama dua kali"</string>
|
||||
<string name="screen_app_lock_setup_pin_mismatch_dialog_title">"PIN tidak cocok"</string>
|
||||
<string name="screen_app_lock_signout_alert_message">"Anda harus masuk ulang dan membuat PIN baru untuk melanjutkan"</string>
|
||||
<string name="screen_app_lock_signout_alert_title">"Anda sedang dikeluarkan"</string>
|
||||
<string name="screen_app_lock_use_biometric_android">"Gunakan biometrik"</string>
|
||||
<string name="screen_app_lock_use_pin_android">"Gunakan PIN"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Mengeluarkan dari akun…"</string>
|
||||
</resources>
|
||||
|
|
@ -94,8 +94,8 @@ class PinUnlockPresenterTest {
|
|||
}
|
||||
awaitLastSequentialItem().also { state ->
|
||||
assertThat(state.remainingAttempts.dataOrNull()).isEqualTo(0)
|
||||
assertThat(state.showSignOutPrompt).isEqualTo(true)
|
||||
assertThat(state.isSignOutPromptCancellable).isEqualTo(false)
|
||||
assertThat(state.showSignOutPrompt).isTrue()
|
||||
assertThat(state.isSignOutPromptCancellable).isFalse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,16 +112,16 @@ class PinUnlockPresenterTest {
|
|||
state.eventSink(PinUnlockEvents.OnForgetPin)
|
||||
}
|
||||
awaitLastSequentialItem().also { state ->
|
||||
assertThat(state.showSignOutPrompt).isEqualTo(true)
|
||||
assertThat(state.isSignOutPromptCancellable).isEqualTo(true)
|
||||
assertThat(state.showSignOutPrompt).isTrue()
|
||||
assertThat(state.isSignOutPromptCancellable).isTrue()
|
||||
state.eventSink(PinUnlockEvents.ClearSignOutPrompt)
|
||||
}
|
||||
awaitLastSequentialItem().also { state ->
|
||||
assertThat(state.showSignOutPrompt).isEqualTo(false)
|
||||
assertThat(state.showSignOutPrompt).isFalse()
|
||||
state.eventSink(PinUnlockEvents.OnForgetPin)
|
||||
}
|
||||
awaitLastSequentialItem().also { state ->
|
||||
assertThat(state.showSignOutPrompt).isEqualTo(true)
|
||||
assertThat(state.showSignOutPrompt).isTrue()
|
||||
state.eventSink(PinUnlockEvents.SignOut)
|
||||
}
|
||||
consumeItemsUntilPredicate { state ->
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package io.element.android.features.login.impl.resolver
|
||||
|
||||
data class HomeserverData constructor(
|
||||
data class HomeserverData(
|
||||
// The computed homeserver url, for which a wellknown file has been retrieved, or just a valid Url
|
||||
val homeserverUrl: String,
|
||||
// True if a wellknown file has been found and is valid. If false, it means that the [homeserverUrl] is valid
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<string name="screen_change_server_form_header">"Homeserver-URL"</string>
|
||||
<string name="screen_change_server_form_notice">"Du kannst nur eine Verbindung zu einem vorhandenen Server herstellen, der Sliding Sync unterstützt. Dein Homeserver-Administrator muss das konfigurieren. %1$s"</string>
|
||||
<string name="screen_change_server_subtitle">"Wie lautet die Adresse deines Servers?"</string>
|
||||
<string name="screen_change_server_title">"Wähle deinen Server aus"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Dieses Konto wurde deaktiviert."</string>
|
||||
<string name="screen_login_error_invalid_credentials">"Falscher Benutzername und/oder Passwort"</string>
|
||||
<string name="screen_login_error_invalid_user_id">"Dies ist keine gültige Benutzerkennung. Erwartetes Format: \'@user:homeserver.org\'"</string>
|
||||
|
|
|
|||
42
features/login/impl/src/main/res/values-hu/translations.xml
Normal file
42
features/login/impl/src/main/res/values-hu/translations.xml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_account_provider_change">"Fiókszolgáltató módosítása"</string>
|
||||
<string name="screen_account_provider_form_hint">"Matrix-kiszolgáló webcíme"</string>
|
||||
<string name="screen_account_provider_form_notice">"Adjon meg egy keresési kifejezést vagy egy tartománycímet."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Keresés egy cégre, közösségre vagy privát kiszolgálóra."</string>
|
||||
<string name="screen_account_provider_form_title">"Fiókszolgáltató keresése"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_account_provider_signin_title">"Hamarosan bejelentkezik ide: %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_account_provider_signup_title">"Hamarosan létrehoz egy fiókot itt: %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"A Matrix.org egy nagy, ingyenes kiszolgáló a nyilvános Matrix-hálózaton, a biztonságos, decentralizált kommunikáció érdekében, amelyet a Matrix.org Alapítvány üzemeltet."</string>
|
||||
<string name="screen_change_account_provider_other">"Egyéb"</string>
|
||||
<string name="screen_change_account_provider_subtitle">"Másik fiókszolgáltató, például a saját privát kiszolgáló vagy egy munkahelyi fiók használata."</string>
|
||||
<string name="screen_change_account_provider_title">"Fiókszolgáltató módosítása"</string>
|
||||
<string name="screen_change_server_error_invalid_homeserver">"Nem sikerült elérni ezt a Matrix-kiszolgálót. Ellenőrizze, hogy helyesen adta-e meg a Matrix-kiszolgáló webcímét. Ha a webcím helyes, akkor további segítségért lépjen kapcsolatba a Matrix-kiszolgáló rendszergazdájával."</string>
|
||||
<string name="screen_change_server_error_no_sliding_sync_message">"A kiszolgáló jelenleg nem támogatja a Sliding sync protokollt."</string>
|
||||
<string name="screen_change_server_form_header">"Matrix-kiszolgáló webcíme"</string>
|
||||
<string name="screen_change_server_form_notice">"Csak olyan meglévő kiszolgálóhoz csatlakozhat, amely támogatja a Sliding sync protokollt. Ezt a Matrix-kiszolgáló rendszergazdájának kell beállítania. %1$s"</string>
|
||||
<string name="screen_change_server_subtitle">"Mi a kiszolgálója címe?"</string>
|
||||
<string name="screen_change_server_title">"Válassza ki a kiszolgálóját"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Ez a fiók deaktiválva lett."</string>
|
||||
<string name="screen_login_error_invalid_credentials">"Helytelen felhasználónév vagy jelszó"</string>
|
||||
<string name="screen_login_error_invalid_user_id">"Ez nem érvényes felhasználóazonosító. A várt formátum: „@user:homeserver.org”"</string>
|
||||
<string name="screen_login_error_unsupported_authentication">"A kiválasztott Matrix-kiszolgáló nem támogatja a jelszavas vagy OIDC-alapú bejelentkezést. Lépjen kapcsolatba a kiszolgáló rendszergazdájával, vagy válasszon másik Matrix-kiszolgálót."</string>
|
||||
<string name="screen_login_form_header">"Adja meg adatait"</string>
|
||||
<string name="screen_login_title">"Örülünk, hogy visszatért!"</string>
|
||||
<string name="screen_login_title_with_homeserver">"Bejelentkezés ide: %1$s"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Fiókszolgáltató módosítása"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Egy privát kiszolgáló az Element alkalmazottai számára."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"A Matrix egy nyitott hálózat a biztonságos, decentralizált kommunikációhoz."</string>
|
||||
<string name="screen_server_confirmation_message_register">"Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez."</string>
|
||||
<string name="screen_server_confirmation_title_login">"Hamarosan bejelentkezik ebbe: %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"Hamarosan létrehoz egy fiókot ezen: %1$s"</string>
|
||||
<string name="screen_waitlist_message">"Jelenleg nagy a kereslet a(z) %2$s oldalon futó %1$s iránt. Térjen vissza néhány nap múlva az alkalmazáshoz, és próbálja újra.
|
||||
|
||||
Köszönjük a türelmét!"</string>
|
||||
<string name="screen_waitlist_title">"Már majdnem kész van."</string>
|
||||
<string name="screen_waitlist_title_success">"Bent van."</string>
|
||||
<string name="screen_login_subtitle">"A Matrix egy nyitott hálózat a biztonságos, decentralizált kommunikációhoz."</string>
|
||||
<string name="screen_waitlist_message_success">"Üdvözli az %1$s!"</string>
|
||||
</resources>
|
||||
42
features/login/impl/src/main/res/values-in/translations.xml
Normal file
42
features/login/impl/src/main/res/values-in/translations.xml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_account_provider_change">"Ubah penyedia akun"</string>
|
||||
<string name="screen_account_provider_form_hint">"Alamat homeserver"</string>
|
||||
<string name="screen_account_provider_form_notice">"Masukkan istilah pencarian atau alamat domain."</string>
|
||||
<string name="screen_account_provider_form_subtitle">"Cari perusahaan, komunitas, atau server pribadi."</string>
|
||||
<string name="screen_account_provider_form_title">"Cari penyedia akun"</string>
|
||||
<string name="screen_account_provider_signin_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_account_provider_signin_title">"Anda akan masuk ke %s"</string>
|
||||
<string name="screen_account_provider_signup_subtitle">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_account_provider_signup_title">"Anda akan membuat akun di %s"</string>
|
||||
<string name="screen_change_account_provider_matrix_org_subtitle">"Matrix.org adalah server besar dan gratis di jaringan Matrix publik untuk komunikasi yang aman dan terdesentralisasi, disediakan oleh Yayasan Matrix.org."</string>
|
||||
<string name="screen_change_account_provider_other">"Lainnya"</string>
|
||||
<string name="screen_change_account_provider_subtitle">"Gunakan penyedia akun yang berbeda, seperti server pribadi Anda sendiri atau akun kerja."</string>
|
||||
<string name="screen_change_account_provider_title">"Ubah penyedia akun"</string>
|
||||
<string name="screen_change_server_error_invalid_homeserver">"Kami tidak dapat menjangkau server ini. Periksa apakah Anda telah memasukkan URL homeserver dengan benar. Jika URL sudah benar, hubungi administrator homeserver Anda untuk bantuan lebih lanjut."</string>
|
||||
<string name="screen_change_server_error_no_sliding_sync_message">"Server ini saat ini tidak mendukung sinkronisasi geser."</string>
|
||||
<string name="screen_change_server_form_header">"URL Homeserver"</string>
|
||||
<string name="screen_change_server_form_notice">"Anda hanya dapat terhubung ke server yang ada yang mendukung sinkronisasi geser. Admin homeserver Anda perlu mengaturnya. %1$s"</string>
|
||||
<string name="screen_change_server_subtitle">"Apa alamat server Anda?"</string>
|
||||
<string name="screen_change_server_title">"Pilih server Anda"</string>
|
||||
<string name="screen_login_error_deactivated_account">"Akun ini telah dinonaktifkan."</string>
|
||||
<string name="screen_login_error_invalid_credentials">"Nama pengguna dan/atau kata sandi salah"</string>
|
||||
<string name="screen_login_error_invalid_user_id">"Ini bukan pengenal pengguna yang valid. Format yang diharapkan: \'@pengguna:homeserver.org\'"</string>
|
||||
<string name="screen_login_error_unsupported_authentication">"Homeserver yang dipilih tidak mendukung log masuk kata sandi atau OIDC. Silakan hubungi admin Anda atau pilih homeserver yang lain."</string>
|
||||
<string name="screen_login_form_header">"Masukkan detail Anda"</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_server_confirmation_change_server">"Ubah penyedia akun"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Server pribadi untuk karyawan Element."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string>
|
||||
<string name="screen_server_confirmation_message_register">"Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda."</string>
|
||||
<string name="screen_server_confirmation_title_login">"Anda akan masuk ke %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"Anda akan membuat akun di %1$s"</string>
|
||||
<string name="screen_waitlist_message">"Ada permintaan tinggi untuk %1$s di %2$s saat ini. Kembalilah ke aplikasi dalam beberapa hari dan coba lagi.
|
||||
|
||||
Terima kasih atas kesabaran Anda!"</string>
|
||||
<string name="screen_waitlist_title">"Anda hampir selesai."</string>
|
||||
<string name="screen_waitlist_title_success">"Anda sudah masuk."</string>
|
||||
<string name="screen_login_subtitle">"Matrix adalah jaringan terbuka untuk komunikasi yang aman dan terdesentralisasi."</string>
|
||||
<string name="screen_waitlist_message_success">"Selamat datang di %1$s!"</string>
|
||||
</resources>
|
||||
|
|
@ -2,4 +2,17 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_signout_confirmation_dialog_content">"Bist du sicher, dass du dich abmelden willst?"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Abmelden…"</string>
|
||||
<string name="screen_signout_key_backup_disabled_subtitle">"Du bist dabei, dich von deiner letzten Sitzung abzumelden. Wenn du dich jetzt abmeldest, verlierst du den Zugriff auf deine verschlüsselten Nachrichten."</string>
|
||||
<string name="screen_signout_key_backup_disabled_title">"Du hast das Backup ausgeschaltet"</string>
|
||||
<string name="screen_signout_key_backup_offline_subtitle">"Deine Schlüssel wurden noch gesichert, als du offline gegangen bist. Stelle die Verbindung wieder her, damit deine Schlüssel gesichert werden können, bevor du dich abmeldest."</string>
|
||||
<string name="screen_signout_key_backup_offline_title">"Deine Schlüssel werden noch gesichert"</string>
|
||||
<string name="screen_signout_key_backup_ongoing_subtitle">"Bitte warte, bis der Vorgang abgeschlossen ist, bevor du dich abmeldest."</string>
|
||||
<string name="screen_signout_key_backup_ongoing_title">"Deine Schlüssel werden noch gesichert"</string>
|
||||
<string name="screen_signout_recovery_disabled_subtitle">"Du bist dabei, dich von deiner letzten Sitzung abzumelden. Wenn du dich jetzt abmeldest, verlierst du den Zugriff auf deine verschlüsselten Nachrichten."</string>
|
||||
<string name="screen_signout_recovery_disabled_title">"Wiederherstellung nicht eingerichtet"</string>
|
||||
<string name="screen_signout_save_recovery_key_subtitle">"Du bist dabei, dich von deiner letzten Sitzung abzumelden. Wenn du dich jetzt abmeldest, verlierst du möglicherweise den Zugriff auf deine verschlüsselten Nachrichten."</string>
|
||||
<string name="screen_signout_save_recovery_key_title">"Hast du deinen Wiederherstellungsschlüssel gespeichert?"</string>
|
||||
<string name="screen_signout_confirmation_dialog_submit">"Abmelden"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Abmelden"</string>
|
||||
<string name="screen_signout_preference_item">"Abmelden"</string>
|
||||
</resources>
|
||||
|
|
|
|||
18
features/logout/impl/src/main/res/values-hu/translations.xml
Normal file
18
features/logout/impl/src/main/res/values-hu/translations.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_signout_confirmation_dialog_content">"Biztos, hogy kijelentkezik?"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Kijelentkezés…"</string>
|
||||
<string name="screen_signout_key_backup_disabled_subtitle">"Arra készül, hogy kijelentkezzen az utolsó munkamenetéből is. Ha most kijelentkezik, akkor elveszti a hozzáférését a titkosított üzeneteihez."</string>
|
||||
<string name="screen_signout_key_backup_disabled_title">"Kikapcsolta a biztonsági mentést"</string>
|
||||
<string name="screen_signout_key_backup_offline_subtitle">"A kulcsai mentése során bontotta a kapcsolatot. Kapcsolódjon újra, hogy a kulcsai továbbra is mentésre kerüljenek mielőtt kijelentkezik."</string>
|
||||
<string name="screen_signout_key_backup_offline_title">"A kulcsai mentése még folyamatban van"</string>
|
||||
<string name="screen_signout_key_backup_ongoing_subtitle">"Kijelentkezés előtt várja meg a befejezését."</string>
|
||||
<string name="screen_signout_key_backup_ongoing_title">"A kulcsai mentése még folyamatban van"</string>
|
||||
<string name="screen_signout_recovery_disabled_subtitle">"Arra készül, hogy kijelentkezzen az utolsó munkamenetéből is. Ha most kijelentkezik, akkor elveszti a hozzáférését a titkosított üzeneteihez."</string>
|
||||
<string name="screen_signout_recovery_disabled_title">"A helyreállítás nincs beállítva"</string>
|
||||
<string name="screen_signout_save_recovery_key_subtitle">"Arra készül, hogy kijelentkezzen az utolsó munkamenetéből is. Ha most kijelentkezik, akkor elveszítheti a hozzáférését a titkosított üzeneteihez."</string>
|
||||
<string name="screen_signout_save_recovery_key_title">"Mentette a helyreállítási kulcsát?"</string>
|
||||
<string name="screen_signout_confirmation_dialog_submit">"Kijelentkezés"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Kijelentkezés"</string>
|
||||
<string name="screen_signout_preference_item">"Kijelentkezés"</string>
|
||||
</resources>
|
||||
18
features/logout/impl/src/main/res/values-in/translations.xml
Normal file
18
features/logout/impl/src/main/res/values-in/translations.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_signout_confirmation_dialog_content">"Apakah Anda yakin ingin keluar dari akun?"</string>
|
||||
<string name="screen_signout_in_progress_dialog_content">"Mengeluarkan dari akun…"</string>
|
||||
<string name="screen_signout_key_backup_disabled_subtitle">"Anda akan keluar dari sesi terakhir Anda. Jika Anda keluar sekarang, Anda akan kehilangan akses ke pesan terenkripsi Anda."</string>
|
||||
<string name="screen_signout_key_backup_disabled_title">"Anda telah menonaktifkan pencadangan"</string>
|
||||
<string name="screen_signout_key_backup_offline_subtitle">"Kunci Anda masih dicadangkan saat Anda luring. Sambungkan kembali sehingga kunci Anda dapat dicadangkan sebelum keluar."</string>
|
||||
<string name="screen_signout_key_backup_offline_title">"Kunci Anda masih dicadangkan"</string>
|
||||
<string name="screen_signout_key_backup_ongoing_subtitle">"Mohon tunggu hingga proses ini selesai sebelum keluar."</string>
|
||||
<string name="screen_signout_key_backup_ongoing_title">"Kunci Anda masih dicadangkan"</string>
|
||||
<string name="screen_signout_recovery_disabled_subtitle">"Anda akan keluar dari sesi Anda yang terakhir. Jika Anda keluar sekarang, Anda akan kehilangan akses ke pesan terenkripsi Anda."</string>
|
||||
<string name="screen_signout_recovery_disabled_title">"Pemulihan belum disiapkan"</string>
|
||||
<string name="screen_signout_save_recovery_key_subtitle">"Anda akan keluar dari sesi terakhir Anda. Jika Anda keluar sekarang, Anda mungkin kehilangan akses ke pesan terenkripsi Anda."</string>
|
||||
<string name="screen_signout_save_recovery_key_title">"Apakah Anda sudah menyimpan kunci pemulihan Anda?"</string>
|
||||
<string name="screen_signout_confirmation_dialog_submit">"Keluar dari akun"</string>
|
||||
<string name="screen_signout_confirmation_dialog_title">"Keluar dari akun"</string>
|
||||
<string name="screen_signout_preference_item">"Keluar dari akun"</string>
|
||||
</resources>
|
||||
|
|
@ -33,6 +33,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class AttachmentsPreviewPresenter @AssistedInject constructor(
|
||||
|
|
@ -114,6 +115,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
|||
sendActionState.value = SendActionState.Done
|
||||
},
|
||||
onFailure = { error ->
|
||||
Timber.e(error, "Failed to send attachment")
|
||||
if (error is CancellationException) {
|
||||
throw error
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ import kotlinx.coroutines.flow.filter
|
|||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
|
@ -432,6 +433,7 @@ class MessageComposerPresenter @Inject constructor(
|
|||
attachmentState.value = AttachmentsState.None
|
||||
}
|
||||
.onFailure { cause ->
|
||||
Timber.e(cause, "Failed to send attachment")
|
||||
attachmentState.value = AttachmentsState.None
|
||||
if (cause is CancellationException) {
|
||||
throw cause
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ class TimelinePresenter @AssistedInject constructor(
|
|||
}
|
||||
|
||||
return TimelineState(
|
||||
timelineRoomInfo = TimelineRoomInfo(
|
||||
isDirect = room.isDirect
|
||||
),
|
||||
highlightedEventId = highlightedEventId.value,
|
||||
userHasPermissionToSendMessage = userHasPermissionToSendMessage,
|
||||
paginationState = paginationState,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
@Immutable
|
||||
data class TimelineState(
|
||||
val timelineItems: ImmutableList<TimelineItem>,
|
||||
val timelineRoomInfo: TimelineRoomInfo,
|
||||
val showReadReceipts: Boolean,
|
||||
val highlightedEventId: EventId?,
|
||||
val userHasPermissionToSendMessage: Boolean,
|
||||
|
|
@ -35,3 +36,8 @@ data class TimelineState(
|
|||
val sessionState: SessionState,
|
||||
val eventSink: (TimelineEvents) -> Unit
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class TimelineRoomInfo(
|
||||
val isDirect: Boolean,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import kotlin.random.Random
|
|||
|
||||
fun aTimelineState(timelineItems: ImmutableList<TimelineItem> = persistentListOf()) = TimelineState(
|
||||
timelineItems = timelineItems,
|
||||
timelineRoomInfo = aTimelineRoomInfo(),
|
||||
showReadReceipts = false,
|
||||
paginationState = MatrixTimeline.PaginationState(
|
||||
isBackPaginating = false,
|
||||
|
|
@ -212,3 +213,9 @@ internal fun aGroupedEvents(id: Long = 0): TimelineItem.GroupedEvents {
|
|||
aggregatedReadReceipts = events.flatMap { it.readReceiptState.receipts }.toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aTimelineRoomInfo(
|
||||
isDirect: Boolean = false,
|
||||
) = TimelineRoomInfo(
|
||||
isDirect = isDirect,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ fun TimelineView(
|
|||
) { timelineItem ->
|
||||
TimelineItemRow(
|
||||
timelineItem = timelineItem,
|
||||
timelineRoomInfo = state.timelineRoomInfo,
|
||||
showReadReceipts = state.showReadReceipts,
|
||||
isLastOutgoingMessage = (timelineItem as? TimelineItem.Event)?.isMine == true
|
||||
&& state.timelineItems.first().identifier() == timelineItem.identifier(),
|
||||
|
|
|
|||
|
|
@ -17,17 +17,21 @@
|
|||
package io.element.android.features.messages.impl.timeline.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
|
||||
// For previews
|
||||
@Composable
|
||||
internal fun ATimelineItemEventRow(
|
||||
event: TimelineItem.Event,
|
||||
timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(),
|
||||
showReadReceipts: Boolean = false,
|
||||
isLastOutgoingMessage: Boolean = false,
|
||||
isHighlighted: Boolean = false,
|
||||
) = TimelineItemEventRow(
|
||||
event = event,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
isHighlighted = isHighlighted,
|
||||
|
|
|
|||
|
|
@ -35,17 +35,17 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleState
|
||||
import io.element.android.features.messages.impl.timeline.model.bubble.BubbleStateProvider
|
||||
import io.element.android.libraries.core.extensions.to01
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.messageFromMeBackground
|
||||
import io.element.android.libraries.designsystem.theme.messageFromOtherBackground
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
||||
private val BUBBLE_RADIUS = 12.dp
|
||||
private val BUBBLE_INCOMING_OFFSET = 16.dp
|
||||
|
|
@ -91,10 +91,10 @@ fun MessageEventBubble(
|
|||
}
|
||||
|
||||
fun Modifier.offsetForItem(): Modifier {
|
||||
return if (state.isMine) {
|
||||
this
|
||||
} else {
|
||||
offset(x = BUBBLE_INCOMING_OFFSET)
|
||||
return when {
|
||||
state.isMine -> this
|
||||
state.timelineRoomInfo.isDirect -> this
|
||||
else -> offset(x = BUBBLE_INCOMING_OFFSET)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import androidx.compose.ui.zIndex
|
|||
import androidx.constraintlayout.compose.ConstrainScope
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
|
||||
|
|
@ -101,6 +102,7 @@ import kotlin.math.roundToInt
|
|||
@Composable
|
||||
fun TimelineItemEventRow(
|
||||
event: TimelineItem.Event,
|
||||
timelineRoomInfo: TimelineRoomInfo,
|
||||
showReadReceipts: Boolean,
|
||||
isLastOutgoingMessage: Boolean,
|
||||
isHighlighted: Boolean,
|
||||
|
|
@ -163,9 +165,8 @@ fun TimelineItemEventRow(
|
|||
state = state.draggableState,
|
||||
),
|
||||
event = event,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
isHighlighted = isHighlighted,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
interactionSource = interactionSource,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
|
|
@ -175,7 +176,6 @@ fun TimelineItemEventRow(
|
|||
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
|
||||
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
|
||||
onMoreReactionsClicked = { onMoreReactionsClick(event) },
|
||||
onReadReceiptsClicked = { onReadReceiptClick(event) },
|
||||
eventSink = eventSink,
|
||||
)
|
||||
}
|
||||
|
|
@ -183,9 +183,8 @@ fun TimelineItemEventRow(
|
|||
} else {
|
||||
TimelineItemEventRowContent(
|
||||
event = event,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
isHighlighted = isHighlighted,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
interactionSource = interactionSource,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
|
|
@ -195,10 +194,20 @@ fun TimelineItemEventRow(
|
|||
onReactionClicked = { emoji -> onReactionClick(emoji, event) },
|
||||
onReactionLongClicked = { emoji -> onReactionLongClick(emoji, event) },
|
||||
onMoreReactionsClicked = { onMoreReactionsClick(event) },
|
||||
onReadReceiptsClicked = { onReadReceiptClick(event) },
|
||||
eventSink = eventSink,
|
||||
)
|
||||
}
|
||||
// Read receipts / Send state
|
||||
TimelineItemReadReceiptView(
|
||||
state = ReadReceiptViewState(
|
||||
sendState = event.localSendState,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
receipts = event.readReceiptState.receipts,
|
||||
),
|
||||
showReadReceipts = showReadReceipts,
|
||||
onReadReceiptsClicked = { onReadReceiptClick(event) },
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -228,9 +237,8 @@ private fun SwipeSensitivity(
|
|||
@Composable
|
||||
private fun TimelineItemEventRowContent(
|
||||
event: TimelineItem.Event,
|
||||
showReadReceipts: Boolean,
|
||||
isLastOutgoingMessage: Boolean,
|
||||
isHighlighted: Boolean,
|
||||
timelineRoomInfo: TimelineRoomInfo,
|
||||
interactionSource: MutableInteractionSource,
|
||||
onClick: () -> Unit,
|
||||
onLongClick: () -> Unit,
|
||||
|
|
@ -238,7 +246,6 @@ private fun TimelineItemEventRowContent(
|
|||
inReplyToClicked: () -> Unit,
|
||||
onUserDataClicked: () -> Unit,
|
||||
onReactionClicked: (emoji: String) -> Unit,
|
||||
onReadReceiptsClicked: () -> Unit,
|
||||
onReactionLongClicked: (emoji: String) -> Unit,
|
||||
onMoreReactionsClicked: (event: TimelineItem.Event) -> Unit,
|
||||
eventSink: (TimelineEvents) -> Unit,
|
||||
|
|
@ -259,12 +266,11 @@ private fun TimelineItemEventRowContent(
|
|||
sender,
|
||||
message,
|
||||
reactions,
|
||||
readReceipts,
|
||||
) = createRefs()
|
||||
|
||||
// Sender
|
||||
val avatarStrokeSize = 3.dp
|
||||
if (event.showSenderInformation) {
|
||||
if (event.showSenderInformation && !timelineRoomInfo.isDirect) {
|
||||
MessageSenderInformation(
|
||||
event.safeSenderName,
|
||||
event.senderAvatar,
|
||||
|
|
@ -284,6 +290,7 @@ private fun TimelineItemEventRowContent(
|
|||
groupPosition = event.groupPosition,
|
||||
isMine = event.isMine,
|
||||
isHighlighted = isHighlighted,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
)
|
||||
MessageEventBubble(
|
||||
modifier = Modifier
|
||||
|
|
@ -326,25 +333,6 @@ private fun TimelineItemEventRowContent(
|
|||
.padding(start = if (event.isMine) 16.dp else 36.dp, end = 16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// Read receipts / Send state
|
||||
TimelineItemReadReceiptView(
|
||||
state = ReadReceiptViewState(
|
||||
sendState = event.localSendState,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
receipts = event.readReceiptState.receipts,
|
||||
),
|
||||
showReadReceipts = showReadReceipts,
|
||||
onReadReceiptsClicked = onReadReceiptsClicked,
|
||||
modifier = Modifier
|
||||
.constrainAs(readReceipts) {
|
||||
if (event.reactionsState.reactions.isNotEmpty()) {
|
||||
top.linkTo(reactions.bottom, margin = 4.dp)
|
||||
} else {
|
||||
top.linkTo(message.bottom, margin = 4.dp)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -378,6 +366,7 @@ private fun MessageSenderInformation(
|
|||
Avatar(senderAvatar)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
modifier = Modifier.clipToBounds(),
|
||||
text = sender,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TimelineItemEventRowForDirectRoomPreview() = ElementPreview {
|
||||
Column {
|
||||
sequenceOf(false, true).forEach {
|
||||
ATimelineItemEventRow(
|
||||
event = aTimelineItemEvent(
|
||||
isMine = it,
|
||||
content = aTimelineItemTextContent().copy(
|
||||
body = "A long text which will be displayed on several lines and" +
|
||||
" hopefully can be manually adjusted to test different behaviors."
|
||||
),
|
||||
groupPosition = TimelineItemGroupPosition.First,
|
||||
),
|
||||
timelineRoomInfo = aTimelineRoomInfo(
|
||||
isDirect = true,
|
||||
),
|
||||
)
|
||||
ATimelineItemEventRow(
|
||||
event = aTimelineItemEvent(
|
||||
isMine = it,
|
||||
content = aTimelineItemImageContent().copy(
|
||||
aspectRatio = 5f
|
||||
),
|
||||
groupPosition = TimelineItemGroupPosition.Last,
|
||||
),
|
||||
timelineRoomInfo = aTimelineRoomInfo(
|
||||
isDirect = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -24,8 +24,10 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import io.element.android.features.messages.impl.R
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
import io.element.android.features.messages.impl.timeline.aGroupedEvents
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.components.group.GroupHeaderView
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState
|
||||
import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView
|
||||
|
|
@ -40,6 +42,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
|||
@Composable
|
||||
fun TimelineItemGroupedEventsRow(
|
||||
timelineItem: TimelineItem.GroupedEvents,
|
||||
timelineRoomInfo: TimelineRoomInfo,
|
||||
showReadReceipts: Boolean,
|
||||
isLastOutgoingMessage: Boolean,
|
||||
highlightedItem: String?,
|
||||
|
|
@ -66,6 +69,7 @@ fun TimelineItemGroupedEventsRow(
|
|||
isExpanded = isExpanded.value,
|
||||
onExpandGroupClick = ::onExpandGroupClick,
|
||||
timelineItem = timelineItem,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
highlightedItem = highlightedItem,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
|
|
@ -89,6 +93,7 @@ private fun TimelineItemGroupedEventsRowContent(
|
|||
isExpanded: Boolean,
|
||||
onExpandGroupClick: () -> Unit,
|
||||
timelineItem: TimelineItem.GroupedEvents,
|
||||
timelineRoomInfo: TimelineRoomInfo,
|
||||
highlightedItem: String?,
|
||||
showReadReceipts: Boolean,
|
||||
isLastOutgoingMessage: Boolean,
|
||||
|
|
@ -121,6 +126,7 @@ private fun TimelineItemGroupedEventsRowContent(
|
|||
timelineItem.events.forEach { subGroupEvent ->
|
||||
TimelineItemRow(
|
||||
timelineItem = subGroupEvent,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
highlightedItem = highlightedItem,
|
||||
|
|
@ -148,7 +154,8 @@ private fun TimelineItemGroupedEventsRowContent(
|
|||
receipts = timelineItem.aggregatedReadReceipts,
|
||||
),
|
||||
showReadReceipts = true,
|
||||
onReadReceiptsClicked = { /* No op for group event */ })
|
||||
onReadReceiptsClicked = onExpandGroupClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -160,6 +167,7 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi
|
|||
isExpanded = true,
|
||||
onExpandGroupClick = {},
|
||||
timelineItem = aGroupedEvents(),
|
||||
timelineRoomInfo = aTimelineRoomInfo(),
|
||||
highlightedItem = null,
|
||||
showReadReceipts = true,
|
||||
isLastOutgoingMessage = false,
|
||||
|
|
@ -184,6 +192,7 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi
|
|||
isExpanded = false,
|
||||
onExpandGroupClick = {},
|
||||
timelineItem = aGroupedEvents(),
|
||||
timelineRoomInfo = aTimelineRoomInfo(),
|
||||
highlightedItem = null,
|
||||
showReadReceipts = true,
|
||||
isLastOutgoingMessage = false,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.timeline.components
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||
|
|
@ -29,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
|||
@Composable
|
||||
internal fun TimelineItemRow(
|
||||
timelineItem: TimelineItem,
|
||||
timelineRoomInfo: TimelineRoomInfo,
|
||||
showReadReceipts: Boolean,
|
||||
isLastOutgoingMessage: Boolean,
|
||||
highlightedItem: String?,
|
||||
|
|
@ -71,6 +73,7 @@ internal fun TimelineItemRow(
|
|||
} else {
|
||||
TimelineItemEventRow(
|
||||
event = timelineItem,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
isHighlighted = highlightedItem == timelineItem.identifier(),
|
||||
|
|
@ -93,6 +96,7 @@ internal fun TimelineItemRow(
|
|||
is TimelineItem.GroupedEvents -> {
|
||||
TimelineItemGroupedEventsRow(
|
||||
timelineItem = timelineItem,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
showReadReceipts = showReadReceipts,
|
||||
isLastOutgoingMessage = isLastOutgoingMessage,
|
||||
highlightedItem = highlightedItem,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.components.group
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
|
@ -26,6 +28,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -76,9 +79,17 @@ fun GroupHeaderView(
|
|||
color = MaterialTheme.colorScheme.secondary,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
)
|
||||
val rotation: Float by animateFloatAsState(
|
||||
targetValue = if (isExpanded) 90f else 0f,
|
||||
animationSpec = tween(
|
||||
delayMillis = 0,
|
||||
durationMillis = 300,
|
||||
),
|
||||
label = "chevron"
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier.rotate(if (isExpanded) 180f else 0f),
|
||||
imageVector = CompoundIcons.ChevronDown,
|
||||
modifier = Modifier.rotate(rotation),
|
||||
imageVector = CompoundIcons.ChevronRight,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.bubble
|
||||
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||
|
||||
data class BubbleState(
|
||||
val groupPosition: TimelineItemGroupPosition,
|
||||
val isMine: Boolean,
|
||||
val isHighlighted: Boolean,
|
||||
val timelineRoomInfo: TimelineRoomInfo,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package io.element.android.features.messages.impl.timeline.model.bubble
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemGroupPosition
|
||||
|
||||
open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
|
||||
|
|
@ -29,7 +31,11 @@ open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
|
|||
).map { groupPosition ->
|
||||
sequenceOf(false, true).map { isMine ->
|
||||
sequenceOf(false, true).map { isHighlighted ->
|
||||
BubbleState(groupPosition, isMine = isMine, isHighlighted = isHighlighted)
|
||||
aBubbleState(
|
||||
groupPosition = groupPosition,
|
||||
isMine = isMine,
|
||||
isHighlighted = isHighlighted,
|
||||
)
|
||||
}
|
||||
}
|
||||
.flatten()
|
||||
|
|
@ -37,8 +43,14 @@ open class BubbleStateProvider : PreviewParameterProvider<BubbleState> {
|
|||
.flatten()
|
||||
}
|
||||
|
||||
fun aBubbleState() = BubbleState(
|
||||
groupPosition = TimelineItemGroupPosition.First,
|
||||
isMine = false,
|
||||
isHighlighted = false,
|
||||
internal fun aBubbleState(
|
||||
groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.First,
|
||||
isMine: Boolean = false,
|
||||
isHighlighted: Boolean = false,
|
||||
timelineRoomInfo: TimelineRoomInfo = aTimelineRoomInfo(),
|
||||
) = BubbleState(
|
||||
groupPosition = groupPosition,
|
||||
isMine = isMine,
|
||||
isHighlighted = isHighlighted,
|
||||
timelineRoomInfo = timelineRoomInfo,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import io.element.android.libraries.di.CacheDirectory
|
|||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.matrix.api.mxc.MxcTools
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
|
|
@ -66,6 +67,7 @@ interface VoiceMessageMediaRepo {
|
|||
|
||||
class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
|
||||
@CacheDirectory private val cacheDir: File,
|
||||
mxcTools: MxcTools,
|
||||
private val matrixMediaLoader: MatrixMediaLoader,
|
||||
@Assisted private val mediaSource: MediaSource,
|
||||
@Assisted("mimeType") private val mimeType: String?,
|
||||
|
|
@ -101,7 +103,7 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val cachedFile: File? = mxcUri2FilePath(mediaSource.url)?.let {
|
||||
private val cachedFile: File? = mxcTools.mxcUri2FilePath(mediaSource.url)?.let {
|
||||
File("${cacheDir.path}/$CACHE_VOICE_SUBDIR/$it")
|
||||
}
|
||||
}
|
||||
|
|
@ -110,24 +112,3 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
|
|||
* Subdirectory of the application's cache directory where voice messages are stored.
|
||||
*/
|
||||
private const val CACHE_VOICE_SUBDIR = "temp/voice"
|
||||
|
||||
/**
|
||||
* Regex to match a Matrix Content (mxc://) URI.
|
||||
*
|
||||
* See: https://spec.matrix.org/v1.8/client-server-api/#matrix-content-mxc-uris
|
||||
*/
|
||||
private val mxcRegex = Regex("""^mxc:\/\/([^\/]+)\/([^\/]+)$""")
|
||||
|
||||
/**
|
||||
* Sanitizes an mxcUri to be used as a relative file path.
|
||||
*
|
||||
* @param mxcUri the Matrix Content (mxc://) URI of the voice message.
|
||||
* @return the relative file path as "<server-name>/<media-id>" or null if the mxcUri is invalid.
|
||||
*/
|
||||
private fun mxcUri2FilePath(mxcUri: String): String? = mxcRegex.matchEntire(mxcUri)?.let { match ->
|
||||
buildString {
|
||||
append(match.groupValues[1])
|
||||
append("/")
|
||||
append(match.groupValues[2])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
<string name="room_timeline_beginning_of_room">"Dies ist der Anfang von %1$s."</string>
|
||||
<string name="room_timeline_beginning_of_room_no_name">"Dies ist der Anfang dieses Gesprächs."</string>
|
||||
<string name="room_timeline_read_marker_title">"Neu"</string>
|
||||
<string name="screen_room_mentions_at_room_subtitle">"Den ganzen Raum benachrichtigen"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Prüfe, ob du alle aktuellen und zukünftigen Nachrichten dieses Benutzers ausblenden möchtest"</string>
|
||||
<string name="screen_room_attachment_source_camera">"Kamera"</string>
|
||||
<string name="screen_room_attachment_source_camera_photo">"Foto machen"</string>
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
<string name="screen_room_attachment_source_poll">"Umfrage"</string>
|
||||
<string name="screen_room_attachment_text_formatting">"Textformatierung"</string>
|
||||
<string name="screen_room_encrypted_history_banner">"Der Nachrichtenverlauf ist derzeit in diesem Raum nicht verfügbar"</string>
|
||||
<string name="screen_room_encrypted_history_banner_unverified">"Der Nachrichtenverlauf ist in diesem Raum nicht verfügbar. Verifiziere dieses Gerät, um deinen Nachrichtenverlauf zu sehen."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"Benutzerdetails konnten nicht abgerufen werden"</string>
|
||||
<string name="screen_room_invite_again_alert_message">"Möchtest du sie wieder einladen?"</string>
|
||||
<string name="screen_room_invite_again_alert_title">"Du bist allein in diesem Chat"</string>
|
||||
|
|
@ -42,6 +44,7 @@
|
|||
<string name="screen_room_notification_settings_error_loading_settings">"Beim Laden der Benachrichtigungseinstellungen ist ein Fehler aufgetreten."</string>
|
||||
<string name="screen_room_notification_settings_error_restoring_default">"Fehler beim Wiederherstellen des Standardmodus. Bitte versuche es erneut."</string>
|
||||
<string name="screen_room_notification_settings_error_setting_mode">"Fehler beim Einstellen des Modus. Bitte versuche es erneut."</string>
|
||||
<string name="screen_room_notification_settings_mentions_only_disclaimer">"Dein Homeserver unterstützt diese Option in verschlüsselten Räumen nicht. Du wirst in diesem Raum nicht benachrichtigt."</string>
|
||||
<string name="screen_room_notification_settings_mode_all_messages">"Alle Nachrichten"</string>
|
||||
<string name="screen_room_notification_settings_room_custom_settings_title">"Benachrichtige mich in diesem Raum bei"</string>
|
||||
<string name="screen_room_reactions_show_less">"Weniger anzeigen"</string>
|
||||
|
|
@ -50,6 +53,8 @@
|
|||
<string name="screen_room_retry_send_menu_title">"Deine Nachricht konnte nicht gesendet werden"</string>
|
||||
<string name="screen_room_timeline_add_reaction">"Emoji hinzufügen"</string>
|
||||
<string name="screen_room_timeline_less_reactions">"Weniger anzeigen"</string>
|
||||
<string name="screen_room_voice_message_tooltip">"Zum Aufnehmen gedrückt halten"</string>
|
||||
<string name="screen_room_mentions_at_room_title">"Alle"</string>
|
||||
<string name="screen_report_content_block_user">"Benutzer sperren"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"Fehler beim Verarbeiten des hochgeladenen Mediums. Bitte versuche es erneut."</string>
|
||||
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Nur Erwähnungen und Schlüsselwörter"</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="emoji_picker_category_activity">"Tevékenységek"</string>
|
||||
<string name="emoji_picker_category_flags">"Zászlók"</string>
|
||||
<string name="emoji_picker_category_foods">"Étel és ital"</string>
|
||||
<string name="emoji_picker_category_nature">"Állatok és természet"</string>
|
||||
<string name="emoji_picker_category_objects">"Tárgyak"</string>
|
||||
<string name="emoji_picker_category_people">"Mosolyok és emberek"</string>
|
||||
<string name="emoji_picker_category_places">"Utazás és helyek"</string>
|
||||
<string name="emoji_picker_category_symbols">"Szimbólumok"</string>
|
||||
<string name="report_content_explanation">"Ez az üzenet jelentve lesz a Matrix-kiszolgáló rendszergazdájának. Nem fogja tudni elolvasni a titkosított üzeneteket."</string>
|
||||
<string name="report_content_hint">"A tartalom jelentésének oka"</string>
|
||||
<string name="room_timeline_beginning_of_room">"Ez a(z) %1$s kezdete."</string>
|
||||
<string name="room_timeline_beginning_of_room_no_name">"Ez a beszélgetés kezdete."</string>
|
||||
<string name="room_timeline_read_marker_title">"Új"</string>
|
||||
<string name="screen_room_mentions_at_room_subtitle">"Teljes szoba értesítése"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Jelölje be, ha el akarja rejteni az összes jelenlegi és jövőbeli üzenetet ettől a felhasználótól"</string>
|
||||
<string name="screen_room_attachment_source_camera">"Kamera"</string>
|
||||
<string name="screen_room_attachment_source_camera_photo">"Fénykép készítése"</string>
|
||||
<string name="screen_room_attachment_source_camera_video">"Videó rögzítése"</string>
|
||||
<string name="screen_room_attachment_source_files">"Melléklet"</string>
|
||||
<string name="screen_room_attachment_source_gallery">"Fénykép- és videótár"</string>
|
||||
<string name="screen_room_attachment_source_location">"Hely"</string>
|
||||
<string name="screen_room_attachment_source_poll">"Szavazás"</string>
|
||||
<string name="screen_room_attachment_text_formatting">"Szövegformázás"</string>
|
||||
<string name="screen_room_encrypted_history_banner">"Az üzenetelőzmények jelenleg nem érhetők el."</string>
|
||||
<string name="screen_room_encrypted_history_banner_unverified">"Az üzenetelőzmények nem érhetők el ebben a szobában. Ellenőrizze ezt az eszközt, hogy lássa az előzményeket."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"Nem sikerült letölteni a felhasználói adatokat"</string>
|
||||
<string name="screen_room_invite_again_alert_message">"Visszahívja?"</string>
|
||||
<string name="screen_room_invite_again_alert_title">"Egyedül van ebben a csevegésben"</string>
|
||||
<string name="screen_room_message_copied">"Üzenet másolva"</string>
|
||||
<string name="screen_room_no_permission_to_post">"Nincs jogosultsága arra, hogy bejegyzést tegyen közzé ebben a szobában"</string>
|
||||
<string name="screen_room_notification_settings_allow_custom">"Egyéni beállítás engedélyezése"</string>
|
||||
<string name="screen_room_notification_settings_allow_custom_footnote">"Ennek bekapcsolása felülírja az alapértelmezett beállítást"</string>
|
||||
<string name="screen_room_notification_settings_custom_settings_title">"Értesítések kérése ebben a csevegésben ezekről:"</string>
|
||||
<string name="screen_room_notification_settings_default_setting_footnote">"Megváltoztathatja a %1$s."</string>
|
||||
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"globális beállításokban"</string>
|
||||
<string name="screen_room_notification_settings_default_setting_title">"Alapértelmezett beállítás"</string>
|
||||
<string name="screen_room_notification_settings_edit_remove_setting">"Egyéni beállítás eltávolítása"</string>
|
||||
<string name="screen_room_notification_settings_error_loading_settings">"Hiba történt az értesítési beállítások betöltésekor."</string>
|
||||
<string name="screen_room_notification_settings_error_restoring_default">"Nem sikerült visszaállítani az alapértelmezett módot, próbálja újra."</string>
|
||||
<string name="screen_room_notification_settings_error_setting_mode">"Nem sikerült a mód beállítása, próbálja újra."</string>
|
||||
<string name="screen_room_notification_settings_mentions_only_disclaimer">"A Matrix-kiszolgálója nem támogatja ezt a beállítást a titkosított szobákban, egyes szobákban nem fog értesítéseket kapni."</string>
|
||||
<string name="screen_room_notification_settings_mode_all_messages">"Összes üzenet"</string>
|
||||
<string name="screen_room_notification_settings_room_custom_settings_title">"Ebben a szobában, értesítés ezekről:"</string>
|
||||
<string name="screen_room_reactions_show_less">"Kevesebb megjelenítése"</string>
|
||||
<string name="screen_room_reactions_show_more">"Több megjelenítése"</string>
|
||||
<string name="screen_room_retry_send_menu_send_again_action">"Újraküldés"</string>
|
||||
<string name="screen_room_retry_send_menu_title">"Az üzenet elküldése sikertelen"</string>
|
||||
<string name="screen_room_timeline_add_reaction">"Emodzsi hozzáadása"</string>
|
||||
<string name="screen_room_timeline_less_reactions">"Kevesebb megjelenítése"</string>
|
||||
<string name="screen_room_voice_message_tooltip">"Tartsa a rögzítéshez"</string>
|
||||
<string name="screen_room_mentions_at_room_title">"Mindenki"</string>
|
||||
<string name="screen_report_content_block_user">"Felhasználó letiltása"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"Nem sikerült feldolgozni a feltöltendő médiát, próbálja újra."</string>
|
||||
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Csak említések és kulcsszavak"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="emoji_picker_category_activity">"Aktivitas"</string>
|
||||
<string name="emoji_picker_category_flags">"Bendera"</string>
|
||||
<string name="emoji_picker_category_foods">"Makanan & Minuman"</string>
|
||||
<string name="emoji_picker_category_nature">"Hewan & Alam"</string>
|
||||
<string name="emoji_picker_category_objects">"Objek"</string>
|
||||
<string name="emoji_picker_category_people">"Senyuman & Orang"</string>
|
||||
<string name="emoji_picker_category_places">"Wisata & Tempat"</string>
|
||||
<string name="emoji_picker_category_symbols">"Simbol"</string>
|
||||
<plurals name="room_timeline_state_changes">
|
||||
<item quantity="other">"%1$d perubahan ruangan"</item>
|
||||
</plurals>
|
||||
<string name="report_content_explanation">"Pesan ini akan dilaporkan ke administrator homeserver Anda. Mereka tidak akan dapat membaca pesan terenkripsi apa pun."</string>
|
||||
<string name="report_content_hint">"Alasan melaporkan konten ini"</string>
|
||||
<string name="room_timeline_beginning_of_room">"Ini adalah awal dari %1$s."</string>
|
||||
<string name="room_timeline_beginning_of_room_no_name">"Ini adalah awal dari percakapan ini."</string>
|
||||
<string name="room_timeline_read_marker_title">"Baru"</string>
|
||||
<string name="screen_room_mentions_at_room_subtitle">"Beri tahu seluruh ruangan"</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_room_attachment_source_camera">"Kamera"</string>
|
||||
<string name="screen_room_attachment_source_camera_photo">"Ambil foto"</string>
|
||||
<string name="screen_room_attachment_source_camera_video">"Rekam video"</string>
|
||||
<string name="screen_room_attachment_source_files">"Lampiran"</string>
|
||||
<string name="screen_room_attachment_source_gallery">"Pustaka Foto & Video"</string>
|
||||
<string name="screen_room_attachment_source_location">"Lokasi"</string>
|
||||
<string name="screen_room_attachment_source_poll">"Pemungutan suara"</string>
|
||||
<string name="screen_room_attachment_text_formatting">"Pemformatan Teks"</string>
|
||||
<string name="screen_room_encrypted_history_banner">"Riwayat pesan saat ini tidak tersedia di ruangan ini"</string>
|
||||
<string name="screen_room_encrypted_history_banner_unverified">"Riwayat pesan tidak tersedia di ruangan ini. Verifikasi perangkat ini untuk melihat riwayat pesan."</string>
|
||||
<string name="screen_room_error_failed_retrieving_user_details">"Tidak dapat mengambil detail pengguna"</string>
|
||||
<string name="screen_room_invite_again_alert_message">"Apakah Anda ingin mengundang mereka kembali?"</string>
|
||||
<string name="screen_room_invite_again_alert_title">"Anda sendirian di obrolan ini"</string>
|
||||
<string name="screen_room_message_copied">"Pesan disalin"</string>
|
||||
<string name="screen_room_no_permission_to_post">"Anda tidak memiliki izin untuk mengirim di ruangan ini"</string>
|
||||
<string name="screen_room_notification_settings_allow_custom">"Izinkan pengaturan khusus"</string>
|
||||
<string name="screen_room_notification_settings_allow_custom_footnote">"Mengaktifkan ini akan mengganti pengaturan bawaan Anda"</string>
|
||||
<string name="screen_room_notification_settings_custom_settings_title">"Beri tahu saya di obrolan ini tentang"</string>
|
||||
<string name="screen_room_notification_settings_default_setting_footnote">"Anda dapat mengubahnya di %1$s Anda."</string>
|
||||
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"pengaturan global"</string>
|
||||
<string name="screen_room_notification_settings_default_setting_title">"Pengaturan bawaan"</string>
|
||||
<string name="screen_room_notification_settings_edit_remove_setting">"Hapus pengaturan khusus"</string>
|
||||
<string name="screen_room_notification_settings_error_loading_settings">"Terjadi kesalahan saat memuat pengaturan pemberitahuan."</string>
|
||||
<string name="screen_room_notification_settings_error_restoring_default">"Gagal memulihkan mode bawaan, silakan coba lagi."</string>
|
||||
<string name="screen_room_notification_settings_error_setting_mode">"Gagal mengatur mode, silakan coba lagi."</string>
|
||||
<string name="screen_room_notification_settings_mentions_only_disclaimer">"Homeserver Anda tidak mendukung opsi ini dalam ruangan terenkripsi, Anda tidak akan diberi tahu dalam ruangan ini."</string>
|
||||
<string name="screen_room_notification_settings_mode_all_messages">"Semua pesan"</string>
|
||||
<string name="screen_room_notification_settings_room_custom_settings_title">"Di ruangan ini, beri tahu saya tentang"</string>
|
||||
<string name="screen_room_reactions_show_less">"Tampilkan lebih sedikit"</string>
|
||||
<string name="screen_room_reactions_show_more">"Tampilkan lebih banyak"</string>
|
||||
<string name="screen_room_retry_send_menu_send_again_action">"Kirim ulang"</string>
|
||||
<string name="screen_room_retry_send_menu_title">"Pesan Anda gagal dikirim"</string>
|
||||
<string name="screen_room_timeline_add_reaction">"Tambahkan emoji"</string>
|
||||
<string name="screen_room_timeline_less_reactions">"Tampilkan lebih sedikit"</string>
|
||||
<string name="screen_room_voice_message_tooltip">"Tahan untuk merekam"</string>
|
||||
<string name="screen_room_mentions_at_room_title">"Semua orang"</string>
|
||||
<string name="screen_report_content_block_user">"Blokir pengguna"</string>
|
||||
<string name="screen_room_error_failed_processing_media">"Gagal memproses media untuk diunggah, silakan coba lagi."</string>
|
||||
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Sebutan dan Kata Kunci saja"</string>
|
||||
</resources>
|
||||
|
|
@ -379,9 +379,9 @@ class MessageComposerPresenterTest {
|
|||
}.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showAttachmentSourcePicker).isEqualTo(false)
|
||||
assertThat(initialState.showAttachmentSourcePicker).isFalse()
|
||||
initialState.eventSink(MessageComposerEvents.AddAttachment)
|
||||
assertThat(awaitItem().showAttachmentSourcePicker).isEqualTo(true)
|
||||
assertThat(awaitItem().showAttachmentSourcePicker).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class ReactionSummaryPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.target).isEqualTo(null)
|
||||
assertThat(initialState.target).isNull()
|
||||
|
||||
initialState.eventSink(summaryEvent)
|
||||
assertThat(awaitItem().target).isNotNull()
|
||||
|
|
@ -69,7 +69,7 @@ class ReactionSummaryPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.target).isEqualTo(null)
|
||||
assertThat(initialState.target).isNull()
|
||||
|
||||
initialState.eventSink(summaryEvent)
|
||||
val reactions = awaitItem().target?.reactions
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.media.AudioInfo
|
||||
|
|
@ -59,7 +59,7 @@ class InReplyToMetadataKtTest {
|
|||
anInReplyToDetails(eventContent = aMessageContent()).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(InReplyToMetadata.Text("textContent"))
|
||||
assertThat(it).isEqualTo(InReplyToMetadata.Text("textContent"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = aMediaSource(),
|
||||
|
|
@ -115,7 +115,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = aMediaSource(),
|
||||
|
|
@ -148,7 +148,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = aMediaSource(),
|
||||
|
|
@ -180,7 +180,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
textContent = "body",
|
||||
|
|
@ -209,7 +209,7 @@ class InReplyToMetadataKtTest {
|
|||
}
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = null,
|
||||
|
|
@ -240,7 +240,7 @@ class InReplyToMetadataKtTest {
|
|||
}
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = null,
|
||||
|
|
@ -262,7 +262,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(
|
||||
assertThat(it).isEqualTo(
|
||||
InReplyToMetadata.Thumbnail(
|
||||
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||
thumbnailSource = null,
|
||||
|
|
@ -284,7 +284,7 @@ class InReplyToMetadataKtTest {
|
|||
).metadata()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it).isEqualTo(null)
|
||||
assertThat(it).isNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@
|
|||
|
||||
package io.element.android.features.messages.impl.voicemessages.timeline
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.matrix.api.mxc.MxcTools
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaLoader
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
|
|
@ -43,10 +44,10 @@ class DefaultVoiceMessageMediaRepoTest {
|
|||
)
|
||||
|
||||
repo.getMediaFile().let { result ->
|
||||
Truth.assertThat(result.isSuccess).isTrue()
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
result.getOrThrow().let { file ->
|
||||
Truth.assertThat(file.path).isEqualTo(temporaryFolder.cachedFilePath)
|
||||
Truth.assertThat(file.exists()).isTrue()
|
||||
assertThat(file.path).isEqualTo(temporaryFolder.cachedFilePath)
|
||||
assertThat(file.exists()).isTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,9 +63,9 @@ class DefaultVoiceMessageMediaRepoTest {
|
|||
)
|
||||
|
||||
repo.getMediaFile().let { result ->
|
||||
Truth.assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.isFailure).isTrue()
|
||||
result.exceptionOrNull()!!.let { exception ->
|
||||
Truth.assertThat(exception).isInstanceOf(RuntimeException::class.java)
|
||||
assertThat(exception).isInstanceOf(RuntimeException::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,9 +88,9 @@ class DefaultVoiceMessageMediaRepoTest {
|
|||
)
|
||||
|
||||
repo.getMediaFile().let { result ->
|
||||
Truth.assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.isFailure).isTrue()
|
||||
result.exceptionOrNull()?.let { exception ->
|
||||
Truth.assertThat(exception).apply {
|
||||
assertThat(exception).apply {
|
||||
isInstanceOf(IllegalStateException::class.java)
|
||||
hasMessageThat().isEqualTo("Failed to move file to cache.")
|
||||
}
|
||||
|
|
@ -109,10 +110,10 @@ class DefaultVoiceMessageMediaRepoTest {
|
|||
)
|
||||
|
||||
repo.getMediaFile().let { result ->
|
||||
Truth.assertThat(result.isSuccess).isTrue()
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
result.getOrThrow().let { file ->
|
||||
Truth.assertThat(file.path).isEqualTo(temporaryFolder.cachedFilePath)
|
||||
Truth.assertThat(file.exists()).isTrue()
|
||||
assertThat(file.path).isEqualTo(temporaryFolder.cachedFilePath)
|
||||
assertThat(file.exists()).isTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,10 +125,10 @@ class DefaultVoiceMessageMediaRepoTest {
|
|||
mxcUri = INVALID_MXC_URI,
|
||||
)
|
||||
repo.getMediaFile().let { result ->
|
||||
Truth.assertThat(result.isFailure).isTrue()
|
||||
assertThat(result.isFailure).isTrue()
|
||||
result.exceptionOrNull()!!.let { exception ->
|
||||
Truth.assertThat(exception).isInstanceOf(RuntimeException::class.java)
|
||||
Truth.assertThat(exception).hasMessageThat().isEqualTo("Invalid mxcUri.")
|
||||
assertThat(exception).isInstanceOf(RuntimeException::class.java)
|
||||
assertThat(exception).hasMessageThat().isEqualTo("Invalid mxcUri.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,6 +140,7 @@ private fun createDefaultVoiceMessageMediaRepo(
|
|||
mxcUri: String = MXC_URI,
|
||||
) = DefaultVoiceMessageMediaRepo(
|
||||
cacheDir = temporaryFolder.root,
|
||||
mxcTools = MxcTools(),
|
||||
matrixMediaLoader = matrixMediaLoader,
|
||||
mediaSource = MediaSource(
|
||||
url = mxcUri,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline
|
|||
|
||||
import app.cash.turbine.TurbineTestContext
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
|
|
@ -42,7 +42,7 @@ class DefaultVoiceMessagePlayerTest {
|
|||
val player = createDefaultVoiceMessagePlayer()
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState()
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ class DefaultVoiceMessagePlayerTest {
|
|||
)
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isFailure).isTrue()
|
||||
assertThat(player.prepare().isFailure).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ class DefaultVoiceMessagePlayerTest {
|
|||
)
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isFailure).isTrue()
|
||||
assertThat(player.prepare().isFailure).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,12 +76,12 @@ class DefaultVoiceMessagePlayerTest {
|
|||
val player = createDefaultVoiceMessagePlayer()
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState()
|
||||
player.play()
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.isPlaying).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,15 +96,15 @@ class DefaultVoiceMessagePlayerTest {
|
|||
)
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState(fakeTotalDurationMs = 1000)
|
||||
player.play()
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -121,72 +121,72 @@ class DefaultVoiceMessagePlayerTest {
|
|||
// Play player1 until the end.
|
||||
player1.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player1.prepare().isSuccess).isTrue()
|
||||
assertThat(player1.prepare().isSuccess).isTrue()
|
||||
matchReadyState(1_000L)
|
||||
player1.play()
|
||||
awaitItem().let { // it plays until the end.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
|
||||
// Play player2 until the end.
|
||||
player2.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player2.prepare().isSuccess).isTrue()
|
||||
assertThat(player2.prepare().isSuccess).isTrue()
|
||||
awaitItem().let { // Additional spurious state due to MediaPlayer owner change.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
awaitItem().let {// Additional spurious state due to MediaPlayer owner change.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(0)
|
||||
Truth.assertThat(it.duration).isEqualTo(null)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(0)
|
||||
assertThat(it.duration).isNull()
|
||||
}
|
||||
matchReadyState(1_000L)
|
||||
player2.play()
|
||||
awaitItem().let { // it plays until the end.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
|
||||
// Play player1 again.
|
||||
player1.state.test {
|
||||
awaitItem().let {// Last previous state/
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
Truth.assertThat(player1.prepare().isSuccess).isTrue()
|
||||
assertThat(player1.prepare().isSuccess).isTrue()
|
||||
awaitItem().let {// Additional spurious state due to MediaPlayer owner change.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(0)
|
||||
Truth.assertThat(it.duration).isEqualTo(null)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(0)
|
||||
assertThat(it.duration).isNull()
|
||||
}
|
||||
matchReadyState(1_000L)
|
||||
player1.play()
|
||||
awaitItem().let { // it played again until the end.
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
Truth.assertThat(it.duration).isEqualTo(1000)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.duration).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -196,14 +196,14 @@ class DefaultVoiceMessagePlayerTest {
|
|||
val player = createDefaultVoiceMessagePlayer()
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState()
|
||||
player.play()
|
||||
skipItems(1) // skip play state
|
||||
player.pause()
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(1000)
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ class DefaultVoiceMessagePlayerTest {
|
|||
val player = createDefaultVoiceMessagePlayer()
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState()
|
||||
player.play()
|
||||
skipItems(1) // skip play state
|
||||
|
|
@ -221,8 +221,8 @@ class DefaultVoiceMessagePlayerTest {
|
|||
skipItems(1) // skip pause state
|
||||
player.play()
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(true)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(2000)
|
||||
assertThat(it.isPlaying).isTrue()
|
||||
assertThat(it.currentPosition).isEqualTo(2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -234,19 +234,19 @@ class DefaultVoiceMessagePlayerTest {
|
|||
matchInitialState()
|
||||
player.seekTo(2000)
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(2000)
|
||||
Truth.assertThat(it.duration).isEqualTo(null)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(2000)
|
||||
assertThat(it.duration).isNull()
|
||||
}
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(true)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(2000)
|
||||
Truth.assertThat(it.duration).isEqualTo(FAKE_TOTAL_DURATION_MS)
|
||||
assertThat(it.isReady).isTrue()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(2000)
|
||||
assertThat(it.duration).isEqualTo(FAKE_TOTAL_DURATION_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -256,15 +256,15 @@ class DefaultVoiceMessagePlayerTest {
|
|||
val player = createDefaultVoiceMessagePlayer()
|
||||
player.state.test {
|
||||
matchInitialState()
|
||||
Truth.assertThat(player.prepare().isSuccess).isTrue()
|
||||
assertThat(player.prepare().isSuccess).isTrue()
|
||||
matchReadyState()
|
||||
player.seekTo(2000)
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(true)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(2000)
|
||||
Truth.assertThat(it.duration).isEqualTo(FAKE_TOTAL_DURATION_MS)
|
||||
assertThat(it.isReady).isTrue()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(2000)
|
||||
assertThat(it.duration).isEqualTo(FAKE_TOTAL_DURATION_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -296,11 +296,11 @@ private const val MXC_URI = "mxc://matrix.org/1234567890abcdefg"
|
|||
|
||||
private suspend fun TurbineTestContext<VoiceMessagePlayer.State>.matchInitialState() {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(false)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(0)
|
||||
Truth.assertThat(it.duration).isEqualTo(null)
|
||||
assertThat(it.isReady).isFalse()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(0)
|
||||
assertThat(it.duration).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,10 +308,10 @@ private suspend fun TurbineTestContext<VoiceMessagePlayer.State>.matchReadyState
|
|||
fakeTotalDurationMs: Long = FAKE_TOTAL_DURATION_MS,
|
||||
) {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.isReady).isEqualTo(true)
|
||||
Truth.assertThat(it.isPlaying).isEqualTo(false)
|
||||
Truth.assertThat(it.isEnded).isEqualTo(false)
|
||||
Truth.assertThat(it.currentPosition).isEqualTo(0)
|
||||
Truth.assertThat(it.duration).isEqualTo(fakeTotalDurationMs)
|
||||
assertThat(it.isReady).isTrue()
|
||||
assertThat(it.isPlaying).isFalse()
|
||||
assertThat(it.isEnded).isFalse()
|
||||
assertThat(it.currentPosition).isEqualTo(0)
|
||||
assertThat(it.duration).isEqualTo(fakeTotalDurationMs)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package io.element.android.features.messages.impl.voicemessages.timeline
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
|
|
@ -44,13 +44,13 @@ class RedactedVoiceMessageManagerTest {
|
|||
}
|
||||
val manager = aDefaultRedactedVoiceMessageManager(mediaPlayer = mediaPlayer)
|
||||
|
||||
Truth.assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
Truth.assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
|
||||
manager.onEachMatrixTimelineItem(aRedactedMatrixTimeline(AN_EVENT_ID_2))
|
||||
|
||||
Truth.assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
Truth.assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -61,13 +61,13 @@ class RedactedVoiceMessageManagerTest {
|
|||
}
|
||||
val manager = aDefaultRedactedVoiceMessageManager(mediaPlayer = mediaPlayer)
|
||||
|
||||
Truth.assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
Truth.assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
assertThat(mediaPlayer.state.value.isPlaying).isTrue()
|
||||
|
||||
manager.onEachMatrixTimelineItem(aRedactedMatrixTimeline(AN_EVENT_ID))
|
||||
|
||||
Truth.assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
Truth.assertThat(mediaPlayer.state.value.isPlaying).isFalse()
|
||||
assertThat(mediaPlayer.state.value.mediaId).isEqualTo(AN_EVENT_ID.value)
|
||||
assertThat(mediaPlayer.state.value.isPlaying).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package io.element.android.features.messages.impl.voicemessages.timeline
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent
|
||||
import io.element.android.features.messages.impl.voicemessages.VoiceMessageException
|
||||
|
|
@ -39,9 +39,9 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
awaitItem().let {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("1:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("1:01")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -56,27 +56,27 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.PlayPause)
|
||||
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:00")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:00")
|
||||
}
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.5f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
assertThat(it.progress).isEqualTo(0.5f)
|
||||
assertThat(it.time).isEqualTo("0:01")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,25 +94,25 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.PlayPause)
|
||||
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Downloading)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Retry)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Retry)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
analyticsService.trackedErrors.first().also {
|
||||
Truth.assertThat(it).apply {
|
||||
assertThat(it).apply {
|
||||
isInstanceOf(VoiceMessageException.PlayMessageError::class.java)
|
||||
hasMessageThat().isEqualTo("Error while trying to play voice message")
|
||||
}
|
||||
|
|
@ -130,25 +130,25 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:02")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:02")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.PlayPause)
|
||||
skipItems(2) // skip downloading states
|
||||
|
||||
val playingState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.5f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
assertThat(it.progress).isEqualTo(0.5f)
|
||||
assertThat(it.time).isEqualTo("0:01")
|
||||
}
|
||||
|
||||
playingState.eventSink(VoiceMessageEvents.PlayPause)
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.5f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0.5f)
|
||||
assertThat(it.time).isEqualTo("0:01")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,9 +162,9 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Disabled)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("1:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Disabled)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("1:01")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -179,17 +179,17 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:10")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:10")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.Seek(0.5f))
|
||||
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.5f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:05")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0.5f)
|
||||
assertThat(it.time).isEqualTo("0:05")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -203,9 +203,9 @@ class VoiceMessagePresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
Truth.assertThat(it.progress).isEqualTo(0f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:10")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Play)
|
||||
assertThat(it.progress).isEqualTo(0f)
|
||||
assertThat(it.time).isEqualTo("0:10")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.PlayPause)
|
||||
|
|
@ -213,17 +213,17 @@ class VoiceMessagePresenterTest {
|
|||
skipItems(2) // skip downloading states
|
||||
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.1f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:01")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
assertThat(it.progress).isEqualTo(0.1f)
|
||||
assertThat(it.time).isEqualTo("0:01")
|
||||
}
|
||||
|
||||
initialState.eventSink(VoiceMessageEvents.Seek(0.5f))
|
||||
|
||||
awaitItem().also {
|
||||
Truth.assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
Truth.assertThat(it.progress).isEqualTo(0.5f)
|
||||
Truth.assertThat(it.time).isEqualTo("0:05")
|
||||
assertThat(it.button).isEqualTo(VoiceMessageState.Button.Pause)
|
||||
assertThat(it.progress).isEqualTo(0.5f)
|
||||
assertThat(it.time).isEqualTo("0:05")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_onboarding_sign_in_manually">"Kézi bejelentkezés"</string>
|
||||
<string name="screen_onboarding_sign_in_with_qr_code">"Bejelentkezés QR-kóddal"</string>
|
||||
<string name="screen_onboarding_sign_up">"Fiók létrehozása"</string>
|
||||
<string name="screen_onboarding_welcome_message">"Üdvözöljük a valaha volt leggyorsabb Elementben. Felturbózva, a sebesség és az egyszerűség érdekében."</string>
|
||||
<string name="screen_onboarding_welcome_subtitle">"Üdvözli az %1$s. Felturbózva, a sebesség és az egyszerűség jegyében."</string>
|
||||
<string name="screen_onboarding_welcome_title">"Legyen elemében"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_onboarding_sign_in_manually">"Masuk secara manual"</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_message">"Selamat datang di Element 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>
|
||||
</resources>
|
||||
|
|
@ -4,7 +4,11 @@
|
|||
<string name="screen_create_poll_anonymous_desc">"Ergebnisse erst nach Ende der Umfrage anzeigen"</string>
|
||||
<string name="screen_create_poll_anonymous_headline">"Anonyme Umfrage"</string>
|
||||
<string name="screen_create_poll_answer_hint">"Option %1$d"</string>
|
||||
<string name="screen_create_poll_cancel_confirmation_content_android">"Deine Änderungen wurden nicht gespeichert. Bist du sicher, dass du zurückgehen willst?"</string>
|
||||
<string name="screen_create_poll_question_desc">"Frage oder Thema"</string>
|
||||
<string name="screen_create_poll_question_hint">"Worum geht es bei der Umfrage?"</string>
|
||||
<string name="screen_create_poll_title">"Umfrage erstellen"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation">"Bist du dir sicher, dass du diese Umfrage löschen möchtest?"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation_title">"Umfrage löschen"</string>
|
||||
<string name="screen_edit_poll_title">"Umfrage bearbeiten"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@
|
|||
<string name="screen_create_poll_anonymous_desc">"Afficher les résultats uniquement après la fin du sondage"</string>
|
||||
<string name="screen_create_poll_anonymous_headline">"Masquer les votes"</string>
|
||||
<string name="screen_create_poll_answer_hint">"Option %1$d"</string>
|
||||
<string name="screen_create_poll_cancel_confirmation_content_android">"Vos modifications n’ont pas été enregistrées. Êtes-vous certain de vouloir quitter?"</string>
|
||||
<string name="screen_create_poll_question_desc">"Question ou sujet"</string>
|
||||
<string name="screen_create_poll_question_hint">"Quel est le sujet du sondage ?"</string>
|
||||
<string name="screen_create_poll_title">"Créer un sondage"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation">"Êtes-vous certain de vouloir supprimer ce sondage?"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation_title">"Supprimer le sondage"</string>
|
||||
<string name="screen_edit_poll_title">"Modifier le sondage"</string>
|
||||
</resources>
|
||||
|
|
|
|||
14
features/poll/impl/src/main/res/values-hu/translations.xml
Normal file
14
features/poll/impl/src/main/res/values-hu/translations.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_poll_add_option_btn">"Lehetőség hozzáadása"</string>
|
||||
<string name="screen_create_poll_anonymous_desc">"Eredmények megjelenítése csak a szavazás befejezése után"</string>
|
||||
<string name="screen_create_poll_anonymous_headline">"Szavazatok elrejtése"</string>
|
||||
<string name="screen_create_poll_answer_hint">"%1$d. lehetőség"</string>
|
||||
<string name="screen_create_poll_cancel_confirmation_content_android">"A módosítások nem lettek mentve. Biztos, hogy vissza akar lépni?"</string>
|
||||
<string name="screen_create_poll_question_desc">"Kérdés vagy téma"</string>
|
||||
<string name="screen_create_poll_question_hint">"Miről szól ez a szavazás?"</string>
|
||||
<string name="screen_create_poll_title">"Szavazás létrehozása"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation">"Biztos, hogy törli ezt a szavazást?"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation_title">"Szavazás törlése"</string>
|
||||
<string name="screen_edit_poll_title">"Szavazás szerkesztése"</string>
|
||||
</resources>
|
||||
14
features/poll/impl/src/main/res/values-in/translations.xml
Normal file
14
features/poll/impl/src/main/res/values-in/translations.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_create_poll_add_option_btn">"Tambahkan opsi"</string>
|
||||
<string name="screen_create_poll_anonymous_desc">"Tampilkan hasil hanya setelah pemungutan suara berakhir"</string>
|
||||
<string name="screen_create_poll_anonymous_headline">"Pemungutan suara anonim"</string>
|
||||
<string name="screen_create_poll_answer_hint">"Opsi %1$d"</string>
|
||||
<string name="screen_create_poll_cancel_confirmation_content_android">"Perubahan Anda belum disimpan. Apakah Anda yakin ingin kembali?"</string>
|
||||
<string name="screen_create_poll_question_desc">"Pertanyaan atau topik"</string>
|
||||
<string name="screen_create_poll_question_hint">"Tentang apa pemungutan suara ini?"</string>
|
||||
<string name="screen_create_poll_title">"Buat pemungutan suara"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation">"Apakah Anda yakin ingin menghapus pemungutan suara ini?"</string>
|
||||
<string name="screen_edit_poll_delete_confirmation_title">"Hapus pemungutan suara"</string>
|
||||
<string name="screen_edit_poll_title">"Sunting pemungutan suara"</string>
|
||||
</resources>
|
||||
|
|
@ -20,7 +20,7 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.TurbineTestContext
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.Composer
|
||||
import im.vector.app.features.analytics.plan.PollCreation
|
||||
import io.element.android.features.messages.test.FakeMessageComposerContext
|
||||
|
|
@ -88,8 +88,8 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
awaitDefaultItem()
|
||||
Truth.assertThat(fakeAnalyticsService.trackedErrors.filterIsInstance<CreatePollException.GetPollFailed>()).isNotEmpty()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
assertThat(fakeAnalyticsService.trackedErrors.filterIsInstance<CreatePollException.GetPollFailed>()).isNotEmpty()
|
||||
assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,19 +100,19 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(initial.canSave).isFalse()
|
||||
assertThat(initial.canSave).isFalse()
|
||||
|
||||
initial.eventSink(CreatePollEvents.SetQuestion("A question?"))
|
||||
val questionSet = awaitItem()
|
||||
Truth.assertThat(questionSet.canSave).isFalse()
|
||||
assertThat(questionSet.canSave).isFalse()
|
||||
|
||||
questionSet.eventSink(CreatePollEvents.SetAnswer(0, "Answer 1"))
|
||||
val answer1Set = awaitItem()
|
||||
Truth.assertThat(answer1Set.canSave).isFalse()
|
||||
assertThat(answer1Set.canSave).isFalse()
|
||||
|
||||
answer1Set.eventSink(CreatePollEvents.SetAnswer(1, "Answer 2"))
|
||||
val answer2Set = awaitItem()
|
||||
Truth.assertThat(answer2Set.canSave).isTrue()
|
||||
assertThat(answer2Set.canSave).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +129,8 @@ class CreatePollPresenterTest {
|
|||
skipItems(3)
|
||||
initial.eventSink(CreatePollEvents.Save)
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
Truth.assertThat(fakeMatrixRoom.createPollInvocations.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeMatrixRoom.createPollInvocations.last()).isEqualTo(
|
||||
assertThat(fakeMatrixRoom.createPollInvocations.size).isEqualTo(1)
|
||||
assertThat(fakeMatrixRoom.createPollInvocations.last()).isEqualTo(
|
||||
SavePollInvocation(
|
||||
question = "A question?",
|
||||
answers = listOf("Answer 1", "Answer 2"),
|
||||
|
|
@ -138,8 +138,8 @@ class CreatePollPresenterTest {
|
|||
pollKind = PollKind.Disclosed
|
||||
)
|
||||
)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(2)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents[0]).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(2)
|
||||
assertThat(fakeAnalyticsService.capturedEvents[0]).isEqualTo(
|
||||
Composer(
|
||||
inThread = false,
|
||||
isEditing = false,
|
||||
|
|
@ -147,7 +147,7 @@ class CreatePollPresenterTest {
|
|||
messageType = Composer.MessageType.Poll,
|
||||
)
|
||||
)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents[1]).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents[1]).isEqualTo(
|
||||
PollCreation(
|
||||
action = PollCreation.Action.Create,
|
||||
isUndisclosed = false,
|
||||
|
|
@ -170,10 +170,10 @@ class CreatePollPresenterTest {
|
|||
awaitItem().eventSink(CreatePollEvents.SetAnswer(1, "Answer 2"))
|
||||
awaitItem().eventSink(CreatePollEvents.Save)
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
Truth.assertThat(fakeMatrixRoom.createPollInvocations).hasSize(1)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents).isEmpty()
|
||||
Truth.assertThat(fakeAnalyticsService.trackedErrors).hasSize(1)
|
||||
Truth.assertThat(fakeAnalyticsService.trackedErrors).containsExactly(
|
||||
assertThat(fakeMatrixRoom.createPollInvocations).hasSize(1)
|
||||
assertThat(fakeAnalyticsService.capturedEvents).isEmpty()
|
||||
assertThat(fakeAnalyticsService.trackedErrors).hasSize(1)
|
||||
assertThat(fakeAnalyticsService.trackedErrors).containsExactly(
|
||||
CreatePollException.SavePollFailed("Failed to create poll", error)
|
||||
)
|
||||
}
|
||||
|
|
@ -203,8 +203,8 @@ class CreatePollPresenterTest {
|
|||
eventSink(CreatePollEvents.Save)
|
||||
}
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
Truth.assertThat(fakeMatrixRoom.editPollInvocations.size).isEqualTo(1)
|
||||
Truth.assertThat(fakeMatrixRoom.editPollInvocations.last()).isEqualTo(
|
||||
assertThat(fakeMatrixRoom.editPollInvocations.size).isEqualTo(1)
|
||||
assertThat(fakeMatrixRoom.editPollInvocations.last()).isEqualTo(
|
||||
SavePollInvocation(
|
||||
question = "Changed question",
|
||||
answers = listOf("Changed answer 1", "Changed answer 2", "Maybe"),
|
||||
|
|
@ -212,8 +212,8 @@ class CreatePollPresenterTest {
|
|||
pollKind = PollKind.Disclosed
|
||||
)
|
||||
)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(2)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents[0]).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(2)
|
||||
assertThat(fakeAnalyticsService.capturedEvents[0]).isEqualTo(
|
||||
Composer(
|
||||
inThread = false,
|
||||
isEditing = true,
|
||||
|
|
@ -221,7 +221,7 @@ class CreatePollPresenterTest {
|
|||
messageType = Composer.MessageType.Poll,
|
||||
)
|
||||
)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents[1]).isEqualTo(
|
||||
assertThat(fakeAnalyticsService.capturedEvents[1]).isEqualTo(
|
||||
PollCreation(
|
||||
action = PollCreation.Action.Edit,
|
||||
isUndisclosed = false,
|
||||
|
|
@ -243,10 +243,10 @@ class CreatePollPresenterTest {
|
|||
awaitPollLoaded().eventSink(CreatePollEvents.SetAnswer(0, "A"))
|
||||
awaitPollLoaded(newAnswer1 = "A").eventSink(CreatePollEvents.Save)
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
Truth.assertThat(fakeMatrixRoom.editPollInvocations).hasSize(1)
|
||||
Truth.assertThat(fakeAnalyticsService.capturedEvents).isEmpty()
|
||||
Truth.assertThat(fakeAnalyticsService.trackedErrors).hasSize(1)
|
||||
Truth.assertThat(fakeAnalyticsService.trackedErrors).containsExactly(
|
||||
assertThat(fakeMatrixRoom.editPollInvocations).hasSize(1)
|
||||
assertThat(fakeAnalyticsService.capturedEvents).isEmpty()
|
||||
assertThat(fakeAnalyticsService.trackedErrors).hasSize(1)
|
||||
assertThat(fakeAnalyticsService.trackedErrors).containsExactly(
|
||||
CreatePollException.SavePollFailed("Failed to edit poll", error)
|
||||
)
|
||||
}
|
||||
|
|
@ -259,16 +259,16 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(initial.answers.size).isEqualTo(2)
|
||||
assertThat(initial.answers.size).isEqualTo(2)
|
||||
|
||||
initial.eventSink(CreatePollEvents.AddAnswer)
|
||||
val answerAdded = awaitItem()
|
||||
Truth.assertThat(answerAdded.answers.size).isEqualTo(3)
|
||||
Truth.assertThat(answerAdded.answers[2].text).isEmpty()
|
||||
assertThat(answerAdded.answers.size).isEqualTo(3)
|
||||
assertThat(answerAdded.answers[2].text).isEmpty()
|
||||
|
||||
initial.eventSink(CreatePollEvents.RemoveAnswer(2))
|
||||
val answerRemoved = awaitItem()
|
||||
Truth.assertThat(answerRemoved.answers.size).isEqualTo(2)
|
||||
assertThat(answerRemoved.answers.size).isEqualTo(2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +281,7 @@ class CreatePollPresenterTest {
|
|||
val initial = awaitItem()
|
||||
initial.eventSink(CreatePollEvents.SetQuestion("A question?"))
|
||||
val questionSet = awaitItem()
|
||||
Truth.assertThat(questionSet.question).isEqualTo("A question?")
|
||||
assertThat(questionSet.question).isEqualTo("A question?")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ class CreatePollPresenterTest {
|
|||
val initial = awaitItem()
|
||||
initial.eventSink(CreatePollEvents.SetAnswer(0, "This is answer 1"))
|
||||
val answerSet = awaitItem()
|
||||
Truth.assertThat(answerSet.answers.first().text).isEqualTo("This is answer 1")
|
||||
assertThat(answerSet.answers.first().text).isEqualTo("This is answer 1")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ class CreatePollPresenterTest {
|
|||
val initial = awaitItem()
|
||||
initial.eventSink(CreatePollEvents.SetPollKind(PollKind.Undisclosed))
|
||||
val kindSet = awaitItem()
|
||||
Truth.assertThat(kindSet.pollKind).isEqualTo(PollKind.Undisclosed)
|
||||
assertThat(kindSet.pollKind).isEqualTo(PollKind.Undisclosed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,13 +318,13 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(initial.canAddAnswer).isTrue()
|
||||
assertThat(initial.canAddAnswer).isTrue()
|
||||
repeat(17) {
|
||||
initial.eventSink(CreatePollEvents.AddAnswer)
|
||||
Truth.assertThat(awaitItem().canAddAnswer).isTrue()
|
||||
assertThat(awaitItem().canAddAnswer).isTrue()
|
||||
}
|
||||
initial.eventSink(CreatePollEvents.AddAnswer)
|
||||
Truth.assertThat(awaitItem().canAddAnswer).isFalse()
|
||||
assertThat(awaitItem().canAddAnswer).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,9 +335,9 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(initial.answers.all { it.canDelete }).isFalse()
|
||||
assertThat(initial.answers.all { it.canDelete }).isFalse()
|
||||
initial.eventSink(CreatePollEvents.AddAnswer)
|
||||
Truth.assertThat(awaitItem().answers.all { it.canDelete }).isTrue()
|
||||
assertThat(awaitItem().answers.all { it.canDelete }).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,7 +349,7 @@ class CreatePollPresenterTest {
|
|||
}.test {
|
||||
val initial = awaitItem()
|
||||
initial.eventSink(CreatePollEvents.SetAnswer(0, "A".repeat(241)))
|
||||
Truth.assertThat(awaitItem().answers.first().text.length).isEqualTo(240)
|
||||
assertThat(awaitItem().answers.first().text.length).isEqualTo(240)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,9 +360,9 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
initial.eventSink(CreatePollEvents.NavBack)
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,10 +373,10 @@ class CreatePollPresenterTest {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initial = awaitItem()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
Truth.assertThat(initial.showBackConfirmation).isFalse()
|
||||
assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
assertThat(initial.showBackConfirmation).isFalse()
|
||||
initial.eventSink(CreatePollEvents.ConfirmNavBack)
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -388,12 +388,12 @@ class CreatePollPresenterTest {
|
|||
}.test {
|
||||
val initial = awaitItem()
|
||||
initial.eventSink(CreatePollEvents.SetQuestion("Non blank"))
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
initial.eventSink(CreatePollEvents.ConfirmNavBack)
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isTrue()
|
||||
assertThat(awaitItem().showBackConfirmation).isTrue()
|
||||
initial.eventSink(CreatePollEvents.HideConfirmation)
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -405,10 +405,10 @@ class CreatePollPresenterTest {
|
|||
}.test {
|
||||
awaitDefaultItem()
|
||||
val loaded = awaitPollLoaded()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
Truth.assertThat(loaded.showBackConfirmation).isFalse()
|
||||
assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
assertThat(loaded.showBackConfirmation).isFalse()
|
||||
loaded.eventSink(CreatePollEvents.ConfirmNavBack)
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
assertThat(navUpInvocationsCount).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,12 +421,12 @@ class CreatePollPresenterTest {
|
|||
awaitDefaultItem()
|
||||
val loaded = awaitPollLoaded()
|
||||
loaded.eventSink(CreatePollEvents.SetQuestion("CHANGED"))
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
loaded.eventSink(CreatePollEvents.ConfirmNavBack)
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isTrue()
|
||||
assertThat(awaitItem().showBackConfirmation).isTrue()
|
||||
loaded.eventSink(CreatePollEvents.HideConfirmation)
|
||||
Truth.assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
Truth.assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
assertThat(awaitItem().showBackConfirmation).isFalse()
|
||||
assertThat(navUpInvocationsCount).isEqualTo(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +439,7 @@ class CreatePollPresenterTest {
|
|||
awaitDefaultItem()
|
||||
awaitPollLoaded().eventSink(CreatePollEvents.Delete(confirmed = false))
|
||||
awaitDeleteConfirmation()
|
||||
Truth.assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -451,12 +451,12 @@ class CreatePollPresenterTest {
|
|||
}.test {
|
||||
awaitDefaultItem()
|
||||
awaitPollLoaded().eventSink(CreatePollEvents.Delete(confirmed = false))
|
||||
Truth.assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
awaitDeleteConfirmation().eventSink(CreatePollEvents.HideConfirmation)
|
||||
awaitPollLoaded().apply {
|
||||
Truth.assertThat(showDeleteConfirmation).isFalse()
|
||||
assertThat(showDeleteConfirmation).isFalse()
|
||||
}
|
||||
Truth.assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -468,29 +468,29 @@ class CreatePollPresenterTest {
|
|||
}.test {
|
||||
awaitDefaultItem()
|
||||
awaitPollLoaded().eventSink(CreatePollEvents.Delete(confirmed = false))
|
||||
Truth.assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
assertThat(fakeMatrixRoom.redactEventEventIdParam).isNull()
|
||||
awaitDeleteConfirmation().eventSink(CreatePollEvents.Delete(confirmed = true))
|
||||
awaitPollLoaded().apply {
|
||||
Truth.assertThat(showDeleteConfirmation).isFalse()
|
||||
assertThat(showDeleteConfirmation).isFalse()
|
||||
}
|
||||
Truth.assertThat(fakeMatrixRoom.redactEventEventIdParam).isEqualTo(pollEventId)
|
||||
assertThat(fakeMatrixRoom.redactEventEventIdParam).isEqualTo(pollEventId)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<CreatePollState>.awaitDefaultItem() =
|
||||
awaitItem().apply {
|
||||
Truth.assertThat(canSave).isFalse()
|
||||
Truth.assertThat(canAddAnswer).isTrue()
|
||||
Truth.assertThat(question).isEmpty()
|
||||
Truth.assertThat(answers).isEqualTo(listOf(Answer("", false), Answer("", false)))
|
||||
Truth.assertThat(pollKind).isEqualTo(PollKind.Disclosed)
|
||||
Truth.assertThat(showBackConfirmation).isFalse()
|
||||
Truth.assertThat(showDeleteConfirmation).isFalse()
|
||||
assertThat(canSave).isFalse()
|
||||
assertThat(canAddAnswer).isTrue()
|
||||
assertThat(question).isEmpty()
|
||||
assertThat(answers).isEqualTo(listOf(Answer("", false), Answer("", false)))
|
||||
assertThat(pollKind).isEqualTo(PollKind.Disclosed)
|
||||
assertThat(showBackConfirmation).isFalse()
|
||||
assertThat(showDeleteConfirmation).isFalse()
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<CreatePollState>.awaitDeleteConfirmation() =
|
||||
awaitItem().apply {
|
||||
Truth.assertThat(showDeleteConfirmation).isTrue()
|
||||
assertThat(showDeleteConfirmation).isTrue()
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<CreatePollState>.awaitPollLoaded(
|
||||
|
|
@ -499,14 +499,14 @@ class CreatePollPresenterTest {
|
|||
newAnswer2: String? = null,
|
||||
) =
|
||||
awaitItem().apply {
|
||||
Truth.assertThat(canSave).isTrue()
|
||||
Truth.assertThat(canAddAnswer).isTrue()
|
||||
Truth.assertThat(question).isEqualTo(newQuestion ?: existingPoll.question)
|
||||
Truth.assertThat(answers).isEqualTo(existingPoll.expectedAnswersState().toMutableList().apply {
|
||||
assertThat(canSave).isTrue()
|
||||
assertThat(canAddAnswer).isTrue()
|
||||
assertThat(question).isEqualTo(newQuestion ?: existingPoll.question)
|
||||
assertThat(answers).isEqualTo(existingPoll.expectedAnswersState().toMutableList().apply {
|
||||
newAnswer1?.let { this[0] = Answer(it, true) }
|
||||
newAnswer2?.let { this[1] = Answer(it, true) }
|
||||
})
|
||||
Truth.assertThat(pollKind).isEqualTo(existingPoll.kind)
|
||||
assertThat(pollKind).isEqualTo(existingPoll.kind)
|
||||
}
|
||||
|
||||
private fun createCreatePollPresenter(
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package io.element.android.features.preferences.impl.notifications
|
||||
|
||||
sealed interface NotificationSettingsEvents {
|
||||
|
||||
data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents
|
||||
data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetInviteForMeNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data object FixConfigurationMismatch : NotificationSettingsEvents
|
||||
data object ClearConfigurationMismatchError : NotificationSettingsEvents
|
||||
data object ClearNotificationChangeError : NotificationSettingsEvents
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
is NotificationSettingsEvents.SetCallNotificationsEnabled -> {
|
||||
localCoroutineScope.setCallNotificationsEnabled(event.enabled, changeNotificationSettingAction)
|
||||
}
|
||||
is NotificationSettingsEvents.SetInviteForMeNotificationsEnabled -> {
|
||||
localCoroutineScope.setInviteForMeNotificationsEnabled(event.enabled, changeNotificationSettingAction)
|
||||
}
|
||||
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
|
||||
NotificationSettingsEvents.ClearConfigurationMismatchError -> {
|
||||
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
|
||||
|
|
@ -123,10 +126,12 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
|
||||
val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow()
|
||||
val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow()
|
||||
val inviteForMeNotificationsEnabled = notificationSettingsService.isInviteForMeEnabled().getOrThrow()
|
||||
|
||||
target.value = NotificationSettingsState.MatrixSettings.Valid(
|
||||
atRoomNotificationsEnabled = atRoomNotificationsEnabled,
|
||||
callNotificationsEnabled = callNotificationsEnabled,
|
||||
inviteForMeNotificationsEnabled = inviteForMeNotificationsEnabled,
|
||||
defaultGroupNotificationMode = encryptedGroupDefaultMode,
|
||||
defaultOneToOneNotificationMode = encryptedOneToOneDefaultMode,
|
||||
)
|
||||
|
|
@ -175,6 +180,12 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
}.runCatchingUpdatingState(action)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setInviteForMeNotificationsEnabled(enabled: Boolean, action: MutableState<Async<Unit>>) = launch {
|
||||
suspend {
|
||||
notificationSettingsService.setInviteForMeEnabled(enabled).getOrThrow()
|
||||
}.runCatchingUpdatingState(action)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch {
|
||||
userPushStore.setNotificationEnabledForDevice(enabled)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ data class NotificationSettingsState(
|
|||
data class Valid(
|
||||
val atRoomNotificationsEnabled: Boolean,
|
||||
val callNotificationsEnabled: Boolean,
|
||||
val inviteForMeNotificationsEnabled: Boolean,
|
||||
val defaultGroupNotificationMode: RoomNotificationMode?,
|
||||
val defaultOneToOneNotificationMode: RoomNotificationMode?,
|
||||
) : MatrixSettings
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ fun aNotificationSettingsState(
|
|||
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
|
||||
atRoomNotificationsEnabled = true,
|
||||
callNotificationsEnabled = true,
|
||||
inviteForMeNotificationsEnabled = true,
|
||||
defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ fun NotificationSettingsView(
|
|||
onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) },
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) },
|
||||
onInviteForMeNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(it)) },
|
||||
)
|
||||
}
|
||||
AsyncView(
|
||||
|
|
@ -98,6 +99,7 @@ private fun NotificationSettingsContentView(
|
|||
onMentionNotificationsChanged: (Boolean) -> Unit,
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// onCallsNotificationsChanged: (Boolean) -> Unit,
|
||||
onInviteForMeNotificationsChanged: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -147,8 +149,8 @@ private fun NotificationSettingsContentView(
|
|||
onCheckedChange = onMentionNotificationsChanged
|
||||
)
|
||||
}
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_additional_settings_section_title)) {
|
||||
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_additional_settings_section_title)) {
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// PreferenceSwitch(
|
||||
// modifier = Modifier,
|
||||
// title = stringResource(id = CommonStrings.screen_notification_settings_calls_label),
|
||||
|
|
@ -156,7 +158,14 @@ private fun NotificationSettingsContentView(
|
|||
// switchAlignment = Alignment.Top,
|
||||
// onCheckedChange = onCallsNotificationsChanged
|
||||
// )
|
||||
// }
|
||||
PreferenceSwitch(
|
||||
modifier = Modifier,
|
||||
title = stringResource(id = R.string.screen_notification_settings_invite_for_me_label),
|
||||
isChecked = matrixSettings.inviteForMeNotificationsEnabled,
|
||||
switchAlignment = Alignment.Top,
|
||||
onCheckedChange = onInviteForMeNotificationsChanged
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ Pokud budete pokračovat, některá nastavení se mohou změnit."</string>
|
|||
<string name="screen_notification_settings_enable_notifications">"Povolit oznámení na tomto zařízení"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"Konfigurace nebyla opravena, zkuste to prosím znovu."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Skupinové chaty"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Pozvánky"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Váš domovský server tuto možnost v zašifrovaných místnostech nepodporuje, v některých místnostech nemusíte být upozorněni."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Zmínky"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Vše"</string>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_advanced_settings_element_call_base_url">"Benutzerdefinierte Element-Aufruf-Basis-URL"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Lege eine eigene Basis-URL für Element Call fest."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"Ungültige URL, bitte stelle sicher, dass du das Protokoll (http/https) und die richtige Adresse angibst."</string>
|
||||
<string name="screen_advanced_settings_developer_mode">"Entwickler-Modus"</string>
|
||||
<string name="screen_advanced_settings_developer_mode_description">"Aktivieren, um Zugriff auf Features und Funktionen für Entwickler zu aktivieren."</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Deaktiviere den Rich-Text-Editor, um Markdown manuell einzugeben."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Option aktiveren, um Nachrichtenquelle in der Zeitleiste anzuzeigen."</string>
|
||||
<string name="screen_edit_profile_display_name">"Anzeigename"</string>
|
||||
<string name="screen_edit_profile_display_name_placeholder">"Dein Anzeigename"</string>
|
||||
<string name="screen_edit_profile_error">"Ein unbekannter Fehler ist aufgetreten und die Informationen konnten nicht geändert werden."</string>
|
||||
|
|
@ -22,6 +27,7 @@
|
|||
<string name="screen_notification_settings_enable_notifications">"Benachrichtigungen auf diesem Gerät aktivieren"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"Die Konfiguration wurde nicht korrigiert, bitte versuche es erneut."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Gruppenchats"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Dein Homeserver unterstützt diese Option in verschlüsselten Räumen nicht. In einigen Räumen wirst du möglicherweise nicht benachrichtigt."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Erwähnungen"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Alle"</string>
|
||||
<string name="screen_notification_settings_mode_mentions">"Erwähnungen"</string>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
<string name="screen_advanced_settings_developer_mode">"Mode développeur"</string>
|
||||
<string name="screen_advanced_settings_developer_mode_description">"Activer pour pouvoir accéder aux fonctionnalités destinées aux développeurs."</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Désactivez l’éditeur de texte enrichi pour saisir manuellement du Markdown."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Activer cette option pour pouvoir voir la source des messages dans la discussion."</string>
|
||||
<string name="screen_edit_profile_display_name">"Pseudonyme"</string>
|
||||
<string name="screen_edit_profile_display_name_placeholder">"Votre pseudonyme"</string>
|
||||
<string name="screen_edit_profile_error">"Une erreur inconnue s’est produite et les informations n’ont pas pu être modifiées."</string>
|
||||
|
|
@ -30,6 +31,7 @@ Si vous continuez, il est possible que certains de vos paramètres soient modifi
|
|||
<string name="screen_notification_settings_enable_notifications">"Activer les notifications sur cet appareil"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"La configuration n’a pas été corrigée, veuillez réessayer."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Discussions de groupe"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Invitations"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Votre serveur d’accueil ne supporte pas cette option pour les salons chiffrés, vous pourriez ne pas être notifié(e) dans certains salons."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Mentions"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Tous"</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_advanced_settings_element_call_base_url">"Egyéni Element Call alapwebcím"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Egyéni alapwebcím beállítása az Element Callhoz."</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_validation_error">"Érvénytelen webcím, győződjön meg arról, hogy szerepel benne a protokoll (http/https), és hogy helyes a cím."</string>
|
||||
<string name="screen_advanced_settings_developer_mode">"Fejlesztői mód"</string>
|
||||
<string name="screen_advanced_settings_developer_mode_description">"Engedélyezze, hogy elérje a fejlesztőknek szánt funkciókat."</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"A formázott szöveges szerkesztő letiltása, hogy kézzel írhasson Markdownt."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Engedélyezze a beállítást az üzenet forrásának megjelenítéséhez az idővonalon."</string>
|
||||
<string name="screen_edit_profile_display_name">"Megjelenítendő név"</string>
|
||||
<string name="screen_edit_profile_display_name_placeholder">"Saját megjelenítendő név"</string>
|
||||
<string name="screen_edit_profile_error">"Ismeretlen hiba történt, és az információ módosítása nem sikerült."</string>
|
||||
<string name="screen_edit_profile_error_title">"Nem sikerült frissíteni a profilt"</string>
|
||||
<string name="screen_edit_profile_title">"Profil szerkesztése"</string>
|
||||
<string name="screen_edit_profile_updating_details">"Profil frissítése…"</string>
|
||||
<string name="screen_notification_settings_additional_settings_section_title">"További beállítások"</string>
|
||||
<string name="screen_notification_settings_calls_label">"Hang- és videóhívások"</string>
|
||||
<string name="screen_notification_settings_configuration_mismatch">"Konfigurációs eltérés"</string>
|
||||
<string name="screen_notification_settings_configuration_mismatch_description">"Egyszerűsítettük az értesítési beállításokat, hogy könnyebben megtalálhatók legyenek a lehetőségek. A korábban kiválasztott egyéni beállítások némelyike nem jelenik meg itt, de továbbra is aktív.
|
||||
|
||||
Ha folytatja, egyes beállítások megváltozhatnak."</string>
|
||||
<string name="screen_notification_settings_direct_chats">"Közvetlen csevegések"</string>
|
||||
<string name="screen_notification_settings_edit_custom_settings_section_title">"Egyéni beállítás csevegésenként"</string>
|
||||
<string name="screen_notification_settings_edit_failed_updating_default_mode">"Hiba történt az értesítési beállítás frissítésekor."</string>
|
||||
<string name="screen_notification_settings_edit_mode_all_messages">"Összes üzenet"</string>
|
||||
<string name="screen_notification_settings_edit_mode_mentions_and_keywords">"Csak említések és kulcsszavak"</string>
|
||||
<string name="screen_notification_settings_edit_screen_direct_section_header">"Közvetlen csevegéseknél értesítés ezekről:"</string>
|
||||
<string name="screen_notification_settings_edit_screen_group_section_header">"Csoportos csevegésekben értesítés ezekről:"</string>
|
||||
<string name="screen_notification_settings_enable_notifications">"Értesítések engedélyezése ezen az eszközön"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"A konfiguráció nem lett kijavítva, próbálja újra."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Csoportos csevegések"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"A Matrix-kiszolgálója nem támogatja ezt a beállítást a titkosított szobákban, előfordulhat, hogy egyes szobákban nem kap értesítést."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Említések"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Összes"</string>
|
||||
<string name="screen_notification_settings_mode_mentions">"Említések"</string>
|
||||
<string name="screen_notification_settings_notification_section_title">"Értesítés ezekről:"</string>
|
||||
<string name="screen_notification_settings_room_mention_label">"Értesítés a @room említésekor"</string>
|
||||
<string name="screen_notification_settings_system_notifications_action_required">"Az értesítések fogadásához kérjük, módosítsa a %1$s."</string>
|
||||
<string name="screen_notification_settings_system_notifications_action_required_content_link">"rendszerbeállításokat"</string>
|
||||
<string name="screen_notification_settings_system_notifications_turned_off">"A rendszerértesítések ki vannak kapcsolva"</string>
|
||||
<string name="screen_notification_settings_title">"Értesítések"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_advanced_settings_element_call_base_url">"URL dasar Element Call khusus"</string>
|
||||
<string name="screen_advanced_settings_element_call_base_url_description">"Tetapkan URL dasar khusus untuk Element Call."</string>
|
||||
<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_developer_mode">"Mode pengembang"</string>
|
||||
<string name="screen_advanced_settings_developer_mode_description">"Aktifkan untuk mengakses fitur dan fungsi untuk para pengembang."</string>
|
||||
<string name="screen_advanced_settings_rich_text_editor_description">"Nonaktifkan penyunting teks kaya untuk mengetik Markdown secara manual."</string>
|
||||
<string name="screen_advanced_settings_view_source_description">"Aktifkan opsi untuk melihat sumber pesan dalam lini masa."</string>
|
||||
<string name="screen_edit_profile_display_name">"Nama tampilan"</string>
|
||||
<string name="screen_edit_profile_display_name_placeholder">"Nama tampilan Anda"</string>
|
||||
<string name="screen_edit_profile_error">"Terjadi kesalahan yang tidak diketahui dan informasi tidak dapat diubah."</string>
|
||||
<string name="screen_edit_profile_error_title">"Tidak dapat memperbarui profil"</string>
|
||||
<string name="screen_edit_profile_title">"Sunting profil"</string>
|
||||
<string name="screen_edit_profile_updating_details">"Memperbarui profil…"</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>
|
||||
<string name="screen_notification_settings_configuration_mismatch_description">"Kami telah menyederhanakan Pengaturan Pemberitahuan untuk membuat opsi lebih mudah ditemukan.
|
||||
|
||||
Beberapa pengaturan khusus yang Anda pilih di masa lalu tidak ditampilkan di sini, tetapi masih aktif.
|
||||
|
||||
Jika Anda melanjutkan, beberapa pengaturan Anda dapat berubah."</string>
|
||||
<string name="screen_notification_settings_direct_chats">"Obrolan langsung"</string>
|
||||
<string name="screen_notification_settings_edit_custom_settings_section_title">"Pengaturan khusus per obrolan"</string>
|
||||
<string name="screen_notification_settings_edit_failed_updating_default_mode">"Terjadi kesalahan saat memperbarui pengaturan pemberitahuan."</string>
|
||||
<string name="screen_notification_settings_edit_mode_all_messages">"Semua pesan"</string>
|
||||
<string name="screen_notification_settings_edit_mode_mentions_and_keywords">"Sebutan dan Kata Kunci saja"</string>
|
||||
<string name="screen_notification_settings_edit_screen_direct_section_header">"Di obrolan langsung, beri tahu saya tentang"</string>
|
||||
<string name="screen_notification_settings_edit_screen_group_section_header">"Di obrolan grup, beri tahu tentang"</string>
|
||||
<string name="screen_notification_settings_enable_notifications">"Aktifkan pemberitahuan di perangkat ini"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"Pengaturan belum diperbaiki, silakan coba lagi."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Obrolan grup"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Undangan"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Homeserver Anda tidak mendukung opsi ini dalam ruangan terenkripsi, Anda mungkin tidak diberi tahu dalam beberapa ruangan."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Sebutan"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Semua"</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_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>
|
||||
</resources>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
<string name="screen_notification_settings_enable_notifications">"Включить уведомления на данном устройстве"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"Конфигурация не была исправлена, попробуйте еще раз."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Групповые чаты"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Приглашения"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Ваш домашний сервер не поддерживает эту опцию в зашифрованных комнатах, в некоторых комнатах вы можете не получать уведомления."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Упоминания"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Все"</string>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ Ak budete pokračovať, niektoré z vašich nastavení sa môžu zmeniť."</stri
|
|||
<string name="screen_notification_settings_enable_notifications">"Povoliť oznámenia na tomto zariadení"</string>
|
||||
<string name="screen_notification_settings_failed_fixing_configuration">"Konfigurácia nebola opravená, skúste to prosím znova."</string>
|
||||
<string name="screen_notification_settings_group_chats">"Skupinové rozhovory"</string>
|
||||
<string name="screen_notification_settings_invite_for_me_label">"Pozvánky"</string>
|
||||
<string name="screen_notification_settings_mentions_only_disclaimer">"Váš domovský server nepodporuje túto možnosť v šifrovaných miestnostiach, v niektorých miestnostiach nemusíte dostať upozornenie."</string>
|
||||
<string name="screen_notification_settings_mentions_section_title">"Zmienky"</string>
|
||||
<string name="screen_notification_settings_mode_all">"Všetky"</string>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package io.element.android.features.preferences.impl.notifications
|
|||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter
|
||||
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
|
|
@ -44,13 +44,13 @@ class EditDefaultNotificationSettingsPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.mode).isNull()
|
||||
Truth.assertThat(initialState.isOneToOne).isFalse()
|
||||
assertThat(initialState.mode).isNull()
|
||||
assertThat(initialState.isOneToOne).isFalse()
|
||||
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
}.last()
|
||||
Truth.assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ class EditDefaultNotificationSettingsPresenterTests {
|
|||
val loadedState = consumeItemsUntilPredicate { state ->
|
||||
state.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES }
|
||||
}.last()
|
||||
Truth.assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
|
||||
assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ class EditDefaultNotificationSettingsPresenterTests {
|
|||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.mode == RoomNotificationMode.ALL_MESSAGES
|
||||
}.last()
|
||||
Truth.assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,12 +103,12 @@ class EditDefaultNotificationSettingsPresenterTests {
|
|||
val errorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isFailure()
|
||||
}.last()
|
||||
Truth.assertThat(errorState.changeNotificationSettingAction.isFailure()).isTrue()
|
||||
assertThat(errorState.changeNotificationSettingAction.isFailure()).isTrue()
|
||||
errorState.eventSink(EditDefaultNotificationSettingStateEvents.ClearError)
|
||||
val clearErrorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isUninitialized()
|
||||
}.last()
|
||||
Truth.assertThat(clearErrorState.changeNotificationSettingAction.isUninitialized()).isTrue()
|
||||
assertThat(clearErrorState.changeNotificationSettingAction.isUninitialized()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
|
|
@ -38,20 +38,20 @@ class NotificationSettingsPresenterTests {
|
|||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
Truth.assertThat(initialState.appSettings.appNotificationsEnabled).isFalse()
|
||||
Truth.assertThat(initialState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
Truth.assertThat(initialState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Uninitialized)
|
||||
|
||||
assertThat(initialState.appSettings.appNotificationsEnabled).isFalse()
|
||||
assertThat(initialState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
assertThat(initialState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Uninitialized)
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
Truth.assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
|
||||
Truth.assertThat(loadedState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
|
||||
assertThat(loadedState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
val valid = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(valid?.atRoomNotificationsEnabled).isFalse()
|
||||
Truth.assertThat(valid?.callNotificationsEnabled).isFalse()
|
||||
Truth.assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
Truth.assertThat(valid?.defaultOneToOneNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
assertThat(valid?.atRoomNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.callNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.inviteForMeNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
assertThat(valid?.defaultOneToOneNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +63,6 @@ class NotificationSettingsPresenterTests {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
|
|
@ -71,7 +70,7 @@ class NotificationSettingsPresenterTests {
|
|||
?.defaultGroupNotificationMode == RoomNotificationMode.ALL_MESSAGES
|
||||
}.last()
|
||||
val valid = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +81,6 @@ class NotificationSettingsPresenterTests {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||
isEncrypted = true,
|
||||
isOneToOne = false,
|
||||
|
|
@ -96,7 +94,7 @@ class NotificationSettingsPresenterTests {
|
|||
val updatedState = consumeItemsUntilPredicate {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Invalid
|
||||
}.last()
|
||||
Truth.assertThat(updatedState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false))
|
||||
assertThat(updatedState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,9 +116,8 @@ class NotificationSettingsPresenterTests {
|
|||
val fixedState = consumeItemsUntilPredicate(timeout = 2000.milliseconds) {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
|
||||
val fixedMatrixState = fixedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(fixedMatrixState?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
assertThat(fixedMatrixState?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,13 +130,12 @@ class NotificationSettingsPresenterTests {
|
|||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
Truth.assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
|
||||
|
||||
assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(false))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
!it.appSettings.appNotificationsEnabled
|
||||
}.last()
|
||||
Truth.assertThat(updatedState.appSettings.appNotificationsEnabled).isFalse()
|
||||
assertThat(updatedState.appSettings.appNotificationsEnabled).isFalse()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
@ -154,14 +150,34 @@ class NotificationSettingsPresenterTests {
|
|||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == false
|
||||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(validMatrixState?.callNotificationsEnabled).isFalse()
|
||||
|
||||
assertThat(validMatrixState?.callNotificationsEnabled).isFalse()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == true
|
||||
}.last()
|
||||
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(updatedMatrixState?.callNotificationsEnabled).isTrue()
|
||||
assertThat(updatedMatrixState?.callNotificationsEnabled).isTrue()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - set invite for me notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == false
|
||||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(validMatrixState?.inviteForMeNotificationsEnabled).isFalse()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == true
|
||||
}.last()
|
||||
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(updatedMatrixState?.inviteForMeNotificationsEnabled).isTrue()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
@ -176,14 +192,13 @@ class NotificationSettingsPresenterTests {
|
|||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == false
|
||||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
|
||||
assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == true
|
||||
}.last()
|
||||
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(updatedMatrixState?.atRoomNotificationsEnabled).isTrue()
|
||||
assertThat(updatedMatrixState?.atRoomNotificationsEnabled).isTrue()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
@ -200,19 +215,17 @@ class NotificationSettingsPresenterTests {
|
|||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == false
|
||||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
Truth.assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
|
||||
assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(true))
|
||||
val errorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isFailure()
|
||||
}.last()
|
||||
Truth.assertThat(errorState.changeNotificationSettingAction.isFailure()).isTrue()
|
||||
assertThat(errorState.changeNotificationSettingAction.isFailure()).isTrue()
|
||||
errorState.eventSink(NotificationSettingsEvents.ClearNotificationChangeError)
|
||||
|
||||
val clearErrorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isUninitialized()
|
||||
}.last()
|
||||
Truth.assertThat(clearErrorState.changeNotificationSettingAction.isUninitialized()).isTrue()
|
||||
assertThat(clearErrorState.changeNotificationSettingAction.isUninitialized()).isTrue()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ class PreferencesRootPresenterTest {
|
|||
avatarUrl = AN_AVATAR_URL
|
||||
)
|
||||
)
|
||||
assertThat(loadedState.showDeveloperSettings).isEqualTo(true)
|
||||
assertThat(loadedState.showAnalyticsSettings).isEqualTo(false)
|
||||
assertThat(loadedState.showDeveloperSettings).isTrue()
|
||||
assertThat(loadedState.showAnalyticsSettings).isFalse()
|
||||
assertThat(loadedState.accountManagementUrl).isNull()
|
||||
assertThat(loadedState.devicesManagementUrl).isNull()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,4 +47,9 @@ interface BugReporter {
|
|||
* Provide the log directory.
|
||||
*/
|
||||
fun logDirectory(): File
|
||||
|
||||
/**
|
||||
* Set the current tracing filter.
|
||||
*/
|
||||
fun setCurrentTracingFilter(tracingFilter: String)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?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$s ist bei der letzten Nutzung abgestürzt. Möchtest du einen Absturzbericht mit uns teilen?"</string>
|
||||
<string name="rageshake_detection_dialog_content">"Du scheinst das Telefon aus Frustration zu schütteln. Möchtest du den Bildschirm für den Fehlerbericht öffnen?"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Erkennungsschwelle"</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="crash_detection_dialog_content">"Az %1$s összeomlott a legutóbbi használata óta. Megosztja velünk az összeomlás-jelentést?"</string>
|
||||
<string name="rageshake_detection_dialog_content">"Úgy tűnik, mintha mérgében a telefont rázná. Megnyitja a hibajelentési képernyőt?"</string>
|
||||
<string name="settings_rageshake">"Ideges rázás"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Észlelési küszöb"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="crash_detection_dialog_content">"%1$s mengalami kemogokan saat terakhir kali digunakan. Apakah Anda ingin berbagi laporan kerusakan dengan kami?"</string>
|
||||
<string name="rageshake_detection_dialog_content">"Anda tampaknya mengguncang telepon karena frustrasi. Apakah Anda ingin membuka layar laporan kutu?"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Ambang batas deteksi"</string>
|
||||
</resources>
|
||||
|
|
@ -136,7 +136,7 @@ class VectorFileLogger(
|
|||
*
|
||||
* @return The list of files with logs.
|
||||
*/
|
||||
fun getLogFiles(): List<File> {
|
||||
private fun getLogFiles(): List<File> {
|
||||
return tryOrNull(
|
||||
onError = { Timber.e(it, "## getLogFiles() failed") }
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import io.element.android.libraries.core.meta.BuildMeta
|
|||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.network.useragent.UserAgentProvider
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
|
|
@ -63,6 +64,7 @@ import javax.inject.Provider
|
|||
/**
|
||||
* BugReporter creates and sends the bug reports.
|
||||
*/
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultBugReporter @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
|
|
@ -86,10 +88,10 @@ class DefaultBugReporter @Inject constructor(
|
|||
|
||||
// the pending bug report call
|
||||
private var bugReportCall: Call? = null
|
||||
|
||||
// boolean to cancel the bug report
|
||||
private val isCancelled = false
|
||||
private val logcatCommandDebug = arrayOf("logcat", "-d", "-v", "threadtime", "*:*")
|
||||
private var currentTracingFilter: String? = null
|
||||
|
||||
override suspend fun sendBugReport(
|
||||
withDevicesLogs: Boolean,
|
||||
|
|
@ -153,6 +155,9 @@ class DefaultBugReporter @Inject constructor(
|
|||
.addFormDataPart("device_id", deviceId)
|
||||
.addFormDataPart("device", Build.MODEL.trim())
|
||||
.addFormDataPart("locale", Locale.getDefault().toString())
|
||||
currentTracingFilter?.let {
|
||||
builder.addFormDataPart("tracing_filter", it)
|
||||
}
|
||||
|
||||
// add the gzipped files, don't cancel the whole upload if only some file failed to upload
|
||||
var uploadedSomeLogs = false
|
||||
|
|
@ -323,6 +328,10 @@ class DefaultBugReporter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun setCurrentTracingFilter(tracingFilter: String) {
|
||||
currentTracingFilter = tracingFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the files on the log directory.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<string name="screen_bug_report_contact_me">"Sie können mich kontaktieren, wenn Sie weitere Fragen haben."</string>
|
||||
<string name="screen_bug_report_contact_me_title">"Kontaktieren Sie mich"</string>
|
||||
<string name="screen_bug_report_edit_screenshot">"Bildschirmfoto bearbeiten"</string>
|
||||
<string name="screen_bug_report_editor_description">"Bitte beschreibe den Fehler. Was hast du getan? Was hast du erwartet, was passiert? Was ist tatsächlich passiert. Bitte gehe so detailliert wie möglich vor."</string>
|
||||
<string name="screen_bug_report_editor_description">"Bitte beschreibe den Fehler. Was hast du getan? Was hast du erwartet, was passiert? Was ist tatsächlich passiert? Bitte gehe so detailliert wie möglich vor."</string>
|
||||
<string name="screen_bug_report_editor_placeholder">"Beschreibe den Fehler…"</string>
|
||||
<string name="screen_bug_report_editor_supporting">"Wenn möglich, verfasse die Beschreibung bitte auf Englisch."</string>
|
||||
<string name="screen_bug_report_include_crash_logs">"Absturzprotokolle senden"</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_bug_report_attach_screenshot">"Képernyőkép mellékelése"</string>
|
||||
<string name="screen_bug_report_contact_me">"Felveheti velem a kapcsolatot, ha bármilyen további kérdése van."</string>
|
||||
<string name="screen_bug_report_contact_me_title">"Kapcsolat"</string>
|
||||
<string name="screen_bug_report_edit_screenshot">"Képernyőkép szerkesztése"</string>
|
||||
<string name="screen_bug_report_editor_description">"Írja le a hibát. Mit csinált? Mire számított, hogy mi fog történni? Mi történt valójában? Fogalmazzon a lehető legrészletesebben."</string>
|
||||
<string name="screen_bug_report_editor_placeholder">"Írja le a problémát…"</string>
|
||||
<string name="screen_bug_report_editor_supporting">"Ha lehetséges, a leírást angolul írja meg."</string>
|
||||
<string name="screen_bug_report_include_crash_logs">"Összeomlásnaplók küldése"</string>
|
||||
<string name="screen_bug_report_include_logs">"Naplók engedélyezése"</string>
|
||||
<string name="screen_bug_report_include_screenshot">"Képernyőkép küldése"</string>
|
||||
<string name="screen_bug_report_logs_description">"A naplók szerepelni fognak az üzenetben, hogy megbizonyosodhassunk arról, hogy minden megfelelően működik-e. Ha naplók nélkül szeretné elküldeni az üzenetet, akkor kapcsolja ki ezt a beállítást."</string>
|
||||
<string name="screen_bug_report_rash_logs_alert_title">"Az %1$s összeomlott a legutóbbi használata óta. Megosztja velünk az összeomlás-jelentést?"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_bug_report_attach_screenshot">"Lampirkan tangkapan layar"</string>
|
||||
<string name="screen_bug_report_contact_me">"Anda dapat menghubungi saya jika Anda memiliki pertanyaan lebih lanjut."</string>
|
||||
<string name="screen_bug_report_contact_me_title">"Hubungi saya"</string>
|
||||
<string name="screen_bug_report_edit_screenshot">"Sunting tangkapan layar"</string>
|
||||
<string name="screen_bug_report_editor_description">"Silakan jelaskan masalah tersebut. Apa yang Anda lakukan? Apa yang Anda harapkan untuk terjadi? Apa yang sebenarnya terjadi? Jelaskan sedetail mungkin."</string>
|
||||
<string name="screen_bug_report_editor_placeholder">"Jelaskan masalah tersebut…"</string>
|
||||
<string name="screen_bug_report_editor_supporting">"Jika memungkinkan, silakan tulis deskripsi dalam bahasa Inggris."</string>
|
||||
<string name="screen_bug_report_include_crash_logs">"Kirim log kerusakan"</string>
|
||||
<string name="screen_bug_report_include_logs">"Izinkan log"</string>
|
||||
<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>
|
||||
</resources>
|
||||
|
|
@ -59,6 +59,10 @@ class FakeBugReporter(val mode: FakeBugReporterMode = FakeBugReporterMode.Succes
|
|||
override fun logDirectory(): File {
|
||||
return File("fake")
|
||||
}
|
||||
|
||||
override fun setCurrentTracingFilter(tracingFilter: String) {
|
||||
// No op
|
||||
}
|
||||
}
|
||||
|
||||
enum class FakeBugReporterMode {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.impl.logs
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class VectorFileLoggerTest {
|
||||
@Test
|
||||
fun `init VectorFileLogger log debug`() = runTest {
|
||||
val sut = createVectorFileLogger()
|
||||
sut.d("A debug log")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `init VectorFileLogger log error`() = runTest {
|
||||
val sut = createVectorFileLogger()
|
||||
sut.e(A_THROWABLE, "A debug log")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reset VectorFileLogger`() = runTest {
|
||||
val sut = createVectorFileLogger()
|
||||
sut.reset()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `check getFromTimber`() {
|
||||
assertThat(VectorFileLogger.getFromTimber()).isNull()
|
||||
}
|
||||
|
||||
private fun TestScope.createVectorFileLogger() = VectorFileLogger(
|
||||
context = RuntimeEnvironment.getApplication(),
|
||||
dispatcher = testCoroutineDispatchers().io,
|
||||
)
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import com.bumble.appyx.core.node.Node
|
|||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ interface RoomDetailsEntryPoint : FeatureEntryPoint {
|
|||
|
||||
interface Callback : Plugin {
|
||||
fun onOpenGlobalNotificationSettings()
|
||||
fun onOpenRoom(roomId: RoomId)
|
||||
}
|
||||
|
||||
interface NodeBuilder {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue