diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index d98a05321d..02f132d34a 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.plus +import kotlinx.serialization.json.Json import java.io.File @BindingContainer @@ -120,4 +121,10 @@ object AppModule { fun providesEmojibaseProvider(@ApplicationContext context: Context): EmojibaseProvider { return DefaultEmojibaseProvider(context) } + + @Provides + @SingleIn(AppScope::class) + fun providesJson(): Json = Json { + ignoreUnknownKeys = true + } } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt index 06929093f5..7604dbae18 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt @@ -64,6 +64,7 @@ class CallScreenPresenter( private val appForegroundStateService: AppForegroundStateService, @AppCoroutineScope private val appCoroutineScope: CoroutineScope, + private val widgetMessageSerializer: WidgetMessageSerializer, ) : Presenter { @AssistedFactory interface Factory { @@ -258,7 +259,7 @@ class CallScreenPresenter( } private fun parseMessage(message: String): WidgetMessage? { - return WidgetMessageSerializer.deserialize(message).getOrNull() + return widgetMessageSerializer.deserialize(message).getOrNull() } private fun sendHangupMessage(widgetId: String, messageInterceptor: WidgetMessageInterceptor) { @@ -269,7 +270,7 @@ class CallScreenPresenter( action = WidgetMessage.Action.HangUp, data = null, ) - messageInterceptor.sendMessage(WidgetMessageSerializer.serialize(message)) + messageInterceptor.sendMessage(widgetMessageSerializer.serialize(message)) } private fun CoroutineScope.close(widgetDriver: MatrixWidgetDriver?, navigator: CallScreenNavigator) = launch(dispatchers.io) { diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt index 88d2e81f8b..2f7a700794 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt @@ -8,7 +8,6 @@ package io.element.android.features.call.impl.ui import android.annotation.SuppressLint -import android.util.Log import android.view.ViewGroup import android.webkit.ConsoleMessage import android.webkit.JavascriptInterface @@ -60,6 +59,7 @@ interface CallScreenNavigator { internal fun CallScreenView( state: CallScreenState, pipState: PictureInPictureState, + onConsoleMessage: (ConsoleMessage) -> Unit, requestPermissions: (Array, RequestPermissionCallback) -> Unit, modifier: Modifier = Modifier, ) { @@ -108,6 +108,7 @@ internal fun CallScreenView( val callback: RequestPermissionCallback = { request.grant(it) } requestPermissions(androidPermissions.toTypedArray(), callback) }, + onConsoleMessage = onConsoleMessage, onCreateWebView = { webView -> webView.addBackHandler(onBackPressed = ::handleBack) val interceptor = WebViewWidgetMessageInterceptor( @@ -174,6 +175,7 @@ private fun CallWebView( url: AsyncData, userAgent: String, onPermissionsRequest: (PermissionRequest) -> Unit, + onConsoleMessage: (ConsoleMessage) -> Unit, onCreateWebView: (WebView) -> Unit, onDestroyWebView: (WebView) -> Unit, modifier: Modifier = Modifier, @@ -188,7 +190,11 @@ private fun CallWebView( factory = { context -> WebView(context).apply { onCreateWebView(this) - setup(userAgent, onPermissionsRequest) + setup( + userAgent = userAgent, + onPermissionsRequested = onPermissionsRequest, + onConsoleMessage = onConsoleMessage, + ) } }, update = { webView -> @@ -208,6 +214,7 @@ private fun CallWebView( private fun WebView.setup( userAgent: String, onPermissionsRequested: (PermissionRequest) -> Unit, + onConsoleMessage: (ConsoleMessage) -> Unit, ) { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -232,35 +239,7 @@ private fun WebView.setup( } override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { - val priority = when (consoleMessage.messageLevel()) { - ConsoleMessage.MessageLevel.ERROR -> Log.ERROR - ConsoleMessage.MessageLevel.WARNING -> Log.WARN - else -> Log.DEBUG - } - - val message = buildString { - append(consoleMessage.sourceId()) - append(":") - append(consoleMessage.lineNumber()) - append(" ") - append(consoleMessage.message()) - } - - if (message.contains("password=")) { - // Avoid logging any messages that contain "password" to prevent leaking sensitive information - return true - } - - Timber.tag("WebView").log( - priority = priority, - message = buildString { - append(consoleMessage.sourceId()) - append(":") - append(consoleMessage.lineNumber()) - append(" ") - append(consoleMessage.message()) - }, - ) + onConsoleMessage(consoleMessage) return true } } @@ -286,6 +265,7 @@ internal fun CallScreenViewPreview( state = state, pipState = aPictureInPictureState(), requestPermissions = { _, _ -> }, + onConsoleMessage = {}, ) } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt index bf210b0a42..ae04606d29 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt @@ -42,6 +42,7 @@ import io.element.android.features.call.impl.pip.PipView import io.element.android.features.call.impl.services.CallForegroundService import io.element.android.features.call.impl.utils.CallIntentDataParser import io.element.android.features.enterprise.api.EnterpriseService +import io.element.android.libraries.androidutils.browser.ConsoleMessageLogger import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.bindings import io.element.android.libraries.audio.api.AudioFocus @@ -65,6 +66,7 @@ class ElementCallActivity : @Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var audioFocus: AudioFocus + @Inject lateinit var consoleMessageLogger: ConsoleMessageLogger private lateinit var presenter: Presenter @@ -119,6 +121,9 @@ class ElementCallActivity : CallScreenView( state = state, pipState = pipState, + onConsoleMessage = { + consoleMessageLogger.log("ElementCall", it) + }, requestPermissions = { permissions, callback -> requestPermissionCallback = callback requestPermissionsLauncher.launch(permissions) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt index a21cadab7a..2beaea7061 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/WidgetMessageSerializer.kt @@ -7,18 +7,20 @@ package io.element.android.features.call.impl.utils +import dev.zacsweers.metro.Inject import io.element.android.features.call.impl.data.WidgetMessage import io.element.android.libraries.core.extensions.runCatchingExceptions import kotlinx.serialization.json.Json -object WidgetMessageSerializer { - private val coder = Json { ignoreUnknownKeys = true } - +@Inject +class WidgetMessageSerializer( + private val json: Json, +) { fun deserialize(message: String): Result { - return runCatchingExceptions { coder.decodeFromString(WidgetMessage.serializer(), message) } + return runCatchingExceptions { json.decodeFromString(WidgetMessage.serializer(), message) } } fun serialize(message: WidgetMessage): String { - return coder.encodeToString(WidgetMessage.serializer(), message) + return json.encodeToString(WidgetMessage.serializer(), message) } } diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt index 47a91afa1c..c3a68994da 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt @@ -16,6 +16,7 @@ import io.element.android.features.call.api.CallType import io.element.android.features.call.impl.ui.CallScreenEvents import io.element.android.features.call.impl.ui.CallScreenNavigator import io.element.android.features.call.impl.ui.CallScreenPresenter +import io.element.android.features.call.impl.utils.WidgetMessageSerializer import io.element.android.features.call.utils.FakeActiveCallManager import io.element.android.features.call.utils.FakeCallWidgetProvider import io.element.android.features.call.utils.FakeWidgetMessageInterceptor @@ -46,11 +47,13 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import kotlinx.serialization.json.Json import org.junit.Rule import org.junit.Test import kotlin.time.Duration.Companion.seconds -@OptIn(ExperimentalCoroutinesApi::class) class CallScreenPresenterTest { +@OptIn(ExperimentalCoroutinesApi::class) +class CallScreenPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -409,6 +412,7 @@ import kotlin.time.Duration.Companion.seconds languageTagProvider = FakeLanguageTagProvider("en-US"), appForegroundStateService = appForegroundStateService, appCoroutineScope = backgroundScope, + widgetMessageSerializer = WidgetMessageSerializer(Json { ignoreUnknownKeys = true }), ) } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt index b18e732b42..66e5403b35 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spaces/HomeSpacesView.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.ui.components.SpaceHeaderRootView @@ -47,6 +48,9 @@ fun HomeSpacesView( ) } } + item { + HorizontalDivider() + } state.spaceRooms.forEach { spaceRoom -> item(spaceRoom.roomId) { val isInvitation = spaceRoom.state == CurrentUserMembership.INVITED diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt index 6e123630d6..2d737a17d4 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt @@ -39,8 +39,6 @@ import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -import io.element.android.libraries.matrix.api.exception.ClientException -import io.element.android.libraries.matrix.api.exception.ErrorKind import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMembershipDetails @@ -141,11 +139,7 @@ class JoinRoomPresenter( preview.previewInfo.toContentState(membershipDetails) }, onFailure = { throwable -> - if (throwable is ClientException.MatrixApi && (throwable.kind == ErrorKind.NotFound || throwable.kind == ErrorKind.Forbidden)) { - ContentState.UnknownRoom - } else { - ContentState.Failure(throwable) - } + ContentState.UnknownRoom } ) } diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt index 10b5c1a712..0aed9ca424 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt @@ -1193,46 +1193,8 @@ class JoinRoomPresenterTest { skipItems(1) awaitItem().also { state -> assertThat(state.contentState).isEqualTo( - ContentState.Failure(error = AN_EXCEPTION) + ContentState.UnknownRoom ) - state.eventSink(JoinRoomEvents.RetryFetchingContent) - } - skipItems(1) - awaitItem().also { state -> - assertThat(state.contentState).isEqualTo(ContentState.Loading) - } - awaitItem().also { state -> - assertThat(state.contentState).isEqualTo( - ContentState.Failure(error = AN_EXCEPTION) - ) - } - } - } - - @Test - fun `present - when room is not known RoomPreview is loaded with error - dismiss`() = runTest { - val client = FakeMatrixClient( - getNotJoinedRoomResult = { _, _ -> - Result.failure(AN_EXCEPTION) - }, - spaceService = FakeSpaceService( - spaceRoomListResult = { FakeSpaceRoomList() }, - ), - ) - val presenter = createJoinRoomPresenter( - matrixClient = client - ) - presenter.test { - skipItems(1) - awaitItem().also { state -> - assertThat(state.contentState).isEqualTo( - ContentState.Failure(error = AN_EXCEPTION) - ) - state.eventSink(JoinRoomEvents.DismissErrorAndHideContent) - } - skipItems(1) - awaitItem().also { state -> - assertThat(state.contentState).isEqualTo(ContentState.Dismissing) } } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt index f6f62eca01..4cd939824e 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/changeaccountprovider/ChangeAccountProviderState.kt @@ -11,7 +11,6 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.changeserver.ChangeServerState import kotlinx.collections.immutable.ImmutableList -// Do not use default value, so no member get forgotten in the presenters. data class ChangeAccountProviderState( val accountProviders: ImmutableList, val canSearchForAccountProviders: Boolean, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt index ad4677ea24..e7df3256d6 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt @@ -12,7 +12,6 @@ import io.element.android.features.login.impl.login.LoginMode import io.element.android.libraries.architecture.AsyncData import kotlinx.collections.immutable.ImmutableList -// Do not use default value, so no member get forgotten in the presenters. data class ChooseAccountProviderState( val accountProviders: ImmutableList, val selectedAccountProvider: AccountProvider?, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderState.kt index d0da9ab85e..3bde254432 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderState.kt @@ -11,7 +11,6 @@ import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.login.LoginMode import io.element.android.libraries.architecture.AsyncData -// Do not use default value, so no member get forgotten in the presenters. data class ConfirmAccountProviderState( val accountProvider: AccountProvider, val isAccountCreation: Boolean, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt index 8450aef1d3..8762bc5e46 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/createaccount/MessageParser.kt @@ -26,10 +26,10 @@ interface MessageParser { @Inject class DefaultMessageParser( private val accountProviderDataSource: AccountProviderDataSource, + private val json: Json, ) : MessageParser { override fun parse(message: String): ExternalSession { - val parser = Json { ignoreUnknownKeys = true } - val response = parser.decodeFromString(MobileRegistrationResponse.serializer(), message) + val response = json.decodeFromString(MobileRegistrationResponse.serializer(), message) val userId = response.userId ?: error("No user ID in response") val homeServer = response.homeServer ?: accountProviderDataSource.flow.value.url val accessToken = response.accessToken ?: error("No access token in response") diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderState.kt index 4fb0a08141..1cb029caae 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/searchaccountprovider/SearchAccountProviderState.kt @@ -11,7 +11,6 @@ import io.element.android.features.login.impl.changeserver.ChangeServerState import io.element.android.features.login.impl.resolver.HomeserverData import io.element.android.libraries.architecture.AsyncData -// Do not use default value, so no member get forgotten in the presenters. data class SearchAccountProviderState( val userInput: String, val userInputResult: AsyncData>, diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt index a1fbbc0fe2..fa97a2b1fc 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/createaccount/DefaultMessageParserTest.kt @@ -13,6 +13,7 @@ import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.libraries.matrix.api.auth.external.ExternalSession import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json import org.junit.Assert.assertThrows import org.junit.Test @@ -68,7 +69,8 @@ class DefaultMessageParserTest { private fun createDefaultMessageParser(): DefaultMessageParser { return DefaultMessageParser( - AccountProviderDataSource(FakeEnterpriseService()) + accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()), + json = Json { ignoreUnknownKeys = true }, ) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/analytics/AnalyticsSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/analytics/AnalyticsSettingsState.kt index 7f0cbb4672..1fd15a8e8a 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/analytics/AnalyticsSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/analytics/AnalyticsSettingsState.kt @@ -9,7 +9,6 @@ package io.element.android.features.preferences.impl.analytics import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState -// Do not use default value, so no member get forgotten in the presenters. data class AnalyticsSettingsState( val analyticsPreferencesState: AnalyticsPreferencesState, ) diff --git a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt index bb625370cf..02e53fbb1c 100644 --- a/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt +++ b/features/rageshake/api/src/main/kotlin/io/element/android/features/rageshake/api/reporter/BugReporter.kt @@ -18,6 +18,7 @@ interface BugReporter { * @param withScreenshot true to include the screenshot * @param problemDescription the bug description * @param canContact true if the user opt in to be contacted directly + * @param sendPushRules true to include the push rules * @param listener the listener */ suspend fun sendBugReport( @@ -26,6 +27,7 @@ interface BugReporter { withScreenshot: Boolean, problemDescription: String, canContact: Boolean = false, + sendPushRules: Boolean = false, listener: BugReporterListener ) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportEvents.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportEvents.kt index fbf2906623..1b0a61e1d5 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportEvents.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportEvents.kt @@ -16,4 +16,5 @@ sealed interface BugReportEvents { data class SetSendLog(val sendLog: Boolean) : BugReportEvents data class SetCanContact(val canContact: Boolean) : BugReportEvents data class SetSendScreenshot(val sendScreenshot: Boolean) : BugReportEvents + data class SetSendPushRules(val sendPushRules: Boolean) : BugReportEvents } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt index 4faef73589..bfcfcf424e 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt @@ -105,6 +105,9 @@ class BugReportPresenter( is BugReportEvents.SetSendScreenshot -> updateFormState(formState) { copy(sendScreenshot = event.sendScreenshot) } + is BugReportEvents.SetSendPushRules -> updateFormState(formState) { + copy(sendPushRules = event.sendPushRules) + } BugReportEvents.ClearError -> { sendingProgress.floatValue = 0f sendingAction.value = AsyncAction.Uninitialized @@ -137,6 +140,7 @@ class BugReportPresenter( withScreenshot = formState.sendScreenshot, problemDescription = formState.description, canContact = formState.canContact, + sendPushRules = formState.sendPushRules, listener = listener ) } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt index 8922446329..54b8608add 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportState.kt @@ -29,14 +29,16 @@ data class BugReportFormState( val description: String, val sendLogs: Boolean, val canContact: Boolean, - val sendScreenshot: Boolean + val sendScreenshot: Boolean, + val sendPushRules: Boolean, ) : Parcelable { companion object { val Default = BugReportFormState( description = "", sendLogs = true, canContact = false, - sendScreenshot = false + sendScreenshot = false, + sendPushRules = false, ) } } diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt index 760106b0fb..95dff10804 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportView.kt @@ -7,6 +7,7 @@ package io.element.android.features.rageshake.impl.bugreport +import android.content.res.Configuration import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -26,6 +27,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage @@ -40,7 +42,6 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext 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.ListItem import io.element.android.libraries.designsystem.theme.components.Text @@ -142,6 +143,13 @@ fun BugReportView( } } } + PreferenceSwitch( + isChecked = state.formState.sendPushRules, + onCheckedChange = { eventSink(BugReportEvents.SetSendPushRules(it)) }, + enabled = isFormEnabled, + title = stringResource(R.string.screen_bug_report_send_notification_settings_title), + subtitle = stringResource(R.string.screen_bug_report_send_notification_settings_description), + ) // Submit PreferenceRow { Button( @@ -174,9 +182,20 @@ fun BugReportView( } } -@PreviewsDayNight +@Preview(heightDp = 1000) @Composable -internal fun BugReportViewPreview(@PreviewParameter(BugReportStateProvider::class) state: BugReportState) = ElementPreview { +internal fun BugReportViewDayPreview(@PreviewParameter(BugReportStateProvider::class) state: BugReportState) = ElementPreview { + BugReportView( + state = state, + onSuccess = {}, + onBackClick = {}, + onViewLogs = {}, + ) +} + +@Preview(heightDp = 1000, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +internal fun BugReportViewNightPreview(@PreviewParameter(BugReportStateProvider::class) state: BugReportState) = ElementPreview { BugReportView( state = state, onSuccess = {}, diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt index 5787939688..5eecd17f31 100755 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporter.kt @@ -44,6 +44,7 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.json.JSONException import org.json.JSONObject @@ -113,6 +114,7 @@ class DefaultBugReporter( withScreenshot: Boolean, problemDescription: String, canContact: Boolean, + sendPushRules: Boolean, listener: BugReporterListener, ) { val url = bugReporterUrlProvider.provide().first() @@ -153,6 +155,7 @@ class DefaultBugReporter( } } val sessionData = sessionStore.getLatestSession() + val numberOfAccounts = sessionStore.getAllSessions().size val deviceId = sessionData?.deviceId ?: "undefined" val userId = sessionData?.userId?.let { UserId(it) } // build the multi part request @@ -161,6 +164,7 @@ class DefaultBugReporter( .addFormDataPart("app", RageshakeConfig.BUG_REPORT_APP_NAME) .addFormDataPart("user_agent", userAgentProvider.provide()) .addFormDataPart("user_id", userId?.toString() ?: "undefined") + .addFormDataPart("number_of_accounts", numberOfAccounts.toString()) .addFormDataPart("can_contact", canContact.toString()) .addFormDataPart("device_id", deviceId) .addFormDataPart("device", Build.MODEL.trim()) @@ -181,6 +185,16 @@ class DefaultBugReporter( if (curveKey != null && edKey != null) { builder.addFormDataPart("device_keys", "curve25519:$curveKey, ed25519:$edKey") } + + if (sendPushRules) { + client.notificationSettingsService.getRawPushRules().getOrNull()?.let { pushRules -> + builder.addFormDataPart( + name = "file", + filename = "push_rules.json", + body = pushRules.toByteArray().toRequestBody(MimeTypes.Json.toMediaTypeOrNull()) + ) + } + } } } if (crashCallStack.isNotEmpty() && withCrashLogs) { diff --git a/features/rageshake/impl/src/main/res/values/localazy.xml b/features/rageshake/impl/src/main/res/values/localazy.xml index f6d93c4114..85af2af4a7 100644 --- a/features/rageshake/impl/src/main/res/values/localazy.xml +++ b/features/rageshake/impl/src/main/res/values/localazy.xml @@ -14,7 +14,7 @@ "Send screenshot" "Logs will be included with your message to make sure that everything is working properly. To send your message without logs, turn off this setting." "%1$s crashed the last time it was used. Would you like to share a crash report with us?" - "If you are having issues with notifications, uploading the notification settings can help us pinpoint the root cause." + "If you are having issues with notifications, uploading the notification push rules can help us pinpoint the root cause. Note these rules can contain private information, such as your display name or keywords to be notified for." "Send notification settings" "View logs" diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt index 362b3798d6..780377025e 100644 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenterTest.kt @@ -106,6 +106,20 @@ class BugReportPresenterTest { } } + @Test + fun `present - send notification settings`() = runTest { + val presenter = createPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + initialState.eventSink.invoke(BugReportEvents.SetSendPushRules(true)) + assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendPushRules = true)) + initialState.eventSink.invoke(BugReportEvents.SetSendPushRules(false)) + assertThat(awaitItem().formState).isEqualTo(BugReportFormState.Default.copy(sendPushRules = false)) + } + } + @Test fun `present - reset all`() = runTest { val presenter = createPresenter( diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt index ebaa524bd5..bd9c538c0d 100644 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/bugreport/FakeBugReporter.kt @@ -26,6 +26,7 @@ class FakeBugReporter(val mode: Mode = Mode.Success) : BugReporter { withScreenshot: Boolean, problemDescription: String, canContact: Boolean, + sendPushRules: Boolean, listener: BugReporterListener, ) { delay(100) diff --git a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt index ecb8d13b12..3f3eecb35d 100755 --- a/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt +++ b/features/rageshake/impl/src/test/kotlin/io/element/android/features/rageshake/impl/reporter/DefaultBugReporterTest.kt @@ -18,12 +18,15 @@ import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.tracing.TracingService import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration +import io.element.android.libraries.matrix.test.A_DEVICE_ID +import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.FakeSdkMetadata import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService +import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.tracing.FakeTracingService import io.element.android.libraries.network.useragent.DefaultUserAgentProvider import io.element.android.libraries.sessionstorage.api.SessionStore @@ -65,6 +68,7 @@ class DefaultBugReporterTest { withDevicesLogs = true, withCrashLogs = true, withScreenshot = true, + sendPushRules = true, problemDescription = "a bug occurred", canContact = true, listener = object : BugReporterListener { @@ -108,6 +112,79 @@ class DefaultBugReporterTest { initialList = listOf(aSessionData(sessionId = "@foo:example.com", deviceId = "ABCDEFGH")) ) + val fakeEncryptionService = FakeEncryptionService() + + val fakePushRules = "{ content: ... }" + val fakeNotificationSettingsService = FakeNotificationSettingsService( + getRawPushRulesResult = { Result.success(fakePushRules) } + ) + val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService, notificationSettingsService = fakeNotificationSettingsService) + + fakeEncryptionService.givenDeviceKeys("CURVECURVECURVE", "EDKEYEDKEYEDKY") + val sut = createDefaultBugReporter( + server = server, + crashDataStore = FakeCrashDataStore(), + sessionStore = mockSessionStore, + matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) }) + ) + + val progressValues = mutableListOf() + sut.sendBugReport( + withDevicesLogs = true, + withCrashLogs = true, + withScreenshot = true, + sendPushRules = true, + problemDescription = "a bug occurred", + canContact = true, + listener = object : BugReporterListener { + override fun onUploadCancelled() {} + + override fun onUploadFailed(reason: String?) {} + + override fun onProgress(progress: Int) { + progressValues.add(progress) + } + + override fun onUploadSucceed() {} + }, + ) + val request = server.takeRequest() + + val foundValues = collectValuesFromFormData(request) + + assertThat(foundValues["app"]).isEqualTo(RageshakeConfig.BUG_REPORT_APP_NAME) + assertThat(foundValues["can_contact"]).isEqualTo("true") + assertThat(foundValues["device_id"]).isEqualTo("ABCDEFGH") + assertThat(foundValues["sdk_sha"]).isEqualTo("123456789") + assertThat(foundValues["user_id"]).isEqualTo("@foo:example.com") + assertThat(foundValues["number_of_accounts"]).isEqualTo("1") + assertThat(foundValues["text"]).isEqualTo("a bug occurred") + assertThat(foundValues["device_keys"]).isEqualTo("curve25519:CURVECURVECURVE, ed25519:EDKEYEDKEYEDKY") + assertThat(foundValues["file"]).contains(fakePushRules) + + // device_key now added given they are not null + // so is the push_rules value + assertThat(progressValues.size).isEqualTo(EXPECTED_NUMBER_OF_PROGRESS_VALUE + 2) + + server.shutdown() + } + + @Test + fun `test sendBugReport multi accounts`() = runTest { + val server = MockWebServer() + server.enqueue( + MockResponse() + .setResponseCode(200) + ) + server.start() + + val mockSessionStore = InMemorySessionStore( + initialList = listOf( + aSessionData(sessionId = "@foo:example.com", deviceId = "ABCDEFGH"), + aSessionData(sessionId = A_USER_ID.value, deviceId = A_DEVICE_ID.value), + ) + ) + val fakeEncryptionService = FakeEncryptionService() val matrixClient = FakeMatrixClient(encryptionService = fakeEncryptionService) @@ -147,6 +224,7 @@ class DefaultBugReporterTest { assertThat(foundValues["device_id"]).isEqualTo("ABCDEFGH") assertThat(foundValues["sdk_sha"]).isEqualTo("123456789") assertThat(foundValues["user_id"]).isEqualTo("@foo:example.com") + assertThat(foundValues["number_of_accounts"]).isEqualTo("2") assertThat(foundValues["text"]).isEqualTo("a bug occurred") assertThat(foundValues["device_keys"]).isEqualTo("curve25519:CURVECURVECURVE, ed25519:EDKEYEDKEYEDKY") @@ -228,6 +306,7 @@ class DefaultBugReporterTest { assertThat(foundValues["device_keys"]).isNull() assertThat(foundValues["device_id"]).isEqualTo("undefined") assertThat(foundValues["user_id"]).isEqualTo("undefined") + assertThat(foundValues["number_of_accounts"]).isEqualTo("0") assertThat(foundValues["label"]).isEqualTo("crash") } @@ -272,6 +351,7 @@ class DefaultBugReporterTest { withDevicesLogs = true, withCrashLogs = true, withScreenshot = true, + sendPushRules = true, problemDescription = "a bug occurred", canContact = true, listener = object : BugReporterListener { @@ -474,6 +554,6 @@ class DefaultBugReporterTest { } companion object { - private const val EXPECTED_NUMBER_OF_PROGRESS_VALUE = 17 + private const val EXPECTED_NUMBER_OF_PROGRESS_VALUE = 18 } } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyState.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyState.kt index 60b73b37a3..aaefd09436 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyState.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyState.kt @@ -10,7 +10,6 @@ package io.element.android.features.securebackup.impl.enter import io.element.android.features.securebackup.impl.setup.views.RecoveryKeyViewState import io.element.android.libraries.architecture.AsyncAction -// Do not use default value, so no member get forgotten in the presenters. data class SecureBackupEnterRecoveryKeyState( val recoveryKeyViewState: RecoveryKeyViewState, val isSubmitEnabled: Boolean, diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupState.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupState.kt index 91f710d07d..7df1bbfa84 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupState.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/SecureBackupSetupState.kt @@ -9,7 +9,6 @@ package io.element.android.features.securebackup.impl.setup import io.element.android.features.securebackup.impl.setup.views.RecoveryKeyViewState -// Do not use default value, so no member get forgotten in the presenters. data class SecureBackupSetupState( val isChangeRecoveryKeyUserStory: Boolean, val recoveryKeyViewState: RecoveryKeyViewState, diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutState.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutState.kt index 725654ca57..b72a20c12f 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutState.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutState.kt @@ -9,7 +9,6 @@ package io.element.android.features.signedout.impl import io.element.android.libraries.sessionstorage.api.SessionData -// Do not use default value, so no member get forgotten in the presenters. data class SignedOutState( val appName: String, val signedOutSession: SessionData?, diff --git a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt index 46c6a10e57..cd722ac6f3 100644 --- a/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt +++ b/features/space/impl/src/main/kotlin/io/element/android/features/space/impl/root/SpaceView.kt @@ -49,6 +49,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.DropdownMenu import io.element.android.libraries.designsystem.theme.components.DropdownMenuItem +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.Scaffold @@ -177,6 +178,9 @@ private fun SpaceViewContent( onTopicClick = onTopicClick ) } + item { + HorizontalDivider() + } } state.children.forEach { spaceRoom -> item { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 21b88ad6b5..83b754b757 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -198,7 +198,7 @@ vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0" telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" } telephoto_flick = { module = "me.saket.telephoto:flick-android", version.ref = "telephoto" } statemachine = "com.freeletics.flowredux:compose:1.2.2" -maplibre = "org.maplibre.gl:android-sdk:12.0.0" +maplibre = "org.maplibre.gl:android-sdk:12.0.1" maplibre_ktx = "org.maplibre.gl:android-sdk-ktx-v7:3.0.2" maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:3.0.2" opusencoder = "io.element.android:opusencoder:1.2.0" diff --git a/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt new file mode 100644 index 0000000000..3c3cf24ebc --- /dev/null +++ b/libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/browser/ConsoleMessageLogger.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.androidutils.browser + +import android.util.Log +import android.webkit.ConsoleMessage +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import dev.zacsweers.metro.Inject +import timber.log.Timber + +interface ConsoleMessageLogger { + fun log( + tag: String, + consoleMessage: ConsoleMessage, + ) +} + +@ContributesBinding(AppScope::class) +@Inject +class DefaultConsoleMessageLogger : ConsoleMessageLogger { + override fun log( + tag: String, + consoleMessage: ConsoleMessage, + ) { + val priority = when (consoleMessage.messageLevel()) { + ConsoleMessage.MessageLevel.ERROR -> Log.ERROR + ConsoleMessage.MessageLevel.WARNING -> Log.WARN + else -> Log.DEBUG + } + + val message = buildString { + append(consoleMessage.sourceId()) + append(":") + append(consoleMessage.lineNumber()) + append(" ") + append(consoleMessage.message()) + } + + // Avoid logging any messages that contain "password" to prevent leaking sensitive information + if (message.contains("password=")) { + return + } + + Timber.tag(tag).log( + priority = priority, + message = buildString { + append(consoleMessage.sourceId()) + append(":") + append(consoleMessage.lineNumber()) + append(" ") + append(consoleMessage.message()) + }, + ) + } +} diff --git a/libraries/core/src/main/kotlin/io/element/android/libraries/core/mimetype/MimeTypes.kt b/libraries/core/src/main/kotlin/io/element/android/libraries/core/mimetype/MimeTypes.kt index 357fce2feb..f18702639f 100644 --- a/libraries/core/src/main/kotlin/io/element/android/libraries/core/mimetype/MimeTypes.kt +++ b/libraries/core/src/main/kotlin/io/element/android/libraries/core/mimetype/MimeTypes.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.core.bool.orFalse @Suppress("ktlint:standard:property-naming") object MimeTypes { const val Any: String = "*/*" + const val Json = "application/json" const val OctetStream = "application/octet-stream" const val Apk = "application/vnd.android.package-archive" const val Pdf = "application/pdf" diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt index 703ec1205e..7f8b2e1c1f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt @@ -33,4 +33,5 @@ interface NotificationSettingsService { suspend fun setInviteForMeEnabled(enabled: Boolean): Result suspend fun getRoomsWithUserDefinedRules(): Result> suspend fun canHomeServerPushEncryptedEventsToDevice(): Result + suspend fun getRawPushRules(): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt index b4f3e70754..40be78cf31 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt @@ -139,4 +139,8 @@ class RustNotificationSettingsService( runCatchingExceptions { notificationSettings.await().canPushEncryptedEventToDevice() } + + override suspend fun getRawPushRules(): Result = runCatchingExceptions { + notificationSettings.await().getRawPushRules() + } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt index c5c09981fc..e23ccb30cc 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationSettings import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NOTIFICATION_MODE +import io.element.android.tests.testutils.lambda.lambdaError import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow @@ -23,6 +24,7 @@ class FakeNotificationSettingsService( initialEncryptedGroupDefaultMode: RoomNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, initialOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, initialEncryptedOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, + private val getRawPushRulesResult: () -> Result = { lambdaError() }, ) : NotificationSettingsService { private val notificationSettingsStateFlow = MutableStateFlow(Unit) private var defaultGroupRoomNotificationMode: RoomNotificationMode = initialGroupDefaultMode @@ -178,4 +180,8 @@ class FakeNotificationSettingsService( fun givenCanHomeServerPushEncryptedEventsToDeviceResult(result: Result) { canHomeServerPushEncryptedEventsToDeviceResult = result } + + override suspend fun getRawPushRules(): Result { + return getRawPushRulesResult() + } } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt index 5a9c49ceb9..90ed843483 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SpaceRoomItemView.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.ui.components import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.IntrinsicSize @@ -42,6 +43,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarType import io.element.android.libraries.designsystem.modifiers.onKeyboardContextMenuAction import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.unreadIndicator @@ -56,6 +58,9 @@ import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +/** + * Figma reference: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=3643-2079&m=dev + */ @Composable fun SpaceRoomItemView( spaceRoom: SpaceRoom, @@ -67,43 +72,65 @@ fun SpaceRoomItemView( trailingAction: @Composable (() -> Unit)? = null, bottomAction: @Composable (() -> Unit)? = null, ) { - SpaceRoomItemScaffold( - modifier = modifier, - avatarData = spaceRoom.getAvatarData(AvatarSize.SpaceListItem), - isSpace = spaceRoom.isSpace, - hideAvatars = hideAvatars, - heroes = spaceRoom.heroes - .map { hero -> hero.getAvatarData(AvatarSize.SpaceListItem) } - .toImmutableList(), - onClick = onClick, - onLongClick = onLongClick, - trailingAction = trailingAction, - ) { - NameAndIndicatorRow( - name = spaceRoom.displayName, - showIndicator = showUnreadIndicator + val clickModifier = Modifier + .combinedClickable( + onClick = onClick, + onLongClick = onLongClick, + onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), + indication = ripple(), + interactionSource = remember { MutableInteractionSource() } ) - Spacer(modifier = Modifier.height(1.dp)) - SubtitleRow( - visibilityIcon = spaceRoom.visibilityIcon(), - subtitle = spaceRoom.subtitle() + .onKeyboardContextMenuAction { onLongClick } + Box(modifier = modifier.then(clickModifier)) { + Column( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + ) { + SpaceRoomItemScaffold( + avatarData = spaceRoom.getAvatarData(AvatarSize.SpaceListItem), + isSpace = spaceRoom.isSpace, + hideAvatars = hideAvatars, + heroes = spaceRoom.heroes + .map { hero -> hero.getAvatarData(AvatarSize.SpaceListItem) } + .toImmutableList(), + trailingAction = trailingAction, + ) { + NameAndIndicatorRow( + name = spaceRoom.displayName, + showIndicator = showUnreadIndicator + ) + Spacer(modifier = Modifier.height(1.dp)) + SubtitleRow( + visibilityIcon = spaceRoom.visibilityIcon(), + subtitle = spaceRoom.subtitle() + ) + Spacer(modifier = Modifier.height(1.dp)) + val info = spaceRoom.info() + if (info.isNotBlank()) { + Text( + modifier = Modifier.weight(1f), + style = ElementTheme.typography.fontBodyMdRegular, + text = info, + color = ElementTheme.colors.textSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + if (bottomAction != null) { + Spacer(modifier = Modifier.height(12.dp)) + // Match the padding of the text content (avatar + spacer) + Box(modifier = Modifier.padding(start = AvatarSize.SpaceListItem.dp + 16.dp)) { + bottomAction() + } + Spacer(modifier = Modifier.height(4.dp)) + } + } + HorizontalDivider( + modifier = Modifier + // Match the padding of the text content (padding + avatar + spacer) + .padding(start = AvatarSize.SpaceListItem.dp + 16.dp + 16.dp) + .align(Alignment.BottomCenter) ) - Spacer(modifier = Modifier.height(1.dp)) - val info = spaceRoom.info() - if (info.isNotBlank()) { - Text( - modifier = Modifier.weight(1f), - style = ElementTheme.typography.fontBodyMdRegular, - text = info, - color = ElementTheme.colors.textSecondary, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - if (bottomAction != null) { - Spacer(modifier = Modifier.height(12.dp)) - bottomAction() - } } } @@ -170,28 +197,16 @@ private fun SpaceRoomItemScaffold( avatarData: AvatarData, isSpace: Boolean, heroes: ImmutableList, - onClick: () -> Unit, - onLongClick: () -> Unit, hideAvatars: Boolean, modifier: Modifier = Modifier, trailingAction: @Composable (() -> Unit)? = null, content: @Composable ColumnScope.() -> Unit, ) { - val clickModifier = Modifier - .combinedClickable( - onClick = onClick, - onLongClick = onLongClick, - onLongClickLabel = stringResource(CommonStrings.action_open_context_menu), - indication = ripple(), - interactionSource = remember { MutableInteractionSource() } - ) - .onKeyboardContextMenuAction { onLongClick } Row( modifier = modifier .fillMaxWidth() - .then(clickModifier) - .padding(horizontal = 16.dp, vertical = 8.dp) .height(IntrinsicSize.Min), + verticalAlignment = Alignment.CenterVertically, ) { Avatar( avatarData = avatarData, @@ -249,7 +264,7 @@ internal fun SpaceRoomItemViewPreview(@PreviewParameter(SpaceRoomProvider::class hideAvatars = false, onClick = {}, onLongClick = {}, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth().padding(8.dp), bottomAction = if (spaceRoom.state == CurrentUserMembership.INVITED) { { InviteButtonsRowMolecule({}, {}) } } else { diff --git a/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt b/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt index 6ede5a0c48..b749ebec39 100644 --- a/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt +++ b/libraries/network/src/main/kotlin/io/element/android/libraries/network/NetworkModule.kt @@ -15,7 +15,6 @@ import dev.zacsweers.metro.SingleIn import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.network.interceptors.FormattedJsonHttpLogger import io.element.android.libraries.network.interceptors.UserAgentInterceptor -import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import java.util.concurrent.TimeUnit @@ -35,12 +34,6 @@ object NetworkModule { addInterceptor(userAgentInterceptor) if (buildMeta.isDebuggable) addInterceptor(providesHttpLoggingInterceptor()) }.build() - - @Provides - @SingleIn(AppScope::class) - fun providesJson(): Json = Json { - ignoreUnknownKeys = true - } } private fun providesHttpLoggingInterceptor(): HttpLoggingInterceptor { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayDevice.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayDevice.kt index 47ebc2754b..c712a2d24b 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayDevice.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/pushgateway/PushGatewayDevice.kt @@ -21,5 +21,14 @@ data class PushGatewayDevice( * Required. The pushkey given when the pusher was created. */ @SerialName("pushkey") - val pushKey: String + val pushKey: String, + /** Optional. Additional pusher data. */ + @SerialName("data") + val data: PusherData? = null, +) + +@Serializable +data class PusherData( + @SerialName("default_payload") + val defaultPayload: Map, ) 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 ebbc305a75..0305ebad8b 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 @@ -20,5 +20,5 @@ data class PushGatewayNotification( * Required. This is an array of devices that the notification should be sent to. */ @SerialName("devices") - val devices: List + val devices: List, ) 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 65f5f8a139..907e307184 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 @@ -42,9 +42,12 @@ class DefaultPushGatewayNotifyRequest( devices = listOf( PushGatewayDevice( params.appId, - params.pushKey + params.pushKey, + PusherData(mapOf( + "cs" to "A_FAKE_SECRET", + )) ) - ) + ), ) ) ) diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt index f1290636c3..14a0bf3e85 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParser.kt @@ -13,9 +13,9 @@ import io.element.android.libraries.pushproviders.api.PushData import kotlinx.serialization.json.Json @Inject -class UnifiedPushParser { - private val json by lazy { Json { ignoreUnknownKeys = true } } - +class UnifiedPushParser( + private val json: Json, +) { fun parse(message: ByteArray, clientSecret: String): PushData? { return tryOrNull { json.decodeFromString(String(message)) }?.toPushData(clientSecret) } diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParserTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParserTest.kt index 89d4fec3b2..a269f906fe 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParserTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/UnifiedPushParserTest.kt @@ -12,6 +12,7 @@ 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.pushproviders.api.PushData import io.element.android.tests.testutils.assertThrowsInDebug +import kotlinx.serialization.json.Json import org.junit.Test class UnifiedPushParserTest { @@ -25,7 +26,7 @@ class UnifiedPushParserTest { @Test fun `test edge cases UnifiedPush`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() // Empty string assertThat(pushParser.parse("".toByteArray(), aClientSecret)).isNull() // Empty Json @@ -36,13 +37,13 @@ class UnifiedPushParserTest { @Test fun `test UnifiedPush format`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() assertThat(pushParser.parse(UNIFIED_PUSH_DATA.toByteArray(), aClientSecret)).isEqualTo(validData) } @Test fun `test empty roomId`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() assertThrowsInDebug { pushParser.parse(UNIFIED_PUSH_DATA.replace(A_ROOM_ID.value, "").toByteArray(), aClientSecret) } @@ -50,7 +51,7 @@ class UnifiedPushParserTest { @Test fun `test invalid roomId`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() assertThrowsInDebug { pushParser.parse(UNIFIED_PUSH_DATA.mutate(A_ROOM_ID.value, "aRoomId:domain"), aClientSecret) } @@ -58,7 +59,7 @@ class UnifiedPushParserTest { @Test fun `test empty eventId`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() assertThrowsInDebug { pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, ""), aClientSecret) } @@ -66,7 +67,7 @@ class UnifiedPushParserTest { @Test fun `test invalid eventId`() { - val pushParser = UnifiedPushParser() + val pushParser = createUnifiedPushParser() assertThrowsInDebug { pushParser.parse(UNIFIED_PUSH_DATA.mutate(AN_EVENT_ID.value, "anEventId"), aClientSecret) } @@ -81,3 +82,9 @@ class UnifiedPushParserTest { private fun String.mutate(oldValue: String, newValue: String): ByteArray { return replace(oldValue, newValue).toByteArray() } + +fun createUnifiedPushParser( + json: Json = Json { ignoreUnknownKeys = true }, +) = UnifiedPushParser( + json = json, +) diff --git a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt index 0215ff66ee..5465149642 100644 --- a/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt +++ b/libraries/pushproviders/unifiedpush/src/test/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiverTest.kt @@ -191,6 +191,7 @@ class VectorUnifiedPushMessagingReceiverTest { } private fun TestScope.createVectorUnifiedPushMessagingReceiver( + unifiedPushParser: UnifiedPushParser = createUnifiedPushParser(), pushHandler: PushHandler = FakePushHandler(), unifiedPushStore: UnifiedPushStore = FakeUnifiedPushStore(), unifiedPushGatewayResolver: UnifiedPushGatewayResolver = FakeUnifiedPushGatewayResolver(), @@ -199,7 +200,7 @@ class VectorUnifiedPushMessagingReceiverTest { endpointRegistrationHandler: EndpointRegistrationHandler = EndpointRegistrationHandler(), ): VectorUnifiedPushMessagingReceiver { return VectorUnifiedPushMessagingReceiver().apply { - this.pushParser = UnifiedPushParser() + this.pushParser = unifiedPushParser this.pushHandler = pushHandler this.guardServiceStarter = NoopGuardServiceStarter() this.unifiedPushStore = unifiedPushStore diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt index 81bbab5ab8..c34a0a12d3 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt @@ -22,7 +22,7 @@ import timber.log.Timber @Inject class DefaultSessionWellknownRetriever( private val matrixClient: MatrixClient, - private val parser: Json, + private val json: Json, ) : SessionWellknownRetriever { private val domain by lazy { matrixClient.userIdServerName() } @@ -32,7 +32,7 @@ class DefaultSessionWellknownRetriever( .getUrl(url) .mapCatchingExceptions { val data = String(it) - parser.decodeFromString(InternalWellKnown.serializer(), data) + json.decodeFromString(InternalWellKnown.serializer(), data) } .onFailure { Timber.e(it, "Failed to retrieve .well-known from $domain") } .map { it.map() } @@ -45,7 +45,7 @@ class DefaultSessionWellknownRetriever( .getUrl(url) .mapCatchingExceptions { val data = String(it) - parser.decodeFromString(InternalElementWellKnown.serializer(), data) + json.decodeFromString(InternalElementWellKnown.serializer(), data) } .onFailure { Timber.e(it, "Failed to retrieve Element .well-known from $domain") } .map { it.map() } diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index 624370466a..2c788cae63 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -244,6 +244,6 @@ class DefaultSessionWellknownRetrieverTest { userIdServerNameLambda = { "user.domain.org" }, getUrlLambda = getUrlLambda, ), - parser = Json { ignoreUnknownKeys = true } + json = Json { ignoreUnknownKeys = true }, ) } diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png index 126917cd1d..8bf9eeded7 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7300d8335682f4b7b8ccbba229da035cc7146f991a4655a1f12951616871398e -size 88697 +oid sha256:40570506b75d7cb582cee70eb3d6453b673087a17a18d8ef148e3ff5edb6f1b9 +size 89228 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png index cfeda876a9..b61f724c29 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1dc4637d968405a887b8db7087e3286995a0aff30c836d413992c9fff29e97a -size 40929 +oid sha256:491d0d8f7d7e269b13548c48a6eacb8fa4df5e2798aae5b3938e7eb7368ce3f9 +size 41251 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png index 9a0a2cb314..20ce14c682 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cc67ba23c47728faf5cea8f19fd4e3815721e6b08dd1432b57886efbe12d1e2 -size 86926 +oid sha256:3fb98e398abcb465b94d4138eecbccf076e229cb0807f6543d4f77ebb0353499 +size 87390 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png index 5c819158aa..0192faf169 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.spaces_HomeSpacesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46eed87406db894f387b653d32214ac376bd02cabdb200efea268bb2a4ee8240 -size 39837 +oid sha256:3bee6454b9fab1a579e86bece32c0d6134d08fed5a63fecf247a58d7acba142d +size 40125 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png index e5e9cd7d9f..71958573f2 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a0fc1b40571d634ccc59e8266861adbaa0e0764c7c625b1352b064d08fd58f2 -size 54916 +oid sha256:08f1583ccded2046d10fd19890bcc70b9fedf0efe310318a6a6209bded37b423 +size 52241 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png index 5d00038e86..e9a3aa0e6e 100644 --- a/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.home.impl_HomeView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f188d6dfb2a084f54af9c11385c227c8ef9b923e14c55713d8e5379830a50ec -size 52078 +oid sha256:e3d89f2829ddb05c63da3f4afcadf55e70a8c70b7df46d0e04eba35932fe947d +size 49455 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png new file mode 100644 index 0000000000..df6127b08e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c229f0f963e247de755f45e55432191f88a51ba79baf49f0002c2c12dbdc09e +size 48613 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png new file mode 100644 index 0000000000..830b19be50 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbf1430985870c99c6e6a2b427257235219250e1c6805bde44de64d1382bd30a +size 113544 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png new file mode 100644 index 0000000000..cb45797e1f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bc84691892f956b6d282ae5aff0a7ef7900aad754bb7f04e25582c25a256342 +size 45892 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png new file mode 100644 index 0000000000..df6127b08e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c229f0f963e247de755f45e55432191f88a51ba79baf49f0002c2c12dbdc09e +size 48613 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png new file mode 100644 index 0000000000..625d293aab --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewDay_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26a5a053b88110ed76a59a99a199ada720fd7a44ff3b95546c4993ae3d8edddf +size 37496 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png new file mode 100644 index 0000000000..d1fe942dc1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1020f77055e3369f012f73159be9e8c7bf582d4211b3b22f5409ecba46b6898 +size 47180 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png new file mode 100644 index 0000000000..fbbcced394 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47c2e74119bd6f2329f15ee3b7dbf0115c69293bd34ed5c2e67de77319b7f820 +size 111436 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png new file mode 100644 index 0000000000..b0496a7ccb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:984d43efa545fb9f104ea6d4eba87e768ade025eee8d1f74260049a64c7e7a7c +size 44401 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png new file mode 100644 index 0000000000..d1fe942dc1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1020f77055e3369f012f73159be9e8c7bf582d4211b3b22f5409ecba46b6898 +size 47180 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png new file mode 100644 index 0000000000..c6fed6a85c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportViewNight_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41c5eb671aaa7c8666942dbc808eb7b03f81cbde98906c5c17cdee61b1d9566b +size 35446 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_0_en.png deleted file mode 100644 index 98aeade96c..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c56f65335dcc9cda18ed7f647bf1dc9428ee07762ea3d40e7d28731a81ca8f2e -size 69552 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_1_en.png deleted file mode 100644 index 954d1ed9f9..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12d9e6e297bbb3429a4fe6dd3ac16847280e479fe89e96ec78f35159a51d01f0 -size 108813 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_2_en.png deleted file mode 100644 index 8f24a727e6..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9b9e42889c2b31dfee71a644b2da66c0b7cf4f4f475030d7aab3a7d500e7246a -size 66366 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_3_en.png deleted file mode 100644 index 98aeade96c..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c56f65335dcc9cda18ed7f647bf1dc9428ee07762ea3d40e7d28731a81ca8f2e -size 69552 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_4_en.png deleted file mode 100644 index a477999b9e..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Day_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:57402ade9b70c2124b6764edbaac71d30b89c49eea8175c448cbe7520867a42f -size 49569 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_0_en.png deleted file mode 100644 index 12f80074b2..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:38b5fb1099f10dae154270b5df1f52f4018d355d04e0040ba9c06ebe57f259c6 -size 67628 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_1_en.png deleted file mode 100644 index ff52e5e80b..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a5920a102082f35d0f0a7171687998f568da5e2d68a9f9d9b5884c55c832bd2 -size 106479 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_2_en.png deleted file mode 100644 index cd533fbb73..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5035c2ffa678e1c761030fbac56dfb3afd043c25a3df0cd6fb7c83b2b311c2ae -size 63678 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_3_en.png deleted file mode 100644 index 12f80074b2..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:38b5fb1099f10dae154270b5df1f52f4018d355d04e0040ba9c06ebe57f259c6 -size 67628 diff --git a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_4_en.png deleted file mode 100644 index d7be6c5994..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.rageshake.impl.bugreport_BugReportView_Night_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:946751ac246e3e833ec39da86b25d80766daed29449b1d0fcebe33c5079b724a -size 46418 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png index 93b42c769b..8e0e2b04ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:529b87a5fd0acf0fa8dedb0d62fae5e88562fca815ab7137c51009bd32124f9c -size 34574 +oid sha256:ba78cafc20c3d865fec9c7ab92f90e2565f233b224f99fb0665ad0d0c3c2be4e +size 34607 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png index cc51a9c8bb..0e81c563f9 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0cf531dc152a18e417ac79f67c6b696721d4c870e6160f865c681b71f5de81cd -size 34769 +oid sha256:fe62bb5d157ba1b4c7a4e4f443f4b1b3e7d68bc0ac59ce7edb6fbc99e2abbdf7 +size 34795 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png index 29e21fa4d8..e692443bf6 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7387422ae0e659b9133f75307fce76d2eeed7d14c5c13c8263989c6512c87159 -size 35056 +oid sha256:88db0bd5d05963761bd3b3a5a97834f8937a9a0e10723238f2c104c5d03eb81a +size 35089 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png index 6d66e293ff..b6c04763dc 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aaeb807d588360026877dbee0b15373ee3930da71b609bb286c1a2472c0046c0 -size 64629 +oid sha256:0534ab33ee18f03d219eb5b1490d41ccd1e3a4eb6bf734f31383a75110e368b3 +size 63084 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png index 807269a48e..b86ae23e63 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcc29bb9583a195023237b3078aaccb8ed50d4bd81556cfd8f2615cdbf4fb460 -size 65318 +oid sha256:85971dfed5e1cb01f5b04f43cc998d9cb69b6f06a24e3ea28f32c74aa3445e94 +size 63755 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png index 92b1384f80..0a12faa0bd 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff38ad633e2b5124c179502eb747e8fd2571160c7899f4ffde1e80a915972ad9 -size 59721 +oid sha256:3e60857b4c0d801d3a6ad7f7383b8ff8428157763ca46d30c2a559a4957cb71e +size 59706 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png index d50d9aa98b..d27c35077e 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74a676ff3c6dcc32a79c9efbf2e73511a95e1659b60a6c09344cd72606240f0c -size 34024 +oid sha256:53b3736b922b746a996f71aa38b3937ebc16e37eb40bb57cd1991d6f9d98ea33 +size 34022 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png index 337bd83602..2dcc62b1d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c983b3fd1d771d3baf38afb9d5d8ea86d13445cce34b29338f256cc97d7ed987 -size 34172 +oid sha256:4f2d6b368d4a8eaa8f3a396ba6edf8252d52b0e7ebd3b3f416c60050d3cd3c57 +size 34170 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png index 55f14f6fb7..bebf4c51f7 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d924b5eede25be4c7854ad6852ebf55b0ea69db70b9fb0815163012f22114da3 -size 34488 +oid sha256:4b0b347f48ac09d05a2348383580d26e3725af2ef48558be86541afa239f3b06 +size 34485 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png index 0bc117076e..f1e6084199 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dfd10b73e17028a8d0be148902dac4e37159b3f897fbe1fd058747bc749f4231 -size 63438 +oid sha256:b5e587b7c669fa8fd02b8202318cd405b6fbb3bc91928d56f4bf2ef12f3bbbcc +size 61863 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png index 3bd5af0514..890440ff1b 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d63f62058595f59b3557df4168e8f704ac912e6cbecbc4bbf5f8c58f3e0cb8dd -size 64034 +oid sha256:a25dcf4e97dddb032713e49e13f46836fd541382aad2a9aa9b683dbcfdd93ccc +size 62409 diff --git a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png index 08c3b84e37..4367883548 100644 --- a/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.space.impl.root_SpaceView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f10de9260c6d376add33518f8703259246663aa42ca6a6f41f080f13fe921b6 -size 57970 +oid sha256:f470577ca0f0de530db1ab0d531f5b14630f9082cc4c34ad4e3fcbc1ab9ee530 +size 57954 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en.png index b9aa714cd5..cbf7bc5ea6 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a7381573761bc4fe583892044618f58e0ff8aa5a94be09df577b1fd5d63fbd8 -size 16499 +oid sha256:ed823d5ab8f1e0b1af536c240b2d50ba741de64d443e54d998a4e2d02e373e05 +size 16202 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en.png index b3fab27ef0..8dfa3132e2 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c30ba9f665b153c5cae97e54a1bedad4f24640e2333b691d713727bf09ea262 -size 13075 +oid sha256:026c69cb2b201c1d753cd6197cdc124e208a3d3c9290d40e4de840ba0ac41cc0 +size 13054 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en.png index fa3190596a..0f72c0ecfd 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ddcf8583e7c5bc93f3d71887960d4db21a57d1b9e0422f80965ddc353fadc0cd -size 8939 +oid sha256:0da8a3a836e8b3eebb48d00fa2b5080caf80a32579d775bebd7564a525423460 +size 9019 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en.png index f87479e24a..8fd804cdb1 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:113450a4368f63f9839e27d884a8e170bde2cec2fbc483376393d7717ca0cebc -size 23564 +oid sha256:a8b5298b33db0c0e74c6a786598b1826767f5ba3bcf9187846b5b9332b81a3e3 +size 23146 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en.png index 3fcc4e2c51..1a7bf98e7c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:960c8e7d357885e40d8bda33cf87042091d1a42ac5010e7096edddb2e18605ce -size 17933 +oid sha256:7607784f41e0e7f6b4b1b4c983ed59aa466b01dd388a149b070a0540f6493d7f +size 18065 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en.png index 6de015ea4d..886a3cbb51 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db4c97fc50d11736276735af850d4416e32831ce69d7501442b23fc9e9799510 -size 13538 +oid sha256:d234be8428b62e19b4192a17f1c9c21eeee25c7fc683f1597631b0599fc34b32 +size 13625 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en.png index 6b084d8231..3ec3a1ec64 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bee6de2e44a69fdd6ebf0cff2b9dfb6871bbd4373d4e1fd0f7365a8af6a27960 -size 33646 +oid sha256:a725468cea9dfbf210d7367277b3a4d30438caf4ace60304e9942e4509c71972 +size 34014 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en.png index 410857803c..182ebc51a3 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1eece85ade6f98c31df6ebed9c20db694cf75f525668c8a838b1ab100364838d -size 38571 +oid sha256:3c325ae3939648b0684e3ce2105e46445359748bf5d765593fa5eaca5d7e7082 +size 38852 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en.png index ef920b87bf..3d321a6803 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:225368f5fd5948bf823d7ddaf712ed65f16170de8de76d01c3d733ed3595429b -size 11012 +oid sha256:82ea9e352708d800c28d2651220294c1a12bd09b98cda6676a14680c337f3b6e +size 11094 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en.png index 65aaf60f62..272b05e17c 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78bd541a6e71205688c8b323812e9c2880821ea2adef232db513548b8ee05a24 -size 15995 +oid sha256:85f42e6853aac517879a0d0379e655c7a23526e8e8a44f5c806323239df65639 +size 15810 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en.png index 993a63ba9e..3d058f4aee 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eeae2ab8fcfc3a73b23d288f721edf0aeb23ee75fec0a1cd8b8e69b5529f11ad -size 12623 +oid sha256:288b0d6fbce8b5e90bca734635705217c01bbb2e82f516d66cd0d0cb5f854f94 +size 12568 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en.png index 44335fef01..8573a7aee5 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3322f5cf8324a7dced0615fd76d26bef157432a7b1ab43d7e2be3760a821bed -size 9158 +oid sha256:0f931739c849cb283722149f9d89286633d7321d78b013281bb3333ae6af9cfd +size 9122 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en.png index 60fad82a29..c66c02a71d 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1084cee1b18ff76198f8c4aaf787f4891df0cdd3b5dc7728707133b1eacea544 -size 22667 +oid sha256:35dcf251e3bb3613c1cf5fcc4bfed6b8bb837dd721404ac80b72d804830cd483 +size 22375 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en.png index 05ed8ce296..fe91d6ff20 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ca741f017239cac3b27197b72fa545945bde79d5f6216a15a474fed84431f2d -size 17212 +oid sha256:283a7f62058a6f4d29b94a7a0d35b381a3e5038cb59bf545179b807f005aa3dd +size 17240 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en.png index 0c8229e631..be21386b79 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24e9202a8ae6fbbed41eab7567af08fbc2e3d294afe502b61463791f45d36220 -size 13131 +oid sha256:8fb4b4a6588f44d637f770456ca621e2c47bb9e730a8d24ace74028b74056309 +size 13032 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en.png index d430cb48f7..6cfb8603b1 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4ecdad099df03a2d19a86237d141e8546cfa86cbb8e03c4ace00a06950be6b6 -size 32668 +oid sha256:083774bc84a79daac071eac0fca284ce49af7fb3ae21c141684fb588bd8842ed +size 32868 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en.png index 91d3115e79..8304ff65d9 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7d25a5255487869831f2f2e65b5dc494e381993806b4ced06b0180d905bba09 -size 37334 +oid sha256:4430144e9fb2637619b0fc9cd41ef5a3be7b5a3af7831caaba8bdeb9b96555ae +size 37560 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en.png index e6086ba1b1..1653879613 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components_SpaceRoomItemView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d129cb5ef7a70ebf9b8a724c8bdc77f6f790f40a010e2712d6f5d59bcb0bf82 -size 10781 +oid sha256:e68cc7f49af74626e7019b2a4eeac37877b94f0bcba31a21fa3e20b6fde1244d +size 10724 diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes.kt.child.3.kt b/tools/templates/files/fileTemplates/Template Presentation Classes.kt.child.3.kt index 3fcdd7f219..d8b57da6b6 100644 --- a/tools/templates/files/fileTemplates/Template Presentation Classes.kt.child.3.kt +++ b/tools/templates/files/fileTemplates/Template Presentation Classes.kt.child.3.kt @@ -1,7 +1,6 @@ #if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end // TODO add your ui models. Remove the eventSink if you don't have events. -// Do not use default value, so no member get forgotten in the presenters. data class ${NAME}State( val eventSink: (${NAME}Events) -> Unit )