From 6c9ea2b920187541609495a730cdca0f2f605bbb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 25 Mar 2024 10:47:18 +0100 Subject: [PATCH 01/27] Create FakePushService. --- appnav/build.gradle.kts | 1 + .../appnav/loggedin/LoggedInPresenterTest.kt | 20 +--------- libraries/push/test/build.gradle.kts | 1 + .../libraries/push/test/FakePushService.kt | 37 +++++++++++++++++++ 4 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index 4e436ec718..ab215f8394 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.push.test) testImplementation(projects.features.networkmonitor.test) testImplementation(projects.features.login.impl) testImplementation(projects.tests.testutils) diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index 079ccab17a..0da579aa76 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -22,13 +22,10 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.features.networkmonitor.test.FakeNetworkMonitor -import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService -import io.element.android.libraries.push.api.PushService -import io.element.android.libraries.pushproviders.api.Distributor -import io.element.android.libraries.pushproviders.api.PushProvider +import io.element.android.libraries.push.test.FakePushService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate import kotlinx.coroutines.test.runTest @@ -73,20 +70,7 @@ class LoggedInPresenterTest { return LoggedInPresenter( matrixClient = FakeMatrixClient(roomListService = roomListService), networkMonitor = FakeNetworkMonitor(networkStatus), - pushService = object : PushService { - override fun notificationStyleChanged() { - } - - override fun getAvailablePushProviders(): List { - return emptyList() - } - - override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { - } - - override suspend fun testPush() { - } - } + pushService = FakePushService(), ) } } diff --git a/libraries/push/test/build.gradle.kts b/libraries/push/test/build.gradle.kts index 9fccadb9be..7826c3072b 100644 --- a/libraries/push/test/build.gradle.kts +++ b/libraries/push/test/build.gradle.kts @@ -25,5 +25,6 @@ android { dependencies { api(projects.libraries.push.api) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.pushproviders.api) implementation(projects.tests.testutils) } diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt new file mode 100644 index 0000000000..7b6422cd1b --- /dev/null +++ b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 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.libraries.push.test + +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.api.PushService +import io.element.android.libraries.pushproviders.api.Distributor +import io.element.android.libraries.pushproviders.api.PushProvider + +class FakePushService : PushService { + override fun notificationStyleChanged() { + } + + override fun getAvailablePushProviders(): List { + return emptyList() + } + + override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { + } + + override suspend fun testPush() { + } +} From 2bfe125a773e034247f3bb7897d67a84dde48fc3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Mar 2024 11:36:31 +0100 Subject: [PATCH 02/27] Troubleshoot notifications screen --- features/preferences/impl/build.gradle.kts | 10 + .../preferences/impl/PreferencesFlowNode.kt | 11 + .../notifications/NotificationSettingsNode.kt | 6 + .../notifications/NotificationSettingsView.kt | 11 + .../TroubleshootNotificationsEvents.kt | 23 ++ .../TroubleshootNotificationsNode.kt | 44 ++++ .../TroubleshootNotificationsPresenter.kt | 58 +++++ .../TroubleshootNotificationsState.kt | 24 ++ .../TroubleshootNotificationsStateProvider.kt | 119 ++++++++++ .../TroubleshootNotificationsView.kt | 220 ++++++++++++++++++ .../troubleshoot/TroubleshootTestSuite.kt | 109 +++++++++ .../TroubleshootTestSuiteState.kt | 26 +++ .../FakeNotificationTroubleshootTest.kt | 82 +++++++ ...TroubleshootNotificationsPresenterTests.kt | 126 ++++++++++ .../TroubleshootNotificationsViewTest.kt | 115 +++++++++ .../androidutils/system/SystemUtils.kt | 8 + .../NotificationTroubleshootTest.kt | 29 +++ .../NotificationTroubleshootTestDelegate.kt | 81 +++++++ .../NotificationTroubleshootTestState.kt | 31 +++ .../core/notifications/TestFilterData.kt | 21 ++ libraries/permissions/api/build.gradle.kts | 1 - libraries/permissions/impl/build.gradle.kts | 2 + .../impl/DefaultPermissionStateProvider.kt | 7 +- .../impl/action/AndroidPermissionActions.kt | 4 +- ...ficationTroubleshootCheckPermissionTest.kt | 66 ++++++ .../impl/action/FakePermissionActions.kt | 5 +- ...tionTroubleshootCheckPermissionTestTest.kt | 100 ++++++++ .../push/api/GetCurrentPushProvider.kt | 21 ++ .../android/libraries/push/api/PushService.kt | 6 +- .../push/api/gateway/PushGatewayFailure.kt | 4 +- libraries/push/impl/build.gradle.kts | 2 + .../impl/DefaultGetCurrentPushProvider.kt | 41 ++++ .../libraries/push/impl/DefaultPushService.kt | 10 +- .../libraries/push/impl/PushersManager.kt | 15 +- .../notifications/NotificationDisplayer.kt | 18 +- .../notifications/TestNotificationReceiver.kt | 8 +- .../TestNotificationReceiverBinding.kt | 25 ++ .../factories/NotificationCreator.kt | 4 +- .../push/impl/push/DefaultPushHandler.kt | 5 +- .../pushgateway/PushGatewayNotification.kt | 2 + .../pushgateway/PushGatewayNotifyRequest.kt | 7 +- .../troubleshoot/CurrentPushProviderTest.kt | 58 +++++ .../troubleshoot/DiagnosticPushHandler.kt | 33 +++ .../troubleshoot/NotificationClickHandler.kt | 33 +++ .../impl/troubleshoot/NotificationTest.kt | 94 ++++++++ .../impl/troubleshoot/PushLoopbackTest.kt | 102 ++++++++ .../impl/troubleshoot/PushProvidersTest.kt | 59 +++++ .../DefaultNotificationDrawerManagerTest.kt | 4 +- .../notifications/NotificationFactoryTest.kt | 4 +- ...nFactory.kt => FakeNotificationCreator.kt} | 8 +- .../fake/FakeNotificationDisplayer.kt | 5 + .../CurrentPushProviderTestTest.kt | 60 +++++ .../impl/troubleshoot/NotificationTestTest.kt | 88 +++++++ .../impl/troubleshoot/PushLoopbackTestTest.kt | 143 ++++++++++++ .../troubleshoot/PushProvidersTestTest.kt | 64 +++++ .../push/test/FakeGetCurrentPushProvider.kt | 25 ++ .../libraries/push/test/FakePushService.kt | 8 +- .../api/CurrentUserPushConfig.kt | 22 ++ .../pushproviders/api/PushProvider.kt | 5 +- .../pushproviders/firebase/build.gradle.kts | 2 + .../firebase/FirebasePushProvider.kt | 28 +-- .../pushproviders/firebase/FirebaseStore.kt | 16 +- .../firebase/FirebaseTroubleshooter.kt | 32 +-- .../firebase/IsPlayServiceAvailable.kt | 47 ++++ .../troubleshoot/FirebaseAvailabilityTest.kt | 65 ++++++ .../troubleshoot/FirebaseTokenTest.kt | 73 ++++++ .../firebase/FakeFirebaseTroubleshooter.kt | 27 +++ .../firebase/InMemoryFirebaseStore.kt | 27 +++ .../FirebaseAvailabilityTestTest.kt | 67 ++++++ .../troubleshoot/FirebaseTokenTestTest.kt | 78 +++++++ libraries/pushproviders/test/build.gradle.kts | 27 +++ .../pushproviders/test/FakePushProvider.kt | 45 ++++ .../unifiedpush/build.gradle.kts | 3 + .../UnifiedPushDistributorProvider.kt | 47 ++++ .../unifiedpush/UnifiedPushProvider.kt | 32 +-- .../OpenDistributorWebPageAction.kt | 41 ++++ .../troubleshoot/UnifiedPushTest.kt | 70 ++++++ .../FakeOpenDistributorWebPageAction.kt | 23 ++ .../FakeUnifiedPushDistributorProvider.kt | 32 +++ .../troubleshoot/UnifiedPushTestTest.kt | 81 +++++++ 80 files changed, 3086 insertions(+), 99 deletions(-) create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt create mode 100644 features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt create mode 100644 libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt create mode 100644 libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt create mode 100644 libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt create mode 100644 libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt create mode 100644 libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt create mode 100644 libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt create mode 100644 libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/GetCurrentPushProvider.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiverBinding.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/DiagnosticPushHandler.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationClickHandler.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt create mode 100644 libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeAndroidNotificationFactory.kt => FakeNotificationCreator.kt} (85%) create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt create mode 100644 libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt create mode 100644 libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakeGetCurrentPushProvider.kt create mode 100644 libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/CurrentUserPushConfig.kt create mode 100644 libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/IsPlayServiceAvailable.kt create mode 100644 libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt create mode 100644 libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt create mode 100644 libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTroubleshooter.kt create mode 100644 libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt create mode 100644 libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt create mode 100644 libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt create mode 100644 libraries/pushproviders/test/build.gradle.kts create mode 100644 libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt create mode 100644 libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushDistributorProvider.kt create mode 100644 libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt create mode 100644 libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt create mode 100644 libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeOpenDistributorWebPageAction.kt create mode 100644 libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeUnifiedPushDistributorProvider.kt create mode 100644 libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index ee0658ddc6..415f0e36b4 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -23,6 +23,11 @@ plugins { android { namespace = "io.element.android.features.preferences.impl" + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } anvil { @@ -50,6 +55,7 @@ dependencies { implementation(projects.libraries.mediapickers.api) implementation(projects.libraries.mediaupload.api) implementation(projects.libraries.permissions.api) + implementation(projects.libraries.push.api) implementation(projects.features.rageshake.api) implementation(projects.features.lockscreen.api) implementation(projects.features.analytics.api) @@ -71,12 +77,14 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(libs.test.mockk) + testImplementation(libs.test.robolectric) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.mediapickers.test) testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.preferences.test) + testImplementation(projects.libraries.push.test) testImplementation(projects.libraries.pushstore.test) testImplementation(projects.features.rageshake.test) testImplementation(projects.features.rageshake.impl) @@ -86,4 +94,6 @@ dependencies { testImplementation(projects.services.toolbox.test) testImplementation(projects.features.analytics.impl) testImplementation(projects.tests.testutils) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index c27a5ec14e..5f57ad8b5e 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -39,6 +39,7 @@ import io.element.android.features.preferences.impl.developer.DeveloperSettingsN import io.element.android.features.preferences.impl.developer.tracing.ConfigureTracingNode import io.element.android.features.preferences.impl.notifications.NotificationSettingsNode import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingNode +import io.element.android.features.preferences.impl.notifications.troubleshoot.TroubleshootNotificationsNode import io.element.android.features.preferences.impl.root.PreferencesRootNode import io.element.android.features.preferences.impl.user.editprofile.EditUserProfileNode import io.element.android.libraries.architecture.BackstackView @@ -85,6 +86,9 @@ class PreferencesFlowNode @AssistedInject constructor( @Parcelize data object NotificationSettings : NavTarget + @Parcelize + data object TroubleshootNotifications : NavTarget + @Parcelize data object LockScreenSettings : NavTarget @@ -177,9 +181,16 @@ class PreferencesFlowNode @AssistedInject constructor( override fun editDefaultNotificationMode(isOneToOne: Boolean) { backstack.push(NavTarget.EditDefaultNotificationSetting(isOneToOne)) } + + override fun onTroubleshootNotificationsClicked() { + backstack.push(NavTarget.TroubleshootNotifications) + } } createNode(buildContext, listOf(notificationSettingsCallback)) } + NavTarget.TroubleshootNotifications -> { + createNode(buildContext) + } is NavTarget.EditDefaultNotificationSetting -> { val callback = object : EditDefaultNotificationSettingNode.Callback { override fun openRoomNotificationSettings(roomId: RoomId) { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsNode.kt index 122d13a817..621b0ed8b1 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsNode.kt @@ -35,6 +35,7 @@ class NotificationSettingsNode @AssistedInject constructor( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun editDefaultNotificationMode(isOneToOne: Boolean) + fun onTroubleshootNotificationsClicked() } private val callbacks = plugins() @@ -43,6 +44,10 @@ class NotificationSettingsNode @AssistedInject constructor( callbacks.forEach { it.editDefaultNotificationMode(isOneToOne) } } + private fun onTroubleshootNotificationsClicked() { + callbacks.forEach { it.onTroubleshootNotificationsClicked() } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -50,6 +55,7 @@ class NotificationSettingsNode @AssistedInject constructor( state = state, onOpenEditDefault = { openEditDefault(isOneToOne = it) }, onBackPressed = ::navigateUp, + onTroubleshootNotificationsClicked = ::onTroubleshootNotificationsClicked, modifier = modifier, ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt index e68b9fc8b5..8f59ffcdba 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt @@ -46,6 +46,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun NotificationSettingsView( state: NotificationSettingsState, onOpenEditDefault: (isOneToOne: Boolean) -> Unit, + onTroubleshootNotificationsClicked: () -> Unit, onBackPressed: () -> Unit, modifier: Modifier = Modifier, ) { @@ -77,6 +78,7 @@ fun NotificationSettingsView( // 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)) }, + onTroubleshootNotificationsClicked = onTroubleshootNotificationsClicked, ) } AsyncActionView( @@ -99,6 +101,7 @@ private fun NotificationSettingsContentView( // TODO We are removing the call notification toggle until support for call notifications has been added // onCallsNotificationsChanged: (Boolean) -> Unit, onInviteForMeNotificationsChanged: (Boolean) -> Unit, + onTroubleshootNotificationsClicked: () -> Unit, ) { val context = LocalContext.current if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) { @@ -163,6 +166,13 @@ private fun NotificationSettingsContentView( onCheckedChange = onInviteForMeNotificationsChanged ) } + PreferenceCategory(title = "Troubleshoot") { + PreferenceText( + modifier = Modifier, + title = "Troubleshoot notifications", + onClick = onTroubleshootNotificationsClicked + ) + } } } @@ -204,6 +214,7 @@ internal fun NotificationSettingsViewPreview(@PreviewParameter(NotificationSetti state = state, onBackPressed = {}, onOpenEditDefault = {}, + onTroubleshootNotificationsClicked = {}, ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt new file mode 100644 index 0000000000..a6b361de13 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +sealed interface TroubleshootNotificationsEvents { + data object StartTests : TroubleshootNotificationsEvents + data object RetryFailedTests : TroubleshootNotificationsEvents + data class QuickFix(val testIndex: Int) : TroubleshootNotificationsEvents +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt new file mode 100644 index 0000000000..1ac7c0c079 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.di.SessionScope + +@ContributesNode(SessionScope::class) +class TroubleshootNotificationsNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: TroubleshootNotificationsPresenter, +) : Node(buildContext, plugins = plugins) { + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + TroubleshootNotificationsView( + state = state, + onBackPressed = ::navigateUp, + modifier = modifier, + ) + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt new file mode 100644 index 0000000000..1ccbf86ce9 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope +import io.element.android.libraries.architecture.Presenter +import kotlinx.coroutines.launch +import javax.inject.Inject + +class TroubleshootNotificationsPresenter @Inject constructor( + private val troubleshootTestSuite: TroubleshootTestSuite, +) : Presenter { + @Composable + override fun present(): TroubleshootNotificationsState { + val coroutineScope = rememberCoroutineScope() + LaunchedEffect(Unit) { + troubleshootTestSuite.start(this) + } + + val testSuiteState by troubleshootTestSuite.state.collectAsState() + fun handleEvents(event: TroubleshootNotificationsEvents) { + when (event) { + TroubleshootNotificationsEvents.StartTests -> coroutineScope.launch { + troubleshootTestSuite.runTestSuite(this) + } + is TroubleshootNotificationsEvents.QuickFix -> coroutineScope.launch { + troubleshootTestSuite.quickFix(event.testIndex, this) + } + TroubleshootNotificationsEvents.RetryFailedTests -> coroutineScope.launch { + troubleshootTestSuite.retryFailedTest(this) + } + } + } + + return TroubleshootNotificationsState( + testSuiteState = testSuiteState, + eventSink = ::handleEvents + ) + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt new file mode 100644 index 0000000000..55032b2fe9 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +data class TroubleshootNotificationsState( + val testSuiteState: TroubleshootTestSuiteState, + val eventSink: (TroubleshootNotificationsEvents) -> Unit, +) { + val hasFailedTests: Boolean = testSuiteState.mainState.isFailure() +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt new file mode 100644 index 0000000000..316bd72ad7 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import kotlinx.collections.immutable.toImmutableList + +open class TroubleshootNotificationsStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateIdle(), + aTroubleshootTestStateIdle(), + aTroubleshootTestStateIdle(visible = false), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateInProgress(), + aTroubleshootTestStateIdle(), + aTroubleshootTestStateIdle(), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateInProgress(), + aTroubleshootTestStateIdle(), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateWaitingForUser(), + aTroubleshootTestStateIdle(), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateFailure(hasQuickFix = true), + aTroubleshootTestStateInProgress(), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateFailure(hasQuickFix = true), + aTroubleshootTestStateFailure(hasQuickFix = false), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateSuccess(), + aTroubleshootTestStateSuccess(), + ) + ), + aTroubleshootNotificationsState( + listOf( + aTroubleshootTestStateWaitingForUser(), + ) + ), + ) +} + +fun aTroubleshootNotificationsState( + tests: List = emptyList(), + eventSink: (TroubleshootNotificationsEvents) -> Unit = {}, +) = TroubleshootNotificationsState( + eventSink = eventSink, + testSuiteState = TroubleshootTestSuiteState( + mainState = tests.computeMainState(), + tests = tests.toImmutableList(), + ), +) + +fun aTroubleshootTestState( + status: NotificationTroubleshootTestState.Status, + name: String = "Test", + description: String = "Description", +): NotificationTroubleshootTestState { + return NotificationTroubleshootTestState( + name = name, + description = description, + status = status, + ) +} + +fun aTroubleshootTestStateIdle(visible: Boolean = true) = + aTroubleshootTestState(status = NotificationTroubleshootTestState.Status.Idle(visible = visible)) + +fun aTroubleshootTestStateInProgress() = + aTroubleshootTestState(status = NotificationTroubleshootTestState.Status.InProgress) + +fun aTroubleshootTestStateWaitingForUser() = + aTroubleshootTestState(status = NotificationTroubleshootTestState.Status.WaitingForUser) + +fun aTroubleshootTestStateSuccess() = + aTroubleshootTestState(status = NotificationTroubleshootTestState.Status.Success) + +fun aTroubleshootTestStateFailure(hasQuickFix: Boolean) = + aTroubleshootTestState(status = NotificationTroubleshootTestState.Status.Failure(hasQuickFix = hasQuickFix)) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt new file mode 100644 index 0000000000..cadffa1ba0 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.progressSemantics +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState.Status +import io.element.android.libraries.designsystem.components.list.ListItemContent +import io.element.android.libraries.designsystem.components.preferences.PreferencePage +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.Button +import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.Icon +import io.element.android.libraries.designsystem.theme.components.ListItem +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.utils.OnLifecycleEvent + +/** + * A view that allows a user edit their global notification settings. + */ +@Composable +fun TroubleshootNotificationsView( + state: TroubleshootNotificationsState, + onBackPressed: () -> Unit, + modifier: Modifier = Modifier, +) { + OnLifecycleEvent { _, event -> + when (event) { + Lifecycle.Event.ON_RESUME -> { + if (state.hasFailedTests) { + state.eventSink(TroubleshootNotificationsEvents.RetryFailedTests) + } + } + else -> Unit + } + } + + PreferencePage( + modifier = modifier, + onBackPressed = onBackPressed, + title = "Troubleshoot notifications", + ) { + TroubleshootNotificationsContent(state) + } +} + +@Composable +private fun TroubleshootTestView( + testState: NotificationTroubleshootTestState, + onQuickFixClicked: () -> Unit, +) { + if ((testState.status as? Status.Idle)?.visible == false) return + ListItem( + headlineContent = { Text(text = testState.name) }, + supportingContent = { Text(text = testState.description) }, + trailingContent = when (testState.status) { + is Status.Idle -> null + Status.InProgress -> ListItemContent.Custom { + CircularProgressIndicator( + modifier = Modifier + .progressSemantics() + .size(20.dp), + strokeWidth = 2.dp + ) + } + Status.WaitingForUser -> ListItemContent.Custom { + Icon( + contentDescription = null, + modifier = Modifier.size(24.dp), + imageVector = CompoundIcons.Info(), + tint = ElementTheme.colors.iconAccentTertiary + ) + } + Status.Success -> ListItemContent.Custom { + Icon( + contentDescription = null, + modifier = Modifier.size(24.dp), + imageVector = CompoundIcons.Check(), + tint = ElementTheme.colors.iconAccentTertiary + ) + } + is Status.Failure -> ListItemContent.Custom { + Icon( + contentDescription = null, + modifier = Modifier.size(24.dp), + imageVector = CompoundIcons.Error(), + tint = ElementTheme.colors.textCriticalPrimary + ) + } + } + ) + if ((testState.status as? Status.Failure)?.hasQuickFix == true) { + ListItem( + headlineContent = { + }, + trailingContent = ListItemContent.Custom { + Button( + text = "Attempt to fix", + onClick = onQuickFixClicked + ) + } + ) + } +} + +@Composable +private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsState) { + when (state.testSuiteState.mainState) { + AsyncAction.Loading, + AsyncAction.Confirming, + is AsyncAction.Success, + is AsyncAction.Failure -> { + TestSuiteView( + testSuiteState = state.testSuiteState, + onQuickFixClicked = { + state.eventSink(TroubleshootNotificationsEvents.QuickFix(it)) + } + ) + } + AsyncAction.Uninitialized -> Unit + } + when (state.testSuiteState.mainState) { + AsyncAction.Uninitialized -> { + ListItem(headlineContent = { + Text( + text = "Run the tests to detect any issue in your configuration " + + "that may make notifications not behave as expected." + ) + }) + RunTestButton(state = state) + } + AsyncAction.Loading -> Unit + is AsyncAction.Failure -> { + ListItem(headlineContent = { + Text(text = "Some tests failed, please check the details.") + }) + RunTestButton(state = state) + } + AsyncAction.Confirming -> { + ListItem(headlineContent = { + Text( + text = "Some tests require your attention. Please check the details." + ) + }) + } + is AsyncAction.Success -> { + ListItem(headlineContent = { + Text( + text = "All tests passed successfully." + ) + }) + } + } +} + +@Composable +private fun RunTestButton(state: TroubleshootNotificationsState) { + ListItem( + headlineContent = { + Button( + text = if (state.testSuiteState.mainState is AsyncAction.Failure) "Run tests again" else "Run tests", + onClick = { + state.eventSink(TroubleshootNotificationsEvents.StartTests) + }, + modifier = Modifier.fillMaxWidth(), + ) + } + ) +} + +@Composable +private fun TestSuiteView( + testSuiteState: TroubleshootTestSuiteState, + onQuickFixClicked: (Int) -> Unit, +) { + testSuiteState.tests.forEachIndexed { index, testState -> + TroubleshootTestView( + testState = testState, + onQuickFixClicked = { + onQuickFixClicked(index) + }, + ) + } +} + +@PreviewsDayNight +@Composable +internal fun TroubleshootNotificationsViewPreview( + @PreviewParameter(TroubleshootNotificationsStateProvider::class) state: TroubleshootNotificationsState, +) = ElementPreview { + TroubleshootNotificationsView( + state = state, + onBackPressed = {}, + ) +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt new file mode 100644 index 0000000000..4996d278de --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.core.notifications.TestFilterData +import io.element.android.libraries.push.api.GetCurrentPushProvider +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +class TroubleshootTestSuite @Inject constructor( + private val notificationTroubleshootTests: Set<@JvmSuppressWildcards NotificationTroubleshootTest>, + private val getCurrentPushProvider: GetCurrentPushProvider, +) { + lateinit var tests: List + + private val _state: MutableStateFlow = MutableStateFlow( + TroubleshootTestSuiteState( + mainState = AsyncAction.Uninitialized, + tests = emptyList().toImmutableList() + ) + ) + val state: StateFlow = _state + + suspend fun start(coroutineScope: CoroutineScope) { + val testFilterData = TestFilterData( + currentPushProviderName = getCurrentPushProvider.getCurrentPushProvider() + ) + tests = notificationTroubleshootTests + .filter { it.isRelevant(testFilterData) } + .sortedBy { it.order } + tests.forEach { + // Observe the state of the tests + it.state.onEach { + emitState() + }.launchIn(coroutineScope) + } + } + + suspend fun runTestSuite(coroutineScope: CoroutineScope) { + tests.forEach { + it.reset() + } + tests.forEach { + it.run(coroutineScope) + } + } + + suspend fun retryFailedTest(coroutineScope: CoroutineScope) { + tests + .filter { it.state.value.status is NotificationTroubleshootTestState.Status.Failure } + .forEach { + it.run(coroutineScope) + } + } + + private fun emitState() { + val states = tests.map { it.state.value } + _state.tryEmit( + TroubleshootTestSuiteState( + mainState = states.computeMainState(), + tests = states.toImmutableList() + ) + ) + } + + suspend fun quickFix(testIndex: Int, coroutineScope: CoroutineScope) { + tests[testIndex].quickFix(coroutineScope) + } +} + +fun List.computeMainState(): AsyncAction { + val isIdle = all { it.status is NotificationTroubleshootTestState.Status.Idle } + val isRunning = any { it.status is NotificationTroubleshootTestState.Status.InProgress } + return when { + isIdle -> AsyncAction.Uninitialized + isRunning -> AsyncAction.Loading + else -> { + if (any { it.status is NotificationTroubleshootTestState.Status.WaitingForUser }) { + AsyncAction.Confirming + } else if (any { it.status is NotificationTroubleshootTestState.Status.Failure }) { + AsyncAction.Failure(Exception("Some tests failed")) + } else { + AsyncAction.Success(Unit) + } + } + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt new file mode 100644 index 0000000000..e516b65109 --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import kotlinx.collections.immutable.ImmutableList + +data class TroubleshootTestSuiteState( + val mainState: AsyncAction, + val tests: ImmutableList, +) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt new file mode 100644 index 0000000000..e619a62972 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeNotificationTroubleshootTest( + override val order: Int = 0, + private val defaultName: String = "test name", + private val defaultDescription: String = "test description", + private val firstStatus: NotificationTroubleshootTestState.Status = NotificationTroubleshootTestState.Status.Idle(visible = true), + private val runAction: () -> NotificationTroubleshootTestState? = { null }, + private val resetAction: () -> NotificationTroubleshootTestState? = { null }, + private val quickFixAction: () -> NotificationTroubleshootTestState? = { null }, +) : NotificationTroubleshootTest { + private val _state = MutableStateFlow( + NotificationTroubleshootTestState( + name = defaultName, + description = defaultDescription, + status = firstStatus + ) + ) + override val state: StateFlow = _state.asStateFlow() + + override suspend fun run(coroutineScope: CoroutineScope) { + updateState(NotificationTroubleshootTestState.Status.InProgress) + runAction()?.let { + _state.tryEmit(it) + } + } + + override fun reset() { + updateState( + name = defaultName, + description = defaultDescription, + status = firstStatus, + ) + resetAction()?.let { + _state.tryEmit(it) + } + } + + override suspend fun quickFix(coroutineScope: CoroutineScope) { + updateState(NotificationTroubleshootTestState.Status.InProgress) + quickFixAction()?.let { + _state.tryEmit(it) + } + } + + fun updateState( + status: NotificationTroubleshootTestState.Status, + name: String = defaultName, + description: String = defaultDescription, + ) { + _state.tryEmit( + NotificationTroubleshootTestState( + name = name, + description = description, + status = status, + ) + ) + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt new file mode 100644 index 0000000000..e6e712b1b8 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt @@ -0,0 +1,126 @@ +/* + * 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.preferences.impl.notifications.troubleshoot + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class TroubleshootNotificationsPresenterTests { + @Test + fun `present - initial state`() = runTest { + val presenter = createTroubleshootNotificationsPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.testSuiteState.tests).isEmpty() + assertThat(initialState.testSuiteState.mainState).isEqualTo(AsyncAction.Uninitialized) + } + } + + @Test + fun `present - start test`() = runTest { + val troubleshootTestSuite = createTroubleshootTestSuite( + tests = setOf(FakeNotificationTroubleshootTest()) + ) + val presenter = createTroubleshootNotificationsPresenter( + troubleshootTestSuite = troubleshootTestSuite, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + initialState.eventSink(TroubleshootNotificationsEvents.StartTests) + skipItems(1) + val stateAfterStart = awaitItem() + assertThat(stateAfterStart.testSuiteState.mainState).isEqualTo(AsyncAction.Loading) + } + } + + @Test + fun `present - start failed test`() = runTest { + val troubleshootTestSuite = createTroubleshootTestSuite( + tests = setOf( + FakeNotificationTroubleshootTest( + firstStatus = NotificationTroubleshootTestState.Status.Failure(hasQuickFix = false) + ) + ) + ) + val presenter = createTroubleshootNotificationsPresenter( + troubleshootTestSuite = troubleshootTestSuite, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + initialState.eventSink(TroubleshootNotificationsEvents.RetryFailedTests) + skipItems(1) + val stateAfterStart = awaitItem() + assertThat(stateAfterStart.testSuiteState.mainState).isEqualTo(AsyncAction.Loading) + } + } + + @Test + fun `present - quick fix test`() = runTest { + val troubleshootTestSuite = createTroubleshootTestSuite( + tests = setOf( + FakeNotificationTroubleshootTest( + firstStatus = NotificationTroubleshootTestState.Status.Failure(hasQuickFix = false) + ) + ) + ) + val presenter = createTroubleshootNotificationsPresenter( + troubleshootTestSuite = troubleshootTestSuite, + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.testSuiteState.mainState).isInstanceOf(AsyncAction.Failure::class.java) + initialState.eventSink(TroubleshootNotificationsEvents.QuickFix(0)) + val stateAfterStart = awaitItem() + assertThat(stateAfterStart.testSuiteState.mainState).isEqualTo(AsyncAction.Loading) + } + } + + private fun createTroubleshootTestSuite( + tests: Set = emptySet(), + currentPushProvider: String? = null, + ): TroubleshootTestSuite { + return TroubleshootTestSuite( + notificationTroubleshootTests = tests, + getCurrentPushProvider = FakeGetCurrentPushProvider(currentPushProvider), + ) + } + + private fun createTroubleshootNotificationsPresenter( + troubleshootTestSuite: TroubleshootTestSuite = createTroubleshootTestSuite(), + ): TroubleshootNotificationsPresenter { + return TroubleshootNotificationsPresenter( + troubleshootTestSuite = troubleshootTestSuite, + ) + } +} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt new file mode 100644 index 0000000000..af2b37d7c0 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications.troubleshoot + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.pressBack +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@RunWith(AndroidJUnit4::class) +class TroubleshootNotificationsViewTest { + @get:Rule + val rule = createAndroidComposeRule() + + @Test + fun `press menu back invokes the expected callback`() { + val eventsRecorder = EventsRecorder(expectEvents = false) + ensureCalledOnce { + rule.setTroubleshootNotificationsView( + state = aTroubleshootNotificationsState( + eventSink = eventsRecorder + ), + onBackPressed = it, + ) + rule.pressBack() + } + } + + @Test + fun `clicking on run test emits the expected Event`() { + val eventsRecorder = EventsRecorder() + rule.setTroubleshootNotificationsView( + aTroubleshootNotificationsState( + eventSink = eventsRecorder + ), + ) + rule.onNodeWithText("Run tests").performClick() + eventsRecorder.assertSingle(TroubleshootNotificationsEvents.StartTests) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on run test again emits the expected Event`() { + val eventsRecorder = EventsRecorder() + rule.setTroubleshootNotificationsView( + aTroubleshootNotificationsState( + tests = listOf(aTroubleshootTestStateFailure(hasQuickFix = false)), + eventSink = eventsRecorder + ), + ) + rule.onNodeWithText("Run tests again").performClick() + eventsRecorder.assertList( + listOf( + TroubleshootNotificationsEvents.RetryFailedTests, + TroubleshootNotificationsEvents.StartTests, + ) + ) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on quick fix emits the expected Event`() { + val eventsRecorder = EventsRecorder() + rule.setTroubleshootNotificationsView( + aTroubleshootNotificationsState( + tests = listOf(aTroubleshootTestStateFailure(hasQuickFix = true)), + eventSink = eventsRecorder + ), + ) + rule.onNodeWithText("Attempt to fix").performClick() + eventsRecorder.assertList( + listOf( + TroubleshootNotificationsEvents.RetryFailedTests, + TroubleshootNotificationsEvents.QuickFix(0), + ) + ) + } +} + +private fun AndroidComposeTestRule.setTroubleshootNotificationsView( + state: TroubleshootNotificationsState, + onBackPressed: () -> Unit = EnsureNeverCalled(), +) { + setContent { + TroubleshootNotificationsView( + state = state, + onBackPressed = onBackPressed, + ) + } +} diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt index 422307ffd9..9f473a7089 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.androidutils.system +import android.app.Activity import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent @@ -73,6 +74,9 @@ fun Context.startNotificationSettingsIntent(activityResultLauncher: ActivityResu val intent = Intent() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS + if (this !is Activity && activityResultLauncher == null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName) } else { intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS @@ -152,8 +156,12 @@ fun Context.startSharePlainTextIntent( fun Context.openUrlInExternalApp( url: String, errorMessage: String = getString(R.string.error_no_compatible_app_found), + inNewTask: Boolean = false, ) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + if (inNewTask) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } try { startActivity(intent) } catch (activityNotFoundException: ActivityNotFoundException) { diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt new file mode 100644 index 0000000000..755e186e8b --- /dev/null +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 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.libraries.core.notifications + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow + +interface NotificationTroubleshootTest { + val order: Int + val state: StateFlow + fun isRelevant(data: TestFilterData): Boolean = true + suspend fun run(coroutineScope: CoroutineScope) + fun reset() + suspend fun quickFix(coroutineScope: CoroutineScope) {} +} diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt new file mode 100644 index 0000000000..9711677253 --- /dev/null +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 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.libraries.core.notifications + +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +/** + * A NotificationTroubleshootTest delegate, with common pattern for running and resetting. + */ +class NotificationTroubleshootTestDelegate( + private val defaultName: String, + private val defaultDescription: String, + private val visibleWhenIdle: Boolean = true, + private val hasQuickFix: Boolean = false, + private val fakeDelay: Long = 0L, +) { + private val _state: MutableStateFlow = MutableStateFlow( + NotificationTroubleshootTestState( + name = defaultName, + description = defaultDescription, + status = NotificationTroubleshootTestState.Status.Idle(visibleWhenIdle), + ) + ) + + val state: StateFlow = _state.asStateFlow() + + fun updateState( + status: NotificationTroubleshootTestState.Status, + name: String = defaultName, + description: String = defaultDescription, + ) { + _state.tryEmit( + NotificationTroubleshootTestState( + name = name, + description = description, + status = status, + ) + ) + } + + fun reset() { + updateState(NotificationTroubleshootTestState.Status.Idle(visibleWhenIdle)) + } + + suspend fun start() { + updateState(NotificationTroubleshootTestState.Status.InProgress) + delay(fakeDelay) + } + + fun done(isSuccess: Boolean = true) { + updateState( + if (isSuccess) { + NotificationTroubleshootTestState.Status.Success + } else { + NotificationTroubleshootTestState.Status.Failure(hasQuickFix) + } + ) + } + + companion object { + const val SHORT_DELAY = 300L + const val LONG_DELAY = 500L + } +} diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt new file mode 100644 index 0000000000..9657be4b3b --- /dev/null +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 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.libraries.core.notifications + +data class NotificationTroubleshootTestState( + val name: String, + val description: String, + val status: Status, +) { + sealed interface Status { + data class Idle(val visible: Boolean) : Status + data object InProgress : Status + data object WaitingForUser : Status + data object Success : Status + data class Failure(val hasQuickFix: Boolean) : Status + } +} diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt new file mode 100644 index 0000000000..e22fefb7f1 --- /dev/null +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 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.libraries.core.notifications + +data class TestFilterData( + val currentPushProviderName: String?, +) diff --git a/libraries/permissions/api/build.gradle.kts b/libraries/permissions/api/build.gradle.kts index 32d3776419..cb60c6c0a7 100644 --- a/libraries/permissions/api/build.gradle.kts +++ b/libraries/permissions/api/build.gradle.kts @@ -24,7 +24,6 @@ android { dependencies { implementation(projects.libraries.architecture) - implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) diff --git a/libraries/permissions/impl/build.gradle.kts b/libraries/permissions/impl/build.gradle.kts index 7d05d9a1d7..82904bc750 100644 --- a/libraries/permissions/impl/build.gradle.kts +++ b/libraries/permissions/impl/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(projects.libraries.matrixui) implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) + implementation(projects.services.toolbox.api) api(projects.libraries.permissions.api) testImplementation(libs.test.junit) @@ -57,6 +58,7 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.permissions.test) + testImplementation(projects.services.toolbox.test) testImplementation(projects.tests.testutils) ksp(libs.showkase.processor) diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt index c05df3de46..61a82aafff 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/DefaultPermissionStateProvider.kt @@ -17,6 +17,8 @@ package io.element.android.libraries.permissions.impl import android.content.Context +import android.content.pm.PackageManager +import androidx.core.content.ContextCompat import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext @@ -33,7 +35,10 @@ class DefaultPermissionStateProvider @Inject constructor( private val permissionsStore: PermissionsStore, ) : PermissionStateProvider { override fun isPermissionGranted(permission: String): Boolean { - return context.checkSelfPermission(permission) == android.content.pm.PackageManager.PERMISSION_GRANTED + return ContextCompat.checkSelfPermission( + context, + permission, + ) == PackageManager.PERMISSION_GRANTED } override suspend fun setPermissionDenied(permission: String, value: Boolean) = permissionsStore.setPermissionDenied(permission, value) diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/action/AndroidPermissionActions.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/action/AndroidPermissionActions.kt index 6370e839a3..405b61a809 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/action/AndroidPermissionActions.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/action/AndroidPermissionActions.kt @@ -18,7 +18,7 @@ package io.element.android.libraries.permissions.impl.action import android.content.Context import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.libraries.androidutils.system.openAppSettingsPage +import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import javax.inject.Inject @@ -28,6 +28,6 @@ class AndroidPermissionActions @Inject constructor( @ApplicationContext private val context: Context ) : PermissionActions { override fun openSettings() { - context.openAppSettingsPage() + context.startNotificationSettingsIntent() } } diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt new file mode 100644 index 0000000000..501b00e14a --- /dev/null +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 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.libraries.permissions.impl.troubleshoot + +import android.Manifest +import android.os.Build +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.permissions.api.PermissionStateProvider +import io.element.android.libraries.permissions.impl.action.PermissionActions +import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class NotificationTroubleshootCheckPermissionTest @Inject constructor( + private val permissionStateProvider: PermissionStateProvider, + private val sdkVersionProvider: BuildVersionSdkIntProvider, + private val permissionActions: PermissionActions, +) : NotificationTroubleshootTest { + override val order: Int = 0 + + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Check permissions", + defaultDescription = "Ensure that the application can show notifications.", + hasQuickFix = true, + fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, + ) + + override val state: StateFlow = delegate.state + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val result = if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { + permissionStateProvider.isPermissionGranted(Manifest.permission.POST_NOTIFICATIONS) + } else { + true + } + delegate.done(result) + } + + override fun reset() = delegate.reset() + + override suspend fun quickFix(coroutineScope: CoroutineScope) { + // Do not bother about asking the permission inline, just lead the user to the settings + permissionActions.openSettings() + } +} diff --git a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/action/FakePermissionActions.kt b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/action/FakePermissionActions.kt index fa17329900..f6709a7f3d 100644 --- a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/action/FakePermissionActions.kt +++ b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/action/FakePermissionActions.kt @@ -16,11 +16,14 @@ package io.element.android.libraries.permissions.impl.action -class FakePermissionActions : PermissionActions { +class FakePermissionActions( + val openSettingsAction: () -> Unit = {} +) : PermissionActions { var openSettingsCalled = false private set override fun openSettings() { + openSettingsAction() openSettingsCalled = true } } diff --git a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt new file mode 100644 index 0000000000..80c07e2ce0 --- /dev/null +++ b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024 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.libraries.permissions.impl.troubleshoot + +import android.os.Build +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.permissions.impl.FakePermissionStateProvider +import io.element.android.libraries.permissions.impl.action.FakePermissionActions +import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class NotificationTroubleshootCheckPermissionTestTest { + @Test + fun `test NotificationTroubleshootCheckPermissionTest below TIRAMISU success`() = runTest { + val sut = NotificationTroubleshootCheckPermissionTest( + permissionStateProvider = FakePermissionStateProvider(), + sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU - 1), + permissionActions = FakePermissionActions() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + @Test + fun `test NotificationTroubleshootCheckPermissionTest TIRAMISU success`() = runTest { + val sut = NotificationTroubleshootCheckPermissionTest( + permissionStateProvider = FakePermissionStateProvider(), + sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), + permissionActions = FakePermissionActions() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + @Test + fun `test NotificationTroubleshootCheckPermissionTest TIRAMISU error`() = runTest { + val permissionStateProvider = FakePermissionStateProvider( + permissionGranted = false + ) + val actions = FakePermissionActions( + openSettingsAction = { + permissionStateProvider.setPermissionGranted() + } + ) + val sut = NotificationTroubleshootCheckPermissionTest( + permissionStateProvider = permissionStateProvider, + sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), + permissionActions = actions + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true)) + // Quick fix + launch { + sut.quickFix(this) + // Run the test again (IRL it will be done thanks to the resuming of the application) + sut.run(this) + } + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } +} diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/GetCurrentPushProvider.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/GetCurrentPushProvider.kt new file mode 100644 index 0000000000..0c6ed41929 --- /dev/null +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/GetCurrentPushProvider.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 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.libraries.push.api + +interface GetCurrentPushProvider { + suspend fun getCurrentPushProvider(): String? +} diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt index 5f4736e5ab..abfc328e9f 100644 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/PushService.kt @@ -37,6 +37,8 @@ interface PushService { */ suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) - // TODO Move away - suspend fun testPush() + /** + * Return false in case of early error. + */ + suspend fun testPush(): Boolean } diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/gateway/PushGatewayFailure.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/gateway/PushGatewayFailure.kt index c7814a1796..07cf9acf52 100644 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/gateway/PushGatewayFailure.kt +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/gateway/PushGatewayFailure.kt @@ -16,6 +16,6 @@ package io.element.android.libraries.push.api.gateway -sealed class PushGatewayFailure : Throwable(cause = null) { - data object PusherRejected : PushGatewayFailure() +sealed class PushGatewayFailure : Exception() { + class PusherRejected : PushGatewayFailure() } diff --git a/libraries/push/impl/build.gradle.kts b/libraries/push/impl/build.gradle.kts index 7df972c3c3..f16f7f23f0 100644 --- a/libraries/push/impl/build.gradle.kts +++ b/libraries/push/impl/build.gradle.kts @@ -69,6 +69,8 @@ dependencies { testImplementation(libs.coil.test) testImplementation(libs.coroutines.test) testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.push.test) + testImplementation(projects.libraries.pushproviders.test) testImplementation(projects.tests.testutils) testImplementation(projects.services.appnavstate.test) testImplementation(projects.services.toolbox.impl) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt new file mode 100644 index 0000000000..bdf36b7f31 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.api.GetCurrentPushProvider +import io.element.android.libraries.pushstore.api.UserPushStoreFactory +import io.element.android.services.appnavstate.api.AppNavigationStateService +import io.element.android.services.appnavstate.api.currentSessionId +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultGetCurrentPushProvider @Inject constructor( + private val pushStoreFactory: UserPushStoreFactory, + private val appNavigationStateService: AppNavigationStateService, +) : GetCurrentPushProvider { + override suspend fun getCurrentPushProvider(): String? { + return appNavigationStateService + .appNavigationState + .value + .navigationState + .currentSessionId() + ?.let { pushStoreFactory.create(it) } + ?.getPushProviderName() + } +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt index e60cd8b014..5a4df57b47 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.push.impl import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.push.api.GetCurrentPushProvider import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager import io.element.android.libraries.pushproviders.api.Distributor @@ -32,6 +33,7 @@ class DefaultPushService @Inject constructor( private val pushersManager: PushersManager, private val userPushStoreFactory: UserPushStoreFactory, private val pushProviders: Set<@JvmSuppressWildcards PushProvider>, + private val getCurrentPushProvider: GetCurrentPushProvider, ) : PushService { override fun notificationStyleChanged() { defaultNotificationDrawerManager.notificationStyleChanged() @@ -58,7 +60,11 @@ class DefaultPushService @Inject constructor( userPushStore.setPushProviderName(pushProvider.name) } - override suspend fun testPush() { - pushersManager.testPush() + override suspend fun testPush(): Boolean { + val currentPushProvider = getCurrentPushProvider.getCurrentPushProvider() + val pushProvider = pushProviders.find { it.name == currentPushProvider } ?: return false + val config = pushProvider.getCurrentUserPushConfig() ?: return false + pushersManager.testPush(config) + return true } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt index d4424da492..dbefc03126 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt @@ -23,9 +23,11 @@ import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest +import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig import io.element.android.libraries.pushproviders.api.PusherSubscriber import io.element.android.libraries.pushstore.api.UserPushStoreFactory import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret @@ -45,16 +47,14 @@ class PushersManager @Inject constructor( private val pushClientSecret: PushClientSecret, private val userPushStoreFactory: UserPushStoreFactory, ) : PusherSubscriber { - // TODO Move this to the PushProvider API - suspend fun testPush() { + suspend fun testPush(config: CurrentUserPushConfig) { pushGatewayNotifyRequest.execute( PushGatewayNotifyRequest.Params( - // unifiedPushHelper.getPushGateway() ?: return - url = "TODO", + url = config.url, appId = PushConfig.PUSHER_APP_ID, - // unifiedPushHelper.getEndpointOrToken().orEmpty() - pushKey = "TODO", - eventId = TEST_EVENT_ID + pushKey = config.pushKey, + eventId = TEST_EVENT_ID, + roomId = TEST_ROOM_ID, ) ) } @@ -112,5 +112,6 @@ class PushersManager @Inject constructor( companion object { val TEST_EVENT_ID = EventId("\$THIS_IS_A_FAKE_EVENT_ID") + val TEST_ROOM_ID = RoomId("!room:domain") } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt index 2cb01ba2f7..04202bbb2f 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDisplayer.kt @@ -17,7 +17,6 @@ package io.element.android.libraries.push.impl.notifications import android.Manifest -import android.annotation.SuppressLint import android.app.Notification import android.content.Context import android.content.pm.PackageManager @@ -32,12 +31,13 @@ class NotificationDisplayer @Inject constructor( ) { private val notificationManager = NotificationManagerCompat.from(context) - fun showNotificationMessage(tag: String?, id: Int, notification: Notification) { + fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { Timber.w("Not allowed to notify.") - return + return false } notificationManager.notify(tag, id, notification) + return true } fun cancelNotificationMessage(tag: String?, id: Int) { @@ -53,15 +53,21 @@ class NotificationDisplayer @Inject constructor( } } - @SuppressLint("LaunchActivityFromNotification") - fun displayDiagnosticNotification(notification: Notification) { - showNotificationMessage( + fun displayDiagnosticNotification(notification: Notification): Boolean { + return showNotificationMessage( tag = "DIAGNOSTIC", id = NOTIFICATION_ID_DIAGNOSTIC, notification = notification ) } + fun dismissDiagnosticNotification() { + cancelNotificationMessage( + tag = "DIAGNOSTIC", + id = NOTIFICATION_ID_DIAGNOSTIC + ) + } + /** * Cancel the foreground notification service. */ diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt index 152ed0a03e..0bc3e69bfb 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiver.kt @@ -19,9 +19,15 @@ package io.element.android.libraries.push.impl.notifications import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import io.element.android.libraries.architecture.bindings +import io.element.android.libraries.push.impl.troubleshoot.NotificationClickHandler +import javax.inject.Inject class TestNotificationReceiver : BroadcastReceiver() { + @Inject lateinit var notificationClickHandler: NotificationClickHandler + override fun onReceive(context: Context, intent: Intent) { - // TODO The test notification has been clicked, notify the ui + context.bindings().inject(this) + notificationClickHandler.handleNotificationClick() } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiverBinding.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiverBinding.kt new file mode 100644 index 0000000000..6390bff885 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/TestNotificationReceiverBinding.kt @@ -0,0 +1,25 @@ +/* + * 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.libraries.push.impl.notifications + +import com.squareup.anvil.annotations.ContributesTo +import io.element.android.libraries.di.AppScope + +@ContributesTo(AppScope::class) +interface TestNotificationReceiverBinding { + fun inject(service: TestNotificationReceiver) +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt index 2beddc53f9..67c8973d13 100755 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt @@ -299,6 +299,7 @@ class NotificationCreator @Inject constructor( } fun createDiagnosticNotification(): Notification { + val intent = pendingIntentFactory.createTestPendingIntent() return NotificationCompat.Builder(context, notificationChannels.getChannelIdForTest()) .setContentTitle(buildMeta.applicationName) .setContentText(stringProvider.getString(R.string.notification_test_push_notification_content)) @@ -308,7 +309,8 @@ class NotificationCreator @Inject constructor( .setPriority(NotificationCompat.PRIORITY_MAX) .setCategory(NotificationCompat.CATEGORY_STATUS) .setAutoCancel(true) - .setContentIntent(pendingIntentFactory.createTestPendingIntent()) + .setContentIntent(intent) + .setDeleteIntent(intent) .build() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index a930db2708..5de0620eca 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.push.impl.PushersManager import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver import io.element.android.libraries.push.impl.store.DefaultPushDataStore +import io.element.android.libraries.push.impl.troubleshoot.DiagnosticPushHandler import io.element.android.libraries.pushproviders.api.PushData import io.element.android.libraries.pushproviders.api.PushHandler import io.element.android.libraries.pushstore.api.UserPushStoreFactory @@ -51,6 +52,7 @@ class DefaultPushHandler @Inject constructor( // private val actionIds: NotificationActionIds, private val buildMeta: BuildMeta, private val matrixAuthenticationService: MatrixAuthenticationService, + private val diagnosticPushHandler: DiagnosticPushHandler, ) : PushHandler { private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -75,8 +77,7 @@ class DefaultPushHandler @Inject constructor( // Diagnostic Push if (pushData.eventId == PushersManager.TEST_EVENT_ID) { - // val intent = Intent(actionIds.push) - // TODO The test push has been received, notify the ui + diagnosticPushHandler.handlePush() return } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotification.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotification.kt index 9e52d94049..5e341e3286 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotification.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotification.kt @@ -23,6 +23,8 @@ import kotlinx.serialization.Serializable internal data class PushGatewayNotification( @SerialName("event_id") val eventId: String, + @SerialName("room_id") + val roomId: String, /** * Required. This is an array of devices that the notification should be sent to. */ diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotifyRequest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotifyRequest.kt index 7130e38d6e..e8c01493ab 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotifyRequest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayNotifyRequest.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.push.impl.pushgateway import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.network.RetrofitFactory import io.element.android.libraries.push.api.gateway.PushGatewayFailure import javax.inject.Inject @@ -27,7 +28,8 @@ class PushGatewayNotifyRequest @Inject constructor( val url: String, val appId: String, val pushKey: String, - val eventId: EventId + val eventId: EventId, + val roomId: RoomId, ) suspend fun execute(params: Params) { @@ -40,6 +42,7 @@ class PushGatewayNotifyRequest @Inject constructor( PushGatewayNotifyBody( PushGatewayNotification( eventId = params.eventId.value, + roomId = params.roomId.value, devices = listOf( PushGatewayDevice( params.appId, @@ -51,7 +54,7 @@ class PushGatewayNotifyRequest @Inject constructor( ) if (response.rejectedPushKeys.contains(params.pushKey)) { - throw PushGatewayFailure.PusherRejected + throw PushGatewayFailure.PusherRejected() } } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt new file mode 100644 index 0000000000..6b8f69e8db --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.api.GetCurrentPushProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class CurrentPushProviderTest @Inject constructor( + private val getCurrentPushProvider: GetCurrentPushProvider, +) : NotificationTroubleshootTest { + override val order = 110 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Current push provider", + defaultDescription = "Get the name of the current provider.", + fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, + ) + override val state: StateFlow = delegate.state + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val provider = getCurrentPushProvider.getCurrentPushProvider() + if (provider != null) { + delegate.updateState( + description = "Current push provider: $provider", + status = NotificationTroubleshootTestState.Status.Success + ) + } else { + delegate.updateState( + description = "No push providers selected", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + } + + override fun reset() = delegate.reset() +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/DiagnosticPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/DiagnosticPushHandler.kt new file mode 100644 index 0000000000..21b78161d9 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/DiagnosticPushHandler.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.SingleIn +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import javax.inject.Inject + +@SingleIn(AppScope::class) +class DiagnosticPushHandler @Inject constructor() { + private val _state = MutableSharedFlow() + val state: SharedFlow = _state + + suspend fun handlePush() { + _state.emit(Unit) + } +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationClickHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationClickHandler.kt new file mode 100644 index 0000000000..29f5fe0b9f --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationClickHandler.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.SingleIn +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import javax.inject.Inject + +@SingleIn(AppScope::class) +class NotificationClickHandler @Inject constructor() { + private val _state = MutableSharedFlow(extraBufferCapacity = 1) + val state: SharedFlow = _state + + fun handleNotificationClick() { + _state.tryEmit(Unit) + } +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt new file mode 100644 index 0000000000..b2e7ef223c --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.impl.notifications.NotificationDisplayer +import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeoutOrNull +import timber.log.Timber +import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds + +@ContributesMultibinding(AppScope::class) +class NotificationTest @Inject constructor( + private val notificationCreator: NotificationCreator, + private val notificationDisplayer: NotificationDisplayer, + private val notificationClickHandler: NotificationClickHandler +) : NotificationTroubleshootTest { + override val order = 50 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Display notification", + defaultDescription = "Check that the application can display notification", + fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, + ) + override val state: StateFlow = delegate.state + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val notification = notificationCreator.createDiagnosticNotification() + val result = notificationDisplayer.displayDiagnosticNotification(notification) + if (result) { + coroutineScope.listenToNotificationClick() + delegate.updateState( + description = "Please click on the notification to continue the test.", + status = NotificationTroubleshootTestState.Status.WaitingForUser + ) + } else { + delegate.updateState( + description = "Cannot display the notification.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + } + + private fun CoroutineScope.listenToNotificationClick() = launch { + val job = launch { + notificationClickHandler.state.first() + Timber.d("Notification clicked!") + } + val s = withTimeoutOrNull(30.seconds) { + job.join() + } + job.cancel() + if (s == null) { + notificationDisplayer.dismissDiagnosticNotification() + delegate.updateState( + description = "The notification has not been clicked.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } else { + delegate.updateState( + description = "The notification has been clicked!", + status = NotificationTroubleshootTestState.Status.Success + ) + } + }.invokeOnCompletion { + // Ensure that the notification is cancelled when the screen is left + notificationDisplayer.dismissDiagnosticNotification() + } + + override fun reset() = delegate.reset() +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt new file mode 100644 index 0000000000..86d7b437a7 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.api.PushService +import io.element.android.libraries.push.api.gateway.PushGatewayFailure +import io.element.android.services.toolbox.api.systemclock.SystemClock +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeoutOrNull +import timber.log.Timber +import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds + +@ContributesMultibinding(AppScope::class) +class PushLoopbackTest @Inject constructor( + private val pushService: PushService, + private val diagnosticPushHandler: DiagnosticPushHandler, + private val clock: SystemClock, +) : NotificationTroubleshootTest { + override val order = 500 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Test Push loopback", + defaultDescription = "Ensure that the application is receiving push.", + ) + override val state: StateFlow = delegate.state + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val startTime = clock.epochMillis() + val completable = CompletableDeferred() + val job = coroutineScope.launch { + diagnosticPushHandler.state.first() + completable.complete(clock.epochMillis() - startTime) + } + val testPushResult = try { + pushService.testPush() + } catch (pusherRejected: PushGatewayFailure.PusherRejected) { + delegate.updateState( + description = "Error: pusher has rejected the request.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + job.cancel() + return + } catch (e: Exception) { + Timber.e(e, "Failed to test push") + delegate.updateState( + description = "Error: ${e.message}.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + job.cancel() + return + } + if (!testPushResult) { + delegate.updateState( + description = "Error, cannot test push.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + job.cancel() + return + } + val result = withTimeoutOrNull(10.seconds) { + completable.await() + } + job.cancel() + if (result == null) { + delegate.updateState( + description = "Error, timeout waiting for push.", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } else { + delegate.updateState( + description = "Push loopback took $result ms", + status = NotificationTroubleshootTestState.Status.Success + ) + } + } + + override fun reset() = delegate.reset() +} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt new file mode 100644 index 0000000000..7beca906b9 --- /dev/null +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.pushproviders.api.PushProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class PushProvidersTest @Inject constructor( + pushProviders: Set<@JvmSuppressWildcards PushProvider>, +) : NotificationTroubleshootTest { + private val sortedPushProvider = pushProviders.sortedBy { it.index } + override val order = 100 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Detect push providers", + defaultDescription = "Ensure that the application has at least one push provider.", + fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, + ) + override val state: StateFlow = delegate.state + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val result = sortedPushProvider.isNotEmpty() + if (result) { + delegate.updateState( + description = "Found ${sortedPushProvider.size} push providers: ${sortedPushProvider.joinToString { it.name }}", + status = NotificationTroubleshootTestState.Status.Success + ) + } else { + delegate.updateState( + description = "No push providers found", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + } + + override fun reset() = delegate.reset() +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt index e641029c0d..a8058fbcc5 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.test.A_SPACE_ID import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory +import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoaderHolder import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator @@ -118,7 +118,7 @@ class DefaultNotificationDrawerManagerTest { NotificationIdProvider(), NotificationDisplayer(context), NotificationFactory( - FakeAndroidNotificationFactory().instance, + FakeNotificationCreator().instance, FakeRoomGroupMessageCreator().instance, FakeSummaryGroupMessageCreator().instance, ) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt index 50ee91f448..cd1d19b3a7 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt @@ -22,7 +22,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID -import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory +import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator @@ -41,7 +41,7 @@ private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roo @RunWith(RobolectricTestRunner::class) class NotificationFactoryTest { - private val androidNotificationFactory = FakeAndroidNotificationFactory() + private val androidNotificationFactory = FakeNotificationCreator() private val roomGroupMessageCreator = FakeRoomGroupMessageCreator() private val summaryGroupMessageCreator = FakeSummaryGroupMessageCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeAndroidNotificationFactory.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt similarity index 85% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeAndroidNotificationFactory.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt index 6637b64979..5029166f06 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeAndroidNotificationFactory.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiab import io.mockk.every import io.mockk.mockk -class FakeAndroidNotificationFactory { +class FakeNotificationCreator { val instance = mockk() fun givenCreateRoomInvitationNotificationFor(event: InviteNotifiableEvent): Notification { @@ -37,4 +37,10 @@ class FakeAndroidNotificationFactory { every { instance.createSimpleEventNotification(event) } returns mockNotification return mockNotification } + + fun givenCreateDiagnosticNotification(): Notification { + val mockNotification = mockk() + every { instance.createDiagnosticNotification() } returns mockNotification + return mockNotification + } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt index 9af681490a..d737c8eae2 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt @@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.push.impl.notifications.NotificationDisplayer import io.element.android.libraries.push.impl.notifications.NotificationIdProvider import io.mockk.confirmVerified +import io.mockk.every import io.mockk.mockk import io.mockk.verify import io.mockk.verifyOrder @@ -27,6 +28,10 @@ import io.mockk.verifyOrder class FakeNotificationDisplayer { val instance = mockk(relaxed = true) + fun givenDisplayDiagnosticNotificationResult(result: Boolean) { + every { instance.displayDiagnosticNotification(any()) } returns result + } + fun verifySummaryCancelled() { verify { instance.cancelNotificationMessage(tag = null, NotificationIdProvider().getSummaryNotificationId(A_SESSION_ID)) } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt new file mode 100644 index 0000000000..8506d826b5 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class CurrentPushProviderTestTest { + @Test + fun `test CurrentPushProviderTest with a push provider`() = runTest { + val sut = CurrentPushProviderTest( + getCurrentPushProvider = FakeGetCurrentPushProvider("foo") + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + assertThat(lastItem.description).contains("foo") + } + } + + @Test + fun `test CurrentPushProviderTest without push provider`() = runTest { + val sut = CurrentPushProviderTest( + getCurrentPushProvider = FakeGetCurrentPushProvider(null) + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + } + } +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt new file mode 100644 index 0000000000..fcef1dcbab --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator +import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class NotificationTestTest { + private val fakeNotificationCreator = FakeNotificationCreator().apply { + givenCreateDiagnosticNotification() + } + private val fakeNotificationDisplayer = FakeNotificationDisplayer().apply { + givenDisplayDiagnosticNotificationResult(true) + } + + private val notificationClickHandler = NotificationClickHandler() + + @Test + fun `test NotificationTest notification cannot be displayed`() = runTest { + fakeNotificationDisplayer.givenDisplayDiagnosticNotificationResult(false) + val sut = createNotificationTest() + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isInstanceOf(NotificationTroubleshootTestState.Status.Failure::class.java) + } + } + + @Test + fun `test NotificationTest user does not click on notification`() = runTest { + val sut = createNotificationTest() + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.WaitingForUser) + assertThat(awaitItem().status).isInstanceOf(NotificationTroubleshootTestState.Status.Failure::class.java) + } + } + + @Test + fun `test NotificationTest user clicks on notification`() = runTest { + val sut = createNotificationTest() + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.WaitingForUser) + notificationClickHandler.handleNotificationClick() + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + private fun createNotificationTest(): NotificationTest { + return NotificationTest( + notificationCreator = fakeNotificationCreator.instance, + notificationDisplayer = fakeNotificationDisplayer.instance, + notificationClickHandler = notificationClickHandler + ) + } +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt new file mode 100644 index 0000000000..354ec60bb9 --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.A_FAILURE_REASON +import io.element.android.libraries.push.api.gateway.PushGatewayFailure +import io.element.android.libraries.push.test.FakePushService +import io.element.android.services.toolbox.test.systemclock.FakeSystemClock +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class PushLoopbackTestTest { + @Test + fun `test PushLoopbackTest timeout - push is not received`() = runTest { + val diagnosticPushHandler = DiagnosticPushHandler() + val sut = PushLoopbackTest( + pushService = FakePushService(), + diagnosticPushHandler = diagnosticPushHandler, + clock = FakeSystemClock() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + assertThat(lastItem.description).contains("timeout") + } + } + + @Test + fun `test PushLoopbackTest PusherRejected error`() = runTest { + val diagnosticPushHandler = DiagnosticPushHandler() + val sut = PushLoopbackTest( + pushService = FakePushService( + testPushBlock = { + throw PushGatewayFailure.PusherRejected() + } + ), + diagnosticPushHandler = diagnosticPushHandler, + clock = FakeSystemClock() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + assertThat(lastItem.description).contains("rejected") + } + } + + @Test + fun `test PushLoopbackTest setup error`() = runTest { + val diagnosticPushHandler = DiagnosticPushHandler() + val sut = PushLoopbackTest( + pushService = FakePushService( + testPushBlock = { false } + ), + diagnosticPushHandler = diagnosticPushHandler, + clock = FakeSystemClock() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + assertThat(lastItem.description).contains("cannot test push") + } + } + + @Test + fun `test PushLoopbackTest other error`() = runTest { + val diagnosticPushHandler = DiagnosticPushHandler() + val sut = PushLoopbackTest( + pushService = FakePushService( + testPushBlock = { + throw AN_EXCEPTION + } + ), + diagnosticPushHandler = diagnosticPushHandler, + clock = FakeSystemClock() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + assertThat(lastItem.description).contains(A_FAILURE_REASON) + } + } + + @Test + fun `test PushLoopbackTest push is received`() = runTest { + val diagnosticPushHandler = DiagnosticPushHandler() + val sut = PushLoopbackTest( + pushService = FakePushService(testPushBlock = { + diagnosticPushHandler.handlePush() + true + }), + diagnosticPushHandler = diagnosticPushHandler, + clock = FakeSystemClock() + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } +} diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt new file mode 100644 index 0000000000..644392c11b --- /dev/null +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 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.libraries.push.impl.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.pushproviders.test.FakePushProvider +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class PushProvidersTestTest { + @Test + fun `test PushProvidersTest with empty list`() = runTest { + val sut = PushProvidersTest( + pushProviders = emptySet(), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + } + } + + @Test + fun `test PushProvidersTest with 2 push providers`() = runTest { + val sut = PushProvidersTest( + pushProviders = setOf( + FakePushProvider(name = "foo"), + FakePushProvider(name = "bar"), + ), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + assertThat(lastItem.description).contains("foo") + assertThat(lastItem.description).contains("bar") + } + } +} diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakeGetCurrentPushProvider.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakeGetCurrentPushProvider.kt new file mode 100644 index 0000000000..76363c9d99 --- /dev/null +++ b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakeGetCurrentPushProvider.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 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.libraries.push.test + +import io.element.android.libraries.push.api.GetCurrentPushProvider + +class FakeGetCurrentPushProvider( + private val currentPushProvider: String? +) : GetCurrentPushProvider { + override suspend fun getCurrentPushProvider(): String? = currentPushProvider +} diff --git a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt index 7b6422cd1b..969815ec66 100644 --- a/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt +++ b/libraries/push/test/src/main/kotlin/io/element/android/libraries/push/test/FakePushService.kt @@ -20,8 +20,11 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.push.api.PushService import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider +import io.element.android.tests.testutils.simulateLongTask -class FakePushService : PushService { +class FakePushService( + private val testPushBlock: suspend () -> Boolean = { true } +) : PushService { override fun notificationStyleChanged() { } @@ -32,6 +35,7 @@ class FakePushService : PushService { override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { } - override suspend fun testPush() { + override suspend fun testPush(): Boolean = simulateLongTask { + testPushBlock() } } diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/CurrentUserPushConfig.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/CurrentUserPushConfig.kt new file mode 100644 index 0000000000..bfd6488904 --- /dev/null +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/CurrentUserPushConfig.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.api + +data class CurrentUserPushConfig( + val url: String, + val pushKey: String, +) diff --git a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt index 3d8349a117..4e9b818dd4 100644 --- a/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt +++ b/libraries/pushproviders/api/src/main/kotlin/io/element/android/libraries/pushproviders/api/PushProvider.kt @@ -49,8 +49,5 @@ interface PushProvider { */ suspend fun unregister(matrixClient: MatrixClient) - /** - * Attempt to troubleshoot the push provider. - */ - suspend fun troubleshoot(): Result + suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? } diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index 186ab121fd..55dca139b0 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -51,8 +51,10 @@ dependencies { exclude(group = "com.google.firebase", module = "firebase-measurement-connector") } + testImplementation(libs.coroutines.test) testImplementation(libs.test.junit) testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.tests.testutils) } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt index 4c3d6d3a20..317d49f3b6 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebasePushProvider.kt @@ -16,14 +16,11 @@ package io.element.android.libraries.pushproviders.firebase -import android.content.Context -import com.google.android.gms.common.ConnectionResult -import com.google.android.gms.common.GoogleApiAvailability import com.squareup.anvil.annotations.ContributesMultibinding import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope -import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.pushproviders.api.PusherSubscriber @@ -34,25 +31,15 @@ private val loggerTag = LoggerTag("FirebasePushProvider", LoggerTag.PushLoggerTa @ContributesMultibinding(AppScope::class) class FirebasePushProvider @Inject constructor( - @ApplicationContext private val context: Context, private val firebaseStore: FirebaseStore, - private val firebaseTroubleshooter: FirebaseTroubleshooter, private val pusherSubscriber: PusherSubscriber, + private val isPlayServiceAvailable: IsPlayServiceAvailable, ) : PushProvider { override val index = FirebaseConfig.INDEX override val name = FirebaseConfig.NAME override fun isAvailable(): Boolean { - // The PlayServices has to be available - val apiAvailability = GoogleApiAvailability.getInstance() - val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) - return if (resultCode == ConnectionResult.SUCCESS) { - Timber.tag(loggerTag.value).d("Google Play Services is available") - true - } else { - Timber.tag(loggerTag.value).w("Google Play Services is not available") - false - } + return isPlayServiceAvailable.isAvailable() } override fun getDistributors(): List { @@ -73,7 +60,12 @@ class FirebasePushProvider @Inject constructor( pusherSubscriber.unregisterPusher(matrixClient, pushKey, FirebaseConfig.PUSHER_HTTP_URL) } - override suspend fun troubleshoot(): Result { - return firebaseTroubleshooter.troubleshoot() + override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? { + return firebaseStore.getFcmToken()?.let { fcmToken -> + CurrentUserPushConfig( + url = FirebaseConfig.PUSHER_HTTP_URL, + pushKey = fcmToken + ) + } } } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt index 0342c67462..0614e2065c 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseStore.kt @@ -18,20 +18,28 @@ package io.element.android.libraries.pushproviders.firebase import android.content.SharedPreferences import androidx.core.content.edit +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.DefaultPreferences import javax.inject.Inject /** * This class store the Firebase token in SharedPrefs. */ -class FirebaseStore @Inject constructor( +interface FirebaseStore { + fun getFcmToken(): String? + fun storeFcmToken(token: String?) +} + +@ContributesBinding(AppScope::class) +class DefaultFirebaseStore @Inject constructor( @DefaultPreferences private val sharedPrefs: SharedPreferences, -) { - fun getFcmToken(): String? { +) : FirebaseStore { + override fun getFcmToken(): String? { return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null) } - fun storeFcmToken(token: String?) { + override fun storeFcmToken(token: String?) { sharedPrefs.edit { putString(PREFS_KEY_FCM_TOKEN, token) } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt index f3efba1a16..6d205c42ae 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseTroubleshooter.kt @@ -16,25 +16,28 @@ package io.element.android.libraries.pushproviders.firebase -import android.content.Context -import com.google.android.gms.common.ConnectionResult -import com.google.android.gms.common.GoogleApiAvailability import com.google.firebase.messaging.FirebaseMessaging -import io.element.android.libraries.di.ApplicationContext +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope import timber.log.Timber import javax.inject.Inject import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine +interface FirebaseTroubleshooter { + suspend fun troubleshoot(): Result +} + /** * This class force retrieving and storage of the Firebase token. */ -class FirebaseTroubleshooter @Inject constructor( - @ApplicationContext private val context: Context, +@ContributesBinding(AppScope::class) +class DefaultFirebaseTroubleshooter @Inject constructor( private val newTokenHandler: FirebaseNewTokenHandler, -) { - suspend fun troubleshoot(): Result { + private val isPlayServiceAvailable: IsPlayServiceAvailable, +) : FirebaseTroubleshooter { + override suspend fun troubleshoot(): Result { return runCatching { val token = retrievedFirebaseToken() newTokenHandler.handle(token) @@ -44,7 +47,7 @@ class FirebaseTroubleshooter @Inject constructor( private suspend fun retrievedFirebaseToken(): String { return suspendCoroutine { continuation -> // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' - if (checkPlayServices(context)) { + if (isPlayServiceAvailable.isAvailable()) { try { FirebaseMessaging.getInstance().token .addOnSuccessListener { token -> @@ -65,15 +68,4 @@ class FirebaseTroubleshooter @Inject constructor( } } } - - /** - * Check the device to make sure it has the Google Play Services APK. If - * it doesn't, display a dialog that allows users to download the APK from - * the Google Play Store or enable it in the device's system settings. - */ - private fun checkPlayServices(context: Context): Boolean { - val apiAvailability = GoogleApiAvailability.getInstance() - val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) - return resultCode == ConnectionResult.SUCCESS - } } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/IsPlayServiceAvailable.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/IsPlayServiceAvailable.kt new file mode 100644 index 0000000000..50d9d4fe6f --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/IsPlayServiceAvailable.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase + +import android.content.Context +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import timber.log.Timber +import javax.inject.Inject + +interface IsPlayServiceAvailable { + fun isAvailable(): Boolean +} + +@ContributesBinding(AppScope::class) +class DefaultIsPlayServiceAvailable @Inject constructor( + @ApplicationContext private val context: Context, +) : IsPlayServiceAvailable { + override fun isAvailable(): Boolean { + val apiAvailability = GoogleApiAvailability.getInstance() + val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) + return if (resultCode == ConnectionResult.SUCCESS) { + Timber.d("Google Play Services is available") + true + } else { + Timber.w("Google Play Services is not available") + false + } + } +} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt new file mode 100644 index 0000000000..e0891d6081 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.core.notifications.TestFilterData +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.pushproviders.firebase.FirebaseConfig +import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class FirebaseAvailabilityTest @Inject constructor( + private val isPlayServiceAvailable: IsPlayServiceAvailable, +) : NotificationTroubleshootTest { + override val order = 300 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Check Firebase", + defaultDescription = "Ensure that Firebase is available.", + visibleWhenIdle = false, + fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, + ) + override val state: StateFlow = delegate.state + + override fun isRelevant(data: TestFilterData): Boolean { + return data.currentPushProviderName == FirebaseConfig.NAME + } + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val result = isPlayServiceAvailable.isAvailable() + if (result) { + delegate.updateState( + description = "Firebase is available", + status = NotificationTroubleshootTestState.Status.Success + ) + } else { + delegate.updateState( + description = "Firebase is not available", + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + } + + override fun reset() = delegate.reset() +} diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt new file mode 100644 index 0000000000..7c8ce5dfef --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.core.notifications.TestFilterData +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.pushproviders.firebase.FirebaseConfig +import io.element.android.libraries.pushproviders.firebase.FirebaseStore +import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class FirebaseTokenTest @Inject constructor( + private val firebaseStore: FirebaseStore, + private val firebaseTroubleshooter: FirebaseTroubleshooter, +) : NotificationTroubleshootTest { + override val order = 310 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Check Firebase token", + defaultDescription = "Ensure that Firebase token is available.", + visibleWhenIdle = false, + fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, + ) + override val state: StateFlow = delegate.state + + override fun isRelevant(data: TestFilterData): Boolean { + return data.currentPushProviderName == FirebaseConfig.NAME + } + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val token = firebaseStore.getFcmToken() + if (token != null) { + delegate.updateState( + description = "Firebase token: ${token.take(8)}*****", + status = NotificationTroubleshootTestState.Status.Success + ) + } else { + delegate.updateState( + description = "Firebase token is not known", + status = NotificationTroubleshootTestState.Status.Failure(true) + ) + } + } + + override fun reset() = delegate.reset() + + override suspend fun quickFix(coroutineScope: CoroutineScope) { + delegate.start() + firebaseTroubleshooter.troubleshoot() + run(coroutineScope) + } +} diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTroubleshooter.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTroubleshooter.kt new file mode 100644 index 0000000000..b0dae793cd --- /dev/null +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/FakeFirebaseTroubleshooter.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase + +import io.element.android.tests.testutils.simulateLongTask + +class FakeFirebaseTroubleshooter( + private val troubleShootResult: () -> Result = { Result.success(Unit) } +) : FirebaseTroubleshooter { + override suspend fun troubleshoot(): Result = simulateLongTask { + troubleShootResult() + } +} diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt new file mode 100644 index 0000000000..f298b9f30e --- /dev/null +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/InMemoryFirebaseStore.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase + +class InMemoryFirebaseStore( + private var token: String? = null +) : FirebaseStore { + override fun getFcmToken(): String? = token + + override fun storeFcmToken(token: String?) { + this.token = token + } +} diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt new file mode 100644 index 0000000000..eea622849b --- /dev/null +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class FirebaseAvailabilityTestTest { + @Test + fun `test FirebaseAvailabilityTest success`() = runTest { + val sut = FirebaseAvailabilityTest( + isPlayServiceAvailable = object : IsPlayServiceAvailable { + override fun isAvailable(): Boolean { + return true + } + } + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + @Test + fun `test FirebaseAvailabilityTest failure`() = runTest { + val sut = FirebaseAvailabilityTest( + isPlayServiceAvailable = object : IsPlayServiceAvailable { + override fun isAvailable(): Boolean { + return false + } + } + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) + } + } +} diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt new file mode 100644 index 0000000000..0463939234 --- /dev/null +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.firebase.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.pushproviders.firebase.FakeFirebaseTroubleshooter +import io.element.android.libraries.pushproviders.firebase.InMemoryFirebaseStore +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class FirebaseTokenTestTest { + @Test + fun `test FirebaseTokenTest success`() = runTest { + val sut = FirebaseTokenTest( + firebaseStore = InMemoryFirebaseStore(FAKE_TOKEN), + firebaseTroubleshooter = FakeFirebaseTroubleshooter(), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + assertThat(lastItem.description).contains(FAKE_TOKEN.take(8)) + assertThat(lastItem.description).doesNotContain(FAKE_TOKEN) + } + } + + @Test + fun `test FirebaseTokenTest error`() = runTest { + val firebaseStore = InMemoryFirebaseStore(null) + val sut = FirebaseTokenTest( + firebaseStore = firebaseStore, + firebaseTroubleshooter = FakeFirebaseTroubleshooter( + troubleShootResult = { + firebaseStore.storeFcmToken(FAKE_TOKEN) + Result.success(Unit) + } + ), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true)) + // Quick fix + sut.quickFix(this) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + companion object { + private const val FAKE_TOKEN = "abcdefghijk" + } +} diff --git a/libraries/pushproviders/test/build.gradle.kts b/libraries/pushproviders/test/build.gradle.kts new file mode 100644 index 0000000000..ddb68ed43f --- /dev/null +++ b/libraries/pushproviders/test/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 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-library") +} + +android { + namespace = "io.element.android.libraries.pushproviders.test" +} + +dependencies { + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.pushproviders.api) +} diff --git a/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt b/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt new file mode 100644 index 0000000000..8d8b94ec19 --- /dev/null +++ b/libraries/pushproviders/test/src/main/kotlin/io/element/android/libraries/pushproviders/test/FakePushProvider.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.test + +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig +import io.element.android.libraries.pushproviders.api.Distributor +import io.element.android.libraries.pushproviders.api.PushProvider + +class FakePushProvider( + override val index: Int = 0, + override val name: String = "aFakePushProvider", + private val isAvailable: Boolean = true, + private val distributors: List = emptyList() +) : PushProvider { + override fun isAvailable(): Boolean = isAvailable + + override fun getDistributors(): List = distributors + + override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor) { + // No-op + } + + override suspend fun unregister(matrixClient: MatrixClient) { + // No-op + } + + override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? { + return null + } +} diff --git a/libraries/pushproviders/unifiedpush/build.gradle.kts b/libraries/pushproviders/unifiedpush/build.gradle.kts index a3968f4ecc..ecceed6026 100644 --- a/libraries/pushproviders/unifiedpush/build.gradle.kts +++ b/libraries/pushproviders/unifiedpush/build.gradle.kts @@ -37,6 +37,7 @@ dependencies { implementation(projects.libraries.pushproviders.api) implementation(projects.libraries.architecture) implementation(projects.libraries.core) + implementation(projects.services.appnavstate.api) implementation(projects.services.toolbox.api) implementation(projects.libraries.network) @@ -50,8 +51,10 @@ dependencies { // UnifiedPush library api(libs.unifiedpush) + testImplementation(libs.coroutines.test) testImplementation(libs.test.junit) testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.tests.testutils) } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushDistributorProvider.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushDistributorProvider.kt new file mode 100644 index 0000000000..5c9249e8f4 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushDistributorProvider.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush + +import android.content.Context +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.androidutils.system.getApplicationLabel +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.pushproviders.api.Distributor +import org.unifiedpush.android.connector.UnifiedPush +import javax.inject.Inject + +interface UnifiedPushDistributorProvider { + fun getDistributors(): List +} + +@ContributesBinding(AppScope::class) +class DefaultUnifiedPushDistributorProvider @Inject constructor( + @ApplicationContext private val context: Context, +) : UnifiedPushDistributorProvider { + override fun getDistributors(): List { + val distributors = UnifiedPush.getDistributors(context) + return distributors.mapNotNull { + if (it == context.packageName) { + // Exclude self + null + } else { + Distributor(it, context.getApplicationLabel(it)) + } + } + } +} diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt index 5d0a0da7a1..e7ea1841c5 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushProvider.kt @@ -16,17 +16,16 @@ package io.element.android.libraries.pushproviders.unifiedpush -import android.content.Context import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.androidutils.system.getApplicationLabel import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope -import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret -import org.unifiedpush.android.connector.UnifiedPush +import io.element.android.services.appnavstate.api.AppNavigationStateService +import io.element.android.services.appnavstate.api.currentSessionId import timber.log.Timber import javax.inject.Inject @@ -34,10 +33,12 @@ private val loggerTag = LoggerTag("UnifiedPushProvider", LoggerTag.PushLoggerTag @ContributesMultibinding(AppScope::class) class UnifiedPushProvider @Inject constructor( - @ApplicationContext private val context: Context, + private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider, private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase, private val unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase, private val pushClientSecret: PushClientSecret, + private val unifiedPushStore: UnifiedPushStore, + private val appNavigationStateService: AppNavigationStateService, ) : PushProvider { override val index = UnifiedPushConfig.INDEX override val name = UnifiedPushConfig.NAME @@ -54,15 +55,7 @@ class UnifiedPushProvider @Inject constructor( } override fun getDistributors(): List { - val distributors = UnifiedPush.getDistributors(context) - return distributors.mapNotNull { - if (it == context.packageName) { - // Exclude self - null - } else { - Distributor(it, context.getApplicationLabel(it)) - } - } + return unifiedPushDistributorProvider.getDistributors() } override suspend fun registerWith(matrixClient: MatrixClient, distributor: Distributor) { @@ -75,7 +68,14 @@ class UnifiedPushProvider @Inject constructor( unRegisterUnifiedPushUseCase.execute(clientSecret) } - override suspend fun troubleshoot(): Result { - TODO("Not yet implemented") + override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? { + val currentSession = appNavigationStateService.appNavigationState.value.navigationState.currentSessionId() ?: return null + val clientSecret = pushClientSecret.getSecretForUser(currentSession) + val url = unifiedPushStore.getPushGateway(clientSecret) ?: return null + val pushKey = unifiedPushStore.getEndpoint(clientSecret) ?: return null + return CurrentUserPushConfig( + url = url, + pushKey = pushKey, + ) } } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt new file mode 100644 index 0000000000..daad9afda3 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush.troubleshoot + +import android.content.Context +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.androidutils.system.openUrlInExternalApp +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext +import javax.inject.Inject + +interface OpenDistributorWebPageAction { + fun execute() +} + +@ContributesBinding(AppScope::class) +class DefaultOpenDistributorWebPageAction @Inject constructor( + @ApplicationContext private val context: Context, +) : OpenDistributorWebPageAction { + override fun execute() { + // Open the distributor download page + context.openUrlInExternalApp( + url = "https://unifiedpush.org/users/distributors/", + inNewTask = true + ) + } +} diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt new file mode 100644 index 0000000000..3d612b0613 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush.troubleshoot + +import com.squareup.anvil.annotations.ContributesMultibinding +import io.element.android.libraries.core.notifications.NotificationTroubleshootTest +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.core.notifications.TestFilterData +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig +import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +@ContributesMultibinding(AppScope::class) +class UnifiedPushTest @Inject constructor( + private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider, + private val openDistributorWebPageAction: OpenDistributorWebPageAction, +) : NotificationTroubleshootTest { + override val order = 400 + private val delegate = NotificationTroubleshootTestDelegate( + defaultName = "Check UnifiedPush", + defaultDescription = "Ensure that UnifiedPush distributors are available.", + visibleWhenIdle = false, + fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, + ) + override val state: StateFlow = delegate.state + + override fun isRelevant(data: TestFilterData): Boolean { + return data.currentPushProviderName == UnifiedPushConfig.NAME + } + + override suspend fun run(coroutineScope: CoroutineScope) { + delegate.start() + val distributors = unifiedPushDistributorProvider.getDistributors() + if (distributors.isNotEmpty()) { + delegate.updateState( + description = "Distributors found: ${distributors.joinToString { it.name }}", + status = NotificationTroubleshootTestState.Status.Success + ) + } else { + delegate.updateState( + description = "No push distributors found", + status = NotificationTroubleshootTestState.Status.Failure(true) + ) + } + } + + override fun reset() = delegate.reset() + + override suspend fun quickFix(coroutineScope: CoroutineScope) { + openDistributorWebPageAction.execute() + } +} diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeOpenDistributorWebPageAction.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeOpenDistributorWebPageAction.kt new file mode 100644 index 0000000000..ca91807fb9 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeOpenDistributorWebPageAction.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush.troubleshoot + +class FakeOpenDistributorWebPageAction( + private val executeAction: () -> Unit = {} +) : OpenDistributorWebPageAction { + override fun execute() = executeAction() +} diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeUnifiedPushDistributorProvider.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeUnifiedPushDistributorProvider.kt new file mode 100644 index 0000000000..e9734956d7 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/FakeUnifiedPushDistributorProvider.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush.troubleshoot + +import io.element.android.libraries.pushproviders.api.Distributor +import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider + +class FakeUnifiedPushDistributorProvider( + private var getDistributorsResult: List = emptyList() +) : UnifiedPushDistributorProvider { + override fun getDistributors(): List { + return getDistributorsResult + } + + fun setDistributorsResult(list: List) { + getDistributorsResult = list + } +} diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt new file mode 100644 index 0000000000..e7a8ccc680 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 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.libraries.pushproviders.unifiedpush.troubleshoot + +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.pushproviders.api.Distributor +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class UnifiedPushTestTest { + @Test + fun `test UnifiedPushTest success`() = runTest { + val sut = UnifiedPushTest( + unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider( + getDistributorsResult = listOf( + Distributor("value", "Name"), + ) + ), + openDistributorWebPageAction = FakeOpenDistributorWebPageAction(), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } + + @Test + fun `test UnifiedPushTest error`() = runTest { + val providers = FakeUnifiedPushDistributorProvider() + val sut = UnifiedPushTest( + unifiedPushDistributorProvider = providers, + openDistributorWebPageAction = FakeOpenDistributorWebPageAction( + executeAction = { + providers.setDistributorsResult( + listOf( + Distributor("value", "Name"), + ) + ) + } + ), + ) + launch { + sut.run(this) + } + sut.state.test { + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false)) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + val lastItem = awaitItem() + assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true)) + // Quick fix + launch { + sut.quickFix(this) + sut.run(this) + } + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) + assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + } + } +} From a83952814f698f7b93d4514ae3133187bb420ad6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Mar 2024 11:49:57 +0100 Subject: [PATCH 03/27] Rename Fake class with `Mockk` prefix for clarity --- .../DefaultNotificationDrawerManagerTest.kt | 18 +++++----- .../NotifiableEventProcessorTest.kt | 20 +++++------ .../notifications/NotificationFactoryTest.kt | 26 +++++++------- .../notifications/NotificationRendererTest.kt | 36 +++++++++---------- ...Creator.kt => MockkNotificationCreator.kt} | 2 +- ...layer.kt => MockkNotificationDisplayer.kt} | 2 +- ...Factory.kt => MockkNotificationFactory.kt} | 2 +- ...ector.kt => MockkOutdatedEventDetector.kt} | 2 +- ...tor.kt => MockkRoomGroupMessageCreator.kt} | 2 +- ....kt => MockkSummaryGroupMessageCreator.kt} | 2 +- .../impl/troubleshoot/NotificationTestTest.kt | 14 ++++---- 11 files changed, 63 insertions(+), 63 deletions(-) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeNotificationCreator.kt => MockkNotificationCreator.kt} (98%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeNotificationDisplayer.kt => MockkNotificationDisplayer.kt} (97%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeNotificationFactory.kt => MockkNotificationFactory.kt} (98%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeOutdatedEventDetector.kt => MockkOutdatedEventDetector.kt} (97%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeRoomGroupMessageCreator.kt => MockkRoomGroupMessageCreator.kt} (97%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/{FakeSummaryGroupMessageCreator.kt => MockkSummaryGroupMessageCreator.kt} (95%) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt index a8058fbcc5..b84e7b4be3 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManagerTest.kt @@ -23,10 +23,10 @@ import io.element.android.libraries.matrix.test.A_SPACE_ID import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoaderHolder -import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator -import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkRoomGroupMessageCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkSummaryGroupMessageCreator import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.services.appnavstate.api.AppNavigationState @@ -115,12 +115,12 @@ class DefaultNotificationDrawerManagerTest { appNavigationStateService = appNavigationStateService ), notificationRenderer = NotificationRenderer( - NotificationIdProvider(), - NotificationDisplayer(context), - NotificationFactory( - FakeNotificationCreator().instance, - FakeRoomGroupMessageCreator().instance, - FakeSummaryGroupMessageCreator().instance, + notificationIdProvider = NotificationIdProvider(), + notificationDisplayer = NotificationDisplayer(context), + notificationFactory = NotificationFactory( + notificationCreator = MockkNotificationCreator().instance, + roomGroupMessageCreator = MockkRoomGroupMessageCreator().instance, + summaryGroupMessageCreator = MockkSummaryGroupMessageCreator().instance, ) ), notificationEventPersistence = InMemoryNotificationEventPersistence(initialData = initialData), diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventProcessorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventProcessorTest.kt index 02da10a351..a8626766e5 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventProcessorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotifiableEventProcessorTest.kt @@ -25,7 +25,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SPACE_ID import io.element.android.libraries.matrix.test.A_THREAD_ID -import io.element.android.libraries.push.impl.notifications.fake.FakeOutdatedEventDetector +import io.element.android.libraries.push.impl.notifications.fake.MockkOutdatedEventDetector import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent @@ -42,7 +42,7 @@ private val VIEWING_A_ROOM = aNavigationState(A_SESSION_ID, A_SPACE_ID, A_ROOM_I private val VIEWING_A_THREAD = aNavigationState(A_SESSION_ID, A_SPACE_ID, A_ROOM_ID, A_THREAD_ID) class NotifiableEventProcessorTest { - private val outdatedDetector = FakeOutdatedEventDetector() + private val mockkOutdatedDetector = MockkOutdatedEventDetector() @Test fun `given simple events when processing then keep simple events`() { @@ -97,7 +97,7 @@ class NotifiableEventProcessorTest { @Test fun `given out of date message event when processing then removes message event`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)) - outdatedDetector.givenEventIsOutOfDate(events[0]) + mockkOutdatedDetector.givenEventIsOutOfDate(events[0]) val eventProcessor = createProcessor(navigationState = NOT_VIEWING_A_ROOM) @@ -113,7 +113,7 @@ class NotifiableEventProcessorTest { @Test fun `given in date message event when processing then keep message event`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)) - outdatedDetector.givenEventIsInDate(events[0]) + mockkOutdatedDetector.givenEventIsInDate(events[0]) val eventProcessor = createProcessor(navigationState = NOT_VIEWING_A_ROOM) val result = eventProcessor.process(events, renderedEvents = emptyList()) @@ -128,7 +128,7 @@ class NotifiableEventProcessorTest { @Test fun `given viewing the same room main timeline when processing main timeline message event then removes message`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID, threadId = null)) - events.forEach { outdatedDetector.givenEventIsOutOfDate(it) } + events.forEach { mockkOutdatedDetector.givenEventIsOutOfDate(it) } val eventProcessor = createProcessor(isInForeground = true, navigationState = VIEWING_A_ROOM) val result = eventProcessor.process(events, renderedEvents = emptyList()) @@ -143,7 +143,7 @@ class NotifiableEventProcessorTest { @Test fun `given viewing the same thread timeline when processing thread message event then removes message`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID, threadId = A_THREAD_ID)) - events.forEach { outdatedDetector.givenEventIsOutOfDate(it) } + events.forEach { mockkOutdatedDetector.givenEventIsOutOfDate(it) } val eventProcessor = createProcessor(isInForeground = true, navigationState = VIEWING_A_THREAD) val result = eventProcessor.process(events, renderedEvents = emptyList()) @@ -158,7 +158,7 @@ class NotifiableEventProcessorTest { @Test fun `given viewing main timeline of the same room when processing thread timeline message event then keep message`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID, threadId = A_THREAD_ID)) - outdatedDetector.givenEventIsInDate(events[0]) + mockkOutdatedDetector.givenEventIsInDate(events[0]) val eventProcessor = createProcessor(isInForeground = true, navigationState = VIEWING_A_ROOM) val result = eventProcessor.process(events, renderedEvents = emptyList()) @@ -173,7 +173,7 @@ class NotifiableEventProcessorTest { @Test fun `given viewing thread timeline of the same room when processing main timeline message event then keep message`() { val events = listOf(aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)) - outdatedDetector.givenEventIsInDate(events[0]) + mockkOutdatedDetector.givenEventIsInDate(events[0]) val eventProcessor = createProcessor(isInForeground = true, navigationState = VIEWING_A_THREAD) val result = eventProcessor.process(events, renderedEvents = emptyList()) @@ -213,8 +213,8 @@ class NotifiableEventProcessorTest { navigationState: NavigationState ): NotifiableEventProcessor { return NotifiableEventProcessor( - outdatedDetector.instance, - FakeAppNavigationStateService(MutableStateFlow(AppNavigationState(navigationState, isInForeground))), + outdatedDetector = mockkOutdatedDetector.instance, + appNavigationStateService = FakeAppNavigationStateService(MutableStateFlow(AppNavigationState(navigationState, isInForeground))), ) } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt index cd1d19b3a7..6a211fc446 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationFactoryTest.kt @@ -22,10 +22,10 @@ import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader -import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator -import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkRoomGroupMessageCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkSummaryGroupMessageCreator import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent @@ -41,19 +41,19 @@ private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roo @RunWith(RobolectricTestRunner::class) class NotificationFactoryTest { - private val androidNotificationFactory = FakeNotificationCreator() - private val roomGroupMessageCreator = FakeRoomGroupMessageCreator() - private val summaryGroupMessageCreator = FakeSummaryGroupMessageCreator() + private val mockkNotificationCreator = MockkNotificationCreator() + private val mockkRoomGroupMessageCreator = MockkRoomGroupMessageCreator() + private val mockkSummaryGroupMessageCreator = MockkSummaryGroupMessageCreator() private val notificationFactory = NotificationFactory( - androidNotificationFactory.instance, - roomGroupMessageCreator.instance, - summaryGroupMessageCreator.instance + notificationCreator = mockkNotificationCreator.instance, + roomGroupMessageCreator = mockkRoomGroupMessageCreator.instance, + summaryGroupMessageCreator = mockkSummaryGroupMessageCreator.instance ) @Test fun `given a room invitation when mapping to notification then is Append`() = testWith(notificationFactory) { - val expectedNotification = androidNotificationFactory.givenCreateRoomInvitationNotificationFor(AN_INVITATION_EVENT) + val expectedNotification = mockkNotificationCreator.givenCreateRoomInvitationNotificationFor(AN_INVITATION_EVENT) val roomInvitation = listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, AN_INVITATION_EVENT)) val result = roomInvitation.toNotifications() @@ -90,7 +90,7 @@ class NotificationFactoryTest { @Test fun `given a simple event when mapping to notification then is Append`() = testWith(notificationFactory) { - val expectedNotification = androidNotificationFactory.givenCreateSimpleInvitationNotificationFor(A_SIMPLE_EVENT) + val expectedNotification = mockkNotificationCreator.givenCreateSimpleInvitationNotificationFor(A_SIMPLE_EVENT) val roomInvitation = listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, A_SIMPLE_EVENT)) val result = roomInvitation.toNotifications() @@ -128,7 +128,7 @@ class NotificationFactoryTest { @Test fun `given room with message when mapping to notification then delegates to room group message creator`() = testWith(notificationFactory) { val events = listOf(A_MESSAGE_EVENT) - val expectedNotification = roomGroupMessageCreator.givenCreatesRoomMessageFor( + val expectedNotification = mockkRoomGroupMessageCreator.givenCreatesRoomMessageFor( MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL), events, A_ROOM_ID @@ -197,7 +197,7 @@ class NotificationFactoryTest { ) ) val withRedactedRemoved = listOf(A_MESSAGE_EVENT.copy(eventId = EventId("\$not-redacted"))) - val expectedNotification = roomGroupMessageCreator.givenCreatesRoomMessageFor( + val expectedNotification = mockkRoomGroupMessageCreator.givenCreatesRoomMessageFor( MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL), withRedactedRemoved, A_ROOM_ID, diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt index 4780ae3914..21fc1b4fca 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationRendererTest.kt @@ -22,8 +22,8 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationFactory +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationFactory import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.mockk.mockk import kotlinx.coroutines.test.runTest @@ -51,14 +51,14 @@ private val ONE_SHOT_META = OneShotNotification.Append.Meta(key = "ignored", sum @RunWith(RobolectricTestRunner::class) class NotificationRendererTest { - private val notificationDisplayer = FakeNotificationDisplayer() - private val notificationFactory = FakeNotificationFactory() + private val mockkNotificationDisplayer = MockkNotificationDisplayer() + private val mockkNotificationFactory = MockkNotificationFactory() private val notificationIdProvider = NotificationIdProvider() private val notificationRenderer = NotificationRenderer( notificationIdProvider = notificationIdProvider, - notificationDisplayer = notificationDisplayer.instance, - notificationFactory = notificationFactory.instance, + notificationDisplayer = mockkNotificationDisplayer.instance, + notificationFactory = mockkNotificationFactory.instance, ) @Test @@ -67,8 +67,8 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifySummaryCancelled() - notificationDisplayer.verifyNoOtherInteractions() + mockkNotificationDisplayer.verifySummaryCancelled() + mockkNotificationDisplayer.verifyNoOtherInteractions() } @Test @@ -77,7 +77,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)) cancelNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID)) } @@ -89,7 +89,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID)) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -108,7 +108,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { showNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID), A_NOTIFICATION) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -120,7 +120,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)) cancelNotificationMessage(tag = AN_EVENT_ID.value, notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID)) } @@ -132,7 +132,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = AN_EVENT_ID.value, notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID)) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -151,7 +151,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { showNotificationMessage(tag = AN_EVENT_ID.value, notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID), A_NOTIFICATION) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -163,7 +163,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)) cancelNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomInvitationNotificationId(A_SESSION_ID)) } @@ -175,7 +175,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { cancelNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomInvitationNotificationId(A_SESSION_ID)) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -194,7 +194,7 @@ class NotificationRendererTest { renderEventsAsNotifications() - notificationDisplayer.verifyInOrder { + mockkNotificationDisplayer.verifyInOrder { showNotificationMessage(tag = A_ROOM_ID.value, notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID), A_NOTIFICATION) showNotificationMessage(tag = null, notificationIdProvider.getSummaryNotificationId(A_SESSION_ID), A_SUMMARY_NOTIFICATION.notification) } @@ -221,7 +221,7 @@ class NotificationRendererTest { useCompleteNotificationFormat: Boolean = USE_COMPLETE_NOTIFICATION_FORMAT, summaryNotification: SummaryNotification = A_SUMMARY_NOTIFICATION ) { - notificationFactory.givenNotificationsFor( + mockkNotificationFactory.givenNotificationsFor( groupedEvents = A_PROCESSED_EVENTS, matrixUser = MatrixUser(A_SESSION_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR_URL), useCompleteNotificationFormat = useCompleteNotificationFormat, diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationCreator.kt similarity index 98% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationCreator.kt index 5029166f06..205ba058e6 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationCreator.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationCreator.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiab import io.mockk.every import io.mockk.mockk -class FakeNotificationCreator { +class MockkNotificationCreator { val instance = mockk() fun givenCreateRoomInvitationNotificationFor(event: InviteNotifiableEvent): Notification { diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationDisplayer.kt similarity index 97% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationDisplayer.kt index d737c8eae2..dc55cecfac 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationDisplayer.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationDisplayer.kt @@ -25,7 +25,7 @@ import io.mockk.mockk import io.mockk.verify import io.mockk.verifyOrder -class FakeNotificationDisplayer { +class MockkNotificationDisplayer { val instance = mockk(relaxed = true) fun givenDisplayDiagnosticNotificationResult(result: Boolean) { diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationFactory.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationFactory.kt similarity index 98% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationFactory.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationFactory.kt index 9c7755aa9d..6a8410d2cb 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeNotificationFactory.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkNotificationFactory.kt @@ -26,7 +26,7 @@ import io.mockk.coEvery import io.mockk.every import io.mockk.mockk -class FakeNotificationFactory { +class MockkNotificationFactory { val instance = mockk() fun givenNotificationsFor( diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeOutdatedEventDetector.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkOutdatedEventDetector.kt similarity index 97% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeOutdatedEventDetector.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkOutdatedEventDetector.kt index 03bf7e8491..414f7ae652 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeOutdatedEventDetector.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkOutdatedEventDetector.kt @@ -21,7 +21,7 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableEven import io.mockk.every import io.mockk.mockk -class FakeOutdatedEventDetector { +class MockkOutdatedEventDetector { val instance = mockk() fun givenEventIsOutOfDate(notifiableEvent: NotifiableEvent) { diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeRoomGroupMessageCreator.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkRoomGroupMessageCreator.kt similarity index 97% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeRoomGroupMessageCreator.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkRoomGroupMessageCreator.kt index a41a4aadc2..389a4f441d 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeRoomGroupMessageCreator.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkRoomGroupMessageCreator.kt @@ -24,7 +24,7 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableMess import io.mockk.coEvery import io.mockk.mockk -class FakeRoomGroupMessageCreator { +class MockkRoomGroupMessageCreator { val instance = mockk() fun givenCreatesRoomMessageFor( diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeSummaryGroupMessageCreator.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkSummaryGroupMessageCreator.kt similarity index 95% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeSummaryGroupMessageCreator.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkSummaryGroupMessageCreator.kt index 546cb1e054..8f99651c89 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/FakeSummaryGroupMessageCreator.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/fake/MockkSummaryGroupMessageCreator.kt @@ -19,6 +19,6 @@ package io.element.android.libraries.push.impl.notifications.fake import io.element.android.libraries.push.impl.notifications.SummaryGroupMessageCreator import io.mockk.mockk -class FakeSummaryGroupMessageCreator { +class MockkSummaryGroupMessageCreator { val instance = mockk() } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt index fcef1dcbab..0a4ac2d066 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt @@ -19,17 +19,17 @@ package io.element.android.libraries.push.impl.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator -import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator +import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test class NotificationTestTest { - private val fakeNotificationCreator = FakeNotificationCreator().apply { + private val mockkNotificationCreator = MockkNotificationCreator().apply { givenCreateDiagnosticNotification() } - private val fakeNotificationDisplayer = FakeNotificationDisplayer().apply { + private val mockkNotificationDisplayer = MockkNotificationDisplayer().apply { givenDisplayDiagnosticNotificationResult(true) } @@ -37,7 +37,7 @@ class NotificationTestTest { @Test fun `test NotificationTest notification cannot be displayed`() = runTest { - fakeNotificationDisplayer.givenDisplayDiagnosticNotificationResult(false) + mockkNotificationDisplayer.givenDisplayDiagnosticNotificationResult(false) val sut = createNotificationTest() launch { sut.run(this) @@ -80,8 +80,8 @@ class NotificationTestTest { private fun createNotificationTest(): NotificationTest { return NotificationTest( - notificationCreator = fakeNotificationCreator.instance, - notificationDisplayer = fakeNotificationDisplayer.instance, + notificationCreator = mockkNotificationCreator.instance, + notificationDisplayer = mockkNotificationDisplayer.instance, notificationClickHandler = notificationClickHandler ) } From 74048cca8f084aa8633411f17b019fb04abcee0b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 26 Mar 2024 15:29:12 +0100 Subject: [PATCH 04/27] Avoid tryEmit(), use emit() --- .../troubleshoot/FakeNotificationTroubleshootTest.kt | 10 +++++----- .../core/notifications/NotificationTroubleshootTest.kt | 6 ++++-- .../NotificationTroubleshootTestDelegate.kt | 8 ++++---- .../NotificationTroubleshootCheckPermissionTest.kt | 2 +- .../push/impl/troubleshoot/CurrentPushProviderTest.kt | 2 +- .../push/impl/troubleshoot/NotificationTest.kt | 2 +- .../push/impl/troubleshoot/PushLoopbackTest.kt | 2 +- .../push/impl/troubleshoot/PushProvidersTest.kt | 2 +- .../firebase/troubleshoot/FirebaseAvailabilityTest.kt | 2 +- .../firebase/troubleshoot/FirebaseTokenTest.kt | 2 +- .../unifiedpush/troubleshoot/UnifiedPushTest.kt | 2 +- 11 files changed, 21 insertions(+), 19 deletions(-) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt index e619a62972..361c59cae7 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt @@ -48,30 +48,30 @@ class FakeNotificationTroubleshootTest( } } - override fun reset() { + override suspend fun reset() { updateState( name = defaultName, description = defaultDescription, status = firstStatus, ) resetAction()?.let { - _state.tryEmit(it) + _state.emit(it) } } override suspend fun quickFix(coroutineScope: CoroutineScope) { updateState(NotificationTroubleshootTestState.Status.InProgress) quickFixAction()?.let { - _state.tryEmit(it) + _state.emit(it) } } - fun updateState( + suspend fun updateState( status: NotificationTroubleshootTestState.Status, name: String = defaultName, description: String = defaultDescription, ) { - _state.tryEmit( + _state.emit( NotificationTroubleshootTestState( name = name, description = description, diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt index 755e186e8b..7af0b85ffb 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt @@ -24,6 +24,8 @@ interface NotificationTroubleshootTest { val state: StateFlow fun isRelevant(data: TestFilterData): Boolean = true suspend fun run(coroutineScope: CoroutineScope) - fun reset() - suspend fun quickFix(coroutineScope: CoroutineScope) {} + suspend fun reset() + suspend fun quickFix(coroutineScope: CoroutineScope) { + error("Quick fix not implemented, you need to override this method in your test") + } } diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt index 9711677253..88aaae7281 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt @@ -41,12 +41,12 @@ class NotificationTroubleshootTestDelegate( val state: StateFlow = _state.asStateFlow() - fun updateState( + suspend fun updateState( status: NotificationTroubleshootTestState.Status, name: String = defaultName, description: String = defaultDescription, ) { - _state.tryEmit( + _state.emit( NotificationTroubleshootTestState( name = name, description = description, @@ -55,7 +55,7 @@ class NotificationTroubleshootTestDelegate( ) } - fun reset() { + suspend fun reset() { updateState(NotificationTroubleshootTestState.Status.Idle(visibleWhenIdle)) } @@ -64,7 +64,7 @@ class NotificationTroubleshootTestDelegate( delay(fakeDelay) } - fun done(isSuccess: Boolean = true) { + suspend fun done(isSuccess: Boolean = true) { updateState( if (isSuccess) { NotificationTroubleshootTestState.Status.Success diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt index 501b00e14a..f158ccbabd 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt @@ -57,7 +57,7 @@ class NotificationTroubleshootCheckPermissionTest @Inject constructor( delegate.done(result) } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() override suspend fun quickFix(coroutineScope: CoroutineScope) { // Do not bother about asking the permission inline, just lead the user to the settings diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt index 6b8f69e8db..32f99edd13 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt @@ -54,5 +54,5 @@ class CurrentPushProviderTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt index b2e7ef223c..d2bf0b160d 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt @@ -90,5 +90,5 @@ class NotificationTest @Inject constructor( notificationDisplayer.dismissDiagnosticNotification() } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt index 86d7b437a7..b4323b612f 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt @@ -98,5 +98,5 @@ class PushLoopbackTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt index 7beca906b9..bbcee50a54 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt @@ -55,5 +55,5 @@ class PushProvidersTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt index e0891d6081..acd907fb0a 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt @@ -61,5 +61,5 @@ class FirebaseAvailabilityTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt index 7c8ce5dfef..e501ce1e9d 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -63,7 +63,7 @@ class FirebaseTokenTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() override suspend fun quickFix(coroutineScope: CoroutineScope) { delegate.start() diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt index 3d612b0613..df79030c44 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt @@ -62,7 +62,7 @@ class UnifiedPushTest @Inject constructor( } } - override fun reset() = delegate.reset() + override suspend fun reset() = delegate.reset() override suspend fun quickFix(coroutineScope: CoroutineScope) { openDistributorWebPageAction.execute() From 201944890e724e62469888931ee6cd0b7b3a224f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 15:08:42 +0100 Subject: [PATCH 05/27] Update analytics event lib. --- gradle/libs.versions.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2be4f8dbcb..cb7b6ac50c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -177,7 +177,9 @@ kotlinpoet = "com.squareup:kotlinpoet:1.16.0" # Analytics posthog = "com.posthog:posthog-android:3.1.16" sentry = "io.sentry:sentry-android:7.6.0" -matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.14.0" +# Note: only 0.19.0 will compile properly +# main branch can be tested replacing the version with main-SNAPSHOT +matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.15.0" # Emojibase matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.1.3" From ef48c2b5a31f022897db308a204047d823cff51b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 16:11:24 +0100 Subject: [PATCH 06/27] Track NotificationTroubleshoot screen --- .../TroubleshootNotificationsNode.kt | 4 ++ services/analytics/api/build.gradle.kts | 4 +- .../services/analytics/api/ScreenTracker.kt | 29 ++++++++++ .../analytics/impl/DefaultScreenTracker.kt | 58 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt create mode 100644 services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt index 1ac7c0c079..833f512c81 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt @@ -23,17 +23,21 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import dagger.assisted.Assisted import dagger.assisted.AssistedInject +import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.SessionScope +import io.element.android.services.analytics.api.ScreenTracker @ContributesNode(SessionScope::class) class TroubleshootNotificationsNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: TroubleshootNotificationsPresenter, + private val screenTracker: ScreenTracker, ) : Node(buildContext, plugins = plugins) { @Composable override fun View(modifier: Modifier) { + screenTracker.TrackScreen(this, MobileScreen.ScreenName.NotificationTroubleshoot) val state = presenter.present() TroubleshootNotificationsView( state = state, diff --git a/services/analytics/api/build.gradle.kts b/services/analytics/api/build.gradle.kts index 28b871a659..361ad09162 100644 --- a/services/analytics/api/build.gradle.kts +++ b/services/analytics/api/build.gradle.kts @@ -14,7 +14,7 @@ * limitations under the License. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { @@ -23,6 +23,8 @@ android { dependencies { api(projects.services.analyticsproviders.api) + api(projects.services.toolbox.api) + api(libs.appyx.core) implementation(libs.coroutines.core) implementation(projects.libraries.matrix.api) implementation(projects.libraries.core) diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt new file mode 100644 index 0000000000..b2f1e3ab6d --- /dev/null +++ b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 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.services.analytics.api + +import androidx.compose.runtime.Composable +import com.bumble.appyx.core.node.Node +import im.vector.app.features.analytics.plan.MobileScreen + +interface ScreenTracker { + @Composable + fun TrackScreen( + node: Node, + screen: MobileScreen.ScreenName, + ) +} diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt new file mode 100644 index 0000000000..970fcd0c95 --- /dev/null +++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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.services.analytics.impl + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import com.bumble.appyx.core.lifecycle.subscribe +import com.bumble.appyx.core.node.Node +import com.squareup.anvil.annotations.ContributesBinding +import im.vector.app.features.analytics.plan.MobileScreen +import io.element.android.libraries.di.AppScope +import io.element.android.services.analytics.api.AnalyticsService +import io.element.android.services.analytics.api.ScreenTracker +import io.element.android.services.toolbox.api.systemclock.SystemClock +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultScreenTracker @Inject constructor( + private val analyticsService: AnalyticsService, + private val systemClock: SystemClock +) : ScreenTracker { + @Composable + override fun TrackScreen( + node: Node, + screen: MobileScreen.ScreenName, + ) { + LaunchedEffect(Unit) { + var startTime = 0L + node.lifecycle.subscribe( + onResume = { + startTime = systemClock.epochMillis() + }, + onPause = { + analyticsService.screen( + screen = MobileScreen( + durationMs = (systemClock.epochMillis() - startTime).toInt(), + screenName = screen + ) + ) + } + ) + } + } +} From 8da435b5148c5963a1d7db88c4652ee1b3281e42 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 16:16:06 +0100 Subject: [PATCH 07/27] Track NotificationTroubleshoot --- .../troubleshoot/TroubleshootTestSuite.kt | 13 +++++++++++++ .../TroubleshootNotificationsPresenterTests.kt | 2 ++ 2 files changed, 15 insertions(+) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt index 4996d278de..41fad1c3d5 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt @@ -16,11 +16,13 @@ package io.element.android.features.preferences.impl.notifications.troubleshoot +import im.vector.app.features.analytics.plan.NotificationTroubleshoot import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.notifications.NotificationTroubleshootTest import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.push.api.GetCurrentPushProvider +import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -32,6 +34,7 @@ import javax.inject.Inject class TroubleshootTestSuite @Inject constructor( private val notificationTroubleshootTests: Set<@JvmSuppressWildcards NotificationTroubleshootTest>, private val getCurrentPushProvider: GetCurrentPushProvider, + private val analyticsService: AnalyticsService, ) { lateinit var tests: List @@ -77,6 +80,16 @@ class TroubleshootTestSuite @Inject constructor( private fun emitState() { val states = tests.map { it.state.value } + val mainState = states.computeMainState() + when (mainState) { + is AsyncAction.Success -> { + analyticsService.capture(NotificationTroubleshoot(hasError = false)) + } + is AsyncAction.Failure -> { + analyticsService.capture(NotificationTroubleshoot(hasError = true)) + } + else -> Unit + } _state.tryEmit( TroubleshootTestSuiteState( mainState = states.computeMainState(), diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt index e6e712b1b8..686aac2e56 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt @@ -24,6 +24,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.notifications.NotificationTroubleshootTest import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import io.element.android.services.analytics.test.FakeAnalyticsService import kotlinx.coroutines.test.runTest import org.junit.Test @@ -113,6 +114,7 @@ class TroubleshootNotificationsPresenterTests { return TroubleshootTestSuite( notificationTroubleshootTests = tests, getCurrentPushProvider = FakeGetCurrentPushProvider(currentPushProvider), + analyticsService = FakeAnalyticsService(), ) } From a3cb7ab26508684328f812fb0d6d23699fca6f02 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 16:19:05 +0100 Subject: [PATCH 08/27] use emit instead of tryEmit --- .../impl/notifications/troubleshoot/TroubleshootTestSuite.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt index 41fad1c3d5..361cf1601f 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt @@ -78,7 +78,7 @@ class TroubleshootTestSuite @Inject constructor( } } - private fun emitState() { + private suspend fun emitState() { val states = tests.map { it.state.value } val mainState = states.computeMainState() when (mainState) { @@ -90,7 +90,7 @@ class TroubleshootTestSuite @Inject constructor( } else -> Unit } - _state.tryEmit( + _state.emit( TroubleshootTestSuiteState( mainState = states.computeMainState(), tests = states.toImmutableList() From 5e27c54deb68fee38e72298fa791c6351c5934c9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 18:16:44 +0100 Subject: [PATCH 09/27] FakeStringProvider: Ensure parameter are included in the result of getString() --- .../services/toolbox/test/strings/FakeStringProvider.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/strings/FakeStringProvider.kt b/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/strings/FakeStringProvider.kt index c9f9a84fc9..870b3acf39 100644 --- a/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/strings/FakeStringProvider.kt +++ b/services/toolbox/test/src/main/kotlin/io/element/android/services/toolbox/test/strings/FakeStringProvider.kt @@ -26,10 +26,10 @@ class FakeStringProvider( } override fun getString(resId: Int, vararg formatArgs: Any?): String { - return defaultResult + return defaultResult + formatArgs.joinToString() } override fun getQuantityString(resId: Int, quantity: Int, vararg formatArgs: Any?): String { - return defaultResult + return defaultResult + " ($quantity) " + formatArgs.joinToString() } } From 33526db485414facd125145a20e80b56375dd12f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 18:25:31 +0100 Subject: [PATCH 10/27] Fix test in VersionFormatterTest (there was a swap in the test names by the way). --- .../impl/root/VersionFormatterTest.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt index ebab2960e9..e41895440c 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/VersionFormatterTest.kt @@ -23,25 +23,31 @@ import kotlinx.coroutines.test.runTest import org.junit.Test class VersionFormatterTest { - @Test - fun `version formatter should return simplified version for other branch`() = runTest { - val sut = DefaultVersionFormatter( - stringProvider = FakeStringProvider(defaultResult = VERSION), - buildMeta = aBuildMeta(gitBranchName = "main") - ) - assertThat(sut.get()).isEqualTo(VERSION) - } - @Test fun `version formatter should return simplified version for main branch`() = runTest { val sut = DefaultVersionFormatter( stringProvider = FakeStringProvider(defaultResult = VERSION), buildMeta = aBuildMeta( + gitBranchName = "main", + versionName = "versionName", + versionCode = 123 + ) + ) + assertThat(sut.get()).isEqualTo("${VERSION}versionName, 123") + } + + @Test + fun `version formatter should return simplified version for other branch`() = runTest { + val sut = DefaultVersionFormatter( + stringProvider = FakeStringProvider(defaultResult = VERSION), + buildMeta = aBuildMeta( + versionName = "versionName", + versionCode = 123, gitBranchName = "branch", gitRevision = "1234567890", ) ) - assertThat(sut.get()).isEqualTo("$VERSION\nbranch (1234567890)") + assertThat(sut.get()).isEqualTo("${VERSION}versionName, 123\nbranch (1234567890)") } companion object { From 09b2cbaaf5f4c993e79adf5122d6541d661f6c6b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 18:16:47 +0100 Subject: [PATCH 11/27] Localize Troubleshoot notification feature. --- .../notifications/NotificationSettingsView.kt | 4 +-- .../TroubleshootNotificationsView.kt | 22 +++++++++------ .../impl/src/main/res/values/localazy.xml | 10 +++++++ ...ficationTroubleshootCheckPermissionTest.kt | 7 +++-- .../impl/src/main/res/values/localazy.xml | 5 ++++ ...tionTroubleshootCheckPermissionTestTest.kt | 10 +++++-- .../troubleshoot/CurrentPushProviderTest.kt | 11 +++++--- .../impl/troubleshoot/NotificationTest.kt | 17 ++++++----- .../impl/troubleshoot/PushLoopbackTest.kt | 17 ++++++----- .../impl/troubleshoot/PushProvidersTest.kt | 16 ++++++++--- .../impl/src/main/res/values/localazy.xml | 24 ++++++++++++++++ .../CurrentPushProviderTestTest.kt | 7 +++-- .../impl/troubleshoot/NotificationTestTest.kt | 4 ++- .../impl/troubleshoot/PushLoopbackTestTest.kt | 19 +++++++------ .../troubleshoot/PushProvidersTestTest.kt | 4 +++ .../pushproviders/firebase/build.gradle.kts | 3 ++ .../troubleshoot/FirebaseAvailabilityTest.kt | 11 +++++--- .../troubleshoot/FirebaseTokenTest.kt | 14 +++++++--- .../firebase/src/main/res/values/localazy.xml | 11 ++++++++ .../FirebaseAvailabilityTestTest.kt | 7 +++-- .../troubleshoot/FirebaseTokenTestTest.kt | 3 ++ .../unifiedpush/build.gradle.kts | 2 ++ .../troubleshoot/UnifiedPushTest.kt | 16 ++++++++--- .../src/main/res/values/localazy.xml | 10 +++++++ .../troubleshoot/UnifiedPushTestTest.kt | 3 ++ tools/localazy/config.json | 28 +++++++++++++++++-- 26 files changed, 221 insertions(+), 64 deletions(-) create mode 100644 libraries/permissions/impl/src/main/res/values/localazy.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values/localazy.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values/localazy.xml diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt index 8f59ffcdba..5e3610b652 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt @@ -166,10 +166,10 @@ private fun NotificationSettingsContentView( onCheckedChange = onInviteForMeNotificationsChanged ) } - PreferenceCategory(title = "Troubleshoot") { + PreferenceCategory(title = stringResource(id = R.string.troubleshoot_notifications_entry_point_section)) { PreferenceText( modifier = Modifier, - title = "Troubleshoot notifications", + title = stringResource(id = R.string.troubleshoot_notifications_entry_point_title), onClick = onTroubleshootNotificationsClicked ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt index cadffa1ba0..451b4f778e 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt @@ -21,11 +21,13 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.progressSemantics import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.features.preferences.impl.R import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState.Status @@ -63,7 +65,7 @@ fun TroubleshootNotificationsView( PreferencePage( modifier = modifier, onBackPressed = onBackPressed, - title = "Troubleshoot notifications", + title = stringResource(id = R.string.troubleshoot_notifications_screen_title), ) { TroubleshootNotificationsContent(state) } @@ -120,7 +122,7 @@ private fun TroubleshootTestView( }, trailingContent = ListItemContent.Custom { Button( - text = "Attempt to fix", + text = stringResource(id = R.string.troubleshoot_notifications_screen_quick_fix_action), onClick = onQuickFixClicked ) } @@ -148,8 +150,7 @@ private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsSta AsyncAction.Uninitialized -> { ListItem(headlineContent = { Text( - text = "Run the tests to detect any issue in your configuration " + - "that may make notifications not behave as expected." + text = stringResource(id = R.string.troubleshoot_notifications_screen_notice) ) }) RunTestButton(state = state) @@ -157,21 +158,21 @@ private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsSta AsyncAction.Loading -> Unit is AsyncAction.Failure -> { ListItem(headlineContent = { - Text(text = "Some tests failed, please check the details.") + Text(text = stringResource(id = R.string.troubleshoot_notifications_screen_failure)) }) RunTestButton(state = state) } AsyncAction.Confirming -> { ListItem(headlineContent = { Text( - text = "Some tests require your attention. Please check the details." + text = stringResource(id = R.string.troubleshoot_notifications_screen_waiting) ) }) } is AsyncAction.Success -> { ListItem(headlineContent = { Text( - text = "All tests passed successfully." + text = stringResource(id = R.string.troubleshoot_notifications_screen_success) ) }) } @@ -183,7 +184,12 @@ private fun RunTestButton(state: TroubleshootNotificationsState) { ListItem( headlineContent = { Button( - text = if (state.testSuiteState.mainState is AsyncAction.Failure) "Run tests again" else "Run tests", + text = stringResource( + id = if (state.testSuiteState.mainState is AsyncAction.Failure) + R.string.troubleshoot_notifications_screen_action_again + else + R.string.troubleshoot_notifications_screen_action + ), onClick = { state.eventSink(TroubleshootNotificationsEvents.StartTests) }, diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml index 492c75295a..b0e78e0d9e 100644 --- a/features/preferences/impl/src/main/res/values/localazy.xml +++ b/features/preferences/impl/src/main/res/values/localazy.xml @@ -49,4 +49,14 @@ If you proceed, some of your settings may change." "system settings" "System notifications turned off" "Notifications" + "Troubleshoot" + "Troubleshoot notifications" + "Run tests" + "Run tests again" + "Some tests failed. Please check the details." + "Run the tests to detect any issue in your configuration that may make notifications not behave as expected." + "Attempt to fix" + "All tests passed successfully." + "Troubleshoot notifications" + "Some tests require your attention. Please check the details." diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt index f158ccbabd..903b5cd2c4 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt @@ -24,8 +24,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.permissions.api.PermissionStateProvider +import io.element.android.libraries.permissions.impl.R import io.element.android.libraries.permissions.impl.action.PermissionActions import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -35,12 +37,13 @@ class NotificationTroubleshootCheckPermissionTest @Inject constructor( private val permissionStateProvider: PermissionStateProvider, private val sdkVersionProvider: BuildVersionSdkIntProvider, private val permissionActions: PermissionActions, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order: Int = 0 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Check permissions", - defaultDescription = "Ensure that the application can show notifications.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_description), hasQuickFix = true, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, ) diff --git a/libraries/permissions/impl/src/main/res/values/localazy.xml b/libraries/permissions/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..a8859205dc --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values/localazy.xml @@ -0,0 +1,5 @@ + + + "Ensure that the application can show notifications." + "Check permissions" + diff --git a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt index 80c07e2ce0..c17e61f5e7 100644 --- a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt +++ b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.permissions.impl.FakePermissionStateProvider import io.element.android.libraries.permissions.impl.action.FakePermissionActions import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -33,7 +34,8 @@ class NotificationTroubleshootCheckPermissionTestTest { val sut = NotificationTroubleshootCheckPermissionTest( permissionStateProvider = FakePermissionStateProvider(), sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU - 1), - permissionActions = FakePermissionActions() + permissionActions = FakePermissionActions(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -51,7 +53,8 @@ class NotificationTroubleshootCheckPermissionTestTest { val sut = NotificationTroubleshootCheckPermissionTest( permissionStateProvider = FakePermissionStateProvider(), sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), - permissionActions = FakePermissionActions() + permissionActions = FakePermissionActions(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -77,7 +80,8 @@ class NotificationTroubleshootCheckPermissionTestTest { val sut = NotificationTroubleshootCheckPermissionTest( permissionStateProvider = permissionStateProvider, sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), - permissionActions = actions + permissionActions = actions, + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt index 32f99edd13..7a819b3d93 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt @@ -22,6 +22,8 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.api.GetCurrentPushProvider +import io.element.android.libraries.push.impl.R +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -29,11 +31,12 @@ import javax.inject.Inject @ContributesMultibinding(AppScope::class) class CurrentPushProviderTest @Inject constructor( private val getCurrentPushProvider: GetCurrentPushProvider, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 110 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Current push provider", - defaultDescription = "Get the name of the current provider.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_description), fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, ) override val state: StateFlow = delegate.state @@ -43,12 +46,12 @@ class CurrentPushProviderTest @Inject constructor( val provider = getCurrentPushProvider.getCurrentPushProvider() if (provider != null) { delegate.updateState( - description = "Current push provider: $provider", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_success, provider), status = NotificationTroubleshootTestState.Status.Success ) } else { delegate.updateState( - description = "No push providers selected", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_failure), status = NotificationTroubleshootTestState.Status.Failure(false) ) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt index d2bf0b160d..d7e3641e22 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt @@ -21,8 +21,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.notifications.NotificationDisplayer import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first @@ -36,12 +38,13 @@ import kotlin.time.Duration.Companion.seconds class NotificationTest @Inject constructor( private val notificationCreator: NotificationCreator, private val notificationDisplayer: NotificationDisplayer, - private val notificationClickHandler: NotificationClickHandler + private val notificationClickHandler: NotificationClickHandler, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 50 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Display notification", - defaultDescription = "Check that the application can display notification", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_description), fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, ) override val state: StateFlow = delegate.state @@ -53,12 +56,12 @@ class NotificationTest @Inject constructor( if (result) { coroutineScope.listenToNotificationClick() delegate.updateState( - description = "Please click on the notification to continue the test.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_waiting), status = NotificationTroubleshootTestState.Status.WaitingForUser ) } else { delegate.updateState( - description = "Cannot display the notification.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_permission_failure), status = NotificationTroubleshootTestState.Status.Failure(false) ) } @@ -76,12 +79,12 @@ class NotificationTest @Inject constructor( if (s == null) { notificationDisplayer.dismissDiagnosticNotification() delegate.updateState( - description = "The notification has not been clicked.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_failure), status = NotificationTroubleshootTestState.Status.Failure(false) ) } else { delegate.updateState( - description = "The notification has been clicked!", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_success), status = NotificationTroubleshootTestState.Status.Success ) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt index b4323b612f..2ecec61996 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt @@ -23,6 +23,8 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.gateway.PushGatewayFailure +import io.element.android.libraries.push.impl.R +import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope @@ -39,11 +41,12 @@ class PushLoopbackTest @Inject constructor( private val pushService: PushService, private val diagnosticPushHandler: DiagnosticPushHandler, private val clock: SystemClock, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 500 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Test Push loopback", - defaultDescription = "Ensure that the application is receiving push.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_description), ) override val state: StateFlow = delegate.state @@ -59,7 +62,7 @@ class PushLoopbackTest @Inject constructor( pushService.testPush() } catch (pusherRejected: PushGatewayFailure.PusherRejected) { delegate.updateState( - description = "Error: pusher has rejected the request.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_1), status = NotificationTroubleshootTestState.Status.Failure(false) ) job.cancel() @@ -67,7 +70,7 @@ class PushLoopbackTest @Inject constructor( } catch (e: Exception) { Timber.e(e, "Failed to test push") delegate.updateState( - description = "Error: ${e.message}.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_2, e.message), status = NotificationTroubleshootTestState.Status.Failure(false) ) job.cancel() @@ -75,7 +78,7 @@ class PushLoopbackTest @Inject constructor( } if (!testPushResult) { delegate.updateState( - description = "Error, cannot test push.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_3), status = NotificationTroubleshootTestState.Status.Failure(false) ) job.cancel() @@ -87,12 +90,12 @@ class PushLoopbackTest @Inject constructor( job.cancel() if (result == null) { delegate.updateState( - description = "Error, timeout waiting for push.", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_4), status = NotificationTroubleshootTestState.Status.Failure(false) ) } else { delegate.updateState( - description = "Push loopback took $result ms", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_success, result), status = NotificationTroubleshootTestState.Status.Success ) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt index bbcee50a54..df6d220396 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt @@ -21,7 +21,9 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope +import io.element.android.libraries.push.impl.R import io.element.android.libraries.pushproviders.api.PushProvider +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -29,12 +31,13 @@ import javax.inject.Inject @ContributesMultibinding(AppScope::class) class PushProvidersTest @Inject constructor( pushProviders: Set<@JvmSuppressWildcards PushProvider>, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { private val sortedPushProvider = pushProviders.sortedBy { it.index } override val order = 100 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Detect push providers", - defaultDescription = "Ensure that the application has at least one push provider.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_description), fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, ) override val state: StateFlow = delegate.state @@ -44,12 +47,17 @@ class PushProvidersTest @Inject constructor( val result = sortedPushProvider.isNotEmpty() if (result) { delegate.updateState( - description = "Found ${sortedPushProvider.size} push providers: ${sortedPushProvider.joinToString { it.name }}", + description = stringProvider.getQuantityString( + resId = R.plurals.troubleshoot_notifications_test_detect_push_provider_success, + quantity = sortedPushProvider.size, + sortedPushProvider.size, + sortedPushProvider.joinToString { it.name } + ), status = NotificationTroubleshootTestState.Status.Success ) } else { delegate.updateState( - description = "No push providers found", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_failure), status = NotificationTroubleshootTestState.Status.Failure(false) ) } diff --git a/libraries/push/impl/src/main/res/values/localazy.xml b/libraries/push/impl/src/main/res/values/localazy.xml index ed49f5edd8..c9d7627d07 100644 --- a/libraries/push/impl/src/main/res/values/localazy.xml +++ b/libraries/push/impl/src/main/res/values/localazy.xml @@ -50,4 +50,28 @@ "Background synchronization" "Google Services" "No valid Google Play Services found. Notifications may not work properly." + "Get the name of the current provider." + "No push providers selected." + "Current push provider: %1$s." + "Current push provider" + "Ensure that the application has at least one push provider." + "No push providers found." + + "Found %1$d push provider: %2$s" + "Found %1$d push providers: %2$s" + + "Detect push providers" + "Check that the application can display notification." + "The notification has not been clicked." + "Cannot display the notification." + "The notification has been clicked!" + "Display notification" + "Please click on the notification to continue the test." + "Ensure that the application is receiving push." + "Error: pusher has rejected the request." + "Error: %1$s." + "Error, cannot test push." + "Error, timeout waiting for push." + "Push loop back took %1$d ms." + "Test Push loop back" diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt index 8506d826b5..ea8de71222 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt @@ -20,6 +20,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -28,7 +29,8 @@ class CurrentPushProviderTestTest { @Test fun `test CurrentPushProviderTest with a push provider`() = runTest { val sut = CurrentPushProviderTest( - getCurrentPushProvider = FakeGetCurrentPushProvider("foo") + getCurrentPushProvider = FakeGetCurrentPushProvider("foo"), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -45,7 +47,8 @@ class CurrentPushProviderTestTest { @Test fun `test CurrentPushProviderTest without push provider`() = runTest { val sut = CurrentPushProviderTest( - getCurrentPushProvider = FakeGetCurrentPushProvider(null) + getCurrentPushProvider = FakeGetCurrentPushProvider(null), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt index 0a4ac2d066..a900d50b1f 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt @@ -21,6 +21,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -82,7 +83,8 @@ class NotificationTestTest { return NotificationTest( notificationCreator = mockkNotificationCreator.instance, notificationDisplayer = mockkNotificationDisplayer.instance, - notificationClickHandler = notificationClickHandler + notificationClickHandler = notificationClickHandler, + stringProvider = FakeStringProvider(), ) } } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt index 354ec60bb9..01fe2b9847 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_FAILURE_REASON import io.element.android.libraries.push.api.gateway.PushGatewayFailure import io.element.android.libraries.push.test.FakePushService +import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest @@ -35,7 +36,8 @@ class PushLoopbackTestTest { val sut = PushLoopbackTest( pushService = FakePushService(), diagnosticPushHandler = diagnosticPushHandler, - clock = FakeSystemClock() + clock = FakeSystemClock(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -45,7 +47,6 @@ class PushLoopbackTestTest { assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) val lastItem = awaitItem() assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) - assertThat(lastItem.description).contains("timeout") } } @@ -59,7 +60,8 @@ class PushLoopbackTestTest { } ), diagnosticPushHandler = diagnosticPushHandler, - clock = FakeSystemClock() + clock = FakeSystemClock(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -69,7 +71,6 @@ class PushLoopbackTestTest { assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) val lastItem = awaitItem() assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) - assertThat(lastItem.description).contains("rejected") } } @@ -81,7 +82,8 @@ class PushLoopbackTestTest { testPushBlock = { false } ), diagnosticPushHandler = diagnosticPushHandler, - clock = FakeSystemClock() + clock = FakeSystemClock(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -91,7 +93,6 @@ class PushLoopbackTestTest { assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) val lastItem = awaitItem() assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) - assertThat(lastItem.description).contains("cannot test push") } } @@ -105,7 +106,8 @@ class PushLoopbackTestTest { } ), diagnosticPushHandler = diagnosticPushHandler, - clock = FakeSystemClock() + clock = FakeSystemClock(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -128,7 +130,8 @@ class PushLoopbackTestTest { true }), diagnosticPushHandler = diagnosticPushHandler, - clock = FakeSystemClock() + clock = FakeSystemClock(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt index 644392c11b..cf7f750403 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt @@ -20,6 +20,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.test.FakePushProvider +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -29,6 +30,7 @@ class PushProvidersTestTest { fun `test PushProvidersTest with empty list`() = runTest { val sut = PushProvidersTest( pushProviders = emptySet(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -48,6 +50,7 @@ class PushProvidersTestTest { FakePushProvider(name = "foo"), FakePushProvider(name = "bar"), ), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -57,6 +60,7 @@ class PushProvidersTestTest { assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) val lastItem = awaitItem() assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) + assertThat(lastItem.description).contains("2") assertThat(lastItem.description).contains("foo") assertThat(lastItem.description).contains("bar") } diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index 55dca139b0..de19420923 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -40,6 +40,8 @@ dependencies { implementation(projects.libraries.core) implementation(projects.libraries.di) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.uiStrings) + implementation(projects.services.toolbox.api) implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushproviders.api) @@ -57,4 +59,5 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.tests.testutils) + testImplementation(projects.services.toolbox.test) } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt index acd907fb0a..64a5bad67f 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt @@ -24,6 +24,8 @@ import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.di.AppScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable +import io.element.android.libraries.pushproviders.firebase.R +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -31,11 +33,12 @@ import javax.inject.Inject @ContributesMultibinding(AppScope::class) class FirebaseAvailabilityTest @Inject constructor( private val isPlayServiceAvailable: IsPlayServiceAvailable, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 300 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Check Firebase", - defaultDescription = "Ensure that Firebase is available.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_description), visibleWhenIdle = false, fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, ) @@ -50,12 +53,12 @@ class FirebaseAvailabilityTest @Inject constructor( val result = isPlayServiceAvailable.isAvailable() if (result) { delegate.updateState( - description = "Firebase is available", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_success), status = NotificationTroubleshootTestState.Status.Success ) } else { delegate.updateState( - description = "Firebase is not available", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_failure), status = NotificationTroubleshootTestState.Status.Failure(false) ) } diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt index e501ce1e9d..b2164cda32 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -25,6 +25,8 @@ import io.element.android.libraries.di.AppScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.FirebaseStore import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter +import io.element.android.libraries.pushproviders.firebase.R +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -33,11 +35,12 @@ import javax.inject.Inject class FirebaseTokenTest @Inject constructor( private val firebaseStore: FirebaseStore, private val firebaseTroubleshooter: FirebaseTroubleshooter, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 310 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Check Firebase token", - defaultDescription = "Ensure that Firebase token is available.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_description), visibleWhenIdle = false, fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, ) @@ -52,12 +55,15 @@ class FirebaseTokenTest @Inject constructor( val token = firebaseStore.getFcmToken() if (token != null) { delegate.updateState( - description = "Firebase token: ${token.take(8)}*****", + description = stringProvider.getString( + R.string.troubleshoot_notifications_test_firebase_token_success, + "${token.take(8)}*****" + ), status = NotificationTroubleshootTestState.Status.Success ) } else { delegate.updateState( - description = "Firebase token is not known", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_failure), status = NotificationTroubleshootTestState.Status.Failure(true) ) } diff --git a/libraries/pushproviders/firebase/src/main/res/values/localazy.xml b/libraries/pushproviders/firebase/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..654ba04134 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values/localazy.xml @@ -0,0 +1,11 @@ + + + "Ensure that Firebase is available." + "Firebase is not available." + "Firebase is available." + "Check Firebase" + "Ensure that Firebase token is available." + "Firebase token is not known." + "Firebase token: %1$s." + "Check Firebase token" + diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt index eea622849b..0c742fa567 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt @@ -20,6 +20,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -32,7 +33,8 @@ class FirebaseAvailabilityTestTest { override fun isAvailable(): Boolean { return true } - } + }, + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -52,7 +54,8 @@ class FirebaseAvailabilityTestTest { override fun isAvailable(): Boolean { return false } - } + }, + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt index 0463939234..b76e6861fc 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt @@ -21,6 +21,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.firebase.FakeFirebaseTroubleshooter import io.element.android.libraries.pushproviders.firebase.InMemoryFirebaseStore +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -31,6 +32,7 @@ class FirebaseTokenTestTest { val sut = FirebaseTokenTest( firebaseStore = InMemoryFirebaseStore(FAKE_TOKEN), firebaseTroubleshooter = FakeFirebaseTroubleshooter(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -56,6 +58,7 @@ class FirebaseTokenTestTest { Result.success(Unit) } ), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/libraries/pushproviders/unifiedpush/build.gradle.kts b/libraries/pushproviders/unifiedpush/build.gradle.kts index ecceed6026..190c63d350 100644 --- a/libraries/pushproviders/unifiedpush/build.gradle.kts +++ b/libraries/pushproviders/unifiedpush/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.uiStrings) implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushproviders.api) @@ -57,4 +58,5 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.tests.testutils) + testImplementation(projects.services.toolbox.test) } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt index df79030c44..ec3b95e437 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt @@ -22,8 +22,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.di.AppScope +import io.element.android.libraries.pushproviders.unifiedpush.R import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -32,11 +34,12 @@ import javax.inject.Inject class UnifiedPushTest @Inject constructor( private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider, private val openDistributorWebPageAction: OpenDistributorWebPageAction, + private val stringProvider: StringProvider, ) : NotificationTroubleshootTest { override val order = 400 private val delegate = NotificationTroubleshootTestDelegate( - defaultName = "Check UnifiedPush", - defaultDescription = "Ensure that UnifiedPush distributors are available.", + defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_title), + defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_description), visibleWhenIdle = false, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, ) @@ -51,12 +54,17 @@ class UnifiedPushTest @Inject constructor( val distributors = unifiedPushDistributorProvider.getDistributors() if (distributors.isNotEmpty()) { delegate.updateState( - description = "Distributors found: ${distributors.joinToString { it.name }}", + description = stringProvider.getQuantityString( + resId = R.plurals.troubleshoot_notifications_test_unified_push_success, + quantity = distributors.size, + distributors.size, + distributors.joinToString { it.name } + ), status = NotificationTroubleshootTestState.Status.Success ) } else { delegate.updateState( - description = "No push distributors found", + description = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_failure), status = NotificationTroubleshootTestState.Status.Failure(true) ) } diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values/localazy.xml b/libraries/pushproviders/unifiedpush/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..0e16af1f3e --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values/localazy.xml @@ -0,0 +1,10 @@ + + + "Ensure that UnifiedPush distributors are available." + "No push distributors found." + + "%1$d distributor found: %2$s." + "%1$d distributors found: %2$s." + + "Check UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt index e7a8ccc680..29301515cd 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt @@ -20,6 +20,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.api.Distributor +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test @@ -34,6 +35,7 @@ class UnifiedPushTestTest { ) ), openDistributorWebPageAction = FakeOpenDistributorWebPageAction(), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) @@ -60,6 +62,7 @@ class UnifiedPushTestTest { ) } ), + stringProvider = FakeStringProvider(), ) launch { sut.run(this) diff --git a/tools/localazy/config.json b/tools/localazy/config.json index aaa1f6734b..603c04b55c 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -80,7 +80,29 @@ "name" : ":libraries:push:impl", "includeRegex" : [ "push_.*", - "notification_.*" + "notification_.*", + "troubleshoot_notifications_test_current_push_provider.*", + "troubleshoot_notifications_test_detect_push_provider.*", + "troubleshoot_notifications_test_display_notification_.*", + "troubleshoot_notifications_test_push_loop_back_.*" + ] + }, + { + "name" : ":libraries:permissions:impl", + "includeRegex" : [ + "troubleshoot_notifications_test_check_permission_.*" + ] + }, + { + "name" : ":libraries:pushproviders:firebase", + "includeRegex" : [ + "troubleshoot_notifications_test_firebase_.*" + ] + }, + { + "name" : ":libraries:pushproviders:unifiedpush", + "includeRegex" : [ + "troubleshoot_notifications_test_unified_push_.*" ] }, { @@ -182,7 +204,9 @@ "screen\\.advanced_settings\\..*", "screen_edit_profile_.*", "screen_notification_settings_.*", - "screen_blocked_users_.*" + "screen_blocked_users_.*", + "troubleshoot_notifications_entry_point_.*", + "troubleshoot_notifications_screen_.*" ] }, { From 91de03e4b97a7559d1e30fee1a8951e1582bb0a7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 21:30:07 +0100 Subject: [PATCH 12/27] Add test on NotificationSettingsView --- .../NotificationSettingsStateProvider.kt | 15 +- .../NotificationSettingsViewTest.kt | 207 ++++++++++++++++++ 2 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt index 2dc0c02145..008f53d30b 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt @@ -31,18 +31,23 @@ open class NotificationSettingsStateProvider : PreviewParameterProvider = AsyncAction.Uninitialized, + atRoomNotificationsEnabled: Boolean = true, + callNotificationsEnabled: Boolean = true, + inviteForMeNotificationsEnabled: Boolean = true, + appNotificationEnabled: Boolean = true, + eventSink: (NotificationSettingsEvents) -> Unit = {}, ) = NotificationSettingsState( matrixSettings = NotificationSettingsState.MatrixSettings.Valid( - atRoomNotificationsEnabled = true, - callNotificationsEnabled = true, - inviteForMeNotificationsEnabled = true, + atRoomNotificationsEnabled = atRoomNotificationsEnabled, + callNotificationsEnabled = callNotificationsEnabled, + inviteForMeNotificationsEnabled = inviteForMeNotificationsEnabled, defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES, ), appSettings = NotificationSettingsState.AppSettings( systemNotificationsEnabled = false, - appNotificationsEnabled = true, + appNotificationsEnabled = appNotificationEnabled, ), changeNotificationSettingAction = changeNotificationSettingAction, - eventSink = {} + eventSink = eventSink, ) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt new file mode 100644 index 0000000000..980a0aa962 --- /dev/null +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2024 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.preferences.impl.notifications + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.features.preferences.impl.R +import io.element.android.tests.testutils.EnsureNeverCalled +import io.element.android.tests.testutils.EnsureNeverCalledWithParam +import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.clickOn +import io.element.android.tests.testutils.ensureCalledOnce +import io.element.android.tests.testutils.ensureCalledOnceWithParam +import io.element.android.tests.testutils.pressBack +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@RunWith(AndroidJUnit4::class) +class NotificationSettingsViewTest { + @get:Rule + val rule = createAndroidComposeRule() + + @Test + fun `clicking on back invokes the expected callback`() { + val eventsRecorder = EventsRecorder() + ensureCalledOnce { + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + eventSink = eventsRecorder + ), + onBackPressed = it + ) + rule.pressBack() + } + eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on troubleshoot notification invokes the expected callback`() { + val eventsRecorder = EventsRecorder() + ensureCalledOnce { + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + eventSink = eventsRecorder + ), + onTroubleshootNotificationsClicked = it + ) + rule.clickOn(R.string.troubleshoot_notifications_entry_point_title) + } + eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on group chats invokes the expected callback`() { + val eventsRecorder = EventsRecorder() + ensureCalledOnceWithParam(false) { + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + eventSink = eventsRecorder + ), + onOpenEditDefault = it + ) + rule.clickOn(R.string.screen_notification_settings_group_chats) + } + eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on direct chats invokes the expected callback`() { + val eventsRecorder = EventsRecorder() + ensureCalledOnceWithParam(true) { + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + eventSink = eventsRecorder + ), + onOpenEditDefault = it + ) + rule.clickOn(R.string.screen_notification_settings_direct_chats) + } + eventsRecorder.assertSingle(NotificationSettingsEvents.RefreshSystemNotificationsEnabled) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on disable notifications emits the expected events`() { + testNotificationToggle(true) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on enable notifications emits the expected events`() { + testNotificationToggle(false) + } + + private fun testNotificationToggle(initialState: Boolean) { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + appNotificationEnabled = initialState, + eventSink = eventsRecorder + ), + ) + rule.clickOn(R.string.screen_notification_settings_enable_notifications) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.SetNotificationsEnabled(!initialState) + ) + ) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on disable notify me on at room emits the expected events`() { + testAtRoomToggle(true) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on enable notify me on at room emits the expected events`() { + testAtRoomToggle(false) + } + + private fun testAtRoomToggle(initialState: Boolean) { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + atRoomNotificationsEnabled = initialState, + eventSink = eventsRecorder + ), + ) + rule.clickOn(R.string.screen_notification_settings_room_mention_label) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.SetAtRoomNotificationsEnabled(!initialState) + ) + ) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on disable notify me on invitation emits the expected events`() { + testInvitationToggle(true) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `clicking on enable notify me on invitation emits the expected events`() { + testInvitationToggle(false) + } + + private fun testInvitationToggle(initialState: Boolean) { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aNotificationSettingsState( + inviteForMeNotificationsEnabled = initialState, + eventSink = eventsRecorder + ), + ) + rule.clickOn(R.string.screen_notification_settings_invite_for_me_label) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(!initialState) + ) + ) + } +} + +private fun AndroidComposeTestRule.setNotificationSettingsView( + state: NotificationSettingsState, + onOpenEditDefault: (isOneToOne: Boolean) -> Unit = EnsureNeverCalledWithParam(), + onTroubleshootNotificationsClicked: () -> Unit = EnsureNeverCalled(), + onBackPressed: () -> Unit = EnsureNeverCalled(), +) { + setContent { + NotificationSettingsView( + state = state, + onOpenEditDefault = onOpenEditDefault, + onTroubleshootNotificationsClicked = onTroubleshootNotificationsClicked, + onBackPressed = onBackPressed, + ) + } +} From 9f60a28b8c89d349078884b66cac25e3d8ea73ec Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 21:52:15 +0100 Subject: [PATCH 13/27] Improve preview management for NotificationSettingsView --- .../NotificationSettingsStateProvider.kt | 25 ++++++++++++++++--- .../notifications/NotificationSettingsView.kt | 10 -------- .../NotificationSettingsViewTest.kt | 14 +++++------ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt index 008f53d30b..dc1e972aa6 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsStateProvider.kt @@ -23,13 +23,15 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode open class NotificationSettingsStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aNotificationSettingsState(), - aNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading), - aNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))), + aValidNotificationSettingsState(), + aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading), + aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))), + aInvalidNotificationSettingsState(), + aInvalidNotificationSettingsState(fixFailed = true), ) } -fun aNotificationSettingsState( +fun aValidNotificationSettingsState( changeNotificationSettingAction: AsyncAction = AsyncAction.Uninitialized, atRoomNotificationsEnabled: Boolean = true, callNotificationsEnabled: Boolean = true, @@ -51,3 +53,18 @@ fun aNotificationSettingsState( changeNotificationSettingAction = changeNotificationSettingAction, eventSink = eventSink, ) + +fun aInvalidNotificationSettingsState( + fixFailed: Boolean = false, + eventSink: (NotificationSettingsEvents) -> Unit = {}, +) = NotificationSettingsState( + matrixSettings = NotificationSettingsState.MatrixSettings.Invalid( + fixFailed = fixFailed, + ), + appSettings = NotificationSettingsState.AppSettings( + systemNotificationsEnabled = false, + appNotificationsEnabled = true, + ), + changeNotificationSettingAction = AsyncAction.Uninitialized, + eventSink = eventSink, +) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt index 5e3610b652..d62f972d71 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt @@ -217,13 +217,3 @@ internal fun NotificationSettingsViewPreview(@PreviewParameter(NotificationSetti onTroubleshootNotificationsClicked = {}, ) } - -@PreviewsDayNight -@Composable -internal fun InvalidNotificationSettingsViewPreview() = ElementPreview { - InvalidNotificationSettingsView( - showError = false, - onContinueClicked = {}, - onDismissError = {}, - ) -} diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt index 980a0aa962..754885fba8 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt @@ -44,7 +44,7 @@ class NotificationSettingsViewTest { val eventsRecorder = EventsRecorder() ensureCalledOnce { rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( eventSink = eventsRecorder ), onBackPressed = it @@ -60,7 +60,7 @@ class NotificationSettingsViewTest { val eventsRecorder = EventsRecorder() ensureCalledOnce { rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( eventSink = eventsRecorder ), onTroubleshootNotificationsClicked = it @@ -76,7 +76,7 @@ class NotificationSettingsViewTest { val eventsRecorder = EventsRecorder() ensureCalledOnceWithParam(false) { rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( eventSink = eventsRecorder ), onOpenEditDefault = it @@ -92,7 +92,7 @@ class NotificationSettingsViewTest { val eventsRecorder = EventsRecorder() ensureCalledOnceWithParam(true) { rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( eventSink = eventsRecorder ), onOpenEditDefault = it @@ -117,7 +117,7 @@ class NotificationSettingsViewTest { private fun testNotificationToggle(initialState: Boolean) { val eventsRecorder = EventsRecorder() rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( appNotificationEnabled = initialState, eventSink = eventsRecorder ), @@ -146,7 +146,7 @@ class NotificationSettingsViewTest { private fun testAtRoomToggle(initialState: Boolean) { val eventsRecorder = EventsRecorder() rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( atRoomNotificationsEnabled = initialState, eventSink = eventsRecorder ), @@ -175,7 +175,7 @@ class NotificationSettingsViewTest { private fun testInvitationToggle(initialState: Boolean) { val eventsRecorder = EventsRecorder() rule.setNotificationSettingsView( - state = aNotificationSettingsState( + state = aValidNotificationSettingsState( inviteForMeNotificationsEnabled = initialState, eventSink = eventsRecorder ), From 7b16b10a64f77c1cbbb4fefee749570d637f588b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 21:56:36 +0100 Subject: [PATCH 14/27] More tests on NotificationSettingsView. --- .../NotificationSettingsViewTest.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt index 754885fba8..8397d5aef6 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsViewTest.kt @@ -21,6 +21,9 @@ import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.preferences.impl.R +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalledWithParam import io.element.android.tests.testutils.EventsRecorder @@ -188,6 +191,63 @@ class NotificationSettingsViewTest { ) ) } + + @Config(qualifiers = "h1024dp") + @Test + fun `with an error configuration, clicking on continue emits the expected events`() { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aValidNotificationSettingsState( + changeNotificationSettingAction = AsyncAction.Failure(AN_EXCEPTION), + eventSink = eventsRecorder + ), + ) + rule.clickOn(CommonStrings.action_ok) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.ClearNotificationChangeError + ) + ) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `with invalid configuration, clicking on continue emits the expected events`() { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aInvalidNotificationSettingsState( + fixFailed = false, + eventSink = eventsRecorder + ), + ) + rule.clickOn(CommonStrings.action_continue) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.FixConfigurationMismatch + ) + ) + } + + @Config(qualifiers = "h1024dp") + @Test + fun `with invalid configuration and error, clicking on OK emits the expected events`() { + val eventsRecorder = EventsRecorder() + rule.setNotificationSettingsView( + state = aInvalidNotificationSettingsState( + fixFailed = true, + eventSink = eventsRecorder + ), + ) + rule.clickOn(CommonStrings.action_ok) + eventsRecorder.assertList( + listOf( + NotificationSettingsEvents.RefreshSystemNotificationsEnabled, + NotificationSettingsEvents.ClearConfigurationMismatchError + ) + ) + } } private fun AndroidComposeTestRule.setNotificationSettingsView( From 9c89a3b0c7e5ec3d94aa0a4788a6ed25405b6682 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 22:02:22 +0100 Subject: [PATCH 15/27] Code quality --- .../troubleshoot/TroubleshootNotificationsView.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt index 451b4f778e..a908f59350 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt @@ -185,10 +185,11 @@ private fun RunTestButton(state: TroubleshootNotificationsState) { headlineContent = { Button( text = stringResource( - id = if (state.testSuiteState.mainState is AsyncAction.Failure) + id = if (state.testSuiteState.mainState is AsyncAction.Failure) { R.string.troubleshoot_notifications_screen_action_again - else + } else { R.string.troubleshoot_notifications_screen_action + } ), onClick = { state.eventSink(TroubleshootNotificationsEvents.StartTests) From f7f25e1ead7f620e950f415dd67f477d68832ea3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 Mar 2024 22:45:49 +0100 Subject: [PATCH 16/27] towncrier --- changelog.d/2601.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2601.feature diff --git a/changelog.d/2601.feature b/changelog.d/2601.feature new file mode 100644 index 0000000000..ecfc26061d --- /dev/null +++ b/changelog.d/2601.feature @@ -0,0 +1 @@ + Add a notification troubleshoot screen From 5a0e76677bab8783c4f9f8513ce597ea9acd2848 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Mar 2024 09:30:07 +0100 Subject: [PATCH 17/27] Improve ScreenTracker. --- .../TroubleshootNotificationsNode.kt | 2 +- services/analytics/api/build.gradle.kts | 1 - .../services/analytics/api/ScreenTracker.kt | 2 -- services/analytics/impl/build.gradle.kts | 1 + .../analytics/impl/DefaultScreenTracker.kt | 35 ++++++++++--------- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt index 833f512c81..a662e94db8 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt @@ -37,7 +37,7 @@ class TroubleshootNotificationsNode @AssistedInject constructor( ) : Node(buildContext, plugins = plugins) { @Composable override fun View(modifier: Modifier) { - screenTracker.TrackScreen(this, MobileScreen.ScreenName.NotificationTroubleshoot) + screenTracker.TrackScreen(MobileScreen.ScreenName.NotificationTroubleshoot) val state = presenter.present() TroubleshootNotificationsView( state = state, diff --git a/services/analytics/api/build.gradle.kts b/services/analytics/api/build.gradle.kts index 361ad09162..c78a050571 100644 --- a/services/analytics/api/build.gradle.kts +++ b/services/analytics/api/build.gradle.kts @@ -24,7 +24,6 @@ android { dependencies { api(projects.services.analyticsproviders.api) api(projects.services.toolbox.api) - api(libs.appyx.core) implementation(libs.coroutines.core) implementation(projects.libraries.matrix.api) implementation(projects.libraries.core) diff --git a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt index b2f1e3ab6d..c29a045f77 100644 --- a/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt +++ b/services/analytics/api/src/main/kotlin/io/element/android/services/analytics/api/ScreenTracker.kt @@ -17,13 +17,11 @@ package io.element.android.services.analytics.api import androidx.compose.runtime.Composable -import com.bumble.appyx.core.node.Node import im.vector.app.features.analytics.plan.MobileScreen interface ScreenTracker { @Composable fun TrackScreen( - node: Node, screen: MobileScreen.ScreenName, ) } diff --git a/services/analytics/impl/build.gradle.kts b/services/analytics/impl/build.gradle.kts index 5dd72d77bd..623ab493c3 100644 --- a/services/analytics/impl/build.gradle.kts +++ b/services/analytics/impl/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.core) implementation(projects.libraries.architecture) + implementation(projects.libraries.designsystem) implementation(projects.libraries.sessionStorage.api) api(projects.services.analyticsproviders.api) diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt index 970fcd0c95..c53757384d 100644 --- a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt +++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultScreenTracker.kt @@ -17,11 +17,14 @@ package io.element.android.services.analytics.impl import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import com.bumble.appyx.core.lifecycle.subscribe -import com.bumble.appyx.core.node.Node +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.lifecycle.Lifecycle import com.squareup.anvil.annotations.ContributesBinding import im.vector.app.features.analytics.plan.MobileScreen +import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.di.AppScope import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.ScreenTracker @@ -35,24 +38,22 @@ class DefaultScreenTracker @Inject constructor( ) : ScreenTracker { @Composable override fun TrackScreen( - node: Node, screen: MobileScreen.ScreenName, ) { - LaunchedEffect(Unit) { - var startTime = 0L - node.lifecycle.subscribe( - onResume = { + var startTime by remember { mutableLongStateOf(0L) } + OnLifecycleEvent { _, event -> + when (event) { + Lifecycle.Event.ON_RESUME -> { startTime = systemClock.epochMillis() - }, - onPause = { - analyticsService.screen( - screen = MobileScreen( - durationMs = (systemClock.epochMillis() - startTime).toInt(), - screenName = screen - ) - ) } - ) + Lifecycle.Event.ON_PAUSE -> analyticsService.screen( + screen = MobileScreen( + durationMs = (systemClock.epochMillis() - startTime).toInt(), + screenName = screen + ) + ) + else -> Unit + } } } } From a89dde2bb46d9469a4b20f281ff461f85dd3f775 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Mar 2024 09:30:22 +0100 Subject: [PATCH 18/27] Remove wrong comment --- .../troubleshoot/TroubleshootNotificationsView.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt index a908f59350..08d56e5bd0 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt @@ -42,9 +42,6 @@ import io.element.android.libraries.designsystem.theme.components.ListItem import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.OnLifecycleEvent -/** - * A view that allows a user edit their global notification settings. - */ @Composable fun TroubleshootNotificationsView( state: TroubleshootNotificationsState, From 565e5ce87db162daff01573c90a5ce4a1f49d4fd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 28 Mar 2024 09:31:09 +0100 Subject: [PATCH 19/27] Improve openUrlInExternalApp API and move url to UnifiedPushConfig --- .../android/libraries/androidutils/system/SystemUtils.kt | 3 +-- .../libraries/pushproviders/unifiedpush/UnifiedPushConfig.kt | 2 ++ .../unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt index 9f473a7089..737eab7ac7 100644 --- a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/system/SystemUtils.kt @@ -156,10 +156,9 @@ fun Context.startSharePlainTextIntent( fun Context.openUrlInExternalApp( url: String, errorMessage: String = getString(R.string.error_no_compatible_app_found), - inNewTask: Boolean = false, ) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - if (inNewTask) { + if (this !is Activity) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } try { diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushConfig.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushConfig.kt index 07c57496db..b1d321f42f 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushConfig.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushConfig.kt @@ -23,6 +23,8 @@ object UnifiedPushConfig { */ const val DEFAULT_PUSH_GATEWAY_HTTP_URL: String = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify" + const val UNIFIED_PUSH_DISTRIBUTORS_URL = "https://unifiedpush.org/users/distributors/" + const val INDEX = 1 const val NAME = "UnifiedPush" } diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt index daad9afda3..dda4292f12 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/OpenDistributorWebPageAction.kt @@ -21,6 +21,7 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.androidutils.system.openUrlInExternalApp import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig import javax.inject.Inject interface OpenDistributorWebPageAction { @@ -34,8 +35,7 @@ class DefaultOpenDistributorWebPageAction @Inject constructor( override fun execute() { // Open the distributor download page context.openUrlInExternalApp( - url = "https://unifiedpush.org/users/distributors/", - inNewTask = true + url = UnifiedPushConfig.UNIFIED_PUSH_DISTRIBUTORS_URL, ) } } From e18e5f1cc52212d8d3f5fbae2b8a5d0f07f33443 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 16:18:15 +0200 Subject: [PATCH 20/27] Run `./tools/localazy/downloadStrings.sh --all` --- .../src/main/res/values-be/translations.xml | 4 +- .../src/main/res/values-be/translations.xml | 4 +- .../src/main/res/values-be/translations.xml | 2 +- .../src/main/res/values-sv/translations.xml | 4 ++ .../src/main/res/values-be/translations.xml | 2 +- .../src/main/res/values-be/translations.xml | 2 +- .../src/main/res/values-be/translations.xml | 10 ++++ .../src/main/res/values-cs/translations.xml | 10 ++++ .../src/main/res/values-de/translations.xml | 10 ++++ .../src/main/res/values-fr/translations.xml | 10 ++++ .../src/main/res/values-hu/translations.xml | 10 ++++ .../src/main/res/values-in/translations.xml | 10 ++++ .../src/main/res/values-ru/translations.xml | 10 ++++ .../src/main/res/values-sk/translations.xml | 10 ++++ .../src/main/res/values-be/translations.xml | 4 +- .../src/main/res/values-be/translations.xml | 2 +- .../src/main/res/values-be/translations.xml | 1 + .../src/main/res/values-fr/translations.xml | 1 + .../impl/src/main/res/values/localazy.xml | 1 + .../src/main/res/values-be/translations.xml | 2 +- .../src/main/res/values-be/translations.xml | 5 ++ .../src/main/res/values-cs/translations.xml | 5 ++ .../src/main/res/values-de/translations.xml | 5 ++ .../src/main/res/values-fr/translations.xml | 5 ++ .../src/main/res/values-hu/translations.xml | 5 ++ .../src/main/res/values-ru/translations.xml | 5 ++ .../src/main/res/values-sk/translations.xml | 5 ++ .../impl/src/main/res/values/localazy.xml | 2 +- .../src/main/res/values-be/translations.xml | 25 +++++++++ .../src/main/res/values-bg/translations.xml | 1 + .../src/main/res/values-cs/translations.xml | 25 +++++++++ .../src/main/res/values-de/translations.xml | 24 +++++++++ .../src/main/res/values-fr/translations.xml | 24 +++++++++ .../src/main/res/values-hu/translations.xml | 24 +++++++++ .../src/main/res/values-in/translations.xml | 23 ++++++++ .../src/main/res/values-ru/translations.xml | 25 +++++++++ .../src/main/res/values-sk/translations.xml | 25 +++++++++ .../src/main/res/values-be/translations.xml | 11 ++++ .../src/main/res/values-cs/translations.xml | 11 ++++ .../src/main/res/values-de/translations.xml | 11 ++++ .../src/main/res/values-fr/translations.xml | 11 ++++ .../src/main/res/values-hu/translations.xml | 11 ++++ .../src/main/res/values-ru/translations.xml | 11 ++++ .../src/main/res/values-sk/translations.xml | 11 ++++ .../src/main/res/values-be/translations.xml | 11 ++++ .../src/main/res/values-cs/translations.xml | 11 ++++ .../src/main/res/values-de/translations.xml | 10 ++++ .../src/main/res/values-fr/translations.xml | 10 ++++ .../src/main/res/values-hu/translations.xml | 10 ++++ .../src/main/res/values-ru/translations.xml | 11 ++++ .../src/main/res/values-sk/translations.xml | 11 ++++ .../src/main/res/values-be/translations.xml | 53 ------------------- .../src/main/res/values-bg/translations.xml | 1 - .../src/main/res/values-cs/translations.xml | 53 ------------------- .../src/main/res/values-de/translations.xml | 51 ------------------ .../src/main/res/values-fr/translations.xml | 51 ------------------ .../src/main/res/values-hu/translations.xml | 51 ------------------ .../src/main/res/values-in/translations.xml | 49 ----------------- .../src/main/res/values-ru/translations.xml | 53 ------------------- .../src/main/res/values-sk/translations.xml | 53 ------------------- .../src/main/res/values-sv/translations.xml | 1 + .../src/main/res/values/localazy.xml | 51 ------------------ 62 files changed, 482 insertions(+), 478 deletions(-) create mode 100644 libraries/permissions/impl/src/main/res/values-be/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-cs/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-de/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-fr/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-hu/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-ru/translations.xml create mode 100644 libraries/permissions/impl/src/main/res/values-sk/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-be/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-cs/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-de/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-fr/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-hu/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-ru/translations.xml create mode 100644 libraries/pushproviders/firebase/src/main/res/values-sk/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-be/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-cs/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-de/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-fr/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-hu/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-ru/translations.xml create mode 100644 libraries/pushproviders/unifiedpush/src/main/res/values-sk/translations.xml diff --git a/features/invitelist/impl/src/main/res/values-be/translations.xml b/features/invitelist/impl/src/main/res/values-be/translations.xml index 36c895dcb9..9a37d82357 100644 --- a/features/invitelist/impl/src/main/res/values-be/translations.xml +++ b/features/invitelist/impl/src/main/res/values-be/translations.xml @@ -1,8 +1,8 @@ - "Вы ўпэўненыя, што жадаеце адхіліць запрашэнне ў %1$s?" + "Вы ўпэўненыя, што хочаце адхіліць запрашэнне ў %1$s?" "Адхіліць запрашэнне" - "Вы ўпэўненыя, што жадаеце адмовіцца ад прыватных зносін з %1$s?" + "Вы ўпэўненыя, што хочаце адмовіцца ад прыватных зносін з %1$s?" "Адхіліць чат" "Няма запрашэнняў" "%1$s (%2$s) запрасіў вас" diff --git a/features/leaveroom/api/src/main/res/values-be/translations.xml b/features/leaveroom/api/src/main/res/values-be/translations.xml index 0e80bcd433..c8bb068fa7 100644 --- a/features/leaveroom/api/src/main/res/values-be/translations.xml +++ b/features/leaveroom/api/src/main/res/values-be/translations.xml @@ -1,7 +1,7 @@ "Вы ўпэўнены, што хочаце пакінуць гэту размову? Гэта размова не з\'яўляецца публічнай, і вы не зможаце далучыцца зноў без запрашэння." - "Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Вы тут адзіны карыстальнік. Калі вы выйдзеце, ніхто не зможа далучыцца ў будучыні, у тым ліку і вы." - "Вы ўпэўнены, што жадаеце пакінуць гэты пакой? Гэты пакой не агульнадаступны, і вы не зможаце далучыцца да яго зноў без запрашэння." + "Вы ўпэўнены, што хочаце пакінуць гэты пакой? Вы тут адзіны карыстальнік. Калі вы выйдзеце, ніхто не зможа далучыцца ў будучыні, у тым ліку і вы." + "Вы ўпэўнены, што жхочаце пакінуць гэты пакой? Гэты пакой не агульнадаступны, і вы не зможаце далучыцца да яго зноў без запрашэння." "Вы ўпэўнены, што хочаце пакінуць пакой?" diff --git a/features/lockscreen/impl/src/main/res/values-be/translations.xml b/features/lockscreen/impl/src/main/res/values-be/translations.xml index f786884ed0..2c5bd554b0 100644 --- a/features/lockscreen/impl/src/main/res/values-be/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-be/translations.xml @@ -7,7 +7,7 @@ "Змяніць PIN-код" "Дазволіць біяметрычную разблакіроўку" "Выдаліць PIN-код" - "Вы ўпэўнены, што жадаеце выдаліць PIN-код?" + "Вы ўпэўнены, што хочаце выдаліць PIN-код?" "Выдаліць PIN-код?" "Дазволіць %1$s" "Я хацеў бы выкарыстоўваць PIN-код" diff --git a/features/lockscreen/impl/src/main/res/values-sv/translations.xml b/features/lockscreen/impl/src/main/res/values-sv/translations.xml index b89f26bae3..c0ffcd9cdf 100644 --- a/features/lockscreen/impl/src/main/res/values-sv/translations.xml +++ b/features/lockscreen/impl/src/main/res/values-sv/translations.xml @@ -1,4 +1,8 @@ + "Byt PIN-kod" + "Tillåt biometrisk upplåsning" + "Ta bort PIN-kod" + "Ta bort PIN-koden?" "Loggar ut …" diff --git a/features/messages/impl/src/main/res/values-be/translations.xml b/features/messages/impl/src/main/res/values-be/translations.xml index ee875ab37a..f2ea6cfd09 100644 --- a/features/messages/impl/src/main/res/values-be/translations.xml +++ b/features/messages/impl/src/main/res/values-be/translations.xml @@ -9,7 +9,7 @@ "Падарожжы & Месцы" "Сімвалы" "Заблакіраваць карыстальніка" - "Адзначце, ці жадаеце вы схаваць усе бягучыя і будучыя паведамленні ад гэтага карыстальніка" + "Адзначце, ці хочаце вы схаваць усе бягучыя і будучыя паведамленні ад гэтага карыстальніка" "Гэтае паведамленне будзе перададзена адміністратару вашага хатняга сервера. Яны не змогуць прачытаць зашыфраваныя паведамленні." "Прычына, па якой вы паскардзіліся на гэты змест" "Камера" diff --git a/features/poll/impl/src/main/res/values-be/translations.xml b/features/poll/impl/src/main/res/values-be/translations.xml index 4526df8572..1d0238bca3 100644 --- a/features/poll/impl/src/main/res/values-be/translations.xml +++ b/features/poll/impl/src/main/res/values-be/translations.xml @@ -4,7 +4,7 @@ "Паказаць вынікі толькі пасля заканчэння апытання" "Схаваць галасы" "Варыянт %1$d" - "Вашы змены не былі захаваны. Вы ўпэўнены, што жадаеце вярнуцца?" + "Вашы змены не былі захаваны. Вы ўпэўнены, што хочаце вярнуцца?" "Пытанне або тэма" "Пра што апытанне?" "Стварэнне апытання" diff --git a/features/preferences/impl/src/main/res/values-be/translations.xml b/features/preferences/impl/src/main/res/values-be/translations.xml index 8f20b79a09..0a8e477f7f 100644 --- a/features/preferences/impl/src/main/res/values-be/translations.xml +++ b/features/preferences/impl/src/main/res/values-be/translations.xml @@ -49,4 +49,14 @@ "налады сістэмы" "Сістэмныя апавяшчэнні выключаны" "Апавяшчэнні" + "Выпраўленне непаладак" + "Выпраўленне непаладак з апавяшчэннямі" + "Запусціць тэсты" + "Запусціце тэсты яшчэ раз" + "Некаторыя тэсты не ўдаліся. Калі ласка, праглядзіце дэталі." + "Запусціце тэсты, каб выявіць праблемы ў вашай канфігурацыі, з-за якіх апавяшчэння могуць паводзіць сябе не так, як чакалася." + "Спроба выпраўлення" + "Усе тэсты паспяхова пройдзены." + "Выпраўленне непаладак з апавяшчэннямі" + "Некаторыя тэсты патрабуюць вашай увагі. Калі ласка, праглядзіце дэталі." diff --git a/features/preferences/impl/src/main/res/values-cs/translations.xml b/features/preferences/impl/src/main/res/values-cs/translations.xml index ed209124ec..a2a3cc5955 100644 --- a/features/preferences/impl/src/main/res/values-cs/translations.xml +++ b/features/preferences/impl/src/main/res/values-cs/translations.xml @@ -51,4 +51,14 @@ Pokud budete pokračovat, některá nastavení se mohou změnit." "systémová nastavení" "Systémová oznámení byla vypnuta" "Oznámení" + "Odstraňování problémů" + "Odstraňování problémů s upozorněními" + "Spustit testy" + "Spustit testy znovu" + "Některé testy selhaly. Zkontrolujte prosím podrobnosti." + "Spusťte testy, abyste zjistili jakýkoli problém ve vaší konfiguraci, který může způsobit, že se oznámení nebudou chovat podle očekávání." + "Pokus o opravu" + "Všechny testy proběhly úspěšně." + "Odstraňování problémů s upozorněními" + "Některé testy vyžadují vaši pozornost. Zkontrolujte prosím podrobnosti." diff --git a/features/preferences/impl/src/main/res/values-de/translations.xml b/features/preferences/impl/src/main/res/values-de/translations.xml index 6d47e4817d..04a27f9db6 100644 --- a/features/preferences/impl/src/main/res/values-de/translations.xml +++ b/features/preferences/impl/src/main/res/values-de/translations.xml @@ -49,4 +49,14 @@ Wenn du fortfährst, können sich einige deiner Einstellungen ändern." "Systemeinstellungen" "Systembenachrichtigungen deaktiviert" "Benachrichtigungen" + "Fehlerbehebung" + "Fehlerbehebung für Benachrichtigungen" + "Tests durchführen" + "Tests erneut durchführen" + "Einige Tests sind fehlgeschlagen. Bitte überprüfe die Details." + "Führe die Tests durch, um Probleme zu erkennen, die dazu führen können, dass sich die Benachrichtigungen nicht wie erwartet verhalten." + "Versuche das Problem zu beheben" + "Alle Tests wurden erfolgreich bestanden." + "Fehlerbehebung für Benachrichtigungen" + "Einige Tests erfordern deine Aufmerksamkeit. Bitte überprüfe die Details." diff --git a/features/preferences/impl/src/main/res/values-fr/translations.xml b/features/preferences/impl/src/main/res/values-fr/translations.xml index ddfd6eec5c..426c475d4c 100644 --- a/features/preferences/impl/src/main/res/values-fr/translations.xml +++ b/features/preferences/impl/src/main/res/values-fr/translations.xml @@ -49,4 +49,14 @@ Si vous continuez, il est possible que certains de vos paramètres soient modifi "paramètres du système" "Les notifications du système sont désactivées" "Notifications" + "Dépannage" + "Résoudre les problèmes liés aux notifications" + "Exécuter les tests" + "Relancer les tests" + "Certains tests ont échoué. Veuillez vérifier les détails." + "Exécuter les tests pour détecter tout problème dans votre configuration susceptible de provoquer un dysfonctionnement des notifications." + "Tenter de corriger" + "Tous les tests ont réussi." + "Dépanner les notifications" + "Certains tests nécessitent votre attention. Veuillez vérifier les détails." diff --git a/features/preferences/impl/src/main/res/values-hu/translations.xml b/features/preferences/impl/src/main/res/values-hu/translations.xml index 739722f07b..3574b49e6e 100644 --- a/features/preferences/impl/src/main/res/values-hu/translations.xml +++ b/features/preferences/impl/src/main/res/values-hu/translations.xml @@ -49,4 +49,14 @@ Ha folytatja, egyes beállítások megváltozhatnak." "rendszerbeállításokat" "A rendszerértesítések ki vannak kapcsolva" "Értesítések" + "Hibaelhárítás" + "Értesítések hibaelhárítása" + "Tesztek futtatása" + "Tesztek újbóli futtatása" + "Egyes tesztek sikertelenek voltak. Ellenőrizze a részleteket." + "A tesztek futtatása, hogy észlelje a konfigurációban felmerülő olyan problémákat, amelyek miatt az értesítések nem az elvárt módon viselkednek." + "Kísérlet a javításra" + "Minden teszt sikeresen lezajlott." + "Értesítések hibaelhárítása" + "Egyes tesztek a figyelmét igénylik. Ellenőrizze a részleteket." diff --git a/features/preferences/impl/src/main/res/values-in/translations.xml b/features/preferences/impl/src/main/res/values-in/translations.xml index f9fb4c0848..13ac802d4d 100644 --- a/features/preferences/impl/src/main/res/values-in/translations.xml +++ b/features/preferences/impl/src/main/res/values-in/translations.xml @@ -51,4 +51,14 @@ Jika Anda melanjutkan, beberapa pengaturan Anda dapat berubah." "pengaturan sistem" "Pemberitahuan sistem dimatikan" "Notifikasi" + "Pemecahan masalah" + "Pecahkan masalah notifikasi" + "Jalankan tes" + "Jalankan tes lagi" + "Beberapa tes gagal. Silakan periksa detailnya." + "Jalankan pengujian untuk mendeteksi masalah apa pun dalam konfigurasi Anda yang mungkin membuat notifikasi tidak berperilaku seperti yang diharapkan." + "Mencoba untuk memperbaiki" + "Semua tes berhasil dilalui." + "Pecahkan masalah notifikasi" + "Beberapa tes membutuhkan perhatian Anda. Silakan periksa detailnya." diff --git a/features/preferences/impl/src/main/res/values-ru/translations.xml b/features/preferences/impl/src/main/res/values-ru/translations.xml index 06b2cddad5..ca18672e97 100644 --- a/features/preferences/impl/src/main/res/values-ru/translations.xml +++ b/features/preferences/impl/src/main/res/values-ru/translations.xml @@ -49,4 +49,14 @@ "настройки системы" "Системные уведомления выключены" "Уведомления" + "Устранение неполадок" + "Уведомления об устранении неполадок" + "Выполнение тестов" + "Повторное выполнение тестов" + "Некоторые тесты провалились. Пожалуйста, проверьте детали." + "Выполните тесты, чтобы обнаружить любую проблему в конфигурации, из-за которой уведомления могут работать не так, как ожидалось." + "Попытка исправить" + "Все тесты прошли успешно." + "Уведомления об устранении неполадок" + "Некоторые тесты требуют вашего внимания. Пожалуйста, проверьте детали." diff --git a/features/preferences/impl/src/main/res/values-sk/translations.xml b/features/preferences/impl/src/main/res/values-sk/translations.xml index ddc71f8c67..12289b46f4 100644 --- a/features/preferences/impl/src/main/res/values-sk/translations.xml +++ b/features/preferences/impl/src/main/res/values-sk/translations.xml @@ -51,4 +51,14 @@ Ak budete pokračovať, niektoré z vašich nastavení sa môžu zmeniť.""nastavenia systému" "Systémové oznámenia sú vypnuté" "Oznámenia" + "Riešenie problémov" + "Oznámenia riešení problémov" + "Spustiť testy" + "Spustiť testy znova" + "Niektoré testy zlyhali. Skontrolujte prosím podrobnosti." + "Spustite testy, aby ste zistili akýkoľvek problém vo vašej konfigurácii, ktorý môže spôsobiť, že sa upozornenia nebudú správať podľa očakávania." + "Pokus o opravu" + "Všetky testy prebehli úspešne." + "Oznámenia riešení problémov" + "Niektoré testy si vyžadujú vašu pozornosť. Prosím skontrolujte podrobnosti." diff --git a/features/rageshake/api/src/main/res/values-be/translations.xml b/features/rageshake/api/src/main/res/values-be/translations.xml index a73c7eedd5..3d9eec29d2 100644 --- a/features/rageshake/api/src/main/res/values-be/translations.xml +++ b/features/rageshake/api/src/main/res/values-be/translations.xml @@ -1,7 +1,7 @@ - "Пры апошнім выкарыстанні %1$s адбыўся збой. Жадаеце падзяліцца справаздачай аб збоі?" - "Падобна, што вы трасеце тэлефон. Жадаеце адкрыць экран паведамлення пра памылку?" + "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце падзяліцца справаздачай аб збоі?" + "Падобна, што вы трасеце тэлефон. Хочаце адкрыць экран паведамлення пра памылку?" "Rageshake" "Парог выяўлення" diff --git a/features/rageshake/impl/src/main/res/values-be/translations.xml b/features/rageshake/impl/src/main/res/values-be/translations.xml index 8bf98b9c85..f927ba3c5e 100644 --- a/features/rageshake/impl/src/main/res/values-be/translations.xml +++ b/features/rageshake/impl/src/main/res/values-be/translations.xml @@ -12,6 +12,6 @@ "Дазволіць журналы" "Адправіць здымак экрана" "Каб пераканацца, што ўсё працуе правільна, у паведамленне будуць уключаны часопісы. Каб адправіць паведамленне без часопісаў, адключыце гэтую наладу." - "Пры апошнім выкарыстанні %1$s адбыўся збой. Жадаеце падзяліцца справаздачай аб збоі?" + "Пры апошнім выкарыстанні %1$s адбыўся збой. Хочаце падзяліцца справаздачай аб збоі?" "Прагляд журналаў" diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml index 68ef4d8903..be2ac558fd 100644 --- a/features/roomdetails/impl/src/main/res/values-be/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml @@ -30,6 +30,7 @@ "Вы не зможаце адмяніць гэтае змяненне, бо паніжаеце сябе. Калі вы апошні адміністратар у пакоі, вярнуць права будзе немагчыма." "Панізіць сябе?" "%1$s (У чаканні)" + "(У чаканні)" "Рэдагаваць мадэратараў" "Адміністратары" "Мадэратары" diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml index 8479044057..005531b3db 100644 --- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml @@ -30,6 +30,7 @@ "Vous ne pourrez pas annuler ce changement car vous vous rétrogradez, si vous êtes le dernier utilisateur privilégié du salon il sera impossible de retrouver les privilèges." "Vous rétrograder ?" "%1$s (En attente)" + "(En attente)" "Modifier les modérateurs" "Administrateurs" "Modérateurs" diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index b6bf76c440..04afc61ad6 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -30,6 +30,7 @@ "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges." "Demote yourself?" "%1$s (Pending)" + "(Pending)" "Edit Moderators" "Admins" "Moderators" diff --git a/features/securebackup/impl/src/main/res/values-be/translations.xml b/features/securebackup/impl/src/main/res/values-be/translations.xml index 38215dfd20..63a2a9aae8 100644 --- a/features/securebackup/impl/src/main/res/values-be/translations.xml +++ b/features/securebackup/impl/src/main/res/values-be/translations.xml @@ -15,7 +15,7 @@ "Адключэнне рэзервовага капіравання прывядзе да выдалення бягучай рэзервовай копіі ключа шыфравання і адключэння іншых функцый бяспекі. У гэтым выпадку вы:" "Няма зашыфраванай гісторыі паведамленняў на новых прыладах" "Калі вы выходзіце з сістэмы, то губляеце доступ да зашыфраваных паведамленняў %1$s усюды" - "Вы ўпэўнены, што жадаеце адключыць рэзервовае капіраванне?" + "Вы ўпэўнены, што хочаце адключыць рэзервовае капіраванне?" "Атрымайце новы ключ аднаўлення, калі вы страцілі існуючы. Пасля змены ключа аднаўлення ваш стары больш не будзе працаваць." "Стварыць новы ключ аднаўлення" "Пераканайцеся, што вы можаце захаваць ключ аднаўлення ў бяспечным месцы" diff --git a/libraries/permissions/impl/src/main/res/values-be/translations.xml b/libraries/permissions/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..44c9d8376a --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,5 @@ + + + "Пераканайцеся, што праграма можа паказваць апавяшчэнні." + "Праверце дазволы" + diff --git a/libraries/permissions/impl/src/main/res/values-cs/translations.xml b/libraries/permissions/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..038561d93b --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,5 @@ + + + "Ujistěte se, že aplikace může zobrazovat oznámení." + "Kontrola oprávnění" + diff --git a/libraries/permissions/impl/src/main/res/values-de/translations.xml b/libraries/permissions/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..a0ff0ff417 --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,5 @@ + + + "Stelle sicher, dass die Anwendung Benachrichtigungen anzeigen kann." + "Berechtigungen überprüfen" + diff --git a/libraries/permissions/impl/src/main/res/values-fr/translations.xml b/libraries/permissions/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..b2cd018579 --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,5 @@ + + + "Vérifie que l’application peut afficher des notifications." + "Vérifier les autorisations" + diff --git a/libraries/permissions/impl/src/main/res/values-hu/translations.xml b/libraries/permissions/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..4afe7f181b --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,5 @@ + + + "Ellenőrizze, hogy az alkalmazás képes-e értesítéseket megjeleníteni." + "Engedélyek ellenőrzése" + diff --git a/libraries/permissions/impl/src/main/res/values-ru/translations.xml b/libraries/permissions/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..d1acff7ebd --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,5 @@ + + + "Убедитесь, что приложение может показывать уведомления." + "Проверка разрешений" + diff --git a/libraries/permissions/impl/src/main/res/values-sk/translations.xml b/libraries/permissions/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..995754907e --- /dev/null +++ b/libraries/permissions/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,5 @@ + + + "Uistite sa, že aplikácia dokáže zobrazovať upozornenia." + "Skontrolovať povolenia" + diff --git a/libraries/permissions/impl/src/main/res/values/localazy.xml b/libraries/permissions/impl/src/main/res/values/localazy.xml index a8859205dc..948b026970 100644 --- a/libraries/permissions/impl/src/main/res/values/localazy.xml +++ b/libraries/permissions/impl/src/main/res/values/localazy.xml @@ -1,5 +1,5 @@ - "Ensure that the application can show notifications." + "Check that the application can show notifications." "Check permissions" diff --git a/libraries/push/impl/src/main/res/values-be/translations.xml b/libraries/push/impl/src/main/res/values-be/translations.xml index f947eb3a00..686d10a281 100644 --- a/libraries/push/impl/src/main/res/values-be/translations.xml +++ b/libraries/push/impl/src/main/res/values-be/translations.xml @@ -56,4 +56,29 @@ "Фонавая сінхранізацыя" "Сэрвісы Google" "Службы Google Play не знойдзены. Апавяшчэнні могуць не працаваць належным чынам." + "Атрымаць назву бягучага пастаўшчыка." + "Пастаўшчыкі push-апавяшчэнняў не выбраны." + "Бягучы пастаўшчык push-апавяшчэнняў: %1$s." + "Бягучы пастаўшчык push-апавяшчэнняў" + "Пераканайцеся, што ў праграме ёсць хаця б адзін пастаўшчык push-апавяшчэнняў." + "Пастаўшчыкі push-апавяшчэнняў не знойдзены." + + "Знайшлі %1$d пастаўшчыка push-апавяшчэнняў: %2$s" + "Знайшлі %1$d пастаўшчыкоў push-апавяшчэнняў: %2$s" + "Знайшлі %1$d пастаўшчыкоў push-апавяшчэнняў: %2$s" + + "Выяўленне пастаўшчыкоў push-паслуг" + "Праверце, ці можа праграма паказваць апавяшчэнні." + "Апавяшчэнне не было націснута." + "Немагчыма паказаць апавяшчэнне." + "Апавяшчэнне было націснута!" + "Паказаць апавяшчэнне" + "Націсніце на апавяшчэнне, каб працягнуць тэст." + "Пераканайцеся, што праграма атрымлівае push-апавяшчэнні." + "Памылка: pusher адхіліў запыт." + "Памылка: %1$s." + "Памылка, немагчыма праверыць push-апавяшчэнне." + "Памылка, тайм-аўт у чаканні push-апавяшчэння." + "Зварот цыклу назад заняў %1$d мс." + "Тэст Націсніце кнопку вярнуцца" diff --git a/libraries/push/impl/src/main/res/values-bg/translations.xml b/libraries/push/impl/src/main/res/values-bg/translations.xml index 5a9f8d2a59..821ca2f5d8 100644 --- a/libraries/push/impl/src/main/res/values-bg/translations.xml +++ b/libraries/push/impl/src/main/res/values-bg/translations.xml @@ -36,4 +36,5 @@ "%d стая" "%d стаи" + "Грешка: %1$s" diff --git a/libraries/push/impl/src/main/res/values-cs/translations.xml b/libraries/push/impl/src/main/res/values-cs/translations.xml index db4e6e4c6a..fac2a69784 100644 --- a/libraries/push/impl/src/main/res/values-cs/translations.xml +++ b/libraries/push/impl/src/main/res/values-cs/translations.xml @@ -56,4 +56,29 @@ "Synchronizace na pozadí" "Služby Google" "Nebyly nalezeny žádné funkční služby Google Play. Oznámení nemusí fungovat správně." + "Získat název aktuálního poskytovatele." + "Nebyli vybráni žádní push poskytovatelé." + "Aktuální push poskytovatel: %1$s." + "Aktuální push poskytovatel" + "Ujistěte se, že aplikace má alespoň jednoho push poskytovatele." + "Nebyli nalezeni žádní push poskytovatelé." + + "Nalezen %1$d push poskytovatel: %2$s" + "Nalezeni %1$d push poskytovatelé: %2$s" + "Nalezeno %1$d push poskytovatelů: %2$s" + + "Zjistit push poskytovatele" + "Zkontrolujte, zda aplikace může zobrazit oznámení." + "Na oznámení nebylo kliknuto." + "Oznámení nelze zobrazit." + "Na oznámení bylo kliknuto!" + "Zobrazit oznámení" + "Kliknutím na oznámení pokračujte v testu." + "Ujistěte se, že aplikace přijímá push." + "Chyba: pusher odmítl požadavek." + "Chyba: %1$s." + "Chyba, nelze otestovat push." + "Chyba, časový limit čekání na push." + "Push zpětná smyčka trvala %1$d ms." + "Otestovat push zpětnou smyčku" diff --git a/libraries/push/impl/src/main/res/values-de/translations.xml b/libraries/push/impl/src/main/res/values-de/translations.xml index 5476ad2eea..2757e89dea 100644 --- a/libraries/push/impl/src/main/res/values-de/translations.xml +++ b/libraries/push/impl/src/main/res/values-de/translations.xml @@ -50,4 +50,28 @@ "Hintergrundsynchronisation" "Google-Dienste" "Keine gültigen Google Play-Dienste gefunden. Benachrichtigungen funktionieren möglicherweise nicht richtig." + "Ermittele den Namen des aktuellen Anbieters." + "Kein Push-Anbieter ausgewählt." + "Aktueller Push-Anbieter:%1$s." + "Aktueller Push-Anbieter" + "Stelle sicher, dass die Anwendung mindestens einen Push-Anbieter hat." + "Keine Push-Anbieter gefunden." + + "%1$d Push-Anbieter gefunden: %2$s" + "%1$d Push-Anbieter gefunden: %2$s" + + "Push-Anbieter erkennen" + "Prüfe, ob die Anwendung Benachrichtigungen anzeigen kann." + "Die Benachrichtigung wurde nicht angeklickt." + "Die Benachrichtigung kann nicht angezeigt werden." + "Die Benachrichtigung wurde angeklickt!" + "Benachrichtigung anzeigen" + "Bitte klicke auf die Benachrichtigung, um den Test fortzusetzen." + "Stelle sicher, dass die Anwendung Push-Nachrichten empfängt." + "Fehler: Der Pusher hat die Anfrage abgelehnt." + "Fehler:%1$s." + "Fehler: Push kann nicht getestet werden." + "Fehler: Timeout beim Warten auf Push." + "Push-Loop-Back Dauer: %1$d ms." + "Teste Push-Loop-Back" diff --git a/libraries/push/impl/src/main/res/values-fr/translations.xml b/libraries/push/impl/src/main/res/values-fr/translations.xml index eb6e4eabbc..8501b8ad76 100644 --- a/libraries/push/impl/src/main/res/values-fr/translations.xml +++ b/libraries/push/impl/src/main/res/values-fr/translations.xml @@ -50,4 +50,28 @@ "Synchronisation en arrière-plan" "Services Google" "Aucun service Google Play valide n’a été trouvé. Les notifications peuvent ne pas fonctionner correctement." + "Obtenir le nom du fournisseur de Push actuel." + "Aucun fournisseur de Push n’est sélectionné." + "Fournisseur de Push actuel : %1$s." + "Fournisseur de Push actuel" + "Vérifier que l’application possède au moins un fournisseur de Push." + "Aucun fournisseur de Push n’a été trouvé." + + "%1$d fournisseur de Push détecté : %2$s" + "%1$d fournisseurs de Push détectés : %2$s" + + "Détecter les fournisseurs de Push" + "Vérifier que l’application peut afficher des notifications." + "Vous n’avez pas cliqué sur la notification." + "Impossible d’afficher la notification." + "Vous avez cliqué sur la notification!" + "Affichage des notifications" + "Veuillez cliquer sur la notification pour continuer le test." + "Vérifier que l’application reçoit les Push." + "Erreur : le Pusher a rejeté la demande." + "Erreur :%1$s." + "Erreur, impossible de tester les Push." + "Erreur, le délai d’attente du Push est dépassé." + "La demande d’envoi de Push et sa réception ont pris %1$d ms." + "Tester la réception des Push" diff --git a/libraries/push/impl/src/main/res/values-hu/translations.xml b/libraries/push/impl/src/main/res/values-hu/translations.xml index de719fc0c6..7b0c66aa65 100644 --- a/libraries/push/impl/src/main/res/values-hu/translations.xml +++ b/libraries/push/impl/src/main/res/values-hu/translations.xml @@ -50,4 +50,28 @@ "Háttérszinkronizálás" "Google szolgáltatások" "A Google Play szolgáltatások nem találhatók. Előfordulhat, hogy az értesítések nem működnek megfelelően." + "A jelenlegi szolgáltató nevének lekérdezése." + "Nincs kiválasztva leküldéses értesítési szolgáltató." + "Jelenlegi leküldéses értesítési szolgáltató: %1$s." + "Jelenlegi leküldéses értesítési szolgáltató" + "Győződjön meg arról, hogy az alkalmazás legalább egy leküldéses értesítési szolgáltatóval rendelkezik." + "Nem található leküldéses értesítési szolgáltató." + + "%1$d leküldéses szolgáltató találva: %2$s" + "%1$d leküldéses szolgáltató találva: %2$s" + + "Leküldéses értesítési szolgáltatók észlelése" + "Ellenőrizze, hogy az alkalmazás képes-e megjeleníteni az értesítést." + "Az értesítésre nem kattintottak rá." + "Az értesítés nem jeleníthető meg." + "Az értesítésre rákattintottak!" + "Értesítés megjelenítése" + "A teszt folytatásához kattintson az értesítésre." + "Győződjön meg arról, hogy az alkalmazás megkapja-e a leküldéses értesítést." + "Hiba: a leküldő elutasította a kérést." + "Hiba: %1$s." + "Hiba, nem lehet tesztelni a leküldéses értesítést." + "Hiba, időtúllépés a leküldéses értesítésre való várakozás során." + "A leküldéses értesítés folyamata %1$d ezredmásodpercig tartott." + "Tesztelje a leküldéses értesítés folyamatát" diff --git a/libraries/push/impl/src/main/res/values-in/translations.xml b/libraries/push/impl/src/main/res/values-in/translations.xml index 1a81220eeb..b933330be1 100644 --- a/libraries/push/impl/src/main/res/values-in/translations.xml +++ b/libraries/push/impl/src/main/res/values-in/translations.xml @@ -44,4 +44,27 @@ "Sinkronisasi latar belakang" "Layanan Google" "Tidak ditemukan Layanan Google Play yang valid. Pemberitahuan mungkin tidak berfungsi dengan baik." + "Dapatkan nama penyedia saat ini." + "Tidak ada penyedia notifikasi dorongan yang dipilih." + "Penyedia notifikasi dorongan saat ini: %1$s." + "Penyedia notifikasi dorongan saat ini" + "Pastikan aplikasi memiliki setidaknya satu penyedia notifikasi dorongan." + "Tidak ada penyedia notifikasi dorongan yang ditemukan." + + "Ditemukan %1$d penyedia notifikasi dorongan: %2$s" + + "Deteksi penyedia notifikasi dorongan" + "Periksa apakah aplikasi dapat menampilkan notifikasi." + "Notifikasi belum diklik." + "Tidak dapat menampilkan notifikasi." + "Notifikasi telah diklik!" + "Tampilan notifikasi" + "Silakan klik pada notifikasi untuk melanjutkan tes." + "Pastikan aplikasi menerima notifikasi dorongan." + "Kesalahan: pendorong telah menolak permintaan." + "Kesalahan: %1$s." + "Terjadi kesalahan, tidak dapat menguji notifikasi dorongan." + "Terjadi kesalahan, melebihi batas waktu menunggu notifikasi dorongan." + "Ulangan notifikasi dorongan membutuhkan %1$d ms." + "Uji ulangan notifikasi dorongan lagi" diff --git a/libraries/push/impl/src/main/res/values-ru/translations.xml b/libraries/push/impl/src/main/res/values-ru/translations.xml index 8881d488ba..65242651b2 100644 --- a/libraries/push/impl/src/main/res/values-ru/translations.xml +++ b/libraries/push/impl/src/main/res/values-ru/translations.xml @@ -56,4 +56,29 @@ "Фоновая синхронизация" "Сервисы Google" "Не найдены действующие службы Google Play. Уведомления могут работать некорректно." + "Получение имени текущего поставщика." + "Поставщики push-уведомлений не выбраны." + "Текущий поставщик push-уведомлений: %1$s." + "Текущий поставщик push-уведомлений" + "Убедитесь, что у приложения есть хотя бы один поставщик push-сообщений." + "Поставщики push-уведомлений не найдены." + + "Найден %1$d push-провайдер: %2$s" + "Найдено %1$d push-провайдеров: %2$s" + "Найдено %1$d push-провайдеров: %2$s" + + "Обнаружение поставщиков push-уведомлений" + "Убедитесь, что приложение может отображать уведомление." + "Уведомление не было нажато." + "Невозможно отобразить уведомление." + "Уведомление было нажато!" + "Отобразить уведомление" + "Нажмите на уведомление, чтобы продолжить тест." + "Убедитесь, что приложение получает push-сообщение." + "Ошибка: pusher отклонил запрос." + "Ошибка: %1$s." + "Ошибка, невозможно протестировать отправку." + "Ошибка, тайм-аут ожидания push-уведомления." + "Обратная отправка push-уведомления, заняла %1$d мс." + "Тест обратной отправки push-уведомления" diff --git a/libraries/push/impl/src/main/res/values-sk/translations.xml b/libraries/push/impl/src/main/res/values-sk/translations.xml index 4517697945..95aed49bd3 100644 --- a/libraries/push/impl/src/main/res/values-sk/translations.xml +++ b/libraries/push/impl/src/main/res/values-sk/translations.xml @@ -56,4 +56,29 @@ "Synchronizácia na pozadí" "Služby Google" "Nenašli sa žiadne platné služby Google Play. Oznámenia nemusia fungovať správne." + "Získaťe názov aktuálneho poskytovateľa." + "Nie sú vybraní žiadni poskytovatelia push." + "Aktuálny poskytovateľ push: %1$s." + "Aktuálny poskytovateľ push" + "Uistite sa, že aplikácia má aspoň jedného poskytovateľa push." + "Nenašli sa žiadni poskytovatelia push." + + "Nájdený %1$d poskytovateľ služby push: %2$s" + "Nájdení %1$d poskytovatelia služby push: %2$s" + "Nájdených %1$d poskytovateľov služby push: %2$s" + + "Zistiť poskytovateľov push" + "Skontrolujte, či aplikácia dokáže zobraziť upozornenie." + "Na oznámenie nebolo kliknuté." + "Nie je možné zobraziť upozornenie." + "Na oznámenie bolo kliknuté!" + "Zobraziť upozornenie" + "Kliknite na upozornenie a pokračujte v teste." + "Uistite sa, že aplikácia prijíma push oznámenia." + "Chyba: pusher odmietol požiadavku." + "Chyba: %1$s." + "Chyba, nie je možné testovať push." + "Chyba, časový limit na push vypršal." + "Push loop back trvalo %1$d ms." + "Testovať Push loop back" diff --git a/libraries/pushproviders/firebase/src/main/res/values-be/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..cd9082e913 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-be/translations.xml @@ -0,0 +1,11 @@ + + + "Пераканайцеся, што Firebase даступны." + "Firebase недаступны." + "Firebase даступны." + "Праверыць Firebase" + "Пераканайцеся, што маркер Firebase даступны." + "Маркер Firebase невядомы." + "Маркер Firebase: %1$s." + "Праверце маркер Firebase" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-cs/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..e0b7eff47f --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-cs/translations.xml @@ -0,0 +1,11 @@ + + + "Ujistěte se, že je k dispozici Firebase." + "Firebase není k dispozici." + "Firebase je k dispozici." + "Zkontrolovat Firebase" + "Ujistěte se, že je k dispozici Firebase token." + "Firebase token není znám." + "Firebase token: %1$s." + "Zkontrolovat Firebase token" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-de/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..5df74b7284 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-de/translations.xml @@ -0,0 +1,11 @@ + + + "Stelle sicher, dass Firebase verfügbar ist." + "Firebase ist nicht verfügbar." + "Firebase ist verfügbar." + "Überprüfe Firebase" + "Stelle sicher, dass der Firebase Token verfügbar ist." + "Firebase Token ist nicht bekannt." + "Firebase Token: %1$s." + "Prüfe Firebase Token" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-fr/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..75256022a2 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-fr/translations.xml @@ -0,0 +1,11 @@ + + + "Vérification que Firebase est disponible." + "Firebase n’est pas disponible." + "Firebase est disponible." + "Vérification de Firebase" + "Vérifier que le jeton Firebase est disponible." + "Le jeton Firebase n’est pas connu." + "Jeton Firebase :%1$s." + "Vérifier le jeton Firebase" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-hu/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..10fa194159 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-hu/translations.xml @@ -0,0 +1,11 @@ + + + "Győződjön meg arról, hogy a Firebase elérhető-e." + "A Firebase nem érhető el." + "A Firebase elérhető." + "Ellenőrizze a Firebase-t" + "Győződjön meg arról, hogy a Firebase-token elérhető." + "A Firebase-token nem ismert." + "Firebase-token: %1$s." + "Ellenőrizze a Firebase-tokent" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-ru/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..4167dd0d36 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-ru/translations.xml @@ -0,0 +1,11 @@ + + + "Убедитесь, что Firebase доступен." + "Firebase недоступен." + "Firebase доступен." + "Проверить Firebase" + "Убедитесь, что токен Firebase доступен." + "Токен Firebase неизвестен." + "Токен Firebase: %1$s." + "Проверить токен Firebase" + diff --git a/libraries/pushproviders/firebase/src/main/res/values-sk/translations.xml b/libraries/pushproviders/firebase/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..312f751ce5 --- /dev/null +++ b/libraries/pushproviders/firebase/src/main/res/values-sk/translations.xml @@ -0,0 +1,11 @@ + + + "Uistite sa, že Firebase je k dispozícii." + "Firebase nie je k dispozícii." + "Firebase je k dispozícii." + "Skontrolovať Firebase" + "Uistite sa, že je k dispozícii token Firebase." + "Token Firebase nie je známy." + "Token Firebase: %1$s." + "Skontrolovať token Firebase" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-be/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..5fcab0a3f3 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-be/translations.xml @@ -0,0 +1,11 @@ + + + "Пераканайцеся, што размеркавальнікі UnifiedPush даступныя." + "Размеркавальнікі не знойдзены." + + "%1$d знойдзены размеркавальнік: %2$s." + "%1$d знойдзена размеркавальніка: %2$s." + "%1$d знойдзена размеркавальнікаў: %2$s." + + "Праверыць UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-cs/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..d4eeb3ef96 --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-cs/translations.xml @@ -0,0 +1,11 @@ + + + "Ujistěte se, že jsou k dispozici distributoři UnifiedPush." + "Nebyli nalezeni žádní push distributoři." + + "Nalezen %1$d distributor: %2$s." + "Nalezeni %1$d distributoři: %2$s." + "Nalezeno %1$d distributorů: %2$s." + + "Zkontrolovat UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-de/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..92a632a39d --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-de/translations.xml @@ -0,0 +1,10 @@ + + + "Stelle sicher, dass UnifiedPush-Verteiler verfügbar sind." + "Keine Push-Verteiler gefunden." + + "%1$d Verteiler gefunden: %2$s." + "%1$d Verteiler gefunden: %2$s." + + "UnifiedPush prüfen" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-fr/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..fe7769da5e --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-fr/translations.xml @@ -0,0 +1,10 @@ + + + "Vérifier qu’au moins un distributeur UnifiedPush est disponible." + "Aucun distributeur UnifiedPush n’a été trouvé." + + "%1$d distributeur détecté :%2$s." + "%1$d distributeurs détectés :%2$s." + + "Vérifier UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-hu/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..7c92f521da --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-hu/translations.xml @@ -0,0 +1,10 @@ + + + "Győződjön meg arról, hogy a UnifiedPush forgalmazói elérhetők." + "Nem található forgalmazó a leküldéses értesítésekhez." + + "%1$d forgalmazó található: %2$s." + "%1$d forgalmazó található: %2$s." + + "Ellenőrizze a UnifiedPush szolgáltatást" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-ru/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..91a4dbc81b --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-ru/translations.xml @@ -0,0 +1,11 @@ + + + "Убедитесь, что дистрибьюторы UnifiedPush доступны." + "Поставщиков push-уведомлений не найдено." + + "%1$d провайдер найден: %2$s." + "%1$d провайдеров найдено: %2$s." + "%1$d провайдеров найдено: %2$s." + + "Проверка UnifiedPush" + diff --git a/libraries/pushproviders/unifiedpush/src/main/res/values-sk/translations.xml b/libraries/pushproviders/unifiedpush/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..3dc876cb5b --- /dev/null +++ b/libraries/pushproviders/unifiedpush/src/main/res/values-sk/translations.xml @@ -0,0 +1,11 @@ + + + "Uistite sa, že sú dostupní distribútori UnifiedPush." + "Nenašli sa žiadni distribútori push." + + "%1$d nájdený distribútor: %2$s." + "%1$d nájdení distribútori: %2$s." + "%1$d nájdených distribútorov: %2$s." + + "Skontrolovať UnifiedPush" + diff --git a/libraries/ui-strings/src/main/res/values-be/translations.xml b/libraries/ui-strings/src/main/res/values-be/translations.xml index 223ee9740a..ffbafa87f2 100644 --- a/libraries/ui-strings/src/main/res/values-be/translations.xml +++ b/libraries/ui-strings/src/main/res/values-be/translations.xml @@ -275,57 +275,4 @@ "Месцазнаходжанне" "Версія: %1$s (%2$s)" "be" - "Выпраўленне непаладак" - "Выпраўленне непаладак з апавяшчэннямі" - "Запусціць тэсты" - "Запусціце тэсты яшчэ раз" - "Некаторыя тэсты не ўдаліся. Калі ласка, праглядзіце дэталі." - "Запусціце тэсты, каб выявіць праблемы ў вашай канфігурацыі, з-за якіх апавяшчэння могуць паводзіць сябе не так, як чакалася." - "Спроба выпраўлення" - "Усе тэсты паспяхова пройдзены." - "Выпраўленне непаладак з апавяшчэннямі" - "Некаторыя тэсты патрабуюць вашай увагі. Калі ласка, праглядзіце дэталі." - "Пераканайцеся, што праграма можа паказваць апавяшчэнні." - "Праверце дазволы" - "Атрымаць назву бягучага пастаўшчыка." - "Пастаўшчыкі push-апавяшчэнняў не выбраны." - "Бягучы пастаўшчык push-апавяшчэнняў: %1$s." - "Бягучы пастаўшчык push-апавяшчэнняў" - "Пераканайцеся, што ў праграме ёсць хаця б адзін пастаўшчык push-апавяшчэнняў." - "Пастаўшчыкі push-апавяшчэнняў не знойдзены." - - "Знайшлі %1$d пастаўшчыка push-апавяшчэнняў: %2$s" - "Знайшлі %1$d пастаўшчыкоў push-апавяшчэнняў: %2$s" - "Знайшлі %1$d пастаўшчыкоў push-апавяшчэнняў: %2$s" - - "Выяўленне пастаўшчыкоў push-паслуг" - "Праверце, ці можа праграма паказваць апавяшчэнні." - "Апавяшчэнне не было націснута." - "Немагчыма паказаць апавяшчэнне." - "Апавяшчэнне было націснута!" - "Паказаць апавяшчэнне" - "Націсніце на апавяшчэнне, каб працягнуць тэст." - "Пераканайцеся, што Firebase даступны." - "Firebase недаступны." - "Firebase даступны." - "Праверыць Firebase" - "Пераканайцеся, што маркер Firebase даступны." - "Маркер Firebase невядомы." - "Маркер Firebase: %1$s." - "Праверце маркер Firebase" - "Пераканайцеся, што праграма атрымлівае push-апавяшчэнні." - "Памылка: pusher адхіліў запыт." - "Памылка: %1$s." - "Памылка, немагчыма праверыць push-апавяшчэнне." - "Памылка, тайм-аўт у чаканні push-апавяшчэння." - "Зварот цыклу назад заняў %1$d мс." - "Тэст Націсніце кнопку вярнуцца" - "Пераканайцеся, што размеркавальнікі UnifiedPush даступныя." - "Размеркавальнікі не знойдзены." - - "%1$d знойдзены размеркавальнік: %2$s." - "%1$d знойдзена размеркавальніка: %2$s." - "%1$d знойдзена размеркавальнікаў: %2$s." - - "Праверыць UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-bg/translations.xml b/libraries/ui-strings/src/main/res/values-bg/translations.xml index 0e6a31b71d..48c602706b 100644 --- a/libraries/ui-strings/src/main/res/values-bg/translations.xml +++ b/libraries/ui-strings/src/main/res/values-bg/translations.xml @@ -211,5 +211,4 @@ "Местоположение" "Версия: %1$s (%2$s)" "bg" - "Грешка: %1$s" diff --git a/libraries/ui-strings/src/main/res/values-cs/translations.xml b/libraries/ui-strings/src/main/res/values-cs/translations.xml index 04968d8548..9dde757dc1 100644 --- a/libraries/ui-strings/src/main/res/values-cs/translations.xml +++ b/libraries/ui-strings/src/main/res/values-cs/translations.xml @@ -275,57 +275,4 @@ "Poloha" "Verze: %1$s (%2$s)" "en" - "Odstraňování problémů" - "Odstraňování problémů s upozorněními" - "Spustit testy" - "Spustit testy znovu" - "Některé testy selhaly. Zkontrolujte prosím podrobnosti." - "Spusťte testy, abyste zjistili jakýkoli problém ve vaší konfiguraci, který může způsobit, že se oznámení nebudou chovat podle očekávání." - "Pokus o opravu" - "Všechny testy proběhly úspěšně." - "Odstraňování problémů s upozorněními" - "Některé testy vyžadují vaši pozornost. Zkontrolujte prosím podrobnosti." - "Ujistěte se, že aplikace může zobrazovat oznámení." - "Kontrola oprávnění" - "Získat název aktuálního poskytovatele." - "Nebyli vybráni žádní push poskytovatelé." - "Aktuální push poskytovatel: %1$s." - "Aktuální push poskytovatel" - "Ujistěte se, že aplikace má alespoň jednoho push poskytovatele." - "Nebyli nalezeni žádní push poskytovatelé." - - "Nalezen %1$d push poskytovatel: %2$s" - "Nalezeni %1$d push poskytovatelé: %2$s" - "Nalezeno %1$d push poskytovatelů: %2$s" - - "Zjistit push poskytovatele" - "Zkontrolujte, zda aplikace může zobrazit oznámení." - "Na oznámení nebylo kliknuto." - "Oznámení nelze zobrazit." - "Na oznámení bylo kliknuto!" - "Zobrazit oznámení" - "Kliknutím na oznámení pokračujte v testu." - "Ujistěte se, že je k dispozici Firebase." - "Firebase není k dispozici." - "Firebase je k dispozici." - "Zkontrolovat Firebase" - "Ujistěte se, že je k dispozici Firebase token." - "Firebase token není znám." - "Firebase token: %1$s." - "Zkontrolovat Firebase token" - "Ujistěte se, že aplikace přijímá push." - "Chyba: pusher odmítl požadavek." - "Chyba: %1$s." - "Chyba, nelze otestovat push." - "Chyba, časový limit čekání na push." - "Push zpětná smyčka trvala %1$d ms." - "Otestovat push zpětnou smyčku" - "Ujistěte se, že jsou k dispozici distributoři UnifiedPush." - "Nebyli nalezeni žádní push distributoři." - - "Nalezen %1$d distributor: %2$s." - "Nalezeni %1$d distributoři: %2$s." - "Nalezeno %1$d distributorů: %2$s." - - "Zkontrolovat UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-de/translations.xml b/libraries/ui-strings/src/main/res/values-de/translations.xml index 19408138b7..8a3e035833 100644 --- a/libraries/ui-strings/src/main/res/values-de/translations.xml +++ b/libraries/ui-strings/src/main/res/values-de/translations.xml @@ -271,55 +271,4 @@ "Standort" "Version: %1$s (%2$s)" "en" - "Fehlerbehebung" - "Fehlerbehebung für Benachrichtigungen" - "Tests durchführen" - "Tests erneut durchführen" - "Einige Tests sind fehlgeschlagen. Bitte überprüfe die Details." - "Führe die Tests durch, um Probleme zu erkennen, die dazu führen können, dass sich die Benachrichtigungen nicht wie erwartet verhalten." - "Versuche das Problem zu beheben" - "Alle Tests wurden erfolgreich bestanden." - "Fehlerbehebung für Benachrichtigungen" - "Einige Tests erfordern deine Aufmerksamkeit. Bitte überprüfe die Details." - "Stelle sicher, dass die Anwendung Benachrichtigungen anzeigen kann." - "Berechtigungen überprüfen" - "Ermittele den Namen des aktuellen Anbieters." - "Kein Push-Anbieter ausgewählt." - "Aktueller Push-Anbieter:%1$s." - "Aktueller Push-Anbieter" - "Stelle sicher, dass die Anwendung mindestens einen Push-Anbieter hat." - "Keine Push-Anbieter gefunden." - - "%1$d Push-Anbieter gefunden: %2$s" - "%1$d Push-Anbieter gefunden: %2$s" - - "Push-Anbieter erkennen" - "Prüfe, ob die Anwendung Benachrichtigungen anzeigen kann." - "Die Benachrichtigung wurde nicht angeklickt." - "Die Benachrichtigung kann nicht angezeigt werden." - "Die Benachrichtigung wurde angeklickt!" - "Benachrichtigung anzeigen" - "Bitte klicke auf die Benachrichtigung, um den Test fortzusetzen." - "Stelle sicher, dass Firebase verfügbar ist." - "Firebase ist nicht verfügbar." - "Firebase ist verfügbar." - "Überprüfe Firebase" - "Stelle sicher, dass der Firebase Token verfügbar ist." - "Firebase Token ist nicht bekannt." - "Firebase Token: %1$s." - "Prüfe Firebase Token" - "Stelle sicher, dass die Anwendung Push-Nachrichten empfängt." - "Fehler: Der Pusher hat die Anfrage abgelehnt." - "Fehler:%1$s." - "Fehler: Push kann nicht getestet werden." - "Fehler: Timeout beim Warten auf Push." - "Push-Loop-Back Dauer: %1$d ms." - "Teste Push-Loop-Back" - "Stelle sicher, dass UnifiedPush-Verteiler verfügbar sind." - "Keine Push-Verteiler gefunden." - - "%1$d Verteiler gefunden: %2$s." - "%1$d Verteiler gefunden: %2$s." - - "UnifiedPush prüfen" diff --git a/libraries/ui-strings/src/main/res/values-fr/translations.xml b/libraries/ui-strings/src/main/res/values-fr/translations.xml index 9cd0d2715d..e3b6e3d0d9 100644 --- a/libraries/ui-strings/src/main/res/values-fr/translations.xml +++ b/libraries/ui-strings/src/main/res/values-fr/translations.xml @@ -271,55 +271,4 @@ "Position" "Version : %1$s ( %2$s )" "Ang." - "Dépannage" - "Résoudre les problèmes liés aux notifications" - "Exécuter les tests" - "Relancer les tests" - "Certains tests ont échoué. Veuillez vérifier les détails." - "Exécuter les tests pour détecter tout problème dans votre configuration susceptible de provoquer un dysfonctionnement des notifications." - "Tenter de corriger" - "Tous les tests ont réussi." - "Dépanner les notifications" - "Certains tests nécessitent votre attention. Veuillez vérifier les détails." - "Vérifie que l’application peut afficher des notifications." - "Vérifier les autorisations" - "Obtenir le nom du fournisseur de Push actuel." - "Aucun fournisseur de Push n’est sélectionné." - "Fournisseur de Push actuel : %1$s." - "Fournisseur de Push actuel" - "Vérifier que l’application possède au moins un fournisseur de Push." - "Aucun fournisseur de Push n’a été trouvé." - - "%1$d fournisseur de Push détecté : %2$s" - "%1$d fournisseurs de Push détectés : %2$s" - - "Détecter les fournisseurs de Push" - "Vérifier que l’application peut afficher des notifications." - "Vous n’avez pas cliqué sur la notification." - "Impossible d’afficher la notification." - "Vous avez cliqué sur la notification!" - "Affichage des notifications" - "Veuillez cliquer sur la notification pour continuer le test." - "Vérification que Firebase est disponible." - "Firebase n’est pas disponible." - "Firebase est disponible." - "Vérification de Firebase" - "Vérifier que le jeton Firebase est disponible." - "Le jeton Firebase n’est pas connu." - "Jeton Firebase :%1$s." - "Vérifier le jeton Firebase" - "Vérifier que l’application reçoit les Push." - "Erreur : le Pusher a rejeté la demande." - "Erreur :%1$s." - "Erreur, impossible de tester les Push." - "Erreur, le délai d’attente du Push est dépassé." - "La demande d’envoi de Push et sa réception ont pris %1$d ms." - "Tester la réception des Push" - "Vérifier qu’au moins un distributeur UnifiedPush est disponible." - "Aucun distributeur UnifiedPush n’a été trouvé." - - "%1$d distributeur détecté :%2$s." - "%1$d distributeurs détectés :%2$s." - - "Vérifier UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-hu/translations.xml b/libraries/ui-strings/src/main/res/values-hu/translations.xml index 9c343ec200..43568cafb6 100644 --- a/libraries/ui-strings/src/main/res/values-hu/translations.xml +++ b/libraries/ui-strings/src/main/res/values-hu/translations.xml @@ -271,55 +271,4 @@ "Hely" "Verzió: %1$s (%2$s)" "hu" - "Hibaelhárítás" - "Értesítések hibaelhárítása" - "Tesztek futtatása" - "Tesztek újbóli futtatása" - "Egyes tesztek sikertelenek voltak. Ellenőrizze a részleteket." - "A tesztek futtatása, hogy észlelje a konfigurációban felmerülő olyan problémákat, amelyek miatt az értesítések nem az elvárt módon viselkednek." - "Kísérlet a javításra" - "Minden teszt sikeresen lezajlott." - "Értesítések hibaelhárítása" - "Egyes tesztek a figyelmét igénylik. Ellenőrizze a részleteket." - "Ellenőrizze, hogy az alkalmazás képes-e értesítéseket megjeleníteni." - "Engedélyek ellenőrzése" - "A jelenlegi szolgáltató nevének lekérdezése." - "Nincs kiválasztva leküldéses értesítési szolgáltató." - "Jelenlegi leküldéses értesítési szolgáltató: %1$s." - "Jelenlegi leküldéses értesítési szolgáltató" - "Győződjön meg arról, hogy az alkalmazás legalább egy leküldéses értesítési szolgáltatóval rendelkezik." - "Nem található leküldéses értesítési szolgáltató." - - "%1$d leküldéses szolgáltató találva: %2$s" - "%1$d leküldéses szolgáltató találva: %2$s" - - "Leküldéses értesítési szolgáltatók észlelése" - "Ellenőrizze, hogy az alkalmazás képes-e megjeleníteni az értesítést." - "Az értesítésre nem kattintottak rá." - "Az értesítés nem jeleníthető meg." - "Az értesítésre rákattintottak!" - "Értesítés megjelenítése" - "A teszt folytatásához kattintson az értesítésre." - "Győződjön meg arról, hogy a Firebase elérhető-e." - "A Firebase nem érhető el." - "A Firebase elérhető." - "Ellenőrizze a Firebase-t" - "Győződjön meg arról, hogy a Firebase-token elérhető." - "A Firebase-token nem ismert." - "Firebase-token: %1$s." - "Ellenőrizze a Firebase-tokent" - "Győződjön meg arról, hogy az alkalmazás megkapja-e a leküldéses értesítést." - "Hiba: a leküldő elutasította a kérést." - "Hiba: %1$s." - "Hiba, nem lehet tesztelni a leküldéses értesítést." - "Hiba, időtúllépés a leküldéses értesítésre való várakozás során." - "A leküldéses értesítés folyamata %1$d ezredmásodpercig tartott." - "Tesztelje a leküldéses értesítés folyamatát" - "Győződjön meg arról, hogy a UnifiedPush forgalmazói elérhetők." - "Nem található forgalmazó a leküldéses értesítésekhez." - - "%1$d forgalmazó található: %2$s." - "%1$d forgalmazó található: %2$s." - - "Ellenőrizze a UnifiedPush szolgáltatást" diff --git a/libraries/ui-strings/src/main/res/values-in/translations.xml b/libraries/ui-strings/src/main/res/values-in/translations.xml index a5a98b5d35..fc237cac27 100644 --- a/libraries/ui-strings/src/main/res/values-in/translations.xml +++ b/libraries/ui-strings/src/main/res/values-in/translations.xml @@ -267,53 +267,4 @@ "Lokasi" "Versi: %1$s (%2$s)" "id" - "Pemecahan masalah" - "Pecahkan masalah notifikasi" - "Jalankan tes" - "Jalankan tes lagi" - "Beberapa tes gagal. Silakan periksa detailnya." - "Jalankan pengujian untuk mendeteksi masalah apa pun dalam konfigurasi Anda yang mungkin membuat notifikasi tidak berperilaku seperti yang diharapkan." - "Mencoba untuk memperbaiki" - "Semua tes berhasil dilalui." - "Pecahkan masalah notifikasi" - "Beberapa tes membutuhkan perhatian Anda. Silakan periksa detailnya." - "Pastikan aplikasi dapat menampilkan notifikasi." - "Periksa izin" - "Dapatkan nama penyedia saat ini." - "Tidak ada penyedia notifikasi dorongan yang dipilih." - "Penyedia notifikasi dorongan saat ini: %1$s." - "Penyedia notifikasi dorongan saat ini" - "Pastikan aplikasi memiliki setidaknya satu penyedia notifikasi dorongan." - "Tidak ada penyedia notifikasi dorongan yang ditemukan." - - "Ditemukan %1$d penyedia notifikasi dorongan: %2$s" - - "Deteksi penyedia notifikasi dorongan" - "Periksa apakah aplikasi dapat menampilkan notifikasi." - "Notifikasi belum diklik." - "Tidak dapat menampilkan notifikasi." - "Notifikasi telah diklik!" - "Tampilan notifikasi" - "Silakan klik pada notifikasi untuk melanjutkan tes." - "Pastikan bahwa Firebase tersedia." - "Firebase tidak tersedia." - "Firebase tersedia." - "Periksa Firebase" - "Pastikan token Firebase tersedia." - "Token Firebase tidak diketahui." - "Token Firebase: %1$s." - "Periksa token Firebase" - "Pastikan aplikasi menerima notifikasi dorongan." - "Kesalahan: pendorong telah menolak permintaan." - "Kesalahan: %1$s." - "Terjadi kesalahan, tidak dapat menguji notifikasi dorongan." - "Terjadi kesalahan, melebihi batas waktu menunggu notifikasi dorongan." - "Ulangan notifikasi dorongan membutuhkan %1$d ms." - "Uji ulangan notifikasi dorongan lagi" - "Pastikan distributor UnifiedPush tersedia." - "Tidak ada distributor notifikasi dorongan yang ditemukan." - - "%1$d distributor ditemukan: %2$s." - - "Periksa UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-ru/translations.xml b/libraries/ui-strings/src/main/res/values-ru/translations.xml index ca4731f34f..e7a564596d 100644 --- a/libraries/ui-strings/src/main/res/values-ru/translations.xml +++ b/libraries/ui-strings/src/main/res/values-ru/translations.xml @@ -275,57 +275,4 @@ "Местоположение" "Версия: %1$s (%2$s)" "ru" - "Устранение неполадок" - "Уведомления об устранении неполадок" - "Выполнение тестов" - "Повторное выполнение тестов" - "Некоторые тесты провалились. Пожалуйста, проверьте детали." - "Выполните тесты, чтобы обнаружить любую проблему в конфигурации, из-за которой уведомления могут работать не так, как ожидалось." - "Попытка исправить" - "Все тесты прошли успешно." - "Уведомления об устранении неполадок" - "Некоторые тесты требуют вашего внимания. Пожалуйста, проверьте детали." - "Убедитесь, что приложение может показывать уведомления." - "Проверка разрешений" - "Получение имени текущего поставщика." - "Поставщики push-уведомлений не выбраны." - "Текущий поставщик push-уведомлений: %1$s." - "Текущий поставщик push-уведомлений" - "Убедитесь, что у приложения есть хотя бы один поставщик push-сообщений." - "Поставщики push-уведомлений не найдены." - - "Найден %1$d push-провайдер: %2$s" - "Найдено %1$d push-провайдеров: %2$s" - "Найдено %1$d push-провайдеров: %2$s" - - "Обнаружение поставщиков push-уведомлений" - "Убедитесь, что приложение может отображать уведомление." - "Уведомление не было нажато." - "Невозможно отобразить уведомление." - "Уведомление было нажато!" - "Отобразить уведомление" - "Нажмите на уведомление, чтобы продолжить тест." - "Убедитесь, что Firebase доступен." - "Firebase недоступен." - "Firebase доступен." - "Проверить Firebase" - "Убедитесь, что токен Firebase доступен." - "Токен Firebase неизвестен." - "Токен Firebase: %1$s." - "Проверить токен Firebase" - "Убедитесь, что приложение получает push-сообщение." - "Ошибка: pusher отклонил запрос." - "Ошибка: %1$s." - "Ошибка, невозможно протестировать отправку." - "Ошибка, тайм-аут ожидания push-уведомления." - "Обратная отправка push-уведомления, заняла %1$d мс." - "Тест обратной отправки push-уведомления" - "Убедитесь, что дистрибьюторы UnifiedPush доступны." - "Поставщиков push-уведомлений не найдено." - - "%1$d провайдер найден: %2$s." - "%1$d провайдеров найдено: %2$s." - "%1$d провайдеров найдено: %2$s." - - "Проверка UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-sk/translations.xml b/libraries/ui-strings/src/main/res/values-sk/translations.xml index 61e7b50cc0..f49201bda1 100644 --- a/libraries/ui-strings/src/main/res/values-sk/translations.xml +++ b/libraries/ui-strings/src/main/res/values-sk/translations.xml @@ -274,57 +274,4 @@ "Poloha" "Verzia: %1$s (%2$s)" "sk" - "Riešenie problémov" - "Oznámenia riešení problémov" - "Spustiť testy" - "Spustiť testy znova" - "Niektoré testy zlyhali. Skontrolujte prosím podrobnosti." - "Spustite testy, aby ste zistili akýkoľvek problém vo vašej konfigurácii, ktorý môže spôsobiť, že sa upozornenia nebudú správať podľa očakávania." - "Pokus o opravu" - "Všetky testy prebehli úspešne." - "Oznámenia riešení problémov" - "Niektoré testy si vyžadujú vašu pozornosť. Prosím skontrolujte podrobnosti." - "Uistite sa, že aplikácia dokáže zobrazovať upozornenia." - "Skontrolovať povolenia" - "Získaťe názov aktuálneho poskytovateľa." - "Nie sú vybraní žiadni poskytovatelia push." - "Aktuálny poskytovateľ push: %1$s." - "Aktuálny poskytovateľ push" - "Uistite sa, že aplikácia má aspoň jedného poskytovateľa push." - "Nenašli sa žiadni poskytovatelia push." - - "Nájdený %1$d poskytovateľ služby push: %2$s" - "Nájdení %1$d poskytovatelia služby push: %2$s" - "Nájdených %1$d poskytovateľov služby push: %2$s" - - "Zistiť poskytovateľov push" - "Skontrolujte, či aplikácia dokáže zobraziť upozornenie." - "Na oznámenie nebolo kliknuté." - "Nie je možné zobraziť upozornenie." - "Na oznámenie bolo kliknuté!" - "Zobraziť upozornenie" - "Kliknite na upozornenie a pokračujte v teste." - "Uistite sa, že Firebase je k dispozícii." - "Firebase nie je k dispozícii." - "Firebase je k dispozícii." - "Skontrolovať Firebase" - "Uistite sa, že je k dispozícii token Firebase." - "Token Firebase nie je známy." - "Token Firebase: %1$s." - "Skontrolovať token Firebase" - "Uistite sa, že aplikácia prijíma push oznámenia." - "Chyba: pusher odmietol požiadavku." - "Chyba: %1$s." - "Chyba, nie je možné testovať push." - "Chyba, časový limit na push vypršal." - "Push loop back trvalo %1$d ms." - "Testovať Push loop back" - "Uistite sa, že sú dostupní distribútori UnifiedPush." - "Nenašli sa žiadni distribútori push." - - "%1$d nájdený distribútor: %2$s." - "%1$d nájdení distribútori: %2$s." - "%1$d nájdených distribútorov: %2$s." - - "Skontrolovať UnifiedPush" diff --git a/libraries/ui-strings/src/main/res/values-sv/translations.xml b/libraries/ui-strings/src/main/res/values-sv/translations.xml index 7ed1b0daa8..b7029fa178 100644 --- a/libraries/ui-strings/src/main/res/values-sv/translations.xml +++ b/libraries/ui-strings/src/main/res/values-sv/translations.xml @@ -182,6 +182,7 @@ "%1$s kunde inte komma åt din plats. Vänligen försök igen senare." "%1$s är inte behörig att komma åt din plats. Du kan aktivera åtkomst i Inställningar." "%1$s är inte behörig att komma åt din plats. Aktivera åtkomst nedan." + "%1$s är inte behörig att komma åt din mikrofon. Aktivera åtkomst för att spela in ett röstmeddelande." "Vissa meddelanden har inte skickats" "Tyvärr, ett fel uppstod" "🔐️ Häng med mig på %1$s" diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 1bc20364ce..2f9812fc79 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -272,55 +272,4 @@ "Version: %1$s (%2$s)" "en" "en" - "Troubleshoot" - "Troubleshoot notifications" - "Run tests" - "Run tests again" - "Some tests failed. Please check the details." - "Run the tests to detect any issue in your configuration that may make notifications not behave as expected." - "Attempt to fix" - "All tests passed successfully." - "Troubleshoot notifications" - "Some tests require your attention. Please check the details." - "Check that the application can show notifications." - "Check permissions" - "Get the name of the current provider." - "No push providers selected." - "Current push provider: %1$s." - "Current push provider" - "Ensure that the application has at least one push provider." - "No push providers found." - - "Found %1$d push provider: %2$s" - "Found %1$d push providers: %2$s" - - "Detect push providers" - "Check that the application can display notification." - "The notification has not been clicked." - "Cannot display the notification." - "The notification has been clicked!" - "Display notification" - "Please click on the notification to continue the test." - "Ensure that Firebase is available." - "Firebase is not available." - "Firebase is available." - "Check Firebase" - "Ensure that Firebase token is available." - "Firebase token is not known." - "Firebase token: %1$s." - "Check Firebase token" - "Ensure that the application is receiving push." - "Error: pusher has rejected the request." - "Error: %1$s." - "Error, cannot test push." - "Error, timeout waiting for push." - "Push loop back took %1$d ms." - "Test Push loop back" - "Ensure that UnifiedPush distributors are available." - "No push distributors found." - - "%1$d distributor found: %2$s." - "%1$d distributors found: %2$s." - - "Check UnifiedPush" From 52c039d6760ee359b075f4b21a87bad155080519 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 16:23:57 +0200 Subject: [PATCH 21/27] Rename `UserPushStoreFactory.create` to `UserPushStoreFactory.getOrCreate` for code clarity. --- .../impl/notifications/NotificationSettingsPresenter.kt | 2 +- .../libraries/push/impl/DefaultGetCurrentPushProvider.kt | 2 +- .../element/android/libraries/push/impl/DefaultPushService.kt | 2 +- .../io/element/android/libraries/push/impl/PushersManager.kt | 2 +- .../android/libraries/push/impl/push/DefaultPushHandler.kt | 2 +- .../pushproviders/firebase/FirebaseNewTokenHandler.kt | 2 +- .../pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt | 2 +- .../android/libraries/pushstore/api/UserPushStoreFactory.kt | 2 +- .../pushstore/impl/DefaultUserPushStoreFactoryTest.kt | 4 ++-- .../libraries/pushstore/impl/DefaultUserPushStoreFactory.kt | 4 ++-- .../pushstore/test/userpushstore/FakeUserPushStoreFactory.kt | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenter.kt index 7083b9f88b..9aa9cafb81 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenter.kt @@ -48,7 +48,7 @@ class NotificationSettingsPresenter @Inject constructor( ) : Presenter { @Composable override fun present(): NotificationSettingsState { - val userPushStore = remember { userPushStoreFactory.create(matrixClient.sessionId) } + val userPushStore = remember { userPushStoreFactory.getOrCreate(matrixClient.sessionId) } val systemNotificationsEnabled: MutableState = remember { mutableStateOf(systemNotificationsEnabledProvider.notificationsEnabled()) } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt index bdf36b7f31..977d41caca 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultGetCurrentPushProvider.kt @@ -35,7 +35,7 @@ class DefaultGetCurrentPushProvider @Inject constructor( .value .navigationState .currentSessionId() - ?.let { pushStoreFactory.create(it) } + ?.let { pushStoreFactory.getOrCreate(it) } ?.getPushProviderName() } } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt index 5a4df57b47..cff18cfb3d 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/DefaultPushService.kt @@ -49,7 +49,7 @@ class DefaultPushService @Inject constructor( * Get current push provider, compare with provided one, then unregister and register if different, and store change. */ override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributor: Distributor) { - val userPushStore = userPushStoreFactory.create(matrixClient.sessionId) + val userPushStore = userPushStoreFactory.getOrCreate(matrixClient.sessionId) val currentPushProviderName = userPushStore.getPushProviderName() if (currentPushProviderName != pushProvider.name) { // Unregister previous one if any diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt index dbefc03126..4306072e48 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/PushersManager.kt @@ -63,7 +63,7 @@ class PushersManager @Inject constructor( * Register a pusher to the server if not done yet. */ override suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) { - val userDataStore = userPushStoreFactory.create(matrixClient.sessionId) + val userDataStore = userPushStoreFactory.getOrCreate(matrixClient.sessionId) if (userDataStore.getCurrentRegisteredPushKey() == pushKey) { Timber.tag(loggerTag.value) .d("Unnecessary to register again the same pusher, but do it in case the pusher has been removed from the server") diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 5de0620eca..2c9abb77b3 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -122,7 +122,7 @@ class DefaultPushHandler @Inject constructor( return } - val userPushStore = userPushStoreFactory.create(userId) + val userPushStore = userPushStoreFactory.getOrCreate(userId) if (!userPushStore.getNotificationEnabledForDevice().first()) { // TODO We need to check if this is an incoming call Timber.tag(loggerTag.value).i("Notification are disabled for this device, ignore push.") diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt index 313b9ab706..20d0de4ebf 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/FirebaseNewTokenHandler.kt @@ -44,7 +44,7 @@ class FirebaseNewTokenHandler @Inject constructor( sessionStore.getAllSessions().toUserList() .map { SessionId(it) } .forEach { userId -> - val userDataStore = userPushStoreFactory.create(userId) + val userDataStore = userPushStoreFactory.getOrCreate(userId) if (userDataStore.getPushProviderName() == FirebaseConfig.NAME) { matrixAuthenticationService.restoreSession(userId).getOrNull()?.use { client -> pusherSubscriber.registerPusher(client, firebaseToken, FirebaseConfig.PUSHER_HTTP_URL) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt index 2ae8753a1e..4ee637a3ab 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushNewGatewayHandler.kt @@ -40,7 +40,7 @@ class UnifiedPushNewGatewayHandler @Inject constructor( val userId = pushClientSecret.getUserIdFromSecret(clientSecret) ?: return Unit.also { Timber.w("Unable to retrieve session") } - val userDataStore = userPushStoreFactory.create(userId) + val userDataStore = userPushStoreFactory.getOrCreate(userId) if (userDataStore.getPushProviderName() == UnifiedPushConfig.NAME) { matrixAuthenticationService.restoreSession(userId).getOrNull()?.use { client -> pusherSubscriber.registerPusher(client, endpoint, pushGateway) diff --git a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStoreFactory.kt b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStoreFactory.kt index 52e4596ca0..95097845ab 100644 --- a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStoreFactory.kt +++ b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStoreFactory.kt @@ -22,5 +22,5 @@ import io.element.android.libraries.matrix.api.core.SessionId * Store data related to push about a user. */ interface UserPushStoreFactory { - fun create(userId: SessionId): UserPushStore + fun getOrCreate(userId: SessionId): UserPushStore } diff --git a/libraries/pushstore/impl/src/androidTest/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactoryTest.kt b/libraries/pushstore/impl/src/androidTest/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactoryTest.kt index b7bbf46dc4..7f130459fa 100644 --- a/libraries/pushstore/impl/src/androidTest/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactoryTest.kt +++ b/libraries/pushstore/impl/src/androidTest/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactoryTest.kt @@ -40,11 +40,11 @@ class DefaultUserPushStoreFactoryTest { val userPushStoreFactory = DefaultUserPushStoreFactory(context, NoOpSessionObserver()) var userPushStore1: UserPushStore? = null val thread1 = thread { - userPushStore1 = userPushStoreFactory.create(sessionId) + userPushStore1 = userPushStoreFactory.getOrCreate(sessionId) } var userPushStore2: UserPushStore? = null val thread2 = thread { - userPushStore2 = userPushStoreFactory.create(sessionId) + userPushStore2 = userPushStoreFactory.getOrCreate(sessionId) } thread1.join() thread2.join() diff --git a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactory.kt b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactory.kt index 8c85dca80c..3c65c76a01 100644 --- a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactory.kt +++ b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/DefaultUserPushStoreFactory.kt @@ -41,7 +41,7 @@ class DefaultUserPushStoreFactory @Inject constructor( // We can have only one class accessing a single data store, so keep a cache of them. private val cache = ConcurrentHashMap() - override fun create(userId: SessionId): UserPushStore { + override fun getOrCreate(userId: SessionId): UserPushStore { return cache.getOrPut(userId) { UserPushStoreDataStore( context = context, @@ -60,6 +60,6 @@ class DefaultUserPushStoreFactory @Inject constructor( override suspend fun onSessionDeleted(userId: String) { // Delete the store - create(SessionId(userId)).reset() + getOrCreate(SessionId(userId)).reset() } } diff --git a/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStoreFactory.kt b/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStoreFactory.kt index a529e34bc1..2f4f524cc2 100644 --- a/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStoreFactory.kt +++ b/libraries/pushstore/test/src/main/kotlin/com/element/android/libraries/pushstore/test/userpushstore/FakeUserPushStoreFactory.kt @@ -21,7 +21,7 @@ import io.element.android.libraries.pushstore.api.UserPushStore import io.element.android.libraries.pushstore.api.UserPushStoreFactory class FakeUserPushStoreFactory : UserPushStoreFactory { - override fun create(userId: SessionId): UserPushStore { + override fun getOrCreate(userId: SessionId): UserPushStore { return FakeUserPushStore() } } From 4f320fd4f81ac42e58b91e6db8beec4e326c6ed9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 16:40:07 +0200 Subject: [PATCH 22/27] Code clarity: use withTimeout with combination of runCatching instead of withTimeoutOrNull --- .../impl/troubleshoot/NotificationTest.kt | 38 ++++++++++--------- .../impl/troubleshoot/PushLoopbackTest.kt | 36 ++++++++++-------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt index d7e3641e22..26b7161fca 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt @@ -29,7 +29,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeoutOrNull +import kotlinx.coroutines.withTimeout import timber.log.Timber import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -72,22 +72,26 @@ class NotificationTest @Inject constructor( notificationClickHandler.state.first() Timber.d("Notification clicked!") } - val s = withTimeoutOrNull(30.seconds) { - job.join() - } - job.cancel() - if (s == null) { - notificationDisplayer.dismissDiagnosticNotification() - delegate.updateState( - description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_failure), - status = NotificationTroubleshootTestState.Status.Failure(false) - ) - } else { - delegate.updateState( - description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_success), - status = NotificationTroubleshootTestState.Status.Success - ) - } + runCatching { + withTimeout(30.seconds) { + job.join() + } + }.fold( + onSuccess = { + delegate.updateState( + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_success), + status = NotificationTroubleshootTestState.Status.Success + ) + }, + onFailure = { + job.cancel() + notificationDisplayer.dismissDiagnosticNotification() + delegate.updateState( + description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_failure), + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + ) }.invokeOnCompletion { // Ensure that the notification is cancelled when the screen is left notificationDisplayer.dismissDiagnosticNotification() diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt index 2ecec61996..861554bef8 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt @@ -31,7 +31,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeoutOrNull +import kotlinx.coroutines.withTimeout import timber.log.Timber import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -84,21 +84,25 @@ class PushLoopbackTest @Inject constructor( job.cancel() return } - val result = withTimeoutOrNull(10.seconds) { - completable.await() - } - job.cancel() - if (result == null) { - delegate.updateState( - description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_4), - status = NotificationTroubleshootTestState.Status.Failure(false) - ) - } else { - delegate.updateState( - description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_success, result), - status = NotificationTroubleshootTestState.Status.Success - ) - } + runCatching { + withTimeout(10.seconds) { + completable.await() + } + }.fold( + onSuccess = { duration -> + delegate.updateState( + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_success, duration), + status = NotificationTroubleshootTestState.Status.Success + ) + }, + onFailure = { + job.cancel() + delegate.updateState( + description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_4), + status = NotificationTroubleshootTestState.Status.Failure(false) + ) + } + ) } override suspend fun reset() = delegate.reset() From cb435c523b5cf74cc149fbd740c559d5b45b1c7a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 18:03:39 +0200 Subject: [PATCH 23/27] Create dedicated module for notification troubleshoot. --- features/preferences/impl/build.gradle.kts | 1 + .../preferences/impl/PreferencesFlowNode.kt | 12 +++- .../src/main/res/values-be/translations.xml | 8 --- .../src/main/res/values-cs/translations.xml | 8 --- .../src/main/res/values-de/translations.xml | 8 --- .../src/main/res/values-fr/translations.xml | 8 --- .../src/main/res/values-hu/translations.xml | 8 --- .../src/main/res/values-in/translations.xml | 8 --- .../src/main/res/values-ru/translations.xml | 8 --- .../src/main/res/values-sk/translations.xml | 8 --- .../impl/src/main/res/values/localazy.xml | 8 --- libraries/permissions/impl/build.gradle.kts | 1 + ...ficationTroubleshootCheckPermissionTest.kt | 6 +- ...tionTroubleshootCheckPermissionTestTest.kt | 1 - libraries/push/impl/build.gradle.kts | 1 + .../troubleshoot/CurrentPushProviderTest.kt | 6 +- .../impl/troubleshoot/NotificationTest.kt | 6 +- .../impl/troubleshoot/PushLoopbackTest.kt | 6 +- .../impl/troubleshoot/PushProvidersTest.kt | 6 +- .../CurrentPushProviderTestTest.kt | 2 +- .../impl/troubleshoot/NotificationTestTest.kt | 2 +- .../impl/troubleshoot/PushLoopbackTestTest.kt | 2 +- .../troubleshoot/PushProvidersTestTest.kt | 2 +- .../pushproviders/firebase/build.gradle.kts | 1 + .../troubleshoot/FirebaseAvailabilityTest.kt | 8 +-- .../troubleshoot/FirebaseTokenTest.kt | 8 +-- .../FirebaseAvailabilityTestTest.kt | 2 +- .../troubleshoot/FirebaseTokenTestTest.kt | 2 +- .../unifiedpush/build.gradle.kts | 1 + .../troubleshoot/UnifiedPushTest.kt | 8 +-- .../troubleshoot/UnifiedPushTestTest.kt | 2 +- libraries/troubleshoot/api/build.gradle.kts | 28 +++++++++ .../api/NotificationTroubleShootEntryPoint.kt | 35 +++++++++++ .../api/test}/NotificationTroubleshootTest.kt | 2 +- .../NotificationTroubleshootTestDelegate.kt | 2 +- .../NotificationTroubleshootTestState.kt | 2 +- .../troubleshoot/api/test}/TestFilterData.kt | 2 +- libraries/troubleshoot/impl/build.gradle.kts | 58 +++++++++++++++++++ ...faultNotificationTroubleShootEntryPoint.kt | 44 ++++++++++++++ .../impl}/TroubleshootNotificationsEvents.kt | 2 +- .../impl}/TroubleshootNotificationsNode.kt | 12 +++- .../TroubleshootNotificationsPresenter.kt | 2 +- .../impl}/TroubleshootNotificationsState.kt | 2 +- .../TroubleshootNotificationsStateProvider.kt | 4 +- .../impl}/TroubleshootNotificationsView.kt | 7 +-- .../impl}/TroubleshootTestSuite.kt | 8 +-- .../impl}/TroubleshootTestSuiteState.kt | 4 +- .../src/main/res/values-be/translations.xml | 11 ++++ .../src/main/res/values-cs/translations.xml | 11 ++++ .../src/main/res/values-de/translations.xml | 11 ++++ .../src/main/res/values-fr/translations.xml | 11 ++++ .../src/main/res/values-hu/translations.xml | 11 ++++ .../src/main/res/values-ru/translations.xml | 11 ++++ .../src/main/res/values-sk/translations.xml | 11 ++++ .../impl/src/main/res/values/localazy.xml | 11 ++++ .../impl}/FakeNotificationTroubleshootTest.kt | 6 +- ...TroubleshootNotificationsPresenterTests.kt | 8 +-- .../TroubleshootNotificationsViewTest.kt | 14 ++++- .../kotlin/extension/DependencyHandleScope.kt | 1 + tools/localazy/config.json | 7 ++- 60 files changed, 355 insertions(+), 141 deletions(-) create mode 100644 libraries/troubleshoot/api/build.gradle.kts create mode 100644 libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/NotificationTroubleShootEntryPoint.kt rename libraries/{core/src/main/kotlin/io/element/android/libraries/core/notifications => troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test}/NotificationTroubleshootTest.kt (94%) rename libraries/{core/src/main/kotlin/io/element/android/libraries/core/notifications => troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test}/NotificationTroubleshootTestDelegate.kt (97%) rename libraries/{core/src/main/kotlin/io/element/android/libraries/core/notifications => troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test}/NotificationTroubleshootTestState.kt (94%) rename libraries/{core/src/main/kotlin/io/element/android/libraries/core/notifications => troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test}/TestFilterData.kt (91%) create mode 100644 libraries/troubleshoot/impl/build.gradle.kts create mode 100644 libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/DefaultNotificationTroubleShootEntryPoint.kt rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsEvents.kt (91%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsNode.kt (82%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsPresenter.kt (96%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsState.kt (91%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsStateProvider.kt (96%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsView.kt (96%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootTestSuite.kt (93%) rename {features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootTestSuiteState.kt (83%) create mode 100644 libraries/troubleshoot/impl/src/main/res/values-be/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-cs/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-de/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-fr/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-hu/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values-sk/translations.xml create mode 100644 libraries/troubleshoot/impl/src/main/res/values/localazy.xml rename {features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl}/FakeNotificationTroubleshootTest.kt (91%) rename {features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsPresenterTests.kt (94%) rename {features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot => libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl}/TroubleshootNotificationsViewTest.kt (91%) diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index 415f0e36b4..edfb275f17 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -49,6 +49,7 @@ dependencies { implementation(projects.libraries.pushstore.api) implementation(projects.libraries.indicator.api) implementation(projects.libraries.preferences.api) + implementation(projects.libraries.troubleshoot.api) implementation(projects.libraries.testtags) implementation(projects.libraries.uiStrings) implementation(projects.libraries.matrixui) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index 5f57ad8b5e..1dc5f650fd 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -24,6 +24,7 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -39,7 +40,6 @@ import io.element.android.features.preferences.impl.developer.DeveloperSettingsN import io.element.android.features.preferences.impl.developer.tracing.ConfigureTracingNode import io.element.android.features.preferences.impl.notifications.NotificationSettingsNode import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingNode -import io.element.android.features.preferences.impl.notifications.troubleshoot.TroubleshootNotificationsNode import io.element.android.features.preferences.impl.root.PreferencesRootNode import io.element.android.features.preferences.impl.user.editprofile.EditUserProfileNode import io.element.android.libraries.architecture.BackstackView @@ -48,6 +48,7 @@ import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) @@ -55,6 +56,7 @@ class PreferencesFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val lockScreenEntryPoint: LockScreenEntryPoint, + private val notificationTroubleShootEntryPoint: NotificationTroubleShootEntryPoint, private val logoutEntryPoint: LogoutEntryPoint, ) : BaseFlowNode( backstack = BackStack( @@ -189,7 +191,13 @@ class PreferencesFlowNode @AssistedInject constructor( createNode(buildContext, listOf(notificationSettingsCallback)) } NavTarget.TroubleshootNotifications -> { - createNode(buildContext) + notificationTroubleShootEntryPoint.nodeBuilder(this, buildContext) + .callback(object : NotificationTroubleShootEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + }) + .build() } is NavTarget.EditDefaultNotificationSetting -> { val callback = object : EditDefaultNotificationSettingNode.Callback { diff --git a/features/preferences/impl/src/main/res/values-be/translations.xml b/features/preferences/impl/src/main/res/values-be/translations.xml index 0a8e477f7f..450a47ce61 100644 --- a/features/preferences/impl/src/main/res/values-be/translations.xml +++ b/features/preferences/impl/src/main/res/values-be/translations.xml @@ -51,12 +51,4 @@ "Апавяшчэнні" "Выпраўленне непаладак" "Выпраўленне непаладак з апавяшчэннямі" - "Запусціць тэсты" - "Запусціце тэсты яшчэ раз" - "Некаторыя тэсты не ўдаліся. Калі ласка, праглядзіце дэталі." - "Запусціце тэсты, каб выявіць праблемы ў вашай канфігурацыі, з-за якіх апавяшчэння могуць паводзіць сябе не так, як чакалася." - "Спроба выпраўлення" - "Усе тэсты паспяхова пройдзены." - "Выпраўленне непаладак з апавяшчэннямі" - "Некаторыя тэсты патрабуюць вашай увагі. Калі ласка, праглядзіце дэталі." diff --git a/features/preferences/impl/src/main/res/values-cs/translations.xml b/features/preferences/impl/src/main/res/values-cs/translations.xml index a2a3cc5955..60bc4b2b3e 100644 --- a/features/preferences/impl/src/main/res/values-cs/translations.xml +++ b/features/preferences/impl/src/main/res/values-cs/translations.xml @@ -53,12 +53,4 @@ Pokud budete pokračovat, některá nastavení se mohou změnit." "Oznámení" "Odstraňování problémů" "Odstraňování problémů s upozorněními" - "Spustit testy" - "Spustit testy znovu" - "Některé testy selhaly. Zkontrolujte prosím podrobnosti." - "Spusťte testy, abyste zjistili jakýkoli problém ve vaší konfiguraci, který může způsobit, že se oznámení nebudou chovat podle očekávání." - "Pokus o opravu" - "Všechny testy proběhly úspěšně." - "Odstraňování problémů s upozorněními" - "Některé testy vyžadují vaši pozornost. Zkontrolujte prosím podrobnosti." diff --git a/features/preferences/impl/src/main/res/values-de/translations.xml b/features/preferences/impl/src/main/res/values-de/translations.xml index 04a27f9db6..65b4923452 100644 --- a/features/preferences/impl/src/main/res/values-de/translations.xml +++ b/features/preferences/impl/src/main/res/values-de/translations.xml @@ -51,12 +51,4 @@ Wenn du fortfährst, können sich einige deiner Einstellungen ändern." "Benachrichtigungen" "Fehlerbehebung" "Fehlerbehebung für Benachrichtigungen" - "Tests durchführen" - "Tests erneut durchführen" - "Einige Tests sind fehlgeschlagen. Bitte überprüfe die Details." - "Führe die Tests durch, um Probleme zu erkennen, die dazu führen können, dass sich die Benachrichtigungen nicht wie erwartet verhalten." - "Versuche das Problem zu beheben" - "Alle Tests wurden erfolgreich bestanden." - "Fehlerbehebung für Benachrichtigungen" - "Einige Tests erfordern deine Aufmerksamkeit. Bitte überprüfe die Details." diff --git a/features/preferences/impl/src/main/res/values-fr/translations.xml b/features/preferences/impl/src/main/res/values-fr/translations.xml index 426c475d4c..9c415fea2d 100644 --- a/features/preferences/impl/src/main/res/values-fr/translations.xml +++ b/features/preferences/impl/src/main/res/values-fr/translations.xml @@ -51,12 +51,4 @@ Si vous continuez, il est possible que certains de vos paramètres soient modifi "Notifications" "Dépannage" "Résoudre les problèmes liés aux notifications" - "Exécuter les tests" - "Relancer les tests" - "Certains tests ont échoué. Veuillez vérifier les détails." - "Exécuter les tests pour détecter tout problème dans votre configuration susceptible de provoquer un dysfonctionnement des notifications." - "Tenter de corriger" - "Tous les tests ont réussi." - "Dépanner les notifications" - "Certains tests nécessitent votre attention. Veuillez vérifier les détails." diff --git a/features/preferences/impl/src/main/res/values-hu/translations.xml b/features/preferences/impl/src/main/res/values-hu/translations.xml index 3574b49e6e..841695edcf 100644 --- a/features/preferences/impl/src/main/res/values-hu/translations.xml +++ b/features/preferences/impl/src/main/res/values-hu/translations.xml @@ -51,12 +51,4 @@ Ha folytatja, egyes beállítások megváltozhatnak." "Értesítések" "Hibaelhárítás" "Értesítések hibaelhárítása" - "Tesztek futtatása" - "Tesztek újbóli futtatása" - "Egyes tesztek sikertelenek voltak. Ellenőrizze a részleteket." - "A tesztek futtatása, hogy észlelje a konfigurációban felmerülő olyan problémákat, amelyek miatt az értesítések nem az elvárt módon viselkednek." - "Kísérlet a javításra" - "Minden teszt sikeresen lezajlott." - "Értesítések hibaelhárítása" - "Egyes tesztek a figyelmét igénylik. Ellenőrizze a részleteket." diff --git a/features/preferences/impl/src/main/res/values-in/translations.xml b/features/preferences/impl/src/main/res/values-in/translations.xml index 13ac802d4d..8bca603eeb 100644 --- a/features/preferences/impl/src/main/res/values-in/translations.xml +++ b/features/preferences/impl/src/main/res/values-in/translations.xml @@ -53,12 +53,4 @@ Jika Anda melanjutkan, beberapa pengaturan Anda dapat berubah." "Notifikasi" "Pemecahan masalah" "Pecahkan masalah notifikasi" - "Jalankan tes" - "Jalankan tes lagi" - "Beberapa tes gagal. Silakan periksa detailnya." - "Jalankan pengujian untuk mendeteksi masalah apa pun dalam konfigurasi Anda yang mungkin membuat notifikasi tidak berperilaku seperti yang diharapkan." - "Mencoba untuk memperbaiki" - "Semua tes berhasil dilalui." - "Pecahkan masalah notifikasi" - "Beberapa tes membutuhkan perhatian Anda. Silakan periksa detailnya." diff --git a/features/preferences/impl/src/main/res/values-ru/translations.xml b/features/preferences/impl/src/main/res/values-ru/translations.xml index ca18672e97..3b24cf8c80 100644 --- a/features/preferences/impl/src/main/res/values-ru/translations.xml +++ b/features/preferences/impl/src/main/res/values-ru/translations.xml @@ -51,12 +51,4 @@ "Уведомления" "Устранение неполадок" "Уведомления об устранении неполадок" - "Выполнение тестов" - "Повторное выполнение тестов" - "Некоторые тесты провалились. Пожалуйста, проверьте детали." - "Выполните тесты, чтобы обнаружить любую проблему в конфигурации, из-за которой уведомления могут работать не так, как ожидалось." - "Попытка исправить" - "Все тесты прошли успешно." - "Уведомления об устранении неполадок" - "Некоторые тесты требуют вашего внимания. Пожалуйста, проверьте детали." diff --git a/features/preferences/impl/src/main/res/values-sk/translations.xml b/features/preferences/impl/src/main/res/values-sk/translations.xml index 12289b46f4..f382d0ab6f 100644 --- a/features/preferences/impl/src/main/res/values-sk/translations.xml +++ b/features/preferences/impl/src/main/res/values-sk/translations.xml @@ -53,12 +53,4 @@ Ak budete pokračovať, niektoré z vašich nastavení sa môžu zmeniť.""Oznámenia" "Riešenie problémov" "Oznámenia riešení problémov" - "Spustiť testy" - "Spustiť testy znova" - "Niektoré testy zlyhali. Skontrolujte prosím podrobnosti." - "Spustite testy, aby ste zistili akýkoľvek problém vo vašej konfigurácii, ktorý môže spôsobiť, že sa upozornenia nebudú správať podľa očakávania." - "Pokus o opravu" - "Všetky testy prebehli úspešne." - "Oznámenia riešení problémov" - "Niektoré testy si vyžadujú vašu pozornosť. Prosím skontrolujte podrobnosti." diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml index b0e78e0d9e..56a5c0ba03 100644 --- a/features/preferences/impl/src/main/res/values/localazy.xml +++ b/features/preferences/impl/src/main/res/values/localazy.xml @@ -51,12 +51,4 @@ If you proceed, some of your settings may change." "Notifications" "Troubleshoot" "Troubleshoot notifications" - "Run tests" - "Run tests again" - "Some tests failed. Please check the details." - "Run the tests to detect any issue in your configuration that may make notifications not behave as expected." - "Attempt to fix" - "All tests passed successfully." - "Troubleshoot notifications" - "Some tests require your attention. Please check the details." diff --git a/libraries/permissions/impl/build.gradle.kts b/libraries/permissions/impl/build.gradle.kts index 82904bc750..7b80ef0d4f 100644 --- a/libraries/permissions/impl/build.gradle.kts +++ b/libraries/permissions/impl/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrixui) + implementation(projects.libraries.troubleshoot.api) implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) implementation(projects.services.toolbox.api) diff --git a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt index 903b5cd2c4..7e916c37b5 100644 --- a/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt +++ b/libraries/permissions/impl/src/main/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTest.kt @@ -19,13 +19,13 @@ package io.element.android.libraries.permissions.impl.troubleshoot import android.Manifest import android.os.Build import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.permissions.api.PermissionStateProvider import io.element.android.libraries.permissions.impl.R import io.element.android.libraries.permissions.impl.action.PermissionActions +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope diff --git a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt index c17e61f5e7..df0214b08d 100644 --- a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt +++ b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt @@ -19,7 +19,6 @@ package io.element.android.libraries.permissions.impl.troubleshoot import android.os.Build import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.permissions.impl.FakePermissionStateProvider import io.element.android.libraries.permissions.impl.action.FakePermissionActions import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider diff --git a/libraries/push/impl/build.gradle.kts b/libraries/push/impl/build.gradle.kts index f16f7f23f0..ee528a4ae7 100644 --- a/libraries/push/impl/build.gradle.kts +++ b/libraries/push/impl/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrixui) implementation(projects.libraries.uiStrings) + implementation(projects.libraries.troubleshoot.api) api(projects.libraries.pushproviders.api) api(projects.libraries.pushstore.api) api(projects.libraries.push.api) diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt index 7a819b3d93..3e7fe1ae59 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTest.kt @@ -17,12 +17,12 @@ package io.element.android.libraries.push.impl.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.api.GetCurrentPushProvider import io.element.android.libraries.push.impl.R +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt index 26b7161fca..8de8304c2d 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTest.kt @@ -17,13 +17,13 @@ package io.element.android.libraries.push.impl.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.notifications.NotificationDisplayer import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt index 861554bef8..42a6394fc9 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTest.kt @@ -17,13 +17,13 @@ package io.element.android.libraries.push.impl.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.gateway.PushGatewayFailure import io.element.android.libraries.push.impl.R +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CompletableDeferred diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt index df6d220396..190cf8fe98 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTest.kt @@ -17,12 +17,12 @@ package io.element.android.libraries.push.impl.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.di.AppScope import io.element.android.libraries.push.impl.R import io.element.android.libraries.pushproviders.api.PushProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt index ea8de71222..7f7beb9d9b 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/CurrentPushProviderTestTest.kt @@ -18,8 +18,8 @@ package io.element.android.libraries.push.impl.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt index a900d50b1f..1351117527 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/NotificationTestTest.kt @@ -18,9 +18,9 @@ package io.element.android.libraries.push.impl.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt index 01fe2b9847..2c1363af78 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushLoopbackTestTest.kt @@ -18,11 +18,11 @@ package io.element.android.libraries.push.impl.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_FAILURE_REASON import io.element.android.libraries.push.api.gateway.PushGatewayFailure import io.element.android.libraries.push.test.FakePushService +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import kotlinx.coroutines.launch diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt index cf7f750403..e58a490715 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/troubleshoot/PushProvidersTestTest.kt @@ -18,8 +18,8 @@ package io.element.android.libraries.push.impl.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.test.FakePushProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/pushproviders/firebase/build.gradle.kts b/libraries/pushproviders/firebase/build.gradle.kts index de19420923..6e36b92a09 100644 --- a/libraries/pushproviders/firebase/build.gradle.kts +++ b/libraries/pushproviders/firebase/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(projects.libraries.di) implementation(projects.libraries.matrix.api) implementation(projects.libraries.uiStrings) + implementation(projects.libraries.troubleshoot.api) implementation(projects.services.toolbox.api) implementation(projects.libraries.pushstore.api) diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt index 64a5bad67f..6cca3d21af 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTest.kt @@ -17,14 +17,14 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.di.AppScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable import io.element.android.libraries.pushproviders.firebase.R +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.TestFilterData import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt index b2164cda32..a465ca3a7b 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTest.kt @@ -17,15 +17,15 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.di.AppScope import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.FirebaseStore import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter import io.element.android.libraries.pushproviders.firebase.R +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.TestFilterData import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt index 0c742fa567..6f1a3da7cb 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseAvailabilityTestTest.kt @@ -18,8 +18,8 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt index b76e6861fc..2d8de62ad9 100644 --- a/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt +++ b/libraries/pushproviders/firebase/src/test/kotlin/io/element/android/libraries/pushproviders/firebase/troubleshoot/FirebaseTokenTestTest.kt @@ -18,9 +18,9 @@ package io.element.android.libraries.pushproviders.firebase.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.firebase.FakeFirebaseTroubleshooter import io.element.android.libraries.pushproviders.firebase.InMemoryFirebaseStore +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/pushproviders/unifiedpush/build.gradle.kts b/libraries/pushproviders/unifiedpush/build.gradle.kts index 190c63d350..d5dcc9727d 100644 --- a/libraries/pushproviders/unifiedpush/build.gradle.kts +++ b/libraries/pushproviders/unifiedpush/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { implementation(projects.libraries.core) implementation(projects.libraries.matrix.api) implementation(projects.libraries.uiStrings) + api(projects.libraries.troubleshoot.api) implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushproviders.api) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt index ec3b95e437..77a2347429 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTest.kt @@ -17,14 +17,14 @@ package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot import com.squareup.anvil.annotations.ContributesMultibinding -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.di.AppScope import io.element.android.libraries.pushproviders.unifiedpush.R import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.TestFilterData import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt index 29301515cd..117e8b7457 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/troubleshoot/UnifiedPushTestTest.kt @@ -18,8 +18,8 @@ package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.pushproviders.api.Distributor +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/libraries/troubleshoot/api/build.gradle.kts b/libraries/troubleshoot/api/build.gradle.kts new file mode 100644 index 0000000000..5ac917fd0b --- /dev/null +++ b/libraries/troubleshoot/api/build.gradle.kts @@ -0,0 +1,28 @@ +/* + * 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. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.libraries.troubleshoot.api" +} + +dependencies { + implementation(projects.libraries.architecture) + implementation(libs.androidx.corektx) + implementation(libs.coroutines.core) +} diff --git a/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/NotificationTroubleShootEntryPoint.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/NotificationTroubleShootEntryPoint.kt new file mode 100644 index 0000000000..6e4e1c39e3 --- /dev/null +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/NotificationTroubleShootEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * 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.libraries.troubleshoot.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint + +interface NotificationTroubleShootEntryPoint : FeatureEntryPoint { + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + fun onDone() + } +} diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt similarity index 94% rename from libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt rename to libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt index 7af0b85ffb..69073925fb 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTest.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.libraries.core.notifications +package io.element.android.libraries.troubleshoot.api.test import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.StateFlow diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestDelegate.kt similarity index 97% rename from libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt rename to libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestDelegate.kt index 88aaae7281..da36de8ee7 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestDelegate.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestDelegate.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.libraries.core.notifications +package io.element.android.libraries.troubleshoot.api.test import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt similarity index 94% rename from libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt rename to libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt index 9657be4b3b..1429916bcc 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/NotificationTroubleshootTestState.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/NotificationTroubleshootTestState.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.libraries.core.notifications +package io.element.android.libraries.troubleshoot.api.test data class NotificationTroubleshootTestState( val name: String, diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/TestFilterData.kt similarity index 91% rename from libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt rename to libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/TestFilterData.kt index e22fefb7f1..77f633363d 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/notifications/TestFilterData.kt +++ b/libraries/troubleshoot/api/src/main/kotlin/io/element/android/libraries/troubleshoot/api/test/TestFilterData.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.libraries.core.notifications +package io.element.android.libraries.troubleshoot.api.test data class TestFilterData( val currentPushProviderName: String?, diff --git a/libraries/troubleshoot/impl/build.gradle.kts b/libraries/troubleshoot/impl/build.gradle.kts new file mode 100644 index 0000000000..b5a0a9012d --- /dev/null +++ b/libraries/troubleshoot/impl/build.gradle.kts @@ -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. + */ +plugins { + id("io.element.android-compose-library") + alias(libs.plugins.anvil) + alias(libs.plugins.kotlin.serialization) +} + +android { + namespace = "io.element.android.libraries.troubleshoot.impl" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } +} + +anvil { + generateDaggerFactories.set(true) +} + +dependencies { + implementation(projects.anvilannotations) + anvil(projects.anvilcodegen) + implementation(libs.dagger) + implementation(projects.libraries.architecture) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.di) + api(projects.libraries.troubleshoot.api) + api(projects.libraries.push.api) + implementation(projects.services.analytics.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.robolectric) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(libs.coroutines.test) + testImplementation(projects.services.analytics.test) + testImplementation(projects.tests.testutils) + testImplementation(projects.libraries.push.test) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/DefaultNotificationTroubleShootEntryPoint.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/DefaultNotificationTroubleShootEntryPoint.kt new file mode 100644 index 0000000000..81c0cdaf00 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/DefaultNotificationTroubleShootEntryPoint.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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.libraries.troubleshoot.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultNotificationTroubleShootEntryPoint @Inject constructor() : NotificationTroubleShootEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NotificationTroubleShootEntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : NotificationTroubleShootEntryPoint.NodeBuilder { + override fun callback(callback: NotificationTroubleShootEntryPoint.Callback): NotificationTroubleShootEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsEvents.kt similarity index 91% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsEvents.kt index a6b361de13..f2398e3b78 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsEvents.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsEvents.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl sealed interface TroubleshootNotificationsEvents { data object StartTests : TroubleshootNotificationsEvents diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsNode.kt similarity index 82% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsNode.kt index a662e94db8..96404d6d8c 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsNode.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsNode.kt @@ -14,18 +14,20 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint import io.element.android.services.analytics.api.ScreenTracker @ContributesNode(SessionScope::class) @@ -35,13 +37,19 @@ class TroubleshootNotificationsNode @AssistedInject constructor( private val presenter: TroubleshootNotificationsPresenter, private val screenTracker: ScreenTracker, ) : Node(buildContext, plugins = plugins) { + private fun onDone() { + plugins().forEach { + it.onDone() + } + } + @Composable override fun View(modifier: Modifier) { screenTracker.TrackScreen(MobileScreen.ScreenName.NotificationTroubleshoot) val state = presenter.present() TroubleshootNotificationsView( state = state, - onBackPressed = ::navigateUp, + onBackPressed = ::onDone, modifier = modifier, ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenter.kt similarity index 96% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenter.kt index 1ccbf86ce9..a730199fac 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenter.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenter.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsState.kt similarity index 91% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsState.kt index 55032b2fe9..4ff7c2c04c 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsState.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsState.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl data class TroubleshootNotificationsState( val testSuiteState: TroubleshootTestSuiteState, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsStateProvider.kt similarity index 96% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsStateProvider.kt index 316bd72ad7..f2d49a82a0 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsStateProvider.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsStateProvider.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import kotlinx.collections.immutable.toImmutableList open class TroubleshootNotificationsStateProvider : PreviewParameterProvider { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt similarity index 96% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt index 08d56e5bd0..8b2ba843be 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsView.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsView.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size @@ -27,10 +27,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.features.preferences.impl.R import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState.Status import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.preferences.PreferencePage import io.element.android.libraries.designsystem.preview.ElementPreview @@ -41,6 +38,8 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.ListItem import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.OnLifecycleEvent +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState.Status @Composable fun TroubleshootNotificationsView( diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuite.kt similarity index 93% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuite.kt index 361cf1601f..1c5fbbc3e3 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuite.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuite.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import im.vector.app.features.analytics.plan.NotificationTroubleshoot import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState -import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.push.api.GetCurrentPushProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.TestFilterData import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuiteState.kt similarity index 83% rename from features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt rename to libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuiteState.kt index e516b65109..32e71ff9a5 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootTestSuiteState.kt +++ b/libraries/troubleshoot/impl/src/main/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootTestSuiteState.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import kotlinx.collections.immutable.ImmutableList data class TroubleshootTestSuiteState( diff --git a/libraries/troubleshoot/impl/src/main/res/values-be/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..905b9e89b6 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,11 @@ + + + "Запусціць тэсты" + "Запусціце тэсты яшчэ раз" + "Некаторыя тэсты не ўдаліся. Калі ласка, праглядзіце дэталі." + "Запусціце тэсты, каб выявіць праблемы ў вашай канфігурацыі, з-за якіх апавяшчэння могуць паводзіць сябе не так, як чакалася." + "Спроба выпраўлення" + "Усе тэсты паспяхова пройдзены." + "Выпраўленне непаладак з апавяшчэннямі" + "Некаторыя тэсты патрабуюць вашай увагі. Калі ласка, праглядзіце дэталі." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-cs/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..17e47cf56f --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,11 @@ + + + "Spustit testy" + "Spustit testy znovu" + "Některé testy selhaly. Zkontrolujte prosím podrobnosti." + "Spusťte testy, abyste zjistili jakýkoli problém ve vaší konfiguraci, který může způsobit, že se oznámení nebudou chovat podle očekávání." + "Pokus o opravu" + "Všechny testy proběhly úspěšně." + "Odstraňování problémů s upozorněními" + "Některé testy vyžadují vaši pozornost. Zkontrolujte prosím podrobnosti." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-de/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..98b8c579a9 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,11 @@ + + + "Tests durchführen" + "Tests erneut durchführen" + "Einige Tests sind fehlgeschlagen. Bitte überprüfe die Details." + "Führe die Tests durch, um Probleme zu erkennen, die dazu führen können, dass sich die Benachrichtigungen nicht wie erwartet verhalten." + "Versuche das Problem zu beheben" + "Alle Tests wurden erfolgreich bestanden." + "Fehlerbehebung für Benachrichtigungen" + "Einige Tests erfordern deine Aufmerksamkeit. Bitte überprüfe die Details." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-fr/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..497b3e3b56 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,11 @@ + + + "Exécuter les tests" + "Relancer les tests" + "Certains tests ont échoué. Veuillez vérifier les détails." + "Exécuter les tests pour détecter tout problème dans votre configuration susceptible de provoquer un dysfonctionnement des notifications." + "Tenter de corriger" + "Tous les tests ont réussi." + "Dépanner les notifications" + "Certains tests nécessitent votre attention. Veuillez vérifier les détails." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-hu/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..211b1f4a1d --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,11 @@ + + + "Tesztek futtatása" + "Tesztek újbóli futtatása" + "Egyes tesztek sikertelenek voltak. Ellenőrizze a részleteket." + "A tesztek futtatása, hogy észlelje a konfigurációban felmerülő olyan problémákat, amelyek miatt az értesítések nem az elvárt módon viselkednek." + "Kísérlet a javításra" + "Minden teszt sikeresen lezajlott." + "Értesítések hibaelhárítása" + "Egyes tesztek a figyelmét igénylik. Ellenőrizze a részleteket." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..943652fc86 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,11 @@ + + + "Выполнение тестов" + "Повторное выполнение тестов" + "Некоторые тесты провалились. Пожалуйста, проверьте детали." + "Выполните тесты, чтобы обнаружить любую проблему в конфигурации, из-за которой уведомления могут работать не так, как ожидалось." + "Попытка исправить" + "Все тесты прошли успешно." + "Уведомления об устранении неполадок" + "Некоторые тесты требуют вашего внимания. Пожалуйста, проверьте детали." + diff --git a/libraries/troubleshoot/impl/src/main/res/values-sk/translations.xml b/libraries/troubleshoot/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..3b7a08c2f0 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,11 @@ + + + "Spustiť testy" + "Spustiť testy znova" + "Niektoré testy zlyhali. Skontrolujte prosím podrobnosti." + "Spustite testy, aby ste zistili akýkoľvek problém vo vašej konfigurácii, ktorý môže spôsobiť, že sa upozornenia nebudú správať podľa očakávania." + "Pokus o opravu" + "Všetky testy prebehli úspešne." + "Oznámenia riešení problémov" + "Niektoré testy si vyžadujú vašu pozornosť. Prosím skontrolujte podrobnosti." + diff --git a/libraries/troubleshoot/impl/src/main/res/values/localazy.xml b/libraries/troubleshoot/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..eee100d711 --- /dev/null +++ b/libraries/troubleshoot/impl/src/main/res/values/localazy.xml @@ -0,0 +1,11 @@ + + + "Run tests" + "Run tests again" + "Some tests failed. Please check the details." + "Run the tests to detect any issue in your configuration that may make notifications not behave as expected." + "Attempt to fix" + "All tests passed successfully." + "Troubleshoot notifications" + "Some tests require your attention. Please check the details." + diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/FakeNotificationTroubleshootTest.kt similarity index 91% rename from features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt rename to libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/FakeNotificationTroubleshootTest.kt index 361c59cae7..90b8a988bb 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/FakeNotificationTroubleshootTest.kt +++ b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/FakeNotificationTroubleshootTest.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenterTests.kt similarity index 94% rename from features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt rename to libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenterTests.kt index 686aac2e56..25082b63c4 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsPresenterTests.kt +++ b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsPresenterTests.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 New Vector Ltd + * Copyright (c) 2024 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. @@ -14,16 +14,16 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.core.notifications.NotificationTroubleshootTest -import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.push.test.FakeGetCurrentPushProvider +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.analytics.test.FakeAnalyticsService import kotlinx.coroutines.test.runTest import org.junit.Test diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt similarity index 91% rename from features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt rename to libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt index af2b37d7c0..5acd0e5635 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/troubleshoot/TroubleshootNotificationsViewTest.kt +++ b/libraries/troubleshoot/impl/src/test/kotlin/io/element/android/libraries/troubleshoot/impl/TroubleshootNotificationsViewTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.preferences.impl.notifications.troubleshoot +package io.element.android.libraries.troubleshoot.impl import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule @@ -69,7 +69,11 @@ class TroubleshootNotificationsViewTest { val eventsRecorder = EventsRecorder() rule.setTroubleshootNotificationsView( aTroubleshootNotificationsState( - tests = listOf(aTroubleshootTestStateFailure(hasQuickFix = false)), + tests = listOf( + aTroubleshootTestStateFailure( + hasQuickFix = false + ) + ), eventSink = eventsRecorder ), ) @@ -88,7 +92,11 @@ class TroubleshootNotificationsViewTest { val eventsRecorder = EventsRecorder() rule.setTroubleshootNotificationsView( aTroubleshootNotificationsState( - tests = listOf(aTroubleshootTestStateFailure(hasQuickFix = true)), + tests = listOf( + aTroubleshootTestStateFailure( + hasQuickFix = true + ) + ), eventSink = eventsRecorder ), ) diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index cc254511bd..395f690d0e 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -114,6 +114,7 @@ fun DependencyHandlerScope.allLibrariesImpl() { implementation(project(":libraries:voicerecorder:impl")) implementation(project(":libraries:mediaplayer:impl")) implementation(project(":libraries:mediaviewer:impl")) + implementation(project(":libraries:troubleshoot:impl")) } fun DependencyHandlerScope.allServicesImpl() { diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 603c04b55c..d63ede5638 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -205,7 +205,12 @@ "screen_edit_profile_.*", "screen_notification_settings_.*", "screen_blocked_users_.*", - "troubleshoot_notifications_entry_point_.*", + "troubleshoot_notifications_entry_point_.*" + ] + }, + { + "name" : ":libraries:troubleshoot:impl", + "includeRegex" : [ "troubleshoot_notifications_screen_.*" ] }, From 30d77e5123a2467f3d7b1c50ef2ef8d1c3639dbd Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 2 Apr 2024 16:25:27 +0000 Subject: [PATCH 24/27] Update screenshots --- ...otificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png} | 0 ...ificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png} | 0 ...otificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png} | 0 ...otificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png} | 0 ...otificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png} | 0 ...otificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png} | 0 ...otificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png} | 0 ...ficationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png} | 0 ...ficationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png} | 0 ...ficationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png} | 0 ...ficationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png} | 0 ...ficationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png} | 0 ...dNotificationSettingsView-Day-7_8_null,NEXUS_5,1.0,en].png | 3 --- ...otificationSettingsView-Night-7_9_null,NEXUS_5,1.0,en].png | 3 --- ...otificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...otificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...otificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...otificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en].png | 3 +++ ...otificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en].png | 3 +++ ...ificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...ificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...ificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en].png | 3 +++ ...ificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en].png | 3 +++ ..._EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png} | 0 ...ditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png} | 0 ..._null_UserPreferences-Day-9_10_null_0,NEXUS_5,1.0,en].png} | 0 ..._null_UserPreferences-Day-9_10_null_1,NEXUS_5,1.0,en].png} | 0 ..._null_UserPreferences-Day-9_10_null_2,NEXUS_5,1.0,en].png} | 0 ...ull_UserPreferences-Night-9_11_null_0,NEXUS_5,1.0,en].png} | 0 ...ull_UserPreferences-Night-9_11_null_1,NEXUS_5,1.0,en].png} | 0 ...ull_UserPreferences-Night-9_11_null_2,NEXUS_5,1.0,en].png} | 0 32 files changed, 24 insertions(+), 18 deletions(-) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-8_9_null,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-8_10_null,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png} (100%) delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Day-7_8_null,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Night-7_9_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-11_12_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-11_13_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_2,NEXUS_5,1.0,en].png} (100%) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-8_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Day-7_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-8_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_DefaultNotificationSettingOption_null_DefaultNotificationSettingOption-Night-7_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-9_10_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Day-8_9_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-9_11_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_EditDefaultNotificationSettingView_null_EditDefaultNotificationSettingView-Night-8_10_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Day-7_8_null,NEXUS_5,1.0,en].png deleted file mode 100644 index e39ff5329b..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Day-7_8_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f99b8193089b4719c75acdee6339cc89307fb16255cf6e7deaf4486b03c42505 -size 42728 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Night-7_9_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 3fb79982e8..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_InvalidNotificationSettingsView_null_InvalidNotificationSettingsView-Night-7_9_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ecc207ca338b66754c3d0e738f584c0712c8d46958e07bfd1ccd50b19df82006 -size 41413 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en].png index e1135c1e76..8399a4c808 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cae06a603dd5947aa035e0be90a7a649abdce67f5cdcb921c2fa259ead90ac0d -size 60521 +oid sha256:0a566ec9dea61ea21c42cdbdb011f7b74a530d591642c5616038a0cdd6c20a74 +size 63452 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en].png index cd66a12792..3abcdd8dfd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e860dc70a35f5fdecc69eec550e781f6974e66a5a12196572ea169b3422136be -size 54821 +oid sha256:c36ca0694f603d7a3f0ca1965f1b0fe2bb6738aece2a908317a8043b2cb82bc4 +size 57380 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en].png index 742e797349..844ed57393 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f84e508a1a5ec9a402d4adbe5cbe963c0a06c776f7627a9c8eac29b6209c84a -size 54772 +oid sha256:dfd063ea23382a25ec6576b74674d6c2f30a7fbeb9e99d4c4a753a7909ece947 +size 57353 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..1da5935157 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5ae68e5b9dcf951dbc7a77e6606daaa86eceee6b8b54c4fc5072774f149dae2 +size 47346 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f9e918b587 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Day-6_7_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:585f8dcbeef19fbba8e3cddcba7c8ec2831a704ba3fbb3cc05369d42444d919c +size 47975 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en].png index a76c60413f..af460dc892 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22b0073e9e51a790231ab9feca750869e15b4c03e659f2b183dd6d5745be8918 -size 55839 +oid sha256:b9da4314613e463f2da12ac9e7d4c52446ca64133c13980b87a5c447873dfc5b +size 58568 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en].png index 2484839eab..12405f0ce7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02b620889589dcd10057991dad95dd84dfddf9cef135059d1bae45ba4790f5ee -size 50971 +oid sha256:6eed8d6163471878f5281c5fc922537a22216e666366a4d1c6c11535c09aeb11 +size 53402 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en].png index 0a1531e4d9..eba437daf5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:308f6f6d7da94c68212d263fa30f1612387d2e1dbf355314fb128e757f481209 -size 50382 +oid sha256:860cc7bbab5f72a951f7b83fad121040bd1fa1852bd44715a390b8e5db52eaeb +size 52801 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..4ecedce7bd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4eacf4ac22f6c49b96f0891bf53fcc96bd333a6b42e66c7ac12aa4be03232667 +size 45141 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ac4c51e310 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications_NotificationSettingsView_null_NotificationSettingsView-Night-6_8_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6f6367b13643ae480f3d555ea3506bc4caeddeb51c0cd20de6c906b9886e5a5 +size 45015 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-11_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-11_12_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Day-10_11_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-11_13_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-11_13_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_EditUserProfileView_null_EditUserProfileView-Night-10_12_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-10_11_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Day-9_10_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-10_12_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_UserPreferences_null_UserPreferences-Night-9_11_null_2,NEXUS_5,1.0,en].png From 403240256ce7e936509a9fc390b66667eb69538f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 18:37:29 +0200 Subject: [PATCH 25/27] Add showkase processor --- libraries/troubleshoot/impl/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/troubleshoot/impl/build.gradle.kts b/libraries/troubleshoot/impl/build.gradle.kts index b5a0a9012d..4967a34cf3 100644 --- a/libraries/troubleshoot/impl/build.gradle.kts +++ b/libraries/troubleshoot/impl/build.gradle.kts @@ -16,6 +16,7 @@ plugins { id("io.element.android-compose-library") alias(libs.plugins.anvil) + alias(libs.plugins.ksp) alias(libs.plugins.kotlin.serialization) } @@ -43,6 +44,7 @@ dependencies { api(projects.libraries.troubleshoot.api) api(projects.libraries.push.api) implementation(projects.services.analytics.api) + ksp(libs.showkase.processor) testImplementation(libs.test.junit) testImplementation(libs.test.robolectric) From 2aa53f02c509e6c9fff974061bae548a2c96db54 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 2 Apr 2024 16:50:13 +0000 Subject: [PATCH 26/27] Update screenshots --- ...leshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en].png | 3 +++ ...leshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en].png | 3 +++ ...shootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en].png | 3 +++ 16 files changed, 48 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..b232885ed5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7a8e9790e7d4b92e54a4161340c77f691685c28e9d40f272fb2c98808fec154 +size 32662 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..17ea7ac2f6 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5abc8664b6ef86b8f3357207635a3c038d78e3ff907ca56526242186c196cc22 +size 21152 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..4b53087f1c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:504c858c17ef7229ba2bd52f3be7a6769ea2031a97fc7a39461a523cba120e9e +size 21512 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..9ee728e547 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07ad31cb2c341ecddf9963ff93bdd9818f6209c9331c89cac9122293f76097cd +size 32472 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..26cbd8a27f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:05a287eaae96eb6c1d2aabf624d10a1ddf97f50cd9c680a65b0496123fe53b46 +size 26294 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..811a6f1f65 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2a11615004b3b883be7093086a42efda0efabcb03cd580ec813fc827be02937 +size 38878 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..03e98787ba --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_6,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:853b90c82ad1dbbd9c1fa75feaa2115445fbbd6f674fa41f486826bd1ef89b1c +size 27022 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..a0f85489dd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Day-0_1_null_7,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb5f63b160d04544705cf778774d046dfc2915f49fe4adfaa473111c95c86be8 +size 25731 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..b2eb2fc50d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01d2e5fdc0a9f1c5d534c965b0b6f30162dcb14d06e89af9eacc4c0084a13cdc +size 29052 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..99e171d097 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99bb674c5cfdbf86789426fdfb676f84d244b0452ba557915d803d78e4959224 +size 20188 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..8c6c088e36 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ac08cfe788fa4bd19f405862050a49da399c51b6921c977937a022a3f180f7b +size 20559 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f3877ac388 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a31489b3764a8eafe386fbcaf0b806d2acfeb7c92816230cba77e1f84704d645 +size 29818 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..0e6149ea48 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af94bf79e1602817e800adb9a382681a9bf63b4435b9d5c7437a9a6a22d8c373 +size 24581 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..73e0749733 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ca71cd36ee1679c55eac28fc271f02a5dbbfc33d08202137d93a93e7285ac45 +size 35533 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..840c0da5d1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_6,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d7937d6b674014e42d2b7c95104d51da0644f3557d91ea04e4ec9b626a2f4a0 +size 25044 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..b878f43791 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.troubleshoot.impl_TroubleshootNotificationsView_null_TroubleshootNotificationsView-Night-0_2_null_7,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75cec48fca9ca9d551b18fbfabd318c72c33eec16743984ae2be3409f22a8d47 +size 23902 From 5310456b6ced26786672b23db50380915af2c203 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Apr 2024 19:50:41 +0200 Subject: [PATCH 27/27] Fix test compilation. --- .../NotificationTroubleshootCheckPermissionTestTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt index df0214b08d..b38d00ee22 100644 --- a/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt +++ b/libraries/permissions/impl/src/test/kotlin/io/element/android/libraries/permissions/impl/troubleshoot/NotificationTroubleshootCheckPermissionTestTest.kt @@ -21,6 +21,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.permissions.impl.FakePermissionStateProvider import io.element.android.libraries.permissions.impl.action.FakePermissionActions +import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.launch