From 564cd4e25859f5aba52e2a72d7a30adf998de4cc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 08:51:21 +0200 Subject: [PATCH 1/8] Update dependency androidx.recyclerview:recyclerview to v1.3.2 (#1599) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a0bfc3a04..dd711b6d72 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ core = "1.12.0" datastore = "1.0.0" constraintlayout = "2.1.4" constraintlayout_compose = "1.0.1" -recyclerview = "1.3.1" +recyclerview = "1.3.2" lifecycle = "2.6.2" activity = "1.8.0" startup = "1.1.1" From 7c04f270928601bc453f42652eaaf6e359707e91 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 10:48:23 +0200 Subject: [PATCH 2/8] Update dependency io.sentry:sentry-android to v6.32.0 (#1602) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd711b6d72..b2e91fce99 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -167,7 +167,7 @@ maplibre_annotation = "org.maplibre.gl:android-plugin-annotation-v9:2.0.1" # Analytics posthog = "com.posthog.android:posthog:2.0.3" -sentry = "io.sentry:sentry-android:6.31.0" +sentry = "io.sentry:sentry-android:6.32.0" matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:e9cd9adaf18cec52ed851395eb84358b4f9b8d7f" # Emojibase From 643fe1a5e5f315d0f78cfafb0f3427edcb391c65 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Thu, 19 Oct 2023 10:49:11 +0200 Subject: [PATCH 3/8] Hide keyboard when exiting the room screen (#1593) --- changelog.d/1375.bugfix | 1 + .../android/features/messages/impl/MessagesView.kt | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 changelog.d/1375.bugfix diff --git a/changelog.d/1375.bugfix b/changelog.d/1375.bugfix new file mode 100644 index 0000000000..d80ff3543c --- /dev/null +++ b/changelog.d/1375.bugfix @@ -0,0 +1 @@ +Hide keyboard when exiting the chat room screen. diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 971df06053..b79e84a2e0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -35,6 +35,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -222,6 +223,14 @@ fun MessagesView( ReinviteDialog( state = state ) + + // Since the textfield is now based on an Android view, this is no longer done automatically. + // We need to hide the keyboard automatically when navigating out of this screen. + DisposableEffect(Unit) { + onDispose { + localView.hideKeyboard() + } + } } @Composable From fb02f698d7e2f40c02234c040ad81441967d1f76 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Thu, 19 Oct 2023 11:00:32 +0200 Subject: [PATCH 4/8] Include desugaring lib also in library modules (#1604) ## Type of change - [ ] Feature - [ ] Bugfix - [x] Technical - [ ] Other : ## Content Includes the `coreLibraryDesugaring(libs.android.desugar)` dependency in all modules which use one of our gradle plugins. ## Motivation and context Right now desugaring is enabled also in library modules but the desugar dependency is not included in those. This causes some unwanted side effects such as being unable to run compose previews in an emu. This change will also include the desugar dependency in those libraries. --- app/build.gradle.kts | 1 - libraries/pushstore/impl/build.gradle.kts | 2 -- libraries/session-storage/impl/build.gradle.kts | 2 -- plugins/src/main/kotlin/extension/CommonExtension.kt | 1 - .../kotlin/io.element.android-compose-application.gradle.kts | 4 ++++ .../main/kotlin/io.element.android-compose-library.gradle.kts | 4 ++++ plugins/src/main/kotlin/io.element.android-library.gradle.kts | 4 ++++ samples/minimal/build.gradle.kts | 1 - 8 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 839a5095dd..6ac84cfec2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -203,7 +203,6 @@ dependencies { implementation(projects.appnav) anvil(projects.anvilcodegen) - coreLibraryDesugaring(libs.android.desugar) implementation(libs.appyx.core) implementation(libs.androidx.splash) implementation(libs.androidx.core) diff --git a/libraries/pushstore/impl/build.gradle.kts b/libraries/pushstore/impl/build.gradle.kts index 5946e77694..17e0268af1 100644 --- a/libraries/pushstore/impl/build.gradle.kts +++ b/libraries/pushstore/impl/build.gradle.kts @@ -55,6 +55,4 @@ dependencies { androidTestImplementation(libs.test.truth) androidTestImplementation(libs.test.runner) androidTestImplementation(projects.libraries.sessionStorage.test) - - coreLibraryDesugaring(libs.android.desugar) } diff --git a/libraries/session-storage/impl/build.gradle.kts b/libraries/session-storage/impl/build.gradle.kts index 03de9acf86..cfbfa4c57d 100644 --- a/libraries/session-storage/impl/build.gradle.kts +++ b/libraries/session-storage/impl/build.gradle.kts @@ -45,8 +45,6 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(libs.coroutines.test) testImplementation(libs.sqldelight.driver.jvm) - - coreLibraryDesugaring(libs.android.desugar) } sqldelight { diff --git a/plugins/src/main/kotlin/extension/CommonExtension.kt b/plugins/src/main/kotlin/extension/CommonExtension.kt index e3f7b3682e..97305dbc66 100644 --- a/plugins/src/main/kotlin/extension/CommonExtension.kt +++ b/plugins/src/main/kotlin/extension/CommonExtension.kt @@ -31,7 +31,6 @@ fun CommonExtension<*, *, *, *, *>.androidConfig(project: Project) { } compileOptions { - isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } diff --git a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts index af73409888..80bc0f884e 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-application.gradle.kts @@ -32,9 +32,13 @@ plugins { android { androidConfig(project) composeConfig(libs) + compileOptions { + isCoreLibraryDesugaringEnabled = true + } } dependencies { commonDependencies(libs) composeDependencies(libs) + coreLibraryDesugaring(libs.android.desugar) } diff --git a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts index e420ab3c8d..3194505e4e 100644 --- a/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-compose-library.gradle.kts @@ -32,9 +32,13 @@ plugins { android { androidConfig(project) composeConfig(libs) + compileOptions { + isCoreLibraryDesugaringEnabled = true + } } dependencies { commonDependencies(libs) composeDependencies(libs) + coreLibraryDesugaring(libs.android.desugar) } diff --git a/plugins/src/main/kotlin/io.element.android-library.gradle.kts b/plugins/src/main/kotlin/io.element.android-library.gradle.kts index 6c3c77223c..f3a84031e6 100644 --- a/plugins/src/main/kotlin/io.element.android-library.gradle.kts +++ b/plugins/src/main/kotlin/io.element.android-library.gradle.kts @@ -29,8 +29,12 @@ plugins { android { androidConfig(project) + compileOptions { + isCoreLibraryDesugaringEnabled = true + } } dependencies { commonDependencies(libs) + coreLibraryDesugaring(libs.android.desugar) } diff --git a/samples/minimal/build.gradle.kts b/samples/minimal/build.gradle.kts index 1473bd7f93..016989a2d6 100644 --- a/samples/minimal/build.gradle.kts +++ b/samples/minimal/build.gradle.kts @@ -65,5 +65,4 @@ dependencies { implementation(projects.services.toolbox.impl) implementation(projects.libraries.featureflag.impl) implementation(libs.coroutines.core) - coreLibraryDesugaring(libs.android.desugar) } From 80870adfe3b6c9e47cb21c38160d1f7f4d758f80 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Thu, 19 Oct 2023 13:32:43 +0200 Subject: [PATCH 5/8] Extract more content from audio messages. (#1607) `TimelineItemAudioContent`: - Use `java.time.Duration` instead of milliseconds. This will ease up things in the future because currently milliseconds are sent over the wire but in the future seconds will be sent (as per the stable MSC). Using `Duration` will allow our downstream code to be independent of what's passed over the wire. - Rename `audioSource` property to `mediaSource` to better match its type. `AudioMessageType`: - Add and populate new fields `details` and `isVoiceMessage` to be used by voice messages. --- .../messages/impl/MessagesFlowNode.kt | 2 +- .../TimelineItemContentMessageFactory.kt | 7 +++-- .../model/event/TimelineItemAudioContent.kt | 5 ++-- .../event/TimelineItemAudioContentProvider.kt | 5 ++-- .../DefaultRoomLastMessageFormatterTest.kt | 2 +- .../matrix/api/media/AudioDetails.kt | 24 +++++++++++++++ .../api/timeline/item/event/MessageType.kt | 5 +++- .../matrix/impl/media/AudioDetails.kt | 30 +++++++++++++++++++ .../timeline/item/event/EventMessageMapper.kt | 8 ++++- 9 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index fcb2e7e5e8..21e384906e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -238,7 +238,7 @@ class MessagesFlowNode @AssistedInject constructor( backstack.push(navTarget) } is TimelineItemAudioContent -> { - val mediaSource = event.content.audioSource + val mediaSource = event.content.mediaSource val navTarget = NavTarget.MediaViewer( mediaInfo = MediaInfo( name = event.content.body, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt index ae2ea4f350..323f110f47 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt @@ -40,6 +40,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessage import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.api.timeline.item.event.UnknownMessageType import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType +import java.time.Duration import javax.inject.Inject class TimelineItemContentMessageFactory @Inject constructor( @@ -103,11 +104,11 @@ class TimelineItemContentMessageFactory @Inject constructor( } is AudioMessageType -> TimelineItemAudioContent( body = messageType.body, - audioSource = messageType.source, - duration = messageType.info?.duration?.toMillis() ?: 0L, + mediaSource = messageType.source, + duration = messageType.info?.duration ?: Duration.ZERO, mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream, formattedFileSize = fileSizeFormatter.format(messageType.info?.size ?: 0), - fileExtension = fileExtensionExtractor.extractFromName(messageType.body) + fileExtension = fileExtensionExtractor.extractFromName(messageType.body), ) is FileMessageType -> { val fileExtension = fileExtensionExtractor.extractFromName(messageType.body) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt index 485b863170..9d9a41e0e3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContent.kt @@ -18,11 +18,12 @@ package io.element.android.features.messages.impl.timeline.model.event import io.element.android.features.messages.impl.media.helper.formatFileExtensionAndSize import io.element.android.libraries.matrix.api.media.MediaSource +import java.time.Duration data class TimelineItemAudioContent( val body: String, - val duration: Long, - val audioSource: MediaSource, + val duration: Duration, + val mediaSource: MediaSource, val mimeType: String, val formattedFileSize: String, val fileExtension: String, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt index ed424781f8..06cb53b6fe 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemAudioContentProvider.kt @@ -19,6 +19,7 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.media.MediaSource +import java.time.Duration open class TimelineItemAudioContentProvider : PreviewParameterProvider { override val values: Sequence @@ -34,6 +35,6 @@ fun aTimelineItemAudioContent(fileName: String = "A sound.mp3") = TimelineItemAu mimeType = MimeTypes.Pdf, formattedFileSize = "100kB", fileExtension = "mp3", - duration = 100, - audioSource = MediaSource(""), + duration = Duration.ofMillis(100), + mediaSource = MediaSource(""), ) diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt index 4c26fcb3c7..50d313f132 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt @@ -161,7 +161,7 @@ class DefaultRoomLastMessageFormatterTest { val sharedContentMessagesTypes = arrayOf( TextMessageType(body, null), VideoMessageType(body, MediaSource("url"), null), - AudioMessageType(body, MediaSource("url"), null), + AudioMessageType(body, MediaSource("url"), null, null, false), ImageMessageType(body, MediaSource("url"), null), FileMessageType(body, MediaSource("url"), null), LocationMessageType(body, "geo:1,2", null), diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt new file mode 100644 index 0000000000..f8cd2d3fb4 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/AudioDetails.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.media + +import java.time.Duration + +data class AudioDetails( + val duration: Duration, + val waveform: List, +) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt index dc06d5c94a..ba6eeca819 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/MessageType.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.api.timeline.item.event +import io.element.android.libraries.matrix.api.media.AudioDetails import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.ImageInfo @@ -46,7 +47,9 @@ data class LocationMessageType( data class AudioMessageType( val body: String, val source: MediaSource, - val info: AudioInfo? + val info: AudioInfo?, + val details: AudioDetails?, + val isVoiceMessage: Boolean, ) : MessageType data class VideoMessageType( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt new file mode 100644 index 0000000000..c3fa11e40c --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/AudioDetails.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.media + +import io.element.android.libraries.matrix.api.media.AudioDetails +import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent as RustAudioDetails + +fun RustAudioDetails.map(): AudioDetails = AudioDetails( + duration = duration, + waveform = waveform.map { it.toInt() }, +) + +fun AudioDetails.map(): RustAudioDetails = RustAudioDetails( + duration = duration, + waveform = waveform.map { it.toUShort() } +) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt index 0a59cfddab..18d2e1bdeb 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt @@ -75,7 +75,13 @@ class EventMessageMapper { fun mapMessageType(type: RustMessageType?) = when (type) { is RustMessageType.Audio -> { - AudioMessageType(type.content.body, type.content.source.map(), type.content.info?.map()) + AudioMessageType( + body = type.content.body, + source = type.content.source.map(), + info = type.content.info?.map(), + details = type.content.audio?.map(), + isVoiceMessage = type.content.voice != null, + ) } is RustMessageType.File -> { FileMessageType(type.content.body, type.content.source.map(), type.content.info?.map()) From d7054fb34d6b7beae6431a9d19181599c1cf48c1 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Thu, 19 Oct 2023 14:07:45 +0200 Subject: [PATCH 6/8] Add global `context.cacheDir` provider. (#1606) ## Type of change - [ ] Feature - [ ] Bugfix - [x] Technical - [ ] Other : ## Content Dagger now provides the app's `cacheDir` when requesting a `@CacheDirectory File` type. ## Motivation and context To support some upcoming code that needs the `cacheDir` to be changed during tests. --- .../io/element/android/x/di/AppModule.kt | 7 +++++ .../libraries/di/ApplicationContext.kt | 8 +++++- .../android/libraries/di/CacheDirectory.kt | 27 +++++++++++++++++++ .../matrix/impl/RustMatrixClientFactory.kt | 7 +++-- .../android/samples/minimal/MainActivity.kt | 2 +- 5 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 libraries/di/src/main/kotlin/io/element/android/libraries/di/CacheDirectory.kt 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 17ba415762..037cec1e71 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 @@ -31,6 +31,7 @@ import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.di.DefaultPreferences import io.element.android.libraries.di.SingleIn import io.element.android.x.BuildConfig @@ -51,6 +52,12 @@ object AppModule { return File(context.filesDir, "sessions") } + @Provides + @CacheDirectory + fun providesCacheDirectory(@ApplicationContext context: Context): File { + return context.cacheDir + } + @Provides fun providesResources(@ApplicationContext context: Context): Resources { return context.resources diff --git a/libraries/di/src/main/kotlin/io/element/android/libraries/di/ApplicationContext.kt b/libraries/di/src/main/kotlin/io/element/android/libraries/di/ApplicationContext.kt index 2108678097..421b521192 100644 --- a/libraries/di/src/main/kotlin/io/element/android/libraries/di/ApplicationContext.kt +++ b/libraries/di/src/main/kotlin/io/element/android/libraries/di/ApplicationContext.kt @@ -18,4 +18,10 @@ package io.element.android.libraries.di import javax.inject.Qualifier -@Qualifier annotation class ApplicationContext +/** + * Qualifies a [Context] object that represents the application context. + */ +@Retention(AnnotationRetention.RUNTIME) +@MustBeDocumented +@Qualifier +annotation class ApplicationContext diff --git a/libraries/di/src/main/kotlin/io/element/android/libraries/di/CacheDirectory.kt b/libraries/di/src/main/kotlin/io/element/android/libraries/di/CacheDirectory.kt new file mode 100644 index 0000000000..e8513bef45 --- /dev/null +++ b/libraries/di/src/main/kotlin/io/element/android/libraries/di/CacheDirectory.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.di + +import javax.inject.Qualifier + +/** + * Qualifies a [File] object which represents the application cache directory. + */ +@Retention(AnnotationRetention.RUNTIME) +@MustBeDocumented +@Qualifier +annotation class CacheDirectory diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index b37266342e..b1cb3ffac4 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -16,9 +16,8 @@ package io.element.android.libraries.matrix.impl -import android.content.Context import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.network.useragent.UserAgentProvider import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore @@ -32,8 +31,8 @@ import java.io.File import javax.inject.Inject class RustMatrixClientFactory @Inject constructor( - @ApplicationContext private val context: Context, private val baseDirectory: File, + @CacheDirectory private val cacheDirectory: File, private val appCoroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, private val sessionStore: SessionStore, @@ -63,7 +62,7 @@ class RustMatrixClientFactory @Inject constructor( appCoroutineScope = appCoroutineScope, dispatchers = coroutineDispatchers, baseDirectory = baseDirectory, - baseCacheDirectory = context.cacheDir, + baseCacheDirectory = cacheDirectory, clock = clock, ) } diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index c95a44d8ea..a405167cbf 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -49,8 +49,8 @@ class MainActivity : ComponentActivity() { sessionStore = sessionStore, userAgentProvider = userAgentProvider, rustMatrixClientFactory = RustMatrixClientFactory( - context = applicationContext, baseDirectory = baseDirectory, + cacheDirectory = applicationContext.cacheDir, appCoroutineScope = Singleton.appScope, coroutineDispatchers = Singleton.coroutineDispatchers, sessionStore = sessionStore, From cf3039c6f3a75927a4d8c48b23fe046dda68ea46 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Thu, 19 Oct 2023 15:57:34 +0200 Subject: [PATCH 7/8] TimelineItemPresenterFactories (#1609) DI infrastructure to allow injection of presenters into the timeline. Add an `@AssistedFactory` of type `TimelineItemPresenterFactory` to a `Presenter` class and bind this factory into the TimelineItemPresenterFactory map multi binding using: ``` @Binds @IntoMap @TimelineItemEventContentKey(MyTimelineItemContent::class) ``` A map multibinding of such factories will be available in the `LocalTimelineItemPresenterFactories` composition local for further use down the UI tree. --- .../features/messages/impl/MessagesNode.kt | 32 +++++--- .../di/TimelineItemEventContentKey.kt | 29 +++++++ .../di/TimelineItemPresenterFactories.kt | 77 +++++++++++++++++++ .../di/TimelineItemPresenterFactory.kt | 33 ++++++++ tools/detekt/detekt.yml | 2 +- 5 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemEventContentKey.kt create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactories.kt create mode 100644 features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactory.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 6a3cf502d7..dbf7e2fbb2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -17,6 +17,7 @@ package io.element.android.features.messages.impl import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext @@ -28,6 +29,8 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories +import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactories import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId @@ -44,6 +47,7 @@ class MessagesNode @AssistedInject constructor( private val room: MatrixRoom, private val analyticsService: AnalyticsService, private val presenterFactory: MessagesPresenter.Factory, + private val timelineItemPresenterFactories: TimelineItemPresenterFactories, ) : Node(buildContext, plugins = plugins), MessagesNavigator { private val presenter = presenterFactory.create(this) @@ -106,17 +110,21 @@ class MessagesNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - val state = presenter.present() - MessagesView( - state = state, - onBackPressed = this::navigateUp, - onRoomDetailsClicked = this::onRoomDetailsClicked, - onEventClicked = this::onEventClicked, - onPreviewAttachments = this::onPreviewAttachments, - onUserDataClicked = this::onUserDataClicked, - onSendLocationClicked = this::onSendLocationClicked, - onCreatePollClicked = this::onCreatePollClicked, - modifier = modifier, - ) + CompositionLocalProvider( + LocalTimelineItemPresenterFactories provides timelineItemPresenterFactories, + ) { + val state = presenter.present() + MessagesView( + state = state, + onBackPressed = this::navigateUp, + onRoomDetailsClicked = this::onRoomDetailsClicked, + onEventClicked = this::onEventClicked, + onPreviewAttachments = this::onPreviewAttachments, + onUserDataClicked = this::onUserDataClicked, + onSendLocationClicked = this::onSendLocationClicked, + onCreatePollClicked = this::onCreatePollClicked, + modifier = modifier, + ) + } } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemEventContentKey.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemEventContentKey.kt new file mode 100644 index 0000000000..9cb046a054 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemEventContentKey.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.di + +import dagger.MapKey +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import kotlin.reflect.KClass + +/** + * Annotation to add a factory of type [TimelineItemPresenterFactory] to a + * Dagger map multi binding keyed with a subclass of [TimelineItemEventContent]. + */ +@Retention(AnnotationRetention.RUNTIME) +@MapKey +annotation class TimelineItemEventContentKey(val value: KClass) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactories.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactories.kt new file mode 100644 index 0000000000..0574f7e903 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactories.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.di + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.staticCompositionLocalOf +import com.squareup.anvil.annotations.ContributesTo +import dagger.Module +import dagger.multibindings.Multibinds +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.RoomScope +import javax.inject.Inject + +/** + * Dagger module that declares the [TimelineItemPresenterFactory] map multi binding. + * + * Its sole purpose is to support the case of an empty map multibinding. + */ +@Module +@ContributesTo(RoomScope::class) +interface TimelineItemPresenterFactoriesModule { + @Multibinds + fun multiBindTimelineItemPresenterFactories(): @JvmSuppressWildcards Map, TimelineItemPresenterFactory<*, *>> +} + +/** + * Wrapper around the [TimelineItemPresenterFactory] map multi binding. + * + * Its only purpose is to provide a nicer type name than: + * `@JvmSuppressWildcards Map, TimelineItemPresenterFactory<*, *>>`. + * + * A typealias would have been better but typealiases on Dagger types which use @JvmSuppressWildcards + * currently make Dagger crash. + * + * Request this type from Dagger to access the [TimelineItemPresenterFactory] map multibinding. + */ +data class TimelineItemPresenterFactories @Inject constructor( + val factories: @JvmSuppressWildcards Map, TimelineItemPresenterFactory<*, *>>, +) + +/** + * Provides a [TimelineItemPresenterFactories] to the composition. + */ +val LocalTimelineItemPresenterFactories = staticCompositionLocalOf { + TimelineItemPresenterFactories(emptyMap()) +} + +/** + * Creates and remembers a presenter for the given content. + * + * Will throw if the presenter is not found in the [TimelineItemPresenterFactory] map multi binding. + */ +@Composable +inline fun TimelineItemPresenterFactories.rememberPresenter( + content: C +): Presenter = remember(content) { + factories.getValue(C::class.java).let { + @Suppress("UNCHECKED_CAST") + (it as TimelineItemPresenterFactory).create(content) + } +} diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactory.kt new file mode 100644 index 0000000000..f79d606f60 --- /dev/null +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/di/TimelineItemPresenterFactory.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.timeline.di + +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent +import io.element.android.libraries.architecture.Presenter + +/** + * A factory for a [Presenter] associated with a timeline item. + * + * Implementations should be annotated with [AssistedFactory] to be created by Dagger. + * + * @param C The timeline item's [TimelineItemEventContent] subtype. + * @param S The [Presenter]'s state class. + * @return A [Presenter] that produces a state of type [S] for the given content of type [C]. + */ +fun interface TimelineItemPresenterFactory { + fun create(content: C): Presenter +} diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml index 1c226dd5ed..ca8370ae23 100644 --- a/tools/detekt/detekt.yml +++ b/tools/detekt/detekt.yml @@ -219,7 +219,7 @@ Compose: CompositionLocalAllowlist: active: true # You can optionally define a list of CompositionLocals that are allowed here - allowedCompositionLocals: LocalCompoundColors, LocalSnackbarDispatcher, LocalCameraPositionState + allowedCompositionLocals: LocalCompoundColors, LocalSnackbarDispatcher, LocalCameraPositionState, LocalTimelineItemPresenterFactories CompositionLocalNaming: active: true ContentEmitterReturningValues: From 919e0d730107be88bfb151c9f4de961f7239a0b1 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 19 Oct 2023 15:47:25 +0000 Subject: [PATCH 8/8] Update screenshots --- ...ultNotificationSettingView-D-8_8_null_0,NEXUS_5,1.0,en].png | 3 +++ ...ultNotificationSettingView-N-8_9_null_0,NEXUS_5,1.0,en].png | 3 +++ ...ull_EditUserProfileView-D-10_10_null_0,NEXUS_5,1.0,en].png} | 0 ...ull_EditUserProfileView-N-10_11_null_0,NEXUS_5,1.0,en].png} | 0 ...user_null_UserPreferences-D-9_9_null_0,NEXUS_5,1.0,en].png} | 0 ...user_null_UserPreferences-D-9_9_null_1,NEXUS_5,1.0,en].png} | 0 ...user_null_UserPreferences-D-9_9_null_2,NEXUS_5,1.0,en].png} | 0 ...ser_null_UserPreferences-N-9_10_null_0,NEXUS_5,1.0,en].png} | 0 ...ser_null_UserPreferences-N-9_10_null_1,NEXUS_5,1.0,en].png} | 0 ...ser_null_UserPreferences-N-9_10_null_2,NEXUS_5,1.0,en].png} | 0 ...edRoomNotificationSettings-D-5_5_null_0,NEXUS_5,1.0,en].png | 3 +++ ...edRoomNotificationSettings-N-5_6_null_0,NEXUS_5,1.0,en].png | 3 +++ ...ts.avatar_null_Avatars_Avatar_0_null_48,NEXUS_5,1.0,en].png | 3 +++ ...ts.avatar_null_Avatars_Avatar_0_null_49,NEXUS_5,1.0,en].png | 3 +++ ...ts.avatar_null_Avatars_Avatar_0_null_50,NEXUS_5,1.0,en].png | 3 +++ 15 files changed, 21 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-D-8_8_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-N-8_9_null_0,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-9_9_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-10_10_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-9_10_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-10_11_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_2,NEXUS_5,1.0,en].png} (100%) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-D-5_5_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-N-5_6_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_48,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_49,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_50,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-D-8_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-D-8_8_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..1d4750eecb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-D-8_8_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1172d81259b7e7b694f428c5144d96c8a7748134f5b4f515a5c25c58ff8e5e1b +size 31318 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-N-8_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-N-8_9_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..c423fe4456 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.notifications.edit_null_EditDefaultNotificationSettingView-N-8_9_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e835ab12c0a77c4a4dcaf8bac0d78ed5ec9a0ab8eef669c7d814317ab06abd27 +size 28443 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-9_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-10_10_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-9_9_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-D-10_10_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-9_10_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-10_11_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-9_10_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user.editprofile_null_EditUserProfileView-N-10_11_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-8_8_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-D-9_9_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-8_9_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.user_null_UserPreferences-N-9_10_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-D-5_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-D-5_5_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..d26299f528 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-D-5_5_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:372ff5eca3c8c9de6bb15d5ae9a55f1d8ec124c7e454d411be6bd28f78d3aed0 +size 24324 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-N-5_6_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-N-5_6_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..f8beb00ae9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_UserDefinedRoomNotificationSettings-N-5_6_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3795832f75ba48402f228dbd5be5dc05b10dab00242922fb861c0f77fcd391e4 +size 22853 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_48,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_48,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..a3d0076294 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_48,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2619a9a70eca12d5931ebc21adce48a1aed8383f35908bb09546f44b40f04543 +size 23094 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_49,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_49,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..81b9668b0f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_49,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d7d71d58b250bdec2d9b6e1ed46c5e3ffd98ffeefcaf4267b9979970a89750b +size 22226 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_50,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_50,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..5cb8c0a0bf --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.components.avatar_null_Avatars_Avatar_0_null_50,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7bdea3caef3f1be9fac1fbb5511fe2d76b7985576c038f8c1d920615c3d49cd +size 25005