From d0d73e04c122e766da6f512485c7c18dbe43d813 Mon Sep 17 00:00:00 2001 From: Marco Romano Date: Fri, 24 Nov 2023 16:48:01 +0100 Subject: [PATCH 01/24] WIP: Poll History --- .../poll/api/history/PollHistoryEntryPoint.kt | 25 ++++ .../history/DefaultPollHistoryEntryPoint.kt | 32 +++++ .../poll/impl/history/PollHistoryEvents.kt | 21 ++++ .../impl/history/PollHistoryLoadedNode.kt | 69 +++++++++++ .../impl/history/PollHistoryLoadingNode.kt | 50 ++++++++ .../poll/impl/history/PollHistoryNode.kt | 111 +++++++++++++++++ .../poll/impl/history/PollHistoryPresenter.kt | 72 +++++++++++ .../poll/impl/history/PollHistoryState.kt | 27 +++++ .../impl/history/PollHistoryStateProvider.kt | 24 ++++ .../poll/impl/history/PollHistoryView.kt | 113 ++++++++++++++++++ features/roomdetails/impl/build.gradle.kts | 1 + .../roomdetails/impl/RoomDetailsFlowNode.kt | 13 ++ .../roomdetails/impl/RoomDetailsNode.kt | 6 + .../roomdetails/impl/RoomDetailsView.kt | 20 ++++ 14 files changed, 584 insertions(+) create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt new file mode 100644 index 0000000000..573ac0ee10 --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/history/PollHistoryEntryPoint.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.poll.api.history + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import io.element.android.libraries.architecture.FeatureEntryPoint + +interface PollHistoryEntryPoint : FeatureEntryPoint { + fun createNode(parentNode: Node, buildContext: BuildContext): Node +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt new file mode 100644 index 0000000000..bda4e042ab --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt @@ -0,0 +1,32 @@ +/* + * 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.poll.impl.history + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.poll.api.history.PollHistoryEntryPoint +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultPollHistoryEntryPoint @Inject constructor() : PollHistoryEntryPoint { + override fun createNode(parentNode: Node, buildContext: BuildContext): Node { + return parentNode.createNode(buildContext) + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt new file mode 100644 index 0000000000..1eb676b961 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt @@ -0,0 +1,21 @@ +/* + * 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.poll.impl.history + +sealed interface PollHistoryEvents { + data object History : PollHistoryEvents +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt new file mode 100644 index 0000000000..665700e52c --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt @@ -0,0 +1,69 @@ +/* + * 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.poll.impl.history + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.lifecycle.subscribe +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import io.element.android.services.analytics.api.AnalyticsService + +@ContributesNode(RoomScope::class) +class PollHistoryLoadedNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + presenterFactory: PollHistoryPresenter.Factory, + analyticsService: AnalyticsService, +) : Node( + buildContext = buildContext, + plugins = plugins +) { + data class Inputs( + val pollHistory: MatrixTimeline, + ) : NodeInputs + + private val inputs: Inputs = inputs() + private val presenter = presenterFactory.create( + inputs.pollHistory, + ) + + init { + lifecycle.subscribe( + onResume = { + // analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreatePollView)) // TODO + } + ) + } + + @Composable + override fun View(modifier: Modifier) { + PollHistoryView( + state = presenter.present(), + modifier = modifier, + goBack = this::navigateUp, + ) + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt new file mode 100644 index 0000000000..4eddd009e3 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt @@ -0,0 +1,50 @@ +/* + * 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.poll.impl.history + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.di.RoomScope + +@ContributesNode(RoomScope::class) +class PollHistoryLoadingNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : Node( + buildContext = buildContext, + plugins = plugins +) { + @Composable + override fun View(modifier: Modifier) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator() + } + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt new file mode 100644 index 0000000000..2ae20c8e12 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt @@ -0,0 +1,111 @@ +/* + * 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.poll.impl.history + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.lifecycle.lifecycleScope +import com.bumble.appyx.core.composable.Children +import com.bumble.appyx.core.lifecycle.subscribe +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.newRoot +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize + +@ContributesNode(RoomScope::class) +class PollHistoryNode @AssistedInject constructor( + private val room: MatrixRoom, + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.PollHistoryLoading, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins, +) { + sealed interface NavTarget : Parcelable { + @Parcelize + data object PollHistoryLoading : NavTarget + + @Parcelize + data object PollHistoryLoaded : NavTarget + } + + private var pollHistory: MatrixTimeline? = null + + override fun onBuilt() { + super.onBuilt() + lifecycle.subscribe( + onCreate = { + lifecycleScope.launch { + runCatching { + room.pollHistory() + }.onSuccess { + pollHistory = it + backstack.newRoot(NavTarget.PollHistoryLoaded) + } + } + }, + onDestroy = { + pollHistory?.close() + }, + ) + } + + override fun resolve( + navTarget: NavTarget, + buildContext: BuildContext + ): Node = when (navTarget) { + is NavTarget.PollHistoryLoading -> createNode( + buildContext = buildContext, + ) + is NavTarget.PollHistoryLoaded -> { + createNode( + buildContext = buildContext, + plugins = listOf( + PollHistoryLoadedNode.Inputs( + pollHistory = pollHistory ?: error("Poll history not loaded"), + ) + ), + ) + } + } + + @Composable + override fun View(modifier: Modifier) { + Children( + navModel = backstack, + modifier = modifier, + transitionHandler = rememberDefaultTransitionHandler(), + ) + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt new file mode 100644 index 0000000000..1025b2184d --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -0,0 +1,72 @@ +/* + * 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.poll.impl.history + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach + +class PollHistoryPresenter @AssistedInject constructor( + @Assisted private val pollHistory: MatrixTimeline, +) : Presenter { + + @AssistedFactory + interface Factory { + fun create( + pollHistory: MatrixTimeline, + ): PollHistoryPresenter + } + + @Composable + override fun present(): PollHistoryState { + val paginationState by pollHistory.paginationState.collectAsState() + val timelineItemsFlow = remember { + pollHistory.timelineItems.map { items -> + items.filterIsInstance() + .map { it.event.content } + .filterIsInstance() + .reversed() + }.onEach { + if (it.isEmpty()) pollHistory.paginateBackwards(20, 50) + } + } + val items by timelineItemsFlow.collectAsState(initial = emptyList()) + + fun handleEvents(event: PollHistoryEvents) { + when (event) { + is PollHistoryEvents.History -> Unit // TODO which events to handle? + } + } + + return PollHistoryState( + paginationState = paginationState, + matrixTimelineItems = items.toImmutableList(), + eventSink = ::handleEvents, + ) + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt new file mode 100644 index 0000000000..4354736aba --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt @@ -0,0 +1,27 @@ +/* + * 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.poll.impl.history + +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.collections.immutable.ImmutableList + +data class PollHistoryState( + val paginationState: MatrixTimeline.PaginationState, + val matrixTimelineItems: ImmutableList, + val eventSink: (PollHistoryEvents) -> Unit, +) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt new file mode 100644 index 0000000000..880b68d178 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.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.features.poll.impl.history + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +class PollHistoryStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf() // TODO +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt new file mode 100644 index 0000000000..93a3e3c90c --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -0,0 +1,113 @@ +/* + * 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.poll.impl.history + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.PreviewParameter +import io.element.android.compound.theme.ElementTheme +import io.element.android.features.poll.api.PollAnswerItem +import io.element.android.features.poll.api.PollContentView +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.aliasScreenTitle +import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.matrix.api.poll.PollAnswer +import kotlinx.collections.immutable.toImmutableList + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PollHistoryView( + state: PollHistoryState, + modifier: Modifier = Modifier, + goBack: () -> Unit, +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + title = { + Text( + text = "Polls", // TODO Polls: Localazy + style = ElementTheme.typography.aliasScreenTitle, + ) + }, + navigationIcon = { + BackButton(onClick = goBack) + }, + ) + }, + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + reverseLayout = false, + ) { + if (state.paginationState.isBackPaginating) item { + CircularProgressIndicator() + } + items(state.matrixTimelineItems) { pollContent -> + PollContentView( + eventId = null, + question = pollContent.question, + answerItems = pollContent.answers.map { + PollAnswerItem( + answer = PollAnswer( + id = it.id, + text = it.text, + ), + isSelected = false, + isEnabled = false, + isWinner = false, + isDisclosed = false, + votesCount = 9393, + percentage = 4.5f, + ) + }.toImmutableList(), + pollKind = pollContent.kind, + isPollEditable = false, + isPollEnded = false, + isMine = false, + onAnswerSelected = { _, _ -> }, + onPollEdit = {}, + onPollEnd = {}, + ) + } + } + } +} + +@PreviewsDayNight +@Composable +internal fun PollHistoryViewPreview( + @PreviewParameter(PollHistoryStateProvider::class) state: PollHistoryState +) = ElementPreview { + PollHistoryView( + state = state, + goBack = {}, + ) +} diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index e35526ec37..5f389bcfe9 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { implementation(libs.coil.compose) implementation(projects.features.leaveroom.api) implementation(projects.services.analytics.api) + implementation(projects.features.poll.api) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 60e302494e..2e58ccfe4e 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -29,6 +29,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.poll.api.history.PollHistoryEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint import io.element.android.features.roomdetails.impl.edit.RoomDetailsEditNode import io.element.android.features.roomdetails.impl.invite.RoomInviteMembersNode @@ -51,6 +52,7 @@ import kotlinx.parcelize.Parcelize class RoomDetailsFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, + private val pollHistoryEntryPoint: PollHistoryEntryPoint, ) : BackstackNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), @@ -87,6 +89,9 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Parcelize data class MemberAvatarPreview(val userName: String, val avatarUrl: String) : NavTarget + + @Parcelize + data object PollHistory : NavTarget } override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { @@ -112,6 +117,10 @@ class RoomDetailsFlowNode @AssistedInject constructor( override fun openAvatarPreview(username: String, url: String) { backstack.push(NavTarget.MemberAvatarPreview(username, url)) } + + override fun openPollHistory() { + backstack.push(NavTarget.PollHistory) + } } createNode(buildContext, listOf(roomDetailsCallback)) } @@ -173,6 +182,10 @@ class RoomDetailsFlowNode @AssistedInject constructor( ) createNode(buildContext, listOf(input)) } + + is NavTarget.PollHistory -> { + pollHistoryEntryPoint.createNode(this, buildContext) + } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt index f3fa9e2645..d243bcebdf 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt @@ -53,6 +53,7 @@ class RoomDetailsNode @AssistedInject constructor( fun editRoomDetails() fun openRoomNotificationSettings() fun openAvatarPreview(username: String, url: String) + fun openPollHistory() } private val callbacks = plugins() @@ -77,6 +78,10 @@ class RoomDetailsNode @AssistedInject constructor( callbacks.forEach { it.openInviteMembers() } } + private fun openPollHistory() { + callbacks.forEach { it.openPollHistory() } + } + private fun onShareRoom(context: Context) { val alias = room.alias ?: room.alternativeAliases.firstOrNull() val permalinkResult = alias?.let { PermalinkBuilder.permalinkForRoomAlias(it) } @@ -146,6 +151,7 @@ class RoomDetailsNode @AssistedInject constructor( openRoomNotificationSettings = ::openRoomNotificationSettings, invitePeople = ::invitePeople, openAvatarPreview = ::openAvatarPreview, + openPollHistory = ::openPollHistory, ) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 9c7151d4af..0f92b466f4 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -90,6 +90,7 @@ fun RoomDetailsView( openRoomNotificationSettings: () -> Unit, invitePeople: () -> Unit, openAvatarPreview: (username: String, url: String) -> Unit, + openPollHistory: () -> Unit, modifier: Modifier = Modifier, ) { fun onShareMember() { @@ -172,6 +173,10 @@ fun RoomDetailsView( } } + PollsSection( + openPollHistory = openPollHistory + ) + if (state.isEncrypted) { SecuritySection() } @@ -373,6 +378,20 @@ private fun InviteSection( } } +@Composable +private fun PollsSection( + openPollHistory: () -> Unit, + modifier: Modifier = Modifier, +) { + PreferenceCategory(modifier = modifier) { + ListItem( + headlineContent = { Text("Polls") }, // TODO Polls: Localazy + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls)), + onClick = openPollHistory, + ) + } +} + @Composable private fun SecuritySection(modifier: Modifier = Modifier) { PreferenceCategory(title = stringResource(R.string.screen_room_details_security_title), modifier = modifier) { @@ -418,5 +437,6 @@ private fun ContentToPreview(state: RoomDetailsState) { openRoomNotificationSettings = {}, invitePeople = {}, openAvatarPreview = { _, _ -> }, + openPollHistory = {}, ) } From 4a2cbb1ed4444fc93e5c0c5c2eeaeada472c0eaa Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 5 Dec 2023 14:06:59 +0100 Subject: [PATCH 02/24] Polls: share logic around PollContent --- .../impl/timeline/TimelinePresenter.kt | 17 ++- .../components/TimelineItemEventRow.kt | 4 +- .../components/TimelineItemStateEventRow.kt | 4 +- .../event/TimelineItemEventContentView.kt | 4 - .../components/event/TimelineItemPollView.kt | 12 +-- .../event/TimelineItemContentFactory.kt | 2 +- .../event/TimelineItemContentPollFactory.kt | 55 +++------- .../model/event/TimelineItemPollContent.kt | 4 +- .../event/TimelineItemPollContentProvider.kt | 12 ++- .../actionlist/ActionListPresenterTest.kt | 2 +- .../TimelineItemContentPollFactoryTest.kt | 58 +++++++--- .../poll/api/actions/EndPollAction.kt | 23 ++++ .../api/actions/SendPollResponseAction.kt | 23 ++++ .../api/{ => pollcontent}/PollAnswerItem.kt | 2 +- .../api/{ => pollcontent}/PollAnswerView.kt | 2 +- .../PollAnswerViewProvider.kt | 2 +- .../poll/api/pollcontent/PollContentState.kt | 31 ++++++ .../pollcontent/PollContentStateFactory.kt | 24 +++++ .../api/{ => pollcontent}/PollContentView.kt | 25 ++++- features/poll/impl/build.gradle.kts | 1 + .../poll/impl/actions/DefaultEndPollAction.kt | 42 ++++++++ .../actions/DefaultSendPollResponseAction.kt | 43 ++++++++ .../poll/impl/history/PollHistoryEvents.kt | 7 +- .../poll/impl/history/PollHistoryItem.kt | 23 ++++ .../impl/history/PollHistoryItemsFactory.kt | 51 +++++++++ .../poll/impl/history/PollHistoryPresenter.kt | 43 +++++--- .../poll/impl/history/PollHistoryState.kt | 3 +- .../poll/impl/history/PollHistoryView.kt | 102 ++++++++++++------ .../model/DefaultPollContentStateFactory.kt | 80 ++++++++++++++ .../matrix/api/timeline/MatrixTimeline.kt | 3 +- .../impl/timeline/RustMatrixTimeline.kt | 16 +-- 31 files changed, 571 insertions(+), 149 deletions(-) create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/EndPollAction.kt create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/SendPollResponseAction.kt rename features/poll/api/src/main/kotlin/io/element/android/features/poll/api/{ => pollcontent}/PollAnswerItem.kt (96%) rename features/poll/api/src/main/kotlin/io/element/android/features/poll/api/{ => pollcontent}/PollAnswerView.kt (99%) rename features/poll/api/src/main/kotlin/io/element/android/features/poll/api/{ => pollcontent}/PollAnswerViewProvider.kt (97%) create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt create mode 100644 features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt rename features/poll/api/src/main/kotlin/io/element/android/features/poll/api/{ => pollcontent}/PollContentView.kt (93%) create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index a2e9858d9f..00728efc1e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -30,14 +30,14 @@ import androidx.compose.runtime.saveable.rememberSaveable import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.features.analytics.plan.PollEnd -import im.vector.app.features.analytics.plan.PollVote import io.element.android.features.messages.impl.MessagesNavigator import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.featureflag.api.FeatureFlagService @@ -52,7 +52,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemE import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.ui.room.canSendMessageAsState -import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn @@ -69,11 +68,12 @@ class TimelinePresenter @AssistedInject constructor( private val dispatchers: CoroutineDispatchers, private val appScope: CoroutineScope, @Assisted private val navigator: MessagesNavigator, - private val analyticsService: AnalyticsService, private val verificationService: SessionVerificationService, private val encryptionService: EncryptionService, private val featureFlagService: FeatureFlagService, private val redactedVoiceMessageManager: RedactedVoiceMessageManager, + private val sendPollResponseAction: SendPollResponseAction, + private val endPollAction: EndPollAction, ) : Presenter { @AssistedFactory @@ -132,18 +132,15 @@ class TimelinePresenter @AssistedInject constructor( ) } is TimelineEvents.PollAnswerSelected -> appScope.launch { - room.sendPollResponse( + sendPollResponseAction.execute( pollStartId = event.pollStartId, - answers = listOf(event.answerId), + answerId = event.answerId ) - analyticsService.capture(PollVote()) } is TimelineEvents.PollEndClicked -> appScope.launch { - room.endPoll( + endPollAction.execute( pollStartId = event.pollStartId, - text = "The poll with event id: ${event.pollStartId} has ended." ) - analyticsService.capture(PollEnd()) } is TimelineEvents.PollEditClicked -> navigator.onEditPollClicked(event.pollStartId) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 0c5b33747b..7a35d565ef 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -517,12 +517,10 @@ private fun MessageEventBubbleContent( ) { TimelineItemEventContentView( content = event.content, - isMine = event.isMine, - isEditable = event.isEditable, interactionSource = interactionSource, + extraPadding = event.toExtraPadding(), onClick = onMessageClick, onLongClick = onMessageLongClick, - extraPadding = event.toExtraPadding(), eventSink = eventSink, modifier = contentModifier, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt index fbf39125b3..4a48605355 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemStateEventRow.kt @@ -80,12 +80,10 @@ fun TimelineItemStateEventRow( ) { TimelineItemEventContentView( content = event.content, - isMine = event.isMine, - isEditable = event.isEditable, interactionSource = interactionSource, + extraPadding = noExtraPadding, onClick = onClick, onLongClick = onLongClick, - extraPadding = noExtraPadding, eventSink = eventSink, modifier = Modifier.defaultTimelineContentPadding() ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt index 77537b9565..2e243bea6d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemEventContentView.kt @@ -41,8 +41,6 @@ import io.element.android.libraries.architecture.Presenter @Composable fun TimelineItemEventContentView( content: TimelineItemEventContent, - isMine: Boolean, - isEditable: Boolean, interactionSource: MutableInteractionSource, extraPadding: ExtraPadding, onClick: () -> Unit, @@ -103,8 +101,6 @@ fun TimelineItemEventContentView( ) is TimelineItemPollContent -> TimelineItemPollView( content = content, - isMine = isMine, - isEditable = isEditable, eventSink = eventSink, modifier = modifier, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt index c334b2cc56..4754bf6298 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContentProvider -import io.element.android.features.poll.api.PollContentView +import io.element.android.features.poll.api.pollcontent.PollContentView import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.matrix.api.core.EventId @@ -31,8 +31,6 @@ import kotlinx.collections.immutable.toImmutableList @Composable fun TimelineItemPollView( content: TimelineItemPollContent, - isMine: Boolean, - isEditable: Boolean, eventSink: (TimelineEvents) -> Unit, modifier: Modifier = Modifier, ) { @@ -54,8 +52,8 @@ fun TimelineItemPollView( answerItems = content.answerItems.toImmutableList(), pollKind = content.pollKind, isPollEnded = content.isEnded, - isPollEditable = isEditable, - isMine = isMine, + isPollEditable = content.isEditable, + isMine = content.isMine, onAnswerSelected = ::onAnswerSelected, onPollEdit = ::onPollEdit, onPollEnd = ::onPollEnd, @@ -69,8 +67,6 @@ internal fun TimelineItemPollViewPreview(@PreviewParameter(TimelineItemPollConte ElementPreview { TimelineItemPollView( content = content, - isMine = false, - isEditable = false, eventSink = {}, ) } @@ -81,8 +77,6 @@ internal fun TimelineItemPollCreatorViewPreview(@PreviewParameter(TimelineItemPo ElementPreview { TimelineItemPollView( content = content, - isMine = true, - isEditable = false, eventSink = {}, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt index b5a3c9545e..5e72392914 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt @@ -59,7 +59,7 @@ class TimelineItemContentFactory @Inject constructor( is RoomMembershipContent -> roomMembershipFactory.create(eventTimelineItem) is StateContent -> stateFactory.create(eventTimelineItem) is StickerContent -> stickerFactory.create(itemContent) - is PollContent -> pollFactory.create(itemContent, eventTimelineItem.eventId) + is PollContent -> pollFactory.create(eventTimelineItem, itemContent) is UnableToDecryptContent -> utdFactory.create(itemContent) is UnknownContent -> TimelineItemUnknownContent } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt index 04551f7086..d2176aa887 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactory.kt @@ -19,63 +19,32 @@ package io.element.android.features.messages.impl.timeline.factories.event import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent -import io.element.android.features.poll.api.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollContentStateFactory import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.matrix.api.MatrixClient -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.poll.isDisclosed +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import javax.inject.Inject class TimelineItemContentPollFactory @Inject constructor( - private val matrixClient: MatrixClient, private val featureFlagService: FeatureFlagService, + private val pollContentStateFactory: PollContentStateFactory, ) { suspend fun create( + event: EventTimelineItem, content: PollContent, - eventId: EventId? ): TimelineItemEventContent { if (!featureFlagService.isFeatureEnabled(FeatureFlags.Polls)) return TimelineItemUnknownContent - - // Todo Move this computation to the matrix rust sdk - val totalVoteCount = content.votes.flatMap { it.value }.size - val myVotes = content.votes.filter { matrixClient.sessionId in it.value }.keys - val isEndedPoll = content.endTime != null - val winnerIds = if (!isEndedPoll) { - emptyList() - } else { - content.answers - .map { answer -> answer.id } - .groupBy { answerId -> content.votes[answerId]?.size ?: 0 } // Group by votes count - .maxByOrNull { (votes, _) -> votes } // Keep max voted answers - ?.takeIf { (votes, _) -> votes > 0 } // Ignore if no option has been voted - ?.value - .orEmpty() - } - val answerItems = content.answers.map { answer -> - val answerVoteCount = content.votes[answer.id]?.size ?: 0 - val isSelected = answer.id in myVotes - val isWinner = answer.id in winnerIds - val percentage = if (totalVoteCount > 0) answerVoteCount.toFloat() / totalVoteCount.toFloat() else 0f - PollAnswerItem( - answer = answer, - isSelected = isSelected, - isEnabled = !isEndedPoll, - isWinner = isWinner, - isDisclosed = content.kind.isDisclosed || isEndedPoll, - votesCount = answerVoteCount, - percentage = percentage, - ) - } - + val pollContentState = pollContentStateFactory.create(event, content) return TimelineItemPollContent( - eventId = eventId, - question = content.question, - answerItems = answerItems, - pollKind = content.kind, - isEnded = isEndedPoll, + isMine = pollContentState.isMine, + isEditable = pollContentState.isPollEditable, + eventId = event.eventId, + question = pollContentState.question, + answerItems = pollContentState.answerItems, + pollKind = pollContentState.pollKind, + isEnded = pollContentState.isPollEnded, ) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContent.kt index dc47c12a86..9ce94b72d0 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContent.kt @@ -16,11 +16,13 @@ package io.element.android.features.messages.impl.timeline.model.event -import io.element.android.features.poll.api.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollAnswerItem import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind data class TimelineItemPollContent( + val isMine: Boolean, + val isEditable: Boolean, val eventId: EventId?, val question: String, val answerItems: List, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt index d20f9fa856..3a007f31e5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt @@ -17,9 +17,9 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.poll.api.PollAnswerItem -import io.element.android.features.poll.api.aPollAnswerItemList -import io.element.android.features.poll.api.aPollQuestion +import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList +import io.element.android.features.poll.api.pollcontent.aPollQuestion +import io.element.android.features.poll.api.pollcontent.PollAnswerItem import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind @@ -28,12 +28,16 @@ open class TimelineItemPollContentProvider : PreviewParameterProvider = aPollAnswerItemList(), + isMine: Boolean = false, + isEditable: Boolean = false, isEnded: Boolean = false, ): TimelineItemPollContent { return TimelineItemPollContent( @@ -41,6 +45,8 @@ fun aTimelineItemPollContent( pollKind = PollKind.Disclosed, question = question, answerItems = answerItems, + isMine = isMine, + isEditable = isEditable, isEnded = isEnded, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index c2a8cd40d2..d0a7484741 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -29,7 +29,7 @@ import io.element.android.features.messages.impl.timeline.model.event.aTimelineI import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemVoiceContent -import io.element.android.features.poll.api.aPollAnswerItemList +import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList import io.element.android.libraries.featureflag.test.InMemoryPreferencesStore import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.tests.testutils.WarmUpRule diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt index 2ae88288ae..144c70f55d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt @@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.timeline.factories.event import com.google.common.truth.Truth import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent -import io.element.android.features.poll.api.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollAnswerItem import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.EventId @@ -55,14 +55,14 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Disclosed poll - not ended, no votes`() = runTest { - Truth.assertThat(factory.create(aPollContent(), eventId = null)).isEqualTo(aTimelineItemPollContent()) + Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn)).isEqualTo(aTimelineItemPollContent()) } @Test fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest { val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(votes = votes), eventId = null) + factory.create(aPollContent(votes = votes), eventId = null, eventTimelineItem.isOwn) ) .isEqualTo( aTimelineItemPollContent( @@ -79,7 +79,7 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Disclosed poll - ended, no votes, no winner`() = runTest { Truth.assertThat( - factory.create(aPollContent(endTime = 1UL), eventId = null) + factory.create(aPollContent(endTime = 1UL), eventId = null, eventTimelineItem.isOwn) ).isEqualTo( aTimelineItemPollContent().let { it.copy( @@ -94,7 +94,11 @@ internal class TimelineItemContentPollFactoryTest { fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest { val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null) + factory.create( + aPollContent(votes = votes, endTime = 1UL), + eventId = null, + eventTimelineItem.isOwn + ) ) .isEqualTo( aTimelineItemPollContent( @@ -113,7 +117,11 @@ internal class TimelineItemContentPollFactoryTest { fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null) + factory.create( + aPollContent(votes = votes, endTime = 1UL), + eventId = null, + eventTimelineItem.isOwn + ) ) .isEqualTo( aTimelineItemPollContent( @@ -131,7 +139,11 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Undisclosed poll - not ended, no votes`() = runTest { Truth.assertThat( - factory.create(aPollContent(PollKind.Undisclosed).copy(), eventId = null) + factory.create( + aPollContent(PollKind.Undisclosed).copy(), + eventId = null, + eventTimelineItem.isOwn + ) ).isEqualTo( aTimelineItemPollContent(pollKind = PollKind.Undisclosed).let { it.copy(answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = false) }) @@ -143,7 +155,11 @@ internal class TimelineItemContentPollFactoryTest { fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest { val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes), eventId = null) + factory.create( + aPollContent(pollKind = PollKind.Undisclosed, votes = votes), + eventId = null, + eventTimelineItem.isOwn + ) ) .isEqualTo( aTimelineItemPollContent( @@ -161,7 +177,11 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `Undisclosed poll - ended, no votes, no winner`() = runTest { Truth.assertThat( - factory.create(aPollContent(pollKind = PollKind.Undisclosed, endTime = 1UL), eventId = null) + factory.create( + aPollContent(pollKind = PollKind.Undisclosed, endTime = 1UL), + eventId = null, + eventTimelineItem.isOwn + ) ).isEqualTo( aTimelineItemPollContent().let { it.copy( @@ -179,7 +199,11 @@ internal class TimelineItemContentPollFactoryTest { fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest { val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), eventId = null) + factory.create( + aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), + eventId = null, + eventTimelineItem.isOwn + ) ) .isEqualTo( aTimelineItemPollContent( @@ -199,7 +223,11 @@ internal class TimelineItemContentPollFactoryTest { fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() Truth.assertThat( - factory.create(aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), eventId = null) + factory.create( + aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), + eventId = null, + eventTimelineItem.isOwn + ) ) .isEqualTo( aTimelineItemPollContent( @@ -217,10 +245,14 @@ internal class TimelineItemContentPollFactoryTest { @Test fun `eventId is populated`() = runTest { - Truth.assertThat(factory.create(aPollContent(), eventId = null)) + Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn)) .isEqualTo(aTimelineItemPollContent(eventId = null)) - Truth.assertThat(factory.create(aPollContent(), eventId = AN_EVENT_ID)) + Truth.assertThat(factory.create( + aPollContent(), + eventId = AN_EVENT_ID, + eventTimelineItem.isOwn + )) .isEqualTo(aTimelineItemPollContent(eventId = AN_EVENT_ID)) } diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/EndPollAction.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/EndPollAction.kt new file mode 100644 index 0000000000..22982dce97 --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/EndPollAction.kt @@ -0,0 +1,23 @@ +/* + * 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.poll.api.actions + +import io.element.android.libraries.matrix.api.core.EventId + +interface EndPollAction { + suspend fun execute(pollStartId: EventId): Result +} diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/SendPollResponseAction.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/SendPollResponseAction.kt new file mode 100644 index 0000000000..71cf476f59 --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/actions/SendPollResponseAction.kt @@ -0,0 +1,23 @@ +/* + * 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.poll.api.actions + +import io.element.android.libraries.matrix.api.core.EventId + +interface SendPollResponseAction { + suspend fun execute(pollStartId: EventId, answerId: String): Result +} diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerItem.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerItem.kt similarity index 96% rename from features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerItem.kt rename to features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerItem.kt index 1955701c5b..56dbaeb3ca 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerItem.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerItem.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.poll.api +package io.element.android.features.poll.api.pollcontent import io.element.android.libraries.matrix.api.poll.PollAnswer diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerView.kt similarity index 99% rename from features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt rename to features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerView.kt index 9e9ec624e0..a84ef502ca 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerView.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.poll.api +package io.element.android.features.poll.api.pollcontent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerViewProvider.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt similarity index 97% rename from features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerViewProvider.kt rename to features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt index a4a8f2e156..206acf02c6 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerViewProvider.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.poll.api +package io.element.android.features.poll.api.pollcontent import io.element.android.libraries.matrix.api.poll.PollAnswer import kotlinx.collections.immutable.persistentListOf diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt new file mode 100644 index 0000000000..0051f7ebd3 --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.poll.api.pollcontent + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.poll.PollKind +import kotlinx.collections.immutable.ImmutableList + +data class PollContentState( + val eventId: EventId?, + val question: String, + val answerItems: ImmutableList, + val pollKind: PollKind, + val isPollEditable: Boolean, + val isPollEnded: Boolean, + val isMine: Boolean, +) diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.kt new file mode 100644 index 0000000000..7178a6c3ee --- /dev/null +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFactory.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.features.poll.api.pollcontent + +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent + +interface PollContentStateFactory { + suspend fun create(event: EventTimelineItem, content: PollContent): PollContentState +} diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt similarity index 93% rename from features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt rename to features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt index effaadb07e..706fa6e402 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentView.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.element.android.features.poll.api +package io.element.android.features.poll.api.pollcontent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -49,6 +49,29 @@ import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList +@Composable +fun PollContentView( + state: PollContentState, + onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, + onPollEdit: (pollStartId: EventId) -> Unit, + onPollEnd: (pollStartId: EventId) -> Unit, + modifier: Modifier = Modifier, +) { + PollContentView( + eventId = state.eventId, + question = state.question, + answerItems = state.answerItems, + pollKind = state.pollKind, + isPollEditable = state.isPollEditable, + isPollEnded = state.isPollEnded, + isMine = state.isMine, + onPollEdit = onPollEdit, + onAnswerSelected = onAnswerSelected, + onPollEnd = onPollEnd, + modifier = modifier, + ) +} + @Composable fun PollContentView( eventId: EventId?, diff --git a/features/poll/impl/build.gradle.kts b/features/poll/impl/build.gradle.kts index 5ff9025aae..db91377660 100644 --- a/features/poll/impl/build.gradle.kts +++ b/features/poll/impl/build.gradle.kts @@ -40,6 +40,7 @@ dependencies { implementation(projects.libraries.designsystem) implementation(projects.services.analytics.api) implementation(projects.features.messages.api) + implementation(projects.libraries.dateformatter.api) implementation(projects.libraries.uiStrings) testImplementation(libs.test.junit) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt new file mode 100644 index 0000000000..9959f1aecc --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt @@ -0,0 +1,42 @@ +/* + * 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.poll.impl.actions + +import com.squareup.anvil.annotations.ContributesBinding +import im.vector.app.features.analytics.plan.PollEnd +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.services.analytics.api.AnalyticsService +import javax.inject.Inject + +@ContributesBinding(RoomScope::class) +class DefaultEndPollAction @Inject constructor( + private val room: MatrixRoom, + private val analyticsService: AnalyticsService, +) : EndPollAction { + + override suspend fun execute(pollStartId: EventId): Result { + return room.endPoll( + pollStartId = pollStartId, + text = "The poll with event id: $pollStartId has ended." + ).onSuccess { + analyticsService.capture(PollEnd()) + } + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt new file mode 100644 index 0000000000..d6688ecb27 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt @@ -0,0 +1,43 @@ +/* + * 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.poll.impl.actions + +import com.squareup.anvil.annotations.ContributesBinding +import im.vector.app.features.analytics.plan.PollVote +import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.services.analytics.api.AnalyticsService +import javax.inject.Inject + +@ContributesBinding(RoomScope::class) +class DefaultSendPollResponseAction @Inject constructor( + private val room: MatrixRoom, + private val analyticsService: AnalyticsService, +) : SendPollResponseAction { + + override suspend fun execute(pollStartId: EventId, answerId: String): Result { + return room.sendPollResponse( + pollStartId = pollStartId, + answers = listOf(answerId), + ).onSuccess { + analyticsService.capture(PollVote()) + } + } +} + diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt index 1eb676b961..e13f9020b7 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt @@ -16,6 +16,11 @@ package io.element.android.features.poll.impl.history +import io.element.android.libraries.matrix.api.core.EventId + sealed interface PollHistoryEvents { - data object History : PollHistoryEvents + data object LoadMore : PollHistoryEvents + data class PollAnswerSelected(val pollStartId: EventId, val answerId: String) : PollHistoryEvents + data class PollEndClicked(val pollStartId: EventId) : PollHistoryEvents + data object EditPoll : PollHistoryEvents } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt new file mode 100644 index 0000000000..5b12dc8b2c --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt @@ -0,0 +1,23 @@ +/* + * 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.poll.impl.history + +import io.element.android.features.poll.api.pollcontent.PollContentState + +sealed interface PollHistoryItem { + data class PollContent(val formattedDate: String, val state: PollContentState) : PollHistoryItem +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt new file mode 100644 index 0000000000..1d09e115ae --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt @@ -0,0 +1,51 @@ +/* + * 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.poll.impl.history + +import io.element.android.features.poll.api.pollcontent.PollContentStateFactory +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.dateformatter.api.DaySeparatorFormatter +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class PollHistoryItemsFactory @Inject constructor( + private val pollContentStateFactory: PollContentStateFactory, + private val daySeparatorFormatter: DaySeparatorFormatter, + private val dispatchers: CoroutineDispatchers, +) { + + suspend fun create(timelineItems: List): List = withContext(dispatchers.computation) { + timelineItems.mapNotNull { create(it) }.reversed() + } + + private suspend fun create(timelineItem: MatrixTimelineItem): PollHistoryItem? { + return when (timelineItem) { + is MatrixTimelineItem.Event -> { + val pollContent = timelineItem.event.content as? PollContent ?: return null + val pollContentState = pollContentStateFactory.create(timelineItem.event, pollContent) + PollHistoryItem.PollContent( + formattedDate = daySeparatorFormatter.format(timelineItem.event.timestamp), + state = pollContentState + ) + } + else -> null + } + } +} + diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index 1025b2184d..40db94306b 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -17,22 +17,29 @@ package io.element.android.features.poll.impl.history import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem -import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch class PollHistoryPresenter @AssistedInject constructor( @Assisted private val pollHistory: MatrixTimeline, + private val appCoroutineScope: CoroutineScope, + private val sendPollResponseAction: SendPollResponseAction, + private val endPollAction: EndPollAction, + private val pollHistoryItemFactory: PollHistoryItemsFactory, ) : Presenter { @AssistedFactory @@ -47,26 +54,36 @@ class PollHistoryPresenter @AssistedInject constructor( val paginationState by pollHistory.paginationState.collectAsState() val timelineItemsFlow = remember { pollHistory.timelineItems.map { items -> - items.filterIsInstance() - .map { it.event.content } - .filterIsInstance() - .reversed() - }.onEach { - if (it.isEmpty()) pollHistory.paginateBackwards(20, 50) + pollHistoryItemFactory.create(items) } } val items by timelineItemsFlow.collectAsState(initial = emptyList()) - + LaunchedEffect(items.size) { + if (items.isEmpty()) loadMore() + } + val coroutineScope = rememberCoroutineScope() fun handleEvents(event: PollHistoryEvents) { when (event) { - is PollHistoryEvents.History -> Unit // TODO which events to handle? + is PollHistoryEvents.LoadMore -> { + coroutineScope.loadMore() + } + is PollHistoryEvents.PollAnswerSelected -> appCoroutineScope.launch { + sendPollResponseAction.execute(pollStartId = event.pollStartId, answerId = event.answerId) + } + is PollHistoryEvents.PollEndClicked -> appCoroutineScope.launch { + endPollAction.execute(pollStartId = event.pollStartId) + } + PollHistoryEvents.EditPoll -> Unit } } - return PollHistoryState( paginationState = paginationState, - matrixTimelineItems = items.toImmutableList(), + pollItems = items.toImmutableList(), eventSink = ::handleEvents, ) } + + private fun CoroutineScope.loadMore() = launch { + pollHistory.paginateBackwards(20, 3) + } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt index 4354736aba..1c636060ec 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt @@ -17,11 +17,10 @@ package io.element.android.features.poll.impl.history import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import kotlinx.collections.immutable.ImmutableList data class PollHistoryState( val paginationState: MatrixTimeline.PaginationState, - val matrixTimelineItems: ImmutableList, + val pollItems: ImmutableList, val eventSink: (PollHistoryEvents) -> Unit, ) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index 93a3e3c90c..34dee34a59 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -16,27 +16,31 @@ package io.element.android.features.poll.impl.history +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme -import io.element.android.features.poll.api.PollAnswerItem -import io.element.android.features.poll.api.PollContentView +import io.element.android.features.poll.api.pollcontent.PollContentView import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.aliasScreenTitle import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.matrix.api.poll.PollAnswer -import kotlinx.collections.immutable.toImmutableList +import io.element.android.libraries.matrix.api.core.EventId @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -70,37 +74,75 @@ fun PollHistoryView( if (state.paginationState.isBackPaginating) item { CircularProgressIndicator() } - items(state.matrixTimelineItems) { pollContent -> - PollContentView( - eventId = null, - question = pollContent.question, - answerItems = pollContent.answers.map { - PollAnswerItem( - answer = PollAnswer( - id = it.id, - text = it.text, - ), - isSelected = false, - isEnabled = false, - isWinner = false, - isDisclosed = false, - votesCount = 9393, - percentage = 4.5f, - ) - }.toImmutableList(), - pollKind = pollContent.kind, - isPollEditable = false, - isPollEnded = false, - isMine = false, - onAnswerSelected = { _, _ -> }, - onPollEdit = {}, - onPollEnd = {}, + itemsIndexed(state.pollItems) { index, pollHistoryItem -> + PollHistoryItemRow( + pollHistoryItem = pollHistoryItem, + onAnswerSelected = fun(pollStartId: EventId, answerId: String) { + state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) + }, + onPollEdit = { + state.eventSink(PollHistoryEvents.EditPoll) + }, + onPollEnd = { + state.eventSink(PollHistoryEvents.PollEndClicked(it)) + }, ) + if (index != state.pollItems.lastIndex) { + HorizontalDivider() + } } } } } +@Composable +private fun PollHistoryItemRow( + pollHistoryItem: PollHistoryItem, + onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, + onPollEdit: (pollStartId: EventId) -> Unit, + onPollEnd: (pollStartId: EventId) -> Unit, + modifier: Modifier = Modifier, +) { + when (pollHistoryItem) { + is PollHistoryItem.PollContent -> { + PollContentItemRow( + pollContentItem = pollHistoryItem, + onAnswerSelected = onAnswerSelected, + onPollEdit = onPollEdit, + onPollEnd = onPollEnd, + modifier = modifier.padding( + horizontal = 16.dp, + vertical = 24.dp + ), + ) + } + } +} + +@Composable +private fun PollContentItemRow( + pollContentItem: PollHistoryItem.PollContent, + onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, + onPollEdit: (pollStartId: EventId) -> Unit, + onPollEnd: (pollStartId: EventId) -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + Text( + text = pollContentItem.formattedDate, + color = MaterialTheme.colorScheme.secondary, + style = ElementTheme.typography.fontBodySmRegular, + ) + Spacer(modifier = Modifier.height(4.dp)) + PollContentView( + state = pollContentItem.state, + onAnswerSelected = onAnswerSelected, + onPollEdit = onPollEdit, + onPollEnd = onPollEnd, + ) + } +} + @PreviewsDayNight @Composable internal fun PollHistoryViewPreview( diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt new file mode 100644 index 0000000000..f48d2f54dd --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/model/DefaultPollContentStateFactory.kt @@ -0,0 +1,80 @@ +/* + * 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.poll.impl.model + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.poll.api.pollcontent.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollContentState +import io.element.android.features.poll.api.pollcontent.PollContentStateFactory +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.poll.isDisclosed +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.collections.immutable.toImmutableList +import javax.inject.Inject + +@ContributesBinding(RoomScope::class) +class DefaultPollContentStateFactory @Inject constructor( + private val matrixClient: MatrixClient, +) : PollContentStateFactory { + + override suspend fun create( + event: EventTimelineItem, + content: PollContent + ): PollContentState { + val totalVoteCount = content.votes.flatMap { it.value }.size + val myVotes = content.votes.filter { matrixClient.sessionId in it.value }.keys + val isPollEnded = content.endTime != null + val winnerIds = if (!isPollEnded) { + emptyList() + } else { + content.answers + .map { answer -> answer.id } + .groupBy { answerId -> content.votes[answerId]?.size ?: 0 } // Group by votes count + .maxByOrNull { (votes, _) -> votes } // Keep max voted answers + ?.takeIf { (votes, _) -> votes > 0 } // Ignore if no option has been voted + ?.value + .orEmpty() + } + val answerItems = content.answers.map { answer -> + val answerVoteCount = content.votes[answer.id]?.size ?: 0 + val isSelected = answer.id in myVotes + val isWinner = answer.id in winnerIds + val percentage = if (totalVoteCount > 0) answerVoteCount.toFloat() / totalVoteCount.toFloat() else 0f + PollAnswerItem( + answer = answer, + isSelected = isSelected, + isEnabled = !isPollEnded, + isWinner = isWinner, + isDisclosed = content.kind.isDisclosed || isPollEnded, + votesCount = answerVoteCount, + percentage = percentage, + ) + } + + return PollContentState( + eventId = event.eventId, + isMine = event.isOwn, + question = content.question, + answerItems = answerItems.toImmutableList(), + pollKind = content.kind, + isPollEditable = event.isEditable, + isPollEnded = isPollEnded, + ) + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt index 8dfa2e4819..98d5772d23 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt @@ -20,7 +20,7 @@ import io.element.android.libraries.matrix.api.core.EventId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -interface MatrixTimeline: AutoCloseable { +interface MatrixTimeline : AutoCloseable { data class PaginationState( val isBackPaginating: Boolean, @@ -35,6 +35,5 @@ interface MatrixTimeline: AutoCloseable { suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result suspend fun fetchDetailsForEvent(eventId: EventId): Result - suspend fun sendReadReceipt(eventId: EventId): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 85f59f9e57..70978c4fe7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -192,15 +192,19 @@ class RustMatrixTimeline( } } - override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result = withContext(dispatcher) { + override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result { + val paginationOptions = PaginationOptions.UntilNumItems( + eventLimit = requestSize.toUShort(), + items = untilNumberOfItems.toUShort(), + waitForToken = true, + ) + return paginateBackwards(paginationOptions) + } + + private suspend fun paginateBackwards(paginationOptions: PaginationOptions): Result = withContext(dispatcher) { runCatching { if (!canBackPaginate()) throw TimelineException.CannotPaginate Timber.v("Start back paginating for room ${matrixRoom.roomId} ") - val paginationOptions = PaginationOptions.UntilNumItems( - eventLimit = requestSize.toUShort(), - items = untilNumberOfItems.toUShort(), - waitForToken = true, - ) innerTimeline.paginateBackwards(paginationOptions) }.onFailure { error -> if (error is TimelineException.CannotPaginate) { From aa9693126f1e42660bbb1118e092e59b736d9f3d Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 6 Dec 2023 19:27:50 +0100 Subject: [PATCH 03/24] PollHistory : simplify so we only have one Node. Also enrich PollHistoryState. --- .../poll/api/pollcontent/PollContentState.kt | 10 ++ ...rovider.kt => PollContentStateFixtures.kt} | 24 +++++ .../poll/impl/history/PollHistoryEvents.kt | 2 + .../impl/history/PollHistoryLoadedNode.kt | 69 -------------- .../impl/history/PollHistoryLoadingNode.kt | 50 ---------- .../poll/impl/history/PollHistoryNode.kt | 74 +-------------- .../poll/impl/history/PollHistoryPresenter.kt | 68 ++++++++----- .../poll/impl/history/PollHistoryState.kt | 9 +- .../impl/history/PollHistoryStateProvider.kt | 42 +++++++- .../impl/history/model/PollHistoryFilter.kt | 22 +++++ .../history/{ => model}/PollHistoryItem.kt | 9 +- .../impl/history/model/PollHistoryItems.kt | 27 ++++++ .../{ => model}/PollHistoryItemsFactory.kt | 23 ++++- .../libraries/matrix/api/room/MatrixRoom.kt | 2 +- .../matrix/api/timeline/MatrixTimeline.kt | 6 +- .../matrix/impl/room/RustMatrixRoom.kt | 57 ++++++----- .../impl/timeline/AsyncMatrixTimeline.kt | 95 +++++++++++++++++++ .../impl/timeline/RustMatrixTimeline.kt | 6 +- .../libraries/matrix/ui/room/PollHistory.kt | 36 +++++++ 19 files changed, 376 insertions(+), 255 deletions(-) rename features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/{PollAnswerViewProvider.kt => PollContentStateFixtures.kt} (78%) delete mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt delete mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt rename features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/{ => model}/PollHistoryItem.kt (77%) create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItems.kt rename features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/{ => model}/PollHistoryItemsFactory.kt (70%) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt create mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/PollHistory.kt diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt index 0051f7ebd3..b97029a22c 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentState.kt @@ -20,6 +20,16 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind import kotlinx.collections.immutable.ImmutableList +/** + * UI model for a PollContent. + * @property eventId the event id of the poll. + * @property question the poll question. + * @property answerItems the list of answers. + * @property pollKind the kind of poll. + * @property isPollEditable whether the poll is editable. + * @property isPollEnded whether the poll is ended. + * @property isMine whether the poll has been created by me. + */ data class PollContentState( val eventId: EventId?, val question: String, diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFixtures.kt similarity index 78% rename from features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt rename to features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFixtures.kt index 206acf02c6..80c6a6a6c4 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollAnswerViewProvider.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/pollcontent/PollContentStateFixtures.kt @@ -17,6 +17,8 @@ package io.element.android.features.poll.api.pollcontent import io.element.android.libraries.matrix.api.poll.PollAnswer +import io.element.android.libraries.matrix.api.poll.PollKind +import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf fun aPollQuestion() = "What type of food should we have at the party?" @@ -79,3 +81,25 @@ fun aPollAnswerItem( votesCount = votesCount, percentage = percentage ) + +fun aPollContentState( + isMine: Boolean = false, + isEnded: Boolean = false, + isDisclosed: Boolean = true, + hasVotes: Boolean = true, + question: String = aPollQuestion(), + pollKind: PollKind = PollKind.Disclosed, + answerItems: ImmutableList = aPollAnswerItemList( + isEnded = isEnded, + isDisclosed = isDisclosed, + hasVotes = hasVotes + ), +) = PollContentState( + eventId = null, + question = question, + answerItems = answerItems, + pollKind = pollKind, + isPollEditable = isMine && !isEnded, + isPollEnded = isEnded, + isMine = isMine, +) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt index e13f9020b7..d07b6fa24a 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt @@ -16,6 +16,7 @@ package io.element.android.features.poll.impl.history +import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.libraries.matrix.api.core.EventId sealed interface PollHistoryEvents { @@ -23,4 +24,5 @@ sealed interface PollHistoryEvents { data class PollAnswerSelected(val pollStartId: EventId, val answerId: String) : PollHistoryEvents data class PollEndClicked(val pollStartId: EventId) : PollHistoryEvents data object EditPoll : PollHistoryEvents + data class OnFilterSelected(val filter: PollHistoryFilter) : PollHistoryEvents } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt deleted file mode 100644 index 665700e52c..0000000000 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadedNode.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.poll.impl.history - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.lifecycle.subscribe -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.architecture.NodeInputs -import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import io.element.android.services.analytics.api.AnalyticsService - -@ContributesNode(RoomScope::class) -class PollHistoryLoadedNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - presenterFactory: PollHistoryPresenter.Factory, - analyticsService: AnalyticsService, -) : Node( - buildContext = buildContext, - plugins = plugins -) { - data class Inputs( - val pollHistory: MatrixTimeline, - ) : NodeInputs - - private val inputs: Inputs = inputs() - private val presenter = presenterFactory.create( - inputs.pollHistory, - ) - - init { - lifecycle.subscribe( - onResume = { - // analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreatePollView)) // TODO - } - ) - } - - @Composable - override fun View(modifier: Modifier) { - PollHistoryView( - state = presenter.present(), - modifier = modifier, - goBack = this::navigateUp, - ) - } -} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt deleted file mode 100644 index 4eddd009e3..0000000000 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryLoadingNode.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.poll.impl.history - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator -import io.element.android.libraries.di.RoomScope - -@ContributesNode(RoomScope::class) -class PollHistoryLoadingNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, -) : Node( - buildContext = buildContext, - plugins = plugins -) { - @Composable - override fun View(modifier: Modifier) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator() - } - } -} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt index 2ae20c8e12..d466a16aef 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt @@ -16,96 +16,32 @@ package io.element.android.features.poll.impl.history -import android.os.Parcelable import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.lifecycle.lifecycleScope -import com.bumble.appyx.core.composable.Children -import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.newRoot import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.architecture.BackstackNode -import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler -import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import kotlinx.coroutines.launch -import kotlinx.parcelize.Parcelize @ContributesNode(RoomScope::class) class PollHistoryNode @AssistedInject constructor( - private val room: MatrixRoom, @Assisted buildContext: BuildContext, @Assisted plugins: List, -) : BackstackNode( - backstack = BackStack( - initialElement = NavTarget.PollHistoryLoading, - savedStateMap = buildContext.savedStateMap, - ), + private val presenter: PollHistoryPresenter, +) : Node( buildContext = buildContext, plugins = plugins, ) { - sealed interface NavTarget : Parcelable { - @Parcelize - data object PollHistoryLoading : NavTarget - - @Parcelize - data object PollHistoryLoaded : NavTarget - } - - private var pollHistory: MatrixTimeline? = null - - override fun onBuilt() { - super.onBuilt() - lifecycle.subscribe( - onCreate = { - lifecycleScope.launch { - runCatching { - room.pollHistory() - }.onSuccess { - pollHistory = it - backstack.newRoot(NavTarget.PollHistoryLoaded) - } - } - }, - onDestroy = { - pollHistory?.close() - }, - ) - } - - override fun resolve( - navTarget: NavTarget, - buildContext: BuildContext - ): Node = when (navTarget) { - is NavTarget.PollHistoryLoading -> createNode( - buildContext = buildContext, - ) - is NavTarget.PollHistoryLoaded -> { - createNode( - buildContext = buildContext, - plugins = listOf( - PollHistoryLoadedNode.Inputs( - pollHistory = pollHistory ?: error("Poll history not loaded"), - ) - ), - ) - } - } @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, + PollHistoryView( + state = presenter.present(), modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), + goBack = this::navigateUp, ) } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index 40db94306b..a1f0b81315 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -19,53 +19,62 @@ package io.element.android.features.poll.impl.history import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import dagger.assisted.Assisted -import dagger.assisted.AssistedFactory -import dagger.assisted.AssistedInject +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import io.element.android.features.poll.api.actions.EndPollAction import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.features.poll.impl.history.model.PollHistoryFilter +import io.element.android.features.poll.impl.history.model.PollHistoryItems +import io.element.android.features.poll.impl.history.model.PollHistoryItemsFactory import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import kotlinx.collections.immutable.toImmutableList +import io.element.android.libraries.matrix.ui.room.rememberPollHistory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject -class PollHistoryPresenter @AssistedInject constructor( - @Assisted private val pollHistory: MatrixTimeline, +class PollHistoryPresenter @Inject constructor( + private val room: MatrixRoom, private val appCoroutineScope: CoroutineScope, private val sendPollResponseAction: SendPollResponseAction, private val endPollAction: EndPollAction, private val pollHistoryItemFactory: PollHistoryItemsFactory, ) : Presenter { - @AssistedFactory - interface Factory { - fun create( - pollHistory: MatrixTimeline, - ): PollHistoryPresenter - } - @Composable override fun present(): PollHistoryState { + val pollHistory = room.rememberPollHistory() val paginationState by pollHistory.paginationState.collectAsState() - val timelineItemsFlow = remember { + val pollHistoryItemsFlow = remember { pollHistory.timelineItems.map { items -> pollHistoryItemFactory.create(items) } } - val items by timelineItemsFlow.collectAsState(initial = emptyList()) - LaunchedEffect(items.size) { - if (items.isEmpty()) loadMore() + var activeFilter by rememberSaveable { + mutableStateOf(PollHistoryFilter.ONGOING) + } + val pollHistoryItems by pollHistoryItemsFlow.collectAsState(initial = PollHistoryItems()) + LaunchedEffect(paginationState, pollHistoryItems.size) { + if (pollHistoryItems.size == 0 && paginationState.canBackPaginate) loadMore(pollHistory) + } + val isLoading by remember { + derivedStateOf { + pollHistoryItems.size == 0 || paginationState.isBackPaginating + } } val coroutineScope = rememberCoroutineScope() fun handleEvents(event: PollHistoryEvents) { when (event) { is PollHistoryEvents.LoadMore -> { - coroutineScope.loadMore() + coroutineScope.loadMore(pollHistory) } is PollHistoryEvents.PollAnswerSelected -> appCoroutineScope.launch { sendPollResponseAction.execute(pollStartId = event.pollStartId, answerId = event.answerId) @@ -74,16 +83,31 @@ class PollHistoryPresenter @AssistedInject constructor( endPollAction.execute(pollStartId = event.pollStartId) } PollHistoryEvents.EditPoll -> Unit + is PollHistoryEvents.OnFilterSelected -> { + activeFilter = event.filter + } + } + } + + val currentItems by remember { + derivedStateOf { + when (activeFilter) { + PollHistoryFilter.ONGOING -> pollHistoryItems.ongoing + PollHistoryFilter.PAST -> pollHistoryItems.past + } } } return PollHistoryState( - paginationState = paginationState, - pollItems = items.toImmutableList(), + isLoading = isLoading, + hasMoreToLoad = paginationState.hasMoreToLoadBackwards, + currentItems = currentItems, + activeFilter = activeFilter, eventSink = ::handleEvents, ) } - private fun CoroutineScope.loadMore() = launch { - pollHistory.paginateBackwards(20, 3) + private fun CoroutineScope.loadMore(pollHistory: MatrixTimeline) = launch { + Timber.d("LoadMore poll history") + pollHistory.paginateBackwards(50, 3) } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt index 1c636060ec..c3b768993f 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt @@ -16,11 +16,14 @@ package io.element.android.features.poll.impl.history -import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import io.element.android.features.poll.impl.history.model.PollHistoryFilter +import io.element.android.features.poll.impl.history.model.PollHistoryItem import kotlinx.collections.immutable.ImmutableList data class PollHistoryState( - val paginationState: MatrixTimeline.PaginationState, - val pollItems: ImmutableList, + val isLoading: Boolean, + val hasMoreToLoad: Boolean, + val activeFilter: PollHistoryFilter, + val currentItems: ImmutableList, val eventSink: (PollHistoryEvents) -> Unit, ) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt index 880b68d178..24862cd599 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt @@ -17,8 +17,48 @@ package io.element.android.features.poll.impl.history import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.poll.api.pollcontent.PollContentState +import io.element.android.features.poll.api.pollcontent.aPollContentState +import io.element.android.features.poll.impl.history.model.PollHistoryFilter +import io.element.android.features.poll.impl.history.model.PollHistoryItem +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf class PollHistoryStateProvider : PreviewParameterProvider { override val values: Sequence - get() = sequenceOf() // TODO + get() = sequenceOf( + aPollHistoryState( + isLoading = false, + hasMoreToLoad = false, + activeFilter = PollHistoryFilter.ONGOING, + ), + aPollHistoryState( + isLoading = true, + hasMoreToLoad = true, + activeFilter = PollHistoryFilter.PAST, + ), + ) } + +private fun aPollHistoryState( + isLoading: Boolean = false, + hasMoreToLoad: Boolean = false, + activeFilter: PollHistoryFilter = PollHistoryFilter.ONGOING, + currentItems: ImmutableList = persistentListOf( + aPollHistoryItem(), + ), +) = PollHistoryState( + isLoading = isLoading, + hasMoreToLoad = hasMoreToLoad, + activeFilter = activeFilter, + currentItems = currentItems, + eventSink = {}, +) + +private fun aPollHistoryItem( + formattedDate: String = "01/12/2023", + state: PollContentState = aPollContentState(), +) = PollHistoryItem( + formattedDate = formattedDate, + state = state, +) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt new file mode 100644 index 0000000000..d56087d2c1 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt @@ -0,0 +1,22 @@ +/* + * 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.poll.impl.history.model + +enum class PollHistoryFilter { + ONGOING, + PAST, +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItem.kt similarity index 77% rename from features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt rename to features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItem.kt index 5b12dc8b2c..6b55b249bb 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItem.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItem.kt @@ -14,10 +14,11 @@ * limitations under the License. */ -package io.element.android.features.poll.impl.history +package io.element.android.features.poll.impl.history.model import io.element.android.features.poll.api.pollcontent.PollContentState -sealed interface PollHistoryItem { - data class PollContent(val formattedDate: String, val state: PollContentState) : PollHistoryItem -} +data class PollHistoryItem( + val formattedDate: String, + val state: PollContentState, +) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItems.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItems.kt new file mode 100644 index 0000000000..180e31b458 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItems.kt @@ -0,0 +1,27 @@ +/* + * 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.poll.impl.history.model + +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +data class PollHistoryItems( + val ongoing: ImmutableList = persistentListOf(), + val past: ImmutableList = persistentListOf(), +) { + val size = ongoing.size + past.size +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt similarity index 70% rename from features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt rename to features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt index 1d09e115ae..a85e4cada2 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryItemsFactory.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryItemsFactory.kt @@ -14,13 +14,14 @@ * limitations under the License. */ -package io.element.android.features.poll.impl.history +package io.element.android.features.poll.impl.history.model import io.element.android.features.poll.api.pollcontent.PollContentStateFactory import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.dateformatter.api.DaySeparatorFormatter import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.withContext import javax.inject.Inject @@ -30,8 +31,22 @@ class PollHistoryItemsFactory @Inject constructor( private val dispatchers: CoroutineDispatchers, ) { - suspend fun create(timelineItems: List): List = withContext(dispatchers.computation) { - timelineItems.mapNotNull { create(it) }.reversed() + suspend fun create(timelineItems: List): PollHistoryItems = withContext(dispatchers.computation) { + val past = ArrayList() + val ongoing = ArrayList() + for (index in timelineItems.indices.reversed()) { + val timelineItem = timelineItems[index] + val pollHistoryItem = create(timelineItem) ?: continue + if (pollHistoryItem.state.isPollEnded) { + past.add(pollHistoryItem) + } else { + ongoing.add(pollHistoryItem) + } + } + PollHistoryItems( + ongoing = ongoing.toPersistentList(), + past = past.toPersistentList() + ) } private suspend fun create(timelineItem: MatrixTimelineItem): PollHistoryItem? { @@ -39,7 +54,7 @@ class PollHistoryItemsFactory @Inject constructor( is MatrixTimelineItem.Event -> { val pollContent = timelineItem.event.content as? PollContent ?: return null val pollContentState = pollContentStateFactory.create(timelineItem.event, pollContent) - PollHistoryItem.PollContent( + PollHistoryItem( formattedDate = daySeparatorFormatter.format(timelineItem.event.timestamp), state = pollContentState ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index d7c8d7f49c..a7cbdccfa2 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -240,7 +240,7 @@ interface MatrixRoom : Closeable { */ fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result - suspend fun pollHistory(): MatrixTimeline + fun pollHistory(): MatrixTimeline override fun close() = destroy() } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt index 98d5772d23..f2a81ea32e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt @@ -23,9 +23,9 @@ import kotlinx.coroutines.flow.StateFlow interface MatrixTimeline : AutoCloseable { data class PaginationState( - val isBackPaginating: Boolean, - val hasMoreToLoadBackwards: Boolean, - val beginningOfRoomReached: Boolean, + val isBackPaginating: Boolean = false, + val hasMoreToLoadBackwards: Boolean = true, + val beginningOfRoomReached: Boolean = false, ) { val canBackPaginate = !isBackPaginating && hasMoreToLoadBackwards } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 8ec2d2b7b8..e509d05ad2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -41,6 +41,7 @@ import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.roomNotificationSettings +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings import io.element.android.libraries.matrix.impl.core.toProgressWatcher @@ -50,6 +51,7 @@ import io.element.android.libraries.matrix.impl.media.toMSC3246range import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService import io.element.android.libraries.matrix.impl.poll.toInner import io.element.android.libraries.matrix.impl.room.location.toInner +import io.element.android.libraries.matrix.impl.timeline.AsyncMatrixTimeline import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline import io.element.android.libraries.matrix.impl.util.destroyAll import io.element.android.libraries.matrix.impl.util.mxCallbackFlow @@ -70,14 +72,12 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.EventTimelineItem -import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.RoomInfo import org.matrix.rustcomponents.sdk.RoomInfoListener import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.RoomMember import org.matrix.rustcomponents.sdk.RoomMessageEventContentWithoutRelation import org.matrix.rustcomponents.sdk.SendAttachmentJoinHandle -import org.matrix.rustcomponents.sdk.Timeline import org.matrix.rustcomponents.sdk.WidgetCapabilities import org.matrix.rustcomponents.sdk.WidgetCapabilitiesProvider import org.matrix.rustcomponents.sdk.messageEventContentFromHtml @@ -85,14 +85,16 @@ import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown import org.matrix.rustcomponents.sdk.use import timber.log.Timber import java.io.File +import org.matrix.rustcomponents.sdk.Room as InnerRoom +import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline @OptIn(ExperimentalCoroutinesApi::class) class RustMatrixRoom( override val sessionId: SessionId, private val isKeyBackupEnabled: Boolean, private val roomListItem: RoomListItem, - private val innerRoom: Room, - private val innerTimeline: Timeline, + private val innerRoom: InnerRoom, + private val innerTimeline: InnerTimeline, private val roomNotificationSettingsService: RustNotificationSettingsService, sessionCoroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, @@ -130,15 +132,9 @@ class RustMatrixRoom( private val _roomNotificationSettingsStateFlow = MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown) override val roomNotificationSettingsStateFlow: StateFlow = _roomNotificationSettingsStateFlow - override val timeline = RustMatrixTimeline( - isKeyBackupEnabled = isKeyBackupEnabled, - matrixRoom = this, - innerTimeline = innerTimeline, - roomCoroutineScope = roomCoroutineScope, - dispatcher = roomDispatcher, - lastLoginTimestamp = sessionData.loginTimestamp, - onNewSyncedEvent = { _syncUpdateFlow.value = systemClock.epochMillis() } - ) + override val timeline = createMatrixTimeline(innerTimeline) { + _syncUpdateFlow.value = systemClock.epochMillis() + } override val membersStateFlow: StateFlow = _membersStateFlow.asStateFlow() @@ -150,7 +146,7 @@ class RustMatrixRoom( override fun destroy() { roomCoroutineScope.cancel() - innerTimeline.destroy() + timeline.close() innerRoom.destroy() roomListItem.destroy() specialModeEventTimelineItem?.destroy() @@ -570,22 +566,35 @@ class RustMatrixRoom( ) } - override suspend fun pollHistory() = RustMatrixTimeline( - isKeyBackupEnabled = isKeyBackupEnabled, - matrixRoom = this, - innerTimeline = innerRoom.pollHistory(), - roomCoroutineScope = roomCoroutineScope, - dispatcher = roomDispatcher, - lastLoginTimestamp = sessionData.loginTimestamp, - onNewSyncedEvent = { _syncUpdateFlow.value = systemClock.epochMillis() } - ) + override fun pollHistory() = AsyncMatrixTimeline( + coroutineScope = roomCoroutineScope, + dispatcher = roomDispatcher + ) { + val innerTimeline = innerRoom.pollHistory() + createMatrixTimeline(innerTimeline) + } - private suspend fun sendAttachment(files: List, handle: () -> SendAttachmentJoinHandle): Result { + private fun sendAttachment(files: List, handle: () -> SendAttachmentJoinHandle): Result { return runCatching { MediaUploadHandlerImpl(files, handle()) } } + private fun createMatrixTimeline( + timeline: InnerTimeline, + onNewSyncedEvent: () -> Unit = {}, + ): MatrixTimeline { + return RustMatrixTimeline( + isKeyBackupEnabled = isKeyBackupEnabled, + matrixRoom = this, + roomCoroutineScope = roomCoroutineScope, + dispatcher = roomDispatcher, + lastLoginTimestamp = sessionData.loginTimestamp, + onNewSyncedEvent = onNewSyncedEvent, + innerTimeline = timeline, + ) + } + private fun messageEventContentFromParts(body: String, htmlBody: String?): RoomMessageEventContentWithoutRelation = if (htmlBody != null) { messageEventContentFromHtml(body, htmlBody) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt new file mode 100644 index 0000000000..15959476b1 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt @@ -0,0 +1,95 @@ +/* + * 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.timeline + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.async +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import timber.log.Timber + +/** + * This class is a wrapper around a [MatrixTimeline] that will be created asynchronously. + */ +class AsyncMatrixTimeline( + coroutineScope: CoroutineScope, + dispatcher: CoroutineDispatcher, + private val timelineProvider: suspend () -> MatrixTimeline +) : MatrixTimeline { + + private val _timelineItems: MutableStateFlow> = + MutableStateFlow(emptyList()) + + private val _paginationState = MutableStateFlow( + MatrixTimeline.PaginationState() + ) + private val timeline = coroutineScope.async(context = dispatcher, start = CoroutineStart.LAZY) { + timelineProvider() + } + private val closeSignal = CompletableDeferred() + + init { + coroutineScope.launch { + val delegateTimeline = timeline.await() + delegateTimeline.timelineItems + .onEach { _timelineItems.value = it } + .launchIn(this) + delegateTimeline.paginationState + .onEach { _paginationState.value = it } + .launchIn(this) + + launch { + withContext(NonCancellable) { + closeSignal.await() + Timber.d("Close delegate") + delegateTimeline.close() + } + } + } + } + + override val paginationState: StateFlow = _paginationState + override val timelineItems: Flow> = _timelineItems + + override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result { + return timeline.await().paginateBackwards(requestSize, untilNumberOfItems) + } + + override suspend fun fetchDetailsForEvent(eventId: EventId): Result { + return timeline.await().fetchDetailsForEvent(eventId) + } + + override suspend fun sendReadReceipt(eventId: EventId): Result { + return timeline.await().sendReadReceipt(eventId) + } + + override fun close() { + closeSignal.complete(Unit) + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 70978c4fe7..244b73c247 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -72,11 +72,7 @@ class RustMatrixTimeline( MutableStateFlow(emptyList()) private val _paginationState = MutableStateFlow( - MatrixTimeline.PaginationState( - hasMoreToLoadBackwards = true, - isBackPaginating = false, - beginningOfRoomReached = false, - ) + MatrixTimeline.PaginationState() ) private val encryptedHistoryPostProcessor = TimelineEncryptedHistoryPostProcessor( diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/PollHistory.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/PollHistory.kt new file mode 100644 index 0000000000..bc695864f7 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/PollHistory.kt @@ -0,0 +1,36 @@ +/* + * 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.ui.room + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.remember +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.timeline.MatrixTimeline + +@Composable +fun MatrixRoom.rememberPollHistory(): MatrixTimeline { + val pollHistory = remember { + pollHistory() + } + DisposableEffect(pollHistory) { + onDispose { + pollHistory.close() + } + } + return pollHistory +} From 954df6c537190f73b4d6689d0afd4f6a76a5523a Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 6 Dec 2023 19:28:04 +0100 Subject: [PATCH 04/24] Theme : introduce SegmentedButton --- .../theme/components/SegmentedButton.kt | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SegmentedButton.kt diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SegmentedButton.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SegmentedButton.kt new file mode 100644 index 0000000000..1c37cbce1e --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/SegmentedButton.kt @@ -0,0 +1,70 @@ +/* + * 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.designsystem.theme.components + +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SegmentedButtonDefaults +import androidx.compose.material3.SingleChoiceSegmentedButtonRowScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import io.element.android.compound.theme.ElementTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SingleChoiceSegmentedButtonRowScope.SegmentedButton( + index: Int, + count: Int, + selected: Boolean, + onClick: () -> Unit, + text: String, + modifier: Modifier = Modifier, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, + enabled: Boolean = true, +) { + SegmentedButton( + selected = selected, + onClick = onClick, + modifier = modifier, + interactionSource = interactionSource, + enabled = enabled, + shape = SegmentedButtonDefaults.itemShape(index = index, count = count), + label = { + Text( + text = text, + style = ElementTheme.typography.fontBodyMdMedium, + ) + }, + colors = SegmentedButtonDefaults.colors( + activeContainerColor = ElementTheme.materialColors.primary, + activeContentColor = ElementTheme.materialColors.onPrimary, + activeBorderColor = ElementTheme.materialColors.primary, + inactiveContainerColor = ElementTheme.materialColors.surface, + inactiveContentColor = ElementTheme.materialColors.onSurface, + inactiveBorderColor = ElementTheme.materialColors.primary, + disabledActiveContainerColor = ElementTheme.colors.bgActionPrimaryDisabled, + disabledActiveContentColor = ElementTheme.colors.textOnSolidPrimary, + disabledActiveBorderColor = ElementTheme.colors.bgActionPrimaryDisabled, + disabledInactiveContainerColor = ElementTheme.materialColors.surface, + disabledInactiveContentColor = ElementTheme.colors.textDisabled, + disabledInactiveBorderColor = Color.Transparent, + ) + ) +} From 891c05a99c5fc2ceb92173d5cb324fe7b71fe46c Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 6 Dec 2023 19:28:37 +0100 Subject: [PATCH 05/24] PollHistory : use the new PollHistoryState in the view --- .../poll/impl/history/PollHistoryView.kt | 154 +++++++++++------- 1 file changed, 97 insertions(+), 57 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index 34dee34a59..53b3488d46 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -16,28 +16,37 @@ package io.element.android.features.poll.impl.history +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.features.poll.api.pollcontent.PollContentView +import io.element.android.features.poll.impl.history.model.PollHistoryFilter +import io.element.android.features.poll.impl.history.model.PollHistoryItem import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.aliasScreenTitle -import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.SegmentedButton +import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.EventId @@ -64,32 +73,81 @@ fun PollHistoryView( }, ) }, - ) { paddingValues -> - LazyColumn( + ) { padding -> + Column( modifier = Modifier - .fillMaxSize() - .padding(paddingValues), - reverseLayout = false, + .padding(padding) + .consumeWindowInsets(padding) ) { - if (state.paginationState.isBackPaginating) item { - CircularProgressIndicator() - } - itemsIndexed(state.pollItems) { index, pollHistoryItem -> - PollHistoryItemRow( - pollHistoryItem = pollHistoryItem, - onAnswerSelected = fun(pollStartId: EventId, answerId: String) { - state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) - }, - onPollEdit = { - state.eventSink(PollHistoryEvents.EditPoll) - }, - onPollEnd = { - state.eventSink(PollHistoryEvents.PollEndClicked(it)) + PollHistoryFilterButtons( + activeFilter = state.activeFilter, + onFilterSelected = { state.eventSink(PollHistoryEvents.OnFilterSelected(it)) }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + ) + PollHistoryList( + state = state, + modifier = Modifier.fillMaxSize() + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun PollHistoryFilterButtons( + activeFilter: PollHistoryFilter, + onFilterSelected: (PollHistoryFilter) -> Unit, + modifier: Modifier = Modifier, +) { + SingleChoiceSegmentedButtonRow(modifier = modifier) { + PollHistoryFilter.entries.forEach { filter -> + SegmentedButton( + index = filter.ordinal, + count = PollHistoryFilter.entries.size, + selected = activeFilter == filter, + onClick = { onFilterSelected(filter) }, + text = filter.name + ) + } + } +} + +@Composable +private fun PollHistoryList( + state: PollHistoryState, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + items(state.currentItems) { pollHistoryItem -> + PollHistoryItemRow( + pollHistoryItem = pollHistoryItem, + onAnswerSelected = fun(pollStartId: EventId, answerId: String) { + state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) + }, + onPollEdit = { + state.eventSink(PollHistoryEvents.EditPoll) + }, + onPollEnd = { + state.eventSink(PollHistoryEvents.PollEndClicked(it)) + }, + modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp) + ) + } + if (state.hasMoreToLoad) { + item { + Button( + text = "Load more", + showProgress = state.isLoading, + onClick = { + state.eventSink(PollHistoryEvents.LoadMore) }, + modifier = Modifier.padding(vertical = 24.dp), ) - if (index != state.pollItems.lastIndex) { - HorizontalDivider() - } } } } @@ -103,46 +161,28 @@ private fun PollHistoryItemRow( onPollEnd: (pollStartId: EventId) -> Unit, modifier: Modifier = Modifier, ) { - when (pollHistoryItem) { - is PollHistoryItem.PollContent -> { - PollContentItemRow( - pollContentItem = pollHistoryItem, + Surface( + modifier = modifier, + border = BorderStroke(1.dp, ElementTheme.colors.borderInteractiveSecondary), + shape = RoundedCornerShape(size = 12.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = pollHistoryItem.formattedDate, + color = MaterialTheme.colorScheme.secondary, + style = ElementTheme.typography.fontBodySmRegular, + ) + Spacer(modifier = Modifier.height(4.dp)) + PollContentView( + state = pollHistoryItem.state, onAnswerSelected = onAnswerSelected, onPollEdit = onPollEdit, onPollEnd = onPollEnd, - modifier = modifier.padding( - horizontal = 16.dp, - vertical = 24.dp - ), ) } } } -@Composable -private fun PollContentItemRow( - pollContentItem: PollHistoryItem.PollContent, - onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, - onPollEdit: (pollStartId: EventId) -> Unit, - onPollEnd: (pollStartId: EventId) -> Unit, - modifier: Modifier = Modifier, -) { - Column(modifier = modifier) { - Text( - text = pollContentItem.formattedDate, - color = MaterialTheme.colorScheme.secondary, - style = ElementTheme.typography.fontBodySmRegular, - ) - Spacer(modifier = Modifier.height(4.dp)) - PollContentView( - state = pollContentItem.state, - onAnswerSelected = onAnswerSelected, - onPollEdit = onPollEdit, - onPollEnd = onPollEnd, - ) - } -} - @PreviewsDayNight @Composable internal fun PollHistoryViewPreview( From 449c331879766323f066cd928379df47102e64f2 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 14:23:50 +0100 Subject: [PATCH 06/24] Timeline: exposes simple request for backward pagination --- .../libraries/matrix/api/timeline/MatrixTimeline.kt | 1 + .../matrix/impl/timeline/AsyncMatrixTimeline.kt | 4 ++++ .../libraries/matrix/impl/timeline/RustMatrixTimeline.kt | 9 +++++++++ .../libraries/matrix/test/timeline/FakeMatrixTimeline.kt | 5 ++++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt index f2a81ea32e..7a43d1079f 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt @@ -33,6 +33,7 @@ interface MatrixTimeline : AutoCloseable { val paginationState: StateFlow val timelineItems: Flow> + suspend fun paginateBackwards(requestSize: Int): Result suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result suspend fun fetchDetailsForEvent(eventId: EventId): Result suspend fun sendReadReceipt(eventId: EventId): Result diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt index 15959476b1..5f7636eaa9 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt @@ -77,6 +77,10 @@ class AsyncMatrixTimeline( override val paginationState: StateFlow = _paginationState override val timelineItems: Flow> = _timelineItems + override suspend fun paginateBackwards(requestSize: Int): Result { + return timeline.await().paginateBackwards(requestSize) + } + override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result { return timeline.await().paginateBackwards(requestSize, untilNumberOfItems) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 244b73c247..b25ca8bb89 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -188,6 +188,14 @@ class RustMatrixTimeline( } } + override suspend fun paginateBackwards(requestSize: Int): Result { + val paginationOptions = PaginationOptions.SimpleRequest( + eventLimit = requestSize.toUShort(), + waitForToken = true, + ) + return paginateBackwards(paginationOptions) + } + override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result { val paginationOptions = PaginationOptions.UntilNumItems( eventLimit = requestSize.toUShort(), @@ -198,6 +206,7 @@ class RustMatrixTimeline( } private suspend fun paginateBackwards(paginationOptions: PaginationOptions): Result = withContext(dispatcher) { + initLatch.await() runCatching { if (!canBackPaginate()) throw TimelineException.CannotPaginate Timber.v("Start back paginating for room ${matrixRoom.roomId} ") diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt index 21325d7a83..51b504cb9f 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/FakeMatrixTimeline.kt @@ -56,7 +56,10 @@ class FakeMatrixTimeline( override val timelineItems: Flow> = _timelineItems - override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result { + override suspend fun paginateBackwards(requestSize: Int) = paginateBackwards() + override suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int) = paginateBackwards() + + private suspend fun paginateBackwards(): Result { updatePaginationState { copy(isBackPaginating = true) } From 7307e0fb130945dd398a46205e1bf38c158f12e8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 14:24:41 +0100 Subject: [PATCH 07/24] Poll history : use pager to keep scrolling state when switching filter --- .../poll/impl/history/PollHistoryEvents.kt | 1 - .../poll/impl/history/PollHistoryNode.kt | 1 + .../poll/impl/history/PollHistoryPresenter.kt | 16 +--- .../poll/impl/history/PollHistoryState.kt | 13 ++- .../impl/history/PollHistoryStateProvider.kt | 5 +- .../poll/impl/history/PollHistoryView.kt | 84 ++++++++++++++----- 6 files changed, 82 insertions(+), 38 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt index d07b6fa24a..edc848da41 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryEvents.kt @@ -23,6 +23,5 @@ sealed interface PollHistoryEvents { data object LoadMore : PollHistoryEvents data class PollAnswerSelected(val pollStartId: EventId, val answerId: String) : PollHistoryEvents data class PollEndClicked(val pollStartId: EventId) : PollHistoryEvents - data object EditPoll : PollHistoryEvents data class OnFilterSelected(val filter: PollHistoryFilter) : PollHistoryEvents } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt index d466a16aef..7107aba344 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt @@ -41,6 +41,7 @@ class PollHistoryNode @AssistedInject constructor( PollHistoryView( state = presenter.present(), modifier = modifier, + onEditPoll = {}, goBack = this::navigateUp, ) } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index a1f0b81315..ab7392f2db 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -38,7 +38,6 @@ import io.element.android.libraries.matrix.ui.room.rememberPollHistory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject class PollHistoryPresenter @Inject constructor( @@ -82,32 +81,23 @@ class PollHistoryPresenter @Inject constructor( is PollHistoryEvents.PollEndClicked -> appCoroutineScope.launch { endPollAction.execute(pollStartId = event.pollStartId) } - PollHistoryEvents.EditPoll -> Unit is PollHistoryEvents.OnFilterSelected -> { activeFilter = event.filter } } } - val currentItems by remember { - derivedStateOf { - when (activeFilter) { - PollHistoryFilter.ONGOING -> pollHistoryItems.ongoing - PollHistoryFilter.PAST -> pollHistoryItems.past - } - } - } + return PollHistoryState( isLoading = isLoading, hasMoreToLoad = paginationState.hasMoreToLoadBackwards, - currentItems = currentItems, + pollHistoryItems = pollHistoryItems, activeFilter = activeFilter, eventSink = ::handleEvents, ) } private fun CoroutineScope.loadMore(pollHistory: MatrixTimeline) = launch { - Timber.d("LoadMore poll history") - pollHistory.paginateBackwards(50, 3) + pollHistory.paginateBackwards(200) } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt index c3b768993f..4d0f351bfd 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryState.kt @@ -18,12 +18,21 @@ package io.element.android.features.poll.impl.history import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryItem +import io.element.android.features.poll.impl.history.model.PollHistoryItems import kotlinx.collections.immutable.ImmutableList data class PollHistoryState( val isLoading: Boolean, val hasMoreToLoad: Boolean, val activeFilter: PollHistoryFilter, - val currentItems: ImmutableList, + val pollHistoryItems: PollHistoryItems, val eventSink: (PollHistoryEvents) -> Unit, -) +) { + + fun pollHistoryForFilter(filter: PollHistoryFilter): ImmutableList { + return when (filter) { + PollHistoryFilter.ONGOING -> pollHistoryItems.ongoing + PollHistoryFilter.PAST -> pollHistoryItems.past + } + } +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt index 24862cd599..6771e034bf 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt @@ -21,6 +21,7 @@ import io.element.android.features.poll.api.pollcontent.PollContentState import io.element.android.features.poll.api.pollcontent.aPollContentState import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryItem +import io.element.android.features.poll.impl.history.model.PollHistoryItems import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -51,7 +52,9 @@ private fun aPollHistoryState( isLoading = isLoading, hasMoreToLoad = hasMoreToLoad, activeFilter = activeFilter, - currentItems = currentItems, + pollHistoryItems = PollHistoryItems( + ongoing = currentItems, + past = currentItems,), eventSink = {}, ) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index 53b3488d46..191aae3b2b 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -17,6 +17,7 @@ package io.element.android.features.poll.impl.history import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets @@ -26,11 +27,15 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.PreviewParameter @@ -50,14 +55,29 @@ import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.EventId +import kotlinx.collections.immutable.ImmutableList -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun PollHistoryView( state: PollHistoryState, modifier: Modifier = Modifier, + onEditPoll: (EventId) -> Unit, goBack: () -> Unit, ) { + + fun onLoadMore() { + state.eventSink(PollHistoryEvents.LoadMore) + } + + fun onAnswerSelected(pollStartId: EventId, answerId: String) { + state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) + } + + fun onPollEnd(pollStartId: EventId) { + state.eventSink(PollHistoryEvents.PollEndClicked(pollStartId)) + } + Scaffold( modifier = modifier, topBar = { @@ -79,6 +99,12 @@ fun PollHistoryView( .padding(padding) .consumeWindowInsets(padding) ) { + val pagerState = rememberPagerState(state.activeFilter.ordinal, 0f) { + PollHistoryFilter.entries.size + } + LaunchedEffect(state.activeFilter) { + pagerState.scrollToPage(state.activeFilter.ordinal) + } PollHistoryFilterButtons( activeFilter = state.activeFilter, onFilterSelected = { state.eventSink(PollHistoryEvents.OnFilterSelected(it)) }, @@ -86,10 +112,25 @@ fun PollHistoryView( .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) - PollHistoryList( - state = state, - modifier = Modifier.fillMaxSize() - ) + HorizontalPager( + state = pagerState, + userScrollEnabled = false, + modifier = modifier.fillMaxSize() + ) { page -> + val filter = PollHistoryFilter.entries[page] + val pollHistoryItems = state.pollHistoryForFilter(filter) + PollHistoryList( + pollHistoryItems = pollHistoryItems, + hasMoreToLoad = state.hasMoreToLoad, + isLoading = state.isLoading, + onAnswerSelected = ::onAnswerSelected, + onPollEdit = onEditPoll, + onPollEnd = ::onPollEnd, + onLoadMore = ::onLoadMore, + modifier = Modifier.fillMaxSize(), + ) + + } } } } @@ -116,36 +157,36 @@ private fun PollHistoryFilterButtons( @Composable private fun PollHistoryList( - state: PollHistoryState, + pollHistoryItems: ImmutableList, + hasMoreToLoad: Boolean, + isLoading: Boolean, + onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, + onPollEdit: (pollStartId: EventId) -> Unit, + onPollEnd: (pollStartId: EventId) -> Unit, + onLoadMore: () -> Unit, modifier: Modifier = Modifier, ) { + val lazyListState = rememberLazyListState() LazyColumn( + state = lazyListState, modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally, ) { - items(state.currentItems) { pollHistoryItem -> + items(pollHistoryItems) { pollHistoryItem -> PollHistoryItemRow( pollHistoryItem = pollHistoryItem, - onAnswerSelected = fun(pollStartId: EventId, answerId: String) { - state.eventSink(PollHistoryEvents.PollAnswerSelected(pollStartId, answerId)) - }, - onPollEdit = { - state.eventSink(PollHistoryEvents.EditPoll) - }, - onPollEnd = { - state.eventSink(PollHistoryEvents.PollEndClicked(it)) - }, + onAnswerSelected = onAnswerSelected, + onPollEdit = onPollEdit, + onPollEnd = onPollEnd, modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp) ) } - if (state.hasMoreToLoad) { + if (hasMoreToLoad) { item { Button( text = "Load more", - showProgress = state.isLoading, - onClick = { - state.eventSink(PollHistoryEvents.LoadMore) - }, + showProgress = isLoading, + onClick = onLoadMore, modifier = Modifier.padding(vertical = 24.dp), ) } @@ -190,6 +231,7 @@ internal fun PollHistoryViewPreview( ) = ElementPreview { PollHistoryView( state = state, + onEditPoll = {}, goBack = {}, ) } From a2c5cdf4832c9d292d28e0ae3852b20c930154d0 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 14:36:07 +0100 Subject: [PATCH 08/24] Poll history : use localazy strings --- .../poll/impl/history/PollHistoryView.kt | 9 +- .../impl/history/model/PollHistoryFilter.kt | 8 +- .../impl/src/main/res/values/localazy.xml | 5 + .../impl/src/main/res/values/localazy.xml | 1 + .../roomdetails/impl/RoomDetailsView.kt | 2 +- .../impl/src/main/res/values/localazy.xml | 1 + .../impl/src/main/res/values/localazy.xml | 2 + .../src/main/res/values/localazy.xml | 5 +- tools/localazy/config.json | 114 +++++++++--------- 9 files changed, 81 insertions(+), 66 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index 191aae3b2b..e860cd1483 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -38,10 +38,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.features.poll.api.pollcontent.PollContentView +import io.element.android.features.poll.impl.R import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryItem import io.element.android.libraries.designsystem.components.button.BackButton @@ -55,6 +57,7 @@ import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.ImmutableList @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @@ -84,7 +87,7 @@ fun PollHistoryView( TopAppBar( title = { Text( - text = "Polls", // TODO Polls: Localazy + text = stringResource(R.string.screen_polls_history_title), style = ElementTheme.typography.aliasScreenTitle, ) }, @@ -149,7 +152,7 @@ private fun PollHistoryFilterButtons( count = PollHistoryFilter.entries.size, selected = activeFilter == filter, onClick = { onFilterSelected(filter) }, - text = filter.name + text = stringResource(filter.stringResource), ) } } @@ -184,7 +187,7 @@ private fun PollHistoryList( if (hasMoreToLoad) { item { Button( - text = "Load more", + text = stringResource(CommonStrings.action_load_more), showProgress = isLoading, onClick = onLoadMore, modifier = Modifier.padding(vertical = 24.dp), diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt index d56087d2c1..c8d905e031 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/model/PollHistoryFilter.kt @@ -16,7 +16,9 @@ package io.element.android.features.poll.impl.history.model -enum class PollHistoryFilter { - ONGOING, - PAST, +import io.element.android.features.poll.impl.R + +enum class PollHistoryFilter(val stringResource: Int) { + ONGOING(R.string.screen_polls_history_filter_ongoing), + PAST(R.string.screen_polls_history_filter_past), } diff --git a/features/poll/impl/src/main/res/values/localazy.xml b/features/poll/impl/src/main/res/values/localazy.xml index 83942df70d..7a7a15ea3c 100644 --- a/features/poll/impl/src/main/res/values/localazy.xml +++ b/features/poll/impl/src/main/res/values/localazy.xml @@ -11,4 +11,9 @@ "Are you sure you want to delete this poll?" "Delete Poll" "Edit poll" + "Can\'t find any ongoing polls." + "Can\'t find any past polls." + "Ongoing" + "Past" + "Polls" diff --git a/features/preferences/impl/src/main/res/values/localazy.xml b/features/preferences/impl/src/main/res/values/localazy.xml index c76c647bba..55c43f05f4 100644 --- a/features/preferences/impl/src/main/res/values/localazy.xml +++ b/features/preferences/impl/src/main/res/values/localazy.xml @@ -29,6 +29,7 @@ If you proceed, some of your settings may change." "Enable notifications on this device" "The configuration has not been corrected, please try again." "Group chats" + "Invitations" "Your homeserver does not support this option in encrypted rooms, you may not get notified in some rooms." "Mentions" "All" diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 0f92b466f4..8bdba4be73 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -385,7 +385,7 @@ private fun PollsSection( ) { PreferenceCategory(modifier = modifier) { ListItem( - headlineContent = { Text("Polls") }, // TODO Polls: Localazy + headlineContent = { Text(stringResource(R.string.screen_polls_history_title)) }, leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Polls)), onClick = openPollHistory, ) diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index 5363c6a78e..f8bf5ddf6f 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -5,6 +5,7 @@ "%1$d people" "An error occurred while updating the notification setting." + "Polls" "Add topic" "Already a member" "Already invited" diff --git a/features/verifysession/impl/src/main/res/values/localazy.xml b/features/verifysession/impl/src/main/res/values/localazy.xml index 24b3a7cf26..9b785044d8 100644 --- a/features/verifysession/impl/src/main/res/values/localazy.xml +++ b/features/verifysession/impl/src/main/res/values/localazy.xml @@ -3,6 +3,8 @@ "Something doesn’t seem right. Either the request timed out or the request was denied." "Confirm that the emojis below match those shown on your other session." "Compare emojis" + "Confirm that the numbers below match those shown on your other session." + "Compare numbers" "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted." "Prove it’s you in order to access your encrypted message history." "Open an existing session" diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index c816850f98..10d3bbd12e 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -95,6 +95,7 @@ "Try again" "View source" "Yes" + "Load more" "About" "Acceptable use policy" "Advanced settings" @@ -109,6 +110,7 @@ "Dark" "Decryption error" "Developer options" + "Direct chat" "(edited)" "Editing" "* %1$s %2$s" @@ -227,9 +229,6 @@ "%d votes" "Rageshake to report bug" - "Are you sure you want to delete this poll?" - "Delete Poll" - "Edit poll" "Failed selecting media, please try again." "Failed processing media to upload, please try again." "Failed uploading media, please try again." diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 06805d49cc..cc949b7dde 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -1,91 +1,91 @@ { - "modules": [ + "modules" : [ { - "name": ":features:rageshake:impl", - "includeRegex": [ + "name" : ":features:rageshake:impl", + "includeRegex" : [ "screen_bug_report_.*" ] }, { - "name": ":features:rageshake:api", - "includeRegex": [ + "name" : ":features:rageshake:api", + "includeRegex" : [ "crash_detection_.*", "rageshake_detection_.*", "settings_rageshake.*" ] }, { - "name": ":features:logout:impl", - "includeRegex": [ + "name" : ":features:logout:impl", + "includeRegex" : [ "screen_signout_.*" ] }, { - "name": ":features:onboarding:impl", - "includeRegex": [ + "name" : ":features:onboarding:impl", + "includeRegex" : [ "screen_onboarding_.*" ] }, { - "name": ":features:signedout:impl", - "includeRegex": [ + "name" : ":features:signedout:impl", + "includeRegex" : [ "screen_signed_out_.*" ] }, { - "name": ":features:invitelist:impl", - "includeRegex": [ + "name" : ":features:invitelist:impl", + "includeRegex" : [ "screen_invites_.*" ] }, { - "name": ":features:createroom:impl", - "includeRegex": [ + "name" : ":features:createroom:impl", + "includeRegex" : [ "screen_create_room_.*", "screen_start_chat_.*" ] }, { - "name": ":features:verifysession:impl", - "includeRegex": [ + "name" : ":features:verifysession:impl", + "includeRegex" : [ "screen_session_verification_.*" ] }, { - "name": ":libraries:textcomposer:impl", - "includeRegex": [ + "name" : ":libraries:textcomposer:impl", + "includeRegex" : [ "rich_text_editor.*", ".*voice_message_tooltip" ] }, { - "name": ":libraries:permissions:api", - "includeRegex": [ + "name" : ":libraries:permissions:api", + "includeRegex" : [ "dialog\\.permission_.*" ] }, { - "name": ":libraries:androidutils", - "includeRegex": [ + "name" : ":libraries:androidutils", + "includeRegex" : [ "error_no_compatible_app_found" ] }, { - "name": ":libraries:eventformatter:impl", - "includeRegex": [ + "name" : ":libraries:eventformatter:impl", + "includeRegex" : [ "state_event_.*" ] }, { - "name": ":libraries:push:impl", - "includeRegex": [ + "name" : ":libraries:push:impl", + "includeRegex" : [ "push_.*", "notification_.*" ] }, { - "name": ":features:login:impl", - "includeRegex": [ + "name" : ":features:login:impl", + "includeRegex" : [ "screen_login_.*", "screen_server_confirmation_.*", "screen_change_server_.*", @@ -95,32 +95,33 @@ ] }, { - "name": ":features:leaveroom:api", - "includeRegex": [ + "name" : ":features:leaveroom:api", + "includeRegex" : [ "leave_room_alert_.*" ] }, { - "name": ":features:roomlist:impl", - "includeRegex": [ + "name" : ":features:roomlist:impl", + "includeRegex" : [ "screen_roomlist_.*", "session_verification_banner_.*", "confirm_recovery_key_banner_.*" ] }, { - "name": ":features:roomdetails:impl", - "includeRegex": [ + "name" : ":features:roomdetails:impl", + "includeRegex" : [ "screen_room_details_.*", "screen_room_member_list_.*", "screen_dm_details_.*", "screen_room_notification_settings_.*", - "screen_notification_settings_edit_failed_updating_default_mode" + "screen_notification_settings_edit_failed_updating_default_mode", + "screen_polls_history_title" ] }, { - "name": ":features:messages:impl", - "includeRegex": [ + "name" : ":features:messages:impl", + "includeRegex" : [ "room_timeline_.*", "screen_room_.*", "screen\\.room\\..*", @@ -128,50 +129,51 @@ "emoji_picker_category_.*", ".*report_content_.*" ], - "excludeRegex": [ + "excludeRegex" : [ "screen_room_details_.*", "screen_room_member.*", "screen_dm_.*" ] }, { - "name": ":features:analytics:impl", - "includeRegex": [ + "name" : ":features:analytics:impl", + "includeRegex" : [ "screen_analytics_prompt.*" ] }, { - "name": ":features:analytics:api", - "includeRegex": [ + "name" : ":features:analytics:api", + "includeRegex" : [ "screen_analytics_settings_.*" ] }, { - "name": ":features:ftue:impl", - "includeRegex": [ + "name" : ":features:ftue:impl", + "includeRegex" : [ "screen_welcome_.*", "screen_migration_.*", "screen_notification_optin_.*" ] }, { - "name": ":features:poll:impl", - "includeRegex": [ + "name" : ":features:poll:impl", + "includeRegex" : [ "screen_create_poll_.*", - "screen_edit_poll_.*" + "screen_edit_poll_.*", + "screen_polls_history_.*" ] }, { - "name": ":features:securebackup:impl", - "includeRegex": [ + "name" : ":features:securebackup:impl", + "includeRegex" : [ "screen_chat_backup_.*", "screen_key_backup_disable_.*", "screen_recovery_key_.*" ] }, { - "name": ":features:preferences:impl", - "includeRegex": [ + "name" : ":features:preferences:impl", + "includeRegex" : [ "screen_advanced_settings_.*", "screen\\.advanced_settings\\..*", "screen_edit_profile_.*", @@ -179,14 +181,14 @@ ] }, { - "name": ":features:call", - "includeRegex": [ + "name" : ":features:call", + "includeRegex" : [ "call_.*" ] }, { - "name": ":features:lockscreen:impl", - "includeRegex": [ + "name" : ":features:lockscreen:impl", + "includeRegex" : [ "screen_app_lock_.*", "screen_signout_in_progress_dialog_content" ] From 3be12670334f9e97b1c3815dec080d7cfdb6139c Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 15:35:52 +0100 Subject: [PATCH 09/24] Poll history : branch edit flow --- .../history/DefaultPollHistoryEntryPoint.kt | 2 +- .../poll/impl/history/PollHistoryFlowNode.kt | 92 +++++++++++++++++++ .../poll/impl/history/PollHistoryNode.kt | 12 ++- 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt index bda4e042ab..f517c8db06 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/DefaultPollHistoryEntryPoint.kt @@ -27,6 +27,6 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) class DefaultPollHistoryEntryPoint @Inject constructor() : PollHistoryEntryPoint { override fun createNode(parentNode: Node, buildContext: BuildContext): Node { - return parentNode.createNode(buildContext) + return parentNode.createNode(buildContext) } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt new file mode 100644 index 0000000000..425c22e255 --- /dev/null +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt @@ -0,0 +1,92 @@ +/* + * 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.poll.impl.history + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.composable.Children +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.push +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.poll.api.create.CreatePollEntryPoint +import io.element.android.features.poll.api.create.CreatePollMode +import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.core.EventId +import kotlinx.parcelize.Parcelize + +@ContributesNode(RoomScope::class) +class PollHistoryFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val createPollEntryPoint: CreatePollEntryPoint, +) : BackstackNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins +) { + + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data class EditPoll(val pollStartEventId: EventId) : NavTarget + } + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + is NavTarget.EditPoll -> { + createPollEntryPoint.nodeBuilder(this, buildContext) + .params(CreatePollEntryPoint.Params(mode = CreatePollMode.EditPoll(eventId = navTarget.pollStartEventId))) + .build() + } + NavTarget.Root -> { + val callback = object : PollHistoryNode.Callback { + override fun onEditPoll(pollStartEventId: EventId) { + backstack.push(NavTarget.EditPoll(pollStartEventId)) + } + } + createNode( + buildContext = buildContext, + plugins = listOf(callback) + ) + } + } + } + + @Composable + override fun View(modifier: Modifier) { + Children( + navModel = backstack, + modifier = modifier, + transitionHandler = rememberDefaultTransitionHandler() + ) + } + +} diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt index 7107aba344..7e6ba37743 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryNode.kt @@ -21,10 +21,12 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.matrix.api.core.EventId @ContributesNode(RoomScope::class) class PollHistoryNode @AssistedInject constructor( @@ -36,12 +38,20 @@ class PollHistoryNode @AssistedInject constructor( plugins = plugins, ) { + interface Callback : Plugin { + fun onEditPoll(pollStartEventId: EventId) + } + + private fun onEditPoll(pollStartEventId: EventId) { + plugins().forEach { it.onEditPoll(pollStartEventId) } + } + @Composable override fun View(modifier: Modifier) { PollHistoryView( state = presenter.present(), modifier = modifier, - onEditPoll = {}, + onEditPoll = ::onEditPoll, goBack = this::navigateUp, ) } From e76bafc0436460c7e684e3eb89d8f69c61602f83 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 15:36:27 +0100 Subject: [PATCH 10/24] Timeline : avoid crash when destroying --- .../libraries/matrix/impl/timeline/RustMatrixTimeline.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index b25ca8bb89..3995392cbc 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -126,7 +126,11 @@ class RustMatrixTimeline( private suspend fun fetchMembers() = withContext(dispatcher) { initLatch.await() - innerTimeline.fetchMembers() + try { + innerTimeline.fetchMembers() + } catch (exception: Exception) { + Timber.e(exception, "Error fetching members for room ${matrixRoom.roomId}") + } } @OptIn(ExperimentalCoroutinesApi::class) From 5282e1c5c563ee26eba291012de5a341a9b2ad07 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 16:17:05 +0100 Subject: [PATCH 11/24] PollHistory : use the regular timeline instead of pollHistory timeline as not working properly. --- .../poll/impl/history/PollHistoryPresenter.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index ab7392f2db..784f64c416 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -34,7 +34,6 @@ import io.element.android.features.poll.impl.history.model.PollHistoryItemsFacto import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimeline -import io.element.android.libraries.matrix.ui.room.rememberPollHistory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -50,10 +49,11 @@ class PollHistoryPresenter @Inject constructor( @Composable override fun present(): PollHistoryState { - val pollHistory = room.rememberPollHistory() - val paginationState by pollHistory.paginationState.collectAsState() + // TODO use room.rememberPollHistory() when working properly? + val timeline = room.timeline + val paginationState by timeline.paginationState.collectAsState() val pollHistoryItemsFlow = remember { - pollHistory.timelineItems.map { items -> + timeline.timelineItems.map { items -> pollHistoryItemFactory.create(items) } } @@ -62,7 +62,7 @@ class PollHistoryPresenter @Inject constructor( } val pollHistoryItems by pollHistoryItemsFlow.collectAsState(initial = PollHistoryItems()) LaunchedEffect(paginationState, pollHistoryItems.size) { - if (pollHistoryItems.size == 0 && paginationState.canBackPaginate) loadMore(pollHistory) + if (pollHistoryItems.size == 0 && paginationState.canBackPaginate) loadMore(timeline) } val isLoading by remember { derivedStateOf { @@ -73,7 +73,7 @@ class PollHistoryPresenter @Inject constructor( fun handleEvents(event: PollHistoryEvents) { when (event) { is PollHistoryEvents.LoadMore -> { - coroutineScope.loadMore(pollHistory) + coroutineScope.loadMore(timeline) } is PollHistoryEvents.PollAnswerSelected -> appCoroutineScope.launch { sendPollResponseAction.execute(pollStartId = event.pollStartId, answerId = event.answerId) From 8f1e1398f2d6145759aa6055fe1f939a8249f2be Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 12 Dec 2023 16:44:30 +0100 Subject: [PATCH 12/24] Poll history : add empty state --- .../poll/impl/history/PollHistoryView.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index e860cd1483..3b22eed41a 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -123,6 +123,7 @@ fun PollHistoryView( val filter = PollHistoryFilter.entries[page] val pollHistoryItems = state.pollHistoryForFilter(filter) PollHistoryList( + filter = filter, pollHistoryItems = pollHistoryItems, hasMoreToLoad = state.hasMoreToLoad, isLoading = state.isLoading, @@ -160,6 +161,7 @@ private fun PollHistoryFilterButtons( @Composable private fun PollHistoryList( + filter: PollHistoryFilter, pollHistoryItems: ImmutableList, hasMoreToLoad: Boolean, isLoading: Boolean, @@ -184,6 +186,21 @@ private fun PollHistoryList( modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp) ) } + if (pollHistoryItems.isEmpty()) { + item { + val emptyStringResource = if (filter == PollHistoryFilter.PAST) { + stringResource(R.string.screen_polls_history_empty_past) + } else { + stringResource(R.string.screen_polls_history_empty_ongoing) + } + Text( + text = emptyStringResource, + style = ElementTheme.typography.fontBodyLgRegular, + color = ElementTheme.colors.textSecondary, + modifier = Modifier.padding(vertical = 24.dp, horizontal = 16.dp) + ) + } + } if (hasMoreToLoad) { item { Button( From 6378f6cffe302cdf138fda2644d00b618e3268b8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Dec 2023 16:20:01 +0100 Subject: [PATCH 13/24] Poll history : add tests and fix others --- features/messages/impl/build.gradle.kts | 2 + .../messages/impl/MessagesPresenterTest.kt | 5 +- .../impl/fixtures/timelineItemsFactory.kt | 3 +- .../impl/timeline/TimelinePresenterTest.kt | 68 +--- .../TimelineItemContentPollFactoryTest.kt | 328 ------------------ features/poll/impl/build.gradle.kts | 2 + .../features/poll/impl/PollFixtures.kt | 55 +++ .../impl/create/CreatePollPresenterTest.kt | 50 +-- .../impl/history/PollHistoryPresenterTest.kt | 169 +++++++++ .../PollContentStateFactoryTest.kt | 288 +++++++++++++++ features/poll/test/build.gradle.kts | 29 ++ .../poll/test/actions/FakeEndPollAction.kt | 34 ++ .../actions/FakeSendPollResponseAction.kt | 34 ++ .../FakePollContentStateFactory.kt | 39 +++ .../matrix/test/room/FakeMatrixRoom.kt | 3 +- .../matrix/test/room/RoomSummaryFixture.kt | 112 +----- .../matrix/test/timeline/TimelineFixture.kt | 139 ++++++++ 17 files changed, 831 insertions(+), 529 deletions(-) delete mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt create mode 100644 features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/PollFixtures.kt create mode 100644 features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt create mode 100644 features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/pollcontent/PollContentStateFactoryTest.kt create mode 100644 features/poll/test/build.gradle.kts create mode 100644 features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeEndPollAction.kt create mode 100644 features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeSendPollResponseAction.kt create mode 100644 features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt create mode 100644 libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt diff --git a/features/messages/impl/build.gradle.kts b/features/messages/impl/build.gradle.kts index e392c96e04..c6570db10e 100644 --- a/features/messages/impl/build.gradle.kts +++ b/features/messages/impl/build.gradle.kts @@ -97,6 +97,8 @@ dependencies { testImplementation(libs.test.mockk) testImplementation(libs.test.junitext) testImplementation(libs.test.robolectric) + testImplementation(projects.features.poll.test) + testImplementation(projects.features.poll.impl) ksp(libs.showkase.processor) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 1bed98ae06..bf4e03581d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -47,6 +47,8 @@ import io.element.android.features.messages.impl.voicemessages.composer.VoiceMes import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager import io.element.android.features.messages.test.FakeMessageComposerContext import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.features.poll.test.actions.FakeEndPollAction +import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.libraries.androidutils.clipboard.FakeClipboardHelper import io.element.android.libraries.architecture.Async import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -705,11 +707,12 @@ class MessagesPresenterTest { dispatchers = coroutineDispatchers, appScope = this, navigator = navigator, - analyticsService = analyticsService, encryptionService = FakeEncryptionService(), verificationService = FakeSessionVerificationService(), featureFlagService = FakeFeatureFlagService(), redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), + endPollAction = FakeEndPollAction(), + sendPollResponseAction = FakeSendPollResponseAction(), ) val timelinePresenterFactory = object: TimelinePresenter.Factory { override fun create(navigator: MessagesNavigator): TimelinePresenter { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/timelineItemsFactory.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/timelineItemsFactory.kt index 879333f690..23b3d1aea0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/timelineItemsFactory.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/timelineItemsFactory.kt @@ -32,6 +32,7 @@ import io.element.android.features.messages.impl.timeline.factories.event.Timeli import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemDaySeparatorFactory import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper +import io.element.android.features.poll.test.pollcontent.FakePollContentStateFactory import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter @@ -57,7 +58,7 @@ internal fun TestScope.aTimelineItemsFactory(): TimelineItemsFactory { ), redactedMessageFactory = TimelineItemContentRedactedFactory(), stickerFactory = TimelineItemContentStickerFactory(), - pollFactory = TimelineItemContentPollFactory(matrixClient, FakeFeatureFlagService()), + pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()), utdFactory = TimelineItemContentUTDFactory(), roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter), profileChangeFactory = TimelineItemContentProfileChangeFactory(timelineEventFormatter), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index dea1975c6c..c07286dddc 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -20,10 +20,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import im.vector.app.features.analytics.plan.PollEnd -import im.vector.app.features.analytics.plan.PollVote import io.element.android.features.messages.impl.FakeMessagesNavigator -import io.element.android.features.messages.impl.fixtures.aMessageEvent import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory import io.element.android.features.messages.impl.timeline.model.NewEventState @@ -32,8 +29,11 @@ import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager import io.element.android.features.messages.impl.voicemessages.timeline.aRedactedMatrixTimeline +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.features.poll.test.actions.FakeEndPollAction +import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction @@ -48,13 +48,11 @@ import io.element.android.libraries.matrix.test.room.anEventTimelineItem import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.awaitWithLatch import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers -import io.element.android.tests.testutils.waitForPredicate import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.test.TestScope @@ -295,12 +293,10 @@ class TimelinePresenterTest { } @Test - fun `present - PollAnswerSelected event calls into rust room api and analytics`() = runTest { - val room = FakeMatrixRoom() - val analyticsService = FakeAnalyticsService() + fun `present - PollAnswerSelected event`() = runTest { + val sendPollResponseAction = FakeSendPollResponseAction() val presenter = createTimelinePresenter( - room = room, - analyticsService = analyticsService, + sendPollResponseAction = sendPollResponseAction, ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -309,34 +305,23 @@ class TimelinePresenterTest { initialState.eventSink.invoke(TimelineEvents.PollAnswerSelected(AN_EVENT_ID, "anAnswerId")) } delay(1) - assertThat(room.sendPollResponseInvocations.size).isEqualTo(1) - assertThat(room.sendPollResponseInvocations.first().answers).isEqualTo(listOf("anAnswerId")) - assertThat(room.sendPollResponseInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID) - assertThat(analyticsService.capturedEvents.size).isEqualTo(1) - assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollVote()) + sendPollResponseAction.verifyExecutionCount(1) } @Test - fun `present - PollEndClicked event calls into rust room api and analytics`() = runTest { - val room = FakeMatrixRoom() - val analyticsService = FakeAnalyticsService() + fun `present - PollEndClicked event`() = runTest { + val endPollAction = FakeEndPollAction() val presenter = createTimelinePresenter( - room = room, - analyticsService = analyticsService, + endPollAction = endPollAction, ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() - initialState.eventSink(TimelineEvents.PollEndClicked(aMessageEvent().eventId!!)) - waitForPredicate { room.endPollInvocations.size == 1 } - cancelAndIgnoreRemainingEvents() - assertThat(room.endPollInvocations.size).isEqualTo(1) - assertThat(room.endPollInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID) - assertThat(room.endPollInvocations.first().text).isEqualTo("The poll with event id: \$anEventId has ended.") - assertThat(analyticsService.capturedEvents.size).isEqualTo(1) - assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollEnd()) + initialState.eventSink.invoke(TimelineEvents.PollEndClicked(AN_EVENT_ID)) } + delay(1) + endPollAction.verifyExecutionCount(1) } @Test @@ -379,36 +364,21 @@ class TimelinePresenterTest { timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory(), redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(), - ): TimelinePresenter { + endPollAction: EndPollAction = FakeEndPollAction(), + sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(), + ): TimelinePresenter { return TimelinePresenter( timelineItemsFactory = timelineItemsFactory, room = FakeMatrixRoom(matrixTimeline = timeline), dispatchers = testCoroutineDispatchers(), appScope = this, navigator = messagesNavigator, - analyticsService = FakeAnalyticsService(), encryptionService = FakeEncryptionService(), verificationService = FakeSessionVerificationService(), featureFlagService = FakeFeatureFlagService(), redactedVoiceMessageManager = redactedVoiceMessageManager, - ) - } - - private fun TestScope.createTimelinePresenter( - room: MatrixRoom, - analyticsService: FakeAnalyticsService = FakeAnalyticsService(), - ): TimelinePresenter { - return TimelinePresenter( - timelineItemsFactory = aTimelineItemsFactory(), - room = room, - dispatchers = testCoroutineDispatchers(), - appScope = this, - navigator = FakeMessagesNavigator(), - analyticsService = analyticsService, - encryptionService = FakeEncryptionService(), - verificationService = FakeSessionVerificationService(), - featureFlagService = FakeFeatureFlagService(), - redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), + endPollAction = endPollAction, + sendPollResponseAction = sendPollResponseAction, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt deleted file mode 100644 index 144c70f55d..0000000000 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentPollFactoryTest.kt +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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.factories.event - -import com.google.common.truth.Truth -import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent -import io.element.android.features.poll.api.pollcontent.PollAnswerItem -import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.poll.PollAnswer -import io.element.android.libraries.matrix.api.poll.PollKind -import io.element.android.libraries.matrix.api.timeline.item.event.PollContent -import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.A_USER_ID_10 -import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.A_USER_ID_3 -import io.element.android.libraries.matrix.test.A_USER_ID_4 -import io.element.android.libraries.matrix.test.A_USER_ID_5 -import io.element.android.libraries.matrix.test.A_USER_ID_6 -import io.element.android.libraries.matrix.test.A_USER_ID_7 -import io.element.android.libraries.matrix.test.A_USER_ID_8 -import io.element.android.libraries.matrix.test.A_USER_ID_9 -import io.element.android.libraries.matrix.test.FakeMatrixClient -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.ImmutableMap -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentMapOf -import kotlinx.collections.immutable.toImmutableMap -import kotlinx.coroutines.test.runTest -import org.junit.Test - -internal class TimelineItemContentPollFactoryTest { - - private val factory = TimelineItemContentPollFactory( - matrixClient = FakeMatrixClient(), - featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.Polls.key to true)), - ) - - @Test - fun `Disclosed poll - not ended, no votes`() = runTest { - Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn)).isEqualTo(aTimelineItemPollContent()) - } - - @Test - fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create(aPollContent(votes = votes), eventId = null, eventTimelineItem.isOwn) - ) - .isEqualTo( - aTimelineItemPollContent( - answerItems = listOf( - aPollAnswerItem(answer = A_POLL_ANSWER_1, votesCount = 3, percentage = 0.3f), - aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, votesCount = 6, percentage = 0.6f), - aPollAnswerItem(answer = A_POLL_ANSWER_3), - aPollAnswerItem(answer = A_POLL_ANSWER_4, votesCount = 1, percentage = 0.1f), - ), - ) - ) - } - - @Test - fun `Disclosed poll - ended, no votes, no winner`() = runTest { - Truth.assertThat( - factory.create(aPollContent(endTime = 1UL), eventId = null, eventTimelineItem.isOwn) - ).isEqualTo( - aTimelineItemPollContent().let { - it.copy( - answerItems = it.answerItems.map { answerItem -> answerItem.copy(isEnabled = false) }, - isEnded = true, - ) - } - ) - } - - @Test - fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create( - aPollContent(votes = votes, endTime = 1UL), - eventId = null, - eventTimelineItem.isOwn - ) - ) - .isEqualTo( - aTimelineItemPollContent( - answerItems = listOf( - aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f), - aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f), - aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), - aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f), - ), - isEnded = true, - ) - ) - } - - @Test - fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { - val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create( - aPollContent(votes = votes, endTime = 1UL), - eventId = null, - eventTimelineItem.isOwn - ) - ) - .isEqualTo( - aTimelineItemPollContent( - answerItems = listOf( - aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), - aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f), - aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), - aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), - ), - isEnded = true, - ) - ) - } - - @Test - fun `Undisclosed poll - not ended, no votes`() = runTest { - Truth.assertThat( - factory.create( - aPollContent(PollKind.Undisclosed).copy(), - eventId = null, - eventTimelineItem.isOwn - ) - ).isEqualTo( - aTimelineItemPollContent(pollKind = PollKind.Undisclosed).let { - it.copy(answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = false) }) - } - ) - } - - @Test - fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create( - aPollContent(pollKind = PollKind.Undisclosed, votes = votes), - eventId = null, - eventTimelineItem.isOwn - ) - ) - .isEqualTo( - aTimelineItemPollContent( - pollKind = PollKind.Undisclosed, - answerItems = listOf( - aPollAnswerItem(answer = A_POLL_ANSWER_1, isDisclosed = false, votesCount = 3, percentage = 0.3f), - aPollAnswerItem(answer = A_POLL_ANSWER_2, isDisclosed = false, isSelected = true, votesCount = 6, percentage = 0.6f), - aPollAnswerItem(answer = A_POLL_ANSWER_3, isDisclosed = false), - aPollAnswerItem(answer = A_POLL_ANSWER_4, isDisclosed = false, votesCount = 1, percentage = 0.1f), - ), - ) - ) - } - - @Test - fun `Undisclosed poll - ended, no votes, no winner`() = runTest { - Truth.assertThat( - factory.create( - aPollContent(pollKind = PollKind.Undisclosed, endTime = 1UL), - eventId = null, - eventTimelineItem.isOwn - ) - ).isEqualTo( - aTimelineItemPollContent().let { - it.copy( - pollKind = PollKind.Undisclosed, - answerItems = it.answerItems.map { answerItem -> - answerItem.copy(isDisclosed = true, isEnabled = false, isWinner = false) - }, - isEnded = true, - ) - } - ) - } - - @Test - fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest { - val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create( - aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), - eventId = null, - eventTimelineItem.isOwn - ) - ) - .isEqualTo( - aTimelineItemPollContent( - pollKind = PollKind.Undisclosed, - answerItems = listOf( - aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f), - aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f), - aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), - aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f), - ), - isEnded = true, - ) - ) - } - - @Test - fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { - val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() - Truth.assertThat( - factory.create( - aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), - eventId = null, - eventTimelineItem.isOwn - ) - ) - .isEqualTo( - aTimelineItemPollContent( - pollKind = PollKind.Undisclosed, - answerItems = listOf( - aPollAnswerItem(A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), - aPollAnswerItem(A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f), - aPollAnswerItem(A_POLL_ANSWER_3, isEnabled = false), - aPollAnswerItem(A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), - ), - isEnded = true, - ) - ) - } - - @Test - fun `eventId is populated`() = runTest { - Truth.assertThat(factory.create(aPollContent(), eventId = null, eventTimelineItem.isOwn)) - .isEqualTo(aTimelineItemPollContent(eventId = null)) - - Truth.assertThat(factory.create( - aPollContent(), - eventId = AN_EVENT_ID, - eventTimelineItem.isOwn - )) - .isEqualTo(aTimelineItemPollContent(eventId = AN_EVENT_ID)) - } - - private fun aPollContent( - pollKind: PollKind = PollKind.Disclosed, - votes: ImmutableMap> = persistentMapOf(), - endTime: ULong? = null, - ): PollContent = PollContent( - question = A_POLL_QUESTION, - kind = pollKind, - maxSelections = 1UL, - answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4), - votes = votes, - endTime = endTime, - ) - - private fun aTimelineItemPollContent( - eventId: EventId? = null, - pollKind: PollKind = PollKind.Disclosed, - answerItems: List = listOf( - aPollAnswerItem(A_POLL_ANSWER_1), - aPollAnswerItem(A_POLL_ANSWER_2), - aPollAnswerItem(A_POLL_ANSWER_3), - aPollAnswerItem(A_POLL_ANSWER_4), - ), - isEnded: Boolean = false, - ) = TimelineItemPollContent( - eventId = eventId, - question = A_POLL_QUESTION, - answerItems = answerItems, - pollKind = pollKind, - isEnded = isEnded, - ) - - private fun aPollAnswerItem( - answer: PollAnswer, - isSelected: Boolean = false, - isEnabled: Boolean = true, - isWinner: Boolean = false, - isDisclosed: Boolean = true, - votesCount: Int = 0, - percentage: Float = 0f, - ) = PollAnswerItem( - answer = answer, - isSelected = isSelected, - isEnabled = isEnabled, - isWinner = isWinner, - isDisclosed = isDisclosed, - votesCount = votesCount, - percentage = percentage, - ) - - private companion object TestData { - private const val A_POLL_QUESTION = "What is your favorite food?" - private val A_POLL_ANSWER_1 = PollAnswer("id_1", "Pizza") - private val A_POLL_ANSWER_2 = PollAnswer("id_2", "Pasta") - private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries") - private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger") - - private val MY_USER_WINNING_VOTES = persistentMapOf( - A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4), - A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner - A_POLL_ANSWER_3 to persistentListOf(), - A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10), - ) - private val OTHER_WINNING_VOTES = persistentMapOf( - A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner - A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6), - A_POLL_ANSWER_3 to persistentListOf(), - A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner - ) - } -} diff --git a/features/poll/impl/build.gradle.kts b/features/poll/impl/build.gradle.kts index db91377660..bfa74d3684 100644 --- a/features/poll/impl/build.gradle.kts +++ b/features/poll/impl/build.gradle.kts @@ -52,6 +52,8 @@ dependencies { testImplementation(projects.services.analytics.test) testImplementation(projects.features.messages.test) testImplementation(projects.tests.testutils) + testImplementation(projects.libraries.dateformatter.test) + testImplementation(projects.features.poll.test) ksp(libs.showkase.processor) } diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/PollFixtures.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/PollFixtures.kt new file mode 100644 index 0000000000..bfe925a993 --- /dev/null +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/PollFixtures.kt @@ -0,0 +1,55 @@ +/* + * 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.poll.impl + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.poll.PollAnswer +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline +import io.element.android.libraries.matrix.test.timeline.aPollContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import kotlinx.collections.immutable.persistentListOf + +fun aPollTimeline( + polls: Map = emptyMap(), +): FakeMatrixTimeline { + return FakeMatrixTimeline( + initialTimelineItems = polls.map { entry -> + MatrixTimelineItem.Event( + entry.key.hashCode().toLong(), + anEventTimelineItem( + eventId = entry.key, + content = entry.value, + ) + ) + } + ) +} + +fun anOngoingPollContent() = aPollContent( + question = "Do you like polls?", + answers = persistentListOf( + PollAnswer("1", "Yes"), + PollAnswer("2", "No"), + PollAnswer("2", "Maybe"), + ), +) + +fun anEndedPollContent() = anOngoingPollContent().copy( + endTime = 1702400215U +) diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt index 8cb55704d5..114e7cb48f 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt @@ -25,21 +25,17 @@ import im.vector.app.features.analytics.plan.Composer import im.vector.app.features.analytics.plan.PollCreation import io.element.android.features.messages.test.FakeMessageComposerContext import io.element.android.features.poll.api.create.CreatePollMode +import io.element.android.features.poll.impl.aPollTimeline +import io.element.android.features.poll.impl.anOngoingPollContent import io.element.android.features.poll.impl.data.PollRepository -import io.element.android.libraries.matrix.api.poll.PollAnswer import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.SavePollInvocation import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.matrix.test.room.aPollContent -import io.element.android.libraries.matrix.test.room.anEventTimelineItem -import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline +import io.element.android.libraries.matrix.test.room.SavePollInvocation import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule -import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -52,8 +48,12 @@ class CreatePollPresenterTest { private val pollEventId = AN_EVENT_ID private var navUpInvocationsCount = 0 - private val existingPoll = anExistingPoll() - private val fakeMatrixRoom = createFakeMatrixRoom(existingPoll) + private val existingPoll = anOngoingPollContent() + private val fakeMatrixRoom = FakeMatrixRoom( + matrixTimeline = aPollTimeline( + mapOf(pollEventId to existingPoll) + ) + ) private val fakeAnalyticsService = FakeAnalyticsService() private val fakeMessageComposerContext = FakeMessageComposerContext() @@ -80,7 +80,9 @@ class CreatePollPresenterTest { @Test fun `in edit mode, if poll doesn't exist, error is tracked and screen is closed`() = runTest { - val room = createFakeMatrixRoom(existingPoll = null) + val room = FakeMatrixRoom( + matrixTimeline = aPollTimeline() + ) val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(AN_EVENT_ID), room = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -475,7 +477,6 @@ class CreatePollPresenterTest { } } - private suspend fun TurbineTestContext.awaitDefaultItem() = awaitItem().apply { Truth.assertThat(canSave).isFalse() @@ -518,35 +519,8 @@ class CreatePollPresenterTest { navigateUp = { navUpInvocationsCount++ }, mode = mode, ) - - private fun createFakeMatrixRoom( - existingPoll: PollContent? = anExistingPoll(), - ) = FakeMatrixRoom( - matrixTimeline = FakeMatrixTimeline( - initialTimelineItems = existingPoll?.let { - listOf( - MatrixTimelineItem.Event( - 0, - anEventTimelineItem( - eventId = pollEventId, - content = it, - ) - ) - ) - }.orEmpty() - ) - ) } -private fun anExistingPoll() = aPollContent( - question = "Do you like polls?", - answers = persistentListOf( - PollAnswer("1", "Yes"), - PollAnswer("2", "No"), - PollAnswer("2", "Maybe"), - ), -) - private fun PollContent.expectedAnswersState() = answers.map { answer -> Answer( text = answer.text, diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt new file mode 100644 index 0000000000..172ec5fa28 --- /dev/null +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt @@ -0,0 +1,169 @@ +/* + * 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.poll.impl.history + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.features.poll.impl.aPollTimeline +import io.element.android.features.poll.impl.anEndedPollContent +import io.element.android.features.poll.impl.anOngoingPollContent +import io.element.android.features.poll.impl.history.model.PollHistoryFilter +import io.element.android.features.poll.impl.history.model.PollHistoryItemsFactory +import io.element.android.features.poll.impl.model.DefaultPollContentStateFactory +import io.element.android.features.poll.test.actions.FakeEndPollAction +import io.element.android.features.poll.test.actions.FakeSendPollResponseAction +import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter +import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.consumeItemsUntilPredicate +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Rule +import org.junit.Test + +class PollHistoryPresenterTest { + + @get:Rule + val warmUpRule = WarmUpRule() + + private val room = FakeMatrixRoom( + matrixTimeline = aPollTimeline( + polls = mapOf( + AN_EVENT_ID to anOngoingPollContent(), + AN_EVENT_ID_2 to anEndedPollContent() + ) + ) + ) + + @Test + fun `present - initial states`() = runTest { + val presenter = createPollHistoryPresenter(room = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().also { state -> + assertThat(state.activeFilter).isEqualTo(PollHistoryFilter.ONGOING) + assertThat(state.pollHistoryItems.size).isEqualTo(0) + assertThat(state.isLoading).isTrue() + assertThat(state.hasMoreToLoad).isTrue() + } + consumeItemsUntilPredicate { + it.pollHistoryItems.size == 2 + }.last().also { state -> + assertThat(state.pollHistoryItems.size).isEqualTo(2) + assertThat(state.pollHistoryItems.ongoing).hasSize(1) + assertThat(state.pollHistoryItems.past).hasSize(1) + } + } + } + + @Test + fun `present - change filter scenario`() = runTest { + val presenter = createPollHistoryPresenter(room = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().also { state -> + assertThat(state.activeFilter).isEqualTo(PollHistoryFilter.ONGOING) + state.eventSink(PollHistoryEvents.OnFilterSelected(PollHistoryFilter.PAST)) + } + consumeItemsUntilPredicate { + it.activeFilter == PollHistoryFilter.PAST + }.last().also { state -> + state.eventSink(PollHistoryEvents.OnFilterSelected(PollHistoryFilter.ONGOING)) + } + consumeItemsUntilPredicate { + it.activeFilter == PollHistoryFilter.ONGOING + } + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `present - poll actions scenario`() = runTest { + val sendPollResponseAction = FakeSendPollResponseAction() + val endPollAction = FakeEndPollAction() + val presenter = createPollHistoryPresenter( + sendPollResponseAction = sendPollResponseAction, + endPollAction = endPollAction + ) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val state = awaitItem() + state.eventSink(PollHistoryEvents.PollEndClicked(AN_EVENT_ID)) + runCurrent() + endPollAction.verifyExecutionCount(1) + state.eventSink(PollHistoryEvents.PollAnswerSelected(AN_EVENT_ID, "answer")) + runCurrent() + sendPollResponseAction.verifyExecutionCount(1) + cancelAndConsumeRemainingEvents() + } + } + + @Test + fun `present - load more scenario`() = runTest { + val presenter = createPollHistoryPresenter(room = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + consumeItemsUntilPredicate { + it.pollHistoryItems.size == 2 && !it.isLoading + }.last().also { state -> + state.eventSink(PollHistoryEvents.LoadMore) + } + consumeItemsUntilPredicate { + it.isLoading + } + consumeItemsUntilPredicate { + !it.isLoading + } + } + } + + private fun TestScope.createPollHistoryPresenter( + room: MatrixRoom = FakeMatrixRoom(), + appCoroutineScope: CoroutineScope = this, + endPollAction: EndPollAction = FakeEndPollAction(), + sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(), + pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory( + pollContentStateFactory = DefaultPollContentStateFactory(FakeMatrixClient()), + daySeparatorFormatter = FakeDaySeparatorFormatter(), + dispatchers = testCoroutineDispatchers(), + ), + ): PollHistoryPresenter { + return PollHistoryPresenter( + room = room, + appCoroutineScope = appCoroutineScope, + sendPollResponseAction = sendPollResponseAction, + endPollAction = endPollAction, + pollHistoryItemFactory = pollHistoryItemFactory, + ) + } +} diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/pollcontent/PollContentStateFactoryTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/pollcontent/PollContentStateFactoryTest.kt new file mode 100644 index 0000000000..1c2bf88fbf --- /dev/null +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/pollcontent/PollContentStateFactoryTest.kt @@ -0,0 +1,288 @@ +/* + * 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.poll.impl.pollcontent + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.poll.api.pollcontent.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollContentState +import io.element.android.features.poll.impl.model.DefaultPollContentStateFactory +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.poll.PollAnswer +import io.element.android.libraries.matrix.api.poll.PollKind +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_ID_10 +import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.A_USER_ID_3 +import io.element.android.libraries.matrix.test.A_USER_ID_4 +import io.element.android.libraries.matrix.test.A_USER_ID_5 +import io.element.android.libraries.matrix.test.A_USER_ID_6 +import io.element.android.libraries.matrix.test.A_USER_ID_7 +import io.element.android.libraries.matrix.test.A_USER_ID_8 +import io.element.android.libraries.matrix.test.A_USER_ID_9 +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.collections.immutable.toImmutableMap +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class PollContentStateFactoryTest { + + private val factory = DefaultPollContentStateFactory(FakeMatrixClient()) + private val eventTimelineItem = anEventTimelineItem() + + @Test + fun `Disclosed poll - not ended, no votes`() = runTest { + val state = factory.create(eventTimelineItem, aPollContent()) + val expectedState = aPollContentState() + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest { + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(votes = votes) + ) + val expectedState = aPollContentState( + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, votesCount = 3, percentage = 0.3f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, votesCount = 6, percentage = 0.6f), + aPollAnswerItem(answer = A_POLL_ANSWER_3), + aPollAnswerItem(answer = A_POLL_ANSWER_4, votesCount = 1, percentage = 0.1f), + ) + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Disclosed poll - ended, no votes, no winner`() = runTest { + val state = factory.create(eventTimelineItem, aPollContent(endTime = 1UL)) + val expectedState = aPollContentState().let { + it.copy( + answerItems = it.answerItems.map { answerItem -> answerItem.copy(isEnabled = false) }.toImmutableList(), + isPollEnded = true, + ) + } + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest { + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(votes = votes, endTime = 1UL) + ) + val expectedState = aPollContentState( + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f), + aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), + aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f), + ), + isEnded = true, + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { + val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(votes = votes, endTime = 1UL) + ) + val expectedState = aPollContentState( + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f), + aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), + aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), + ), + isEnded = true, + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Undisclosed poll - not ended, no votes`() = runTest { + val state = factory.create(eventTimelineItem, aPollContent(PollKind.Undisclosed)) + val expectedState = aPollContentState(pollKind = PollKind.Undisclosed).let { + it.copy( + answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = false) }.toImmutableList() + ) + } + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest { + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes) + ) + val expectedState = aPollContentState( + pollKind = PollKind.Undisclosed, + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, isDisclosed = false, votesCount = 3, percentage = 0.3f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isDisclosed = false, isSelected = true, votesCount = 6, percentage = 0.6f), + aPollAnswerItem(answer = A_POLL_ANSWER_3, isDisclosed = false), + aPollAnswerItem(answer = A_POLL_ANSWER_4, isDisclosed = false, votesCount = 1, percentage = 0.1f), + ), + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Undisclosed poll - ended, no votes, no winner`() = runTest { + val state = factory.create(eventTimelineItem, aPollContent(PollKind.Undisclosed, endTime = 1UL)) + val expectedState = aPollContentState( + isEnded = true, + pollKind = PollKind.Undisclosed + ).let { + it.copy( + answerItems = it.answerItems.map { answerItem -> answerItem.copy(isDisclosed = true, isEnabled = false) }.toImmutableList(), + ) + } + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest { + val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes, endTime = 1UL) + ) + val expectedState = aPollContentState( + pollKind = PollKind.Undisclosed, + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, votesCount = 3, percentage = 0.3f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, isWinner = true, votesCount = 6, percentage = 0.6f), + aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), + aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, votesCount = 1, percentage = 0.1f), + ), + isEnded = true, + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest { + val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap() + val state = factory.create( + eventTimelineItem, aPollContent(PollKind.Undisclosed, votes = votes, endTime = 1UL) + ) + val expectedState = aPollContentState( + pollKind = PollKind.Undisclosed, + answerItems = listOf( + aPollAnswerItem(answer = A_POLL_ANSWER_1, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), + aPollAnswerItem(answer = A_POLL_ANSWER_2, isSelected = true, isEnabled = false, votesCount = 2, percentage = 0.2f), + aPollAnswerItem(answer = A_POLL_ANSWER_3, isEnabled = false), + aPollAnswerItem(answer = A_POLL_ANSWER_4, isEnabled = false, isWinner = true, votesCount = 4, percentage = 0.4f), + ), + isEnded = true, + ) + assertThat(state).isEqualTo(expectedState) + } + + @Test + fun `eventId is populated`() = runTest { + val state = factory.create(eventTimelineItem, aPollContent()) + assertThat(state.eventId).isEqualTo(eventTimelineItem.eventId) + } + + private fun aPollContent( + pollKind: PollKind = PollKind.Disclosed, + votes: ImmutableMap> = persistentMapOf(), + endTime: ULong? = null, + ): PollContent = PollContent( + question = A_POLL_QUESTION, + kind = pollKind, + maxSelections = 1UL, + answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4), + votes = votes, + endTime = endTime, + ) + + private fun aPollContentState( + eventId: EventId? = AN_EVENT_ID, + pollKind: PollKind = PollKind.Disclosed, + answerItems: List = listOf( + aPollAnswerItem(A_POLL_ANSWER_1), + aPollAnswerItem(A_POLL_ANSWER_2), + aPollAnswerItem(A_POLL_ANSWER_3), + aPollAnswerItem(A_POLL_ANSWER_4), + ), + isEnded: Boolean = false, + isMine: Boolean = false, + isEditable: Boolean = false, + question: String = A_POLL_QUESTION, + ) = PollContentState( + eventId = eventId, + question = question, + answerItems = answerItems.toImmutableList(), + pollKind = pollKind, + isMine = isMine, + isPollEnded = isEnded, + isPollEditable = isEditable, + ) + + private fun aPollAnswerItem( + answer: PollAnswer, + isSelected: Boolean = false, + isEnabled: Boolean = true, + isWinner: Boolean = false, + isDisclosed: Boolean = true, + votesCount: Int = 0, + percentage: Float = 0f, + ) = PollAnswerItem( + answer = answer, + isSelected = isSelected, + isEnabled = isEnabled, + isWinner = isWinner, + isDisclosed = isDisclosed, + votesCount = votesCount, + percentage = percentage, + ) + + private companion object TestData { + private const val A_POLL_QUESTION = "What is your favorite food?" + private val A_POLL_ANSWER_1 = PollAnswer("id_1", "Pizza") + private val A_POLL_ANSWER_2 = PollAnswer("id_2", "Pasta") + private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries") + private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger") + + private val MY_USER_WINNING_VOTES = persistentMapOf( + A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4), + A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner + A_POLL_ANSWER_3 to persistentListOf(), + A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10), + ) + private val OTHER_WINNING_VOTES = persistentMapOf( + A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner + A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6), + A_POLL_ANSWER_3 to persistentListOf(), + A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner + ) + } +} diff --git a/features/poll/test/build.gradle.kts b/features/poll/test/build.gradle.kts new file mode 100644 index 0000000000..2bae89d155 --- /dev/null +++ b/features/poll/test/build.gradle.kts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.poll.test" +} + +dependencies { + implementation(projects.libraries.matrix.api) + api(projects.features.poll.api) + implementation(libs.kotlinx.collections.immutable) +} diff --git a/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeEndPollAction.kt b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeEndPollAction.kt new file mode 100644 index 0000000000..285db277e4 --- /dev/null +++ b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeEndPollAction.kt @@ -0,0 +1,34 @@ +/* + * 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.poll.test.actions + +import io.element.android.features.poll.api.actions.EndPollAction +import io.element.android.libraries.matrix.api.core.EventId + +class FakeEndPollAction : EndPollAction { + + private var executionCount = 0 + + fun verifyExecutionCount(count: Int) { + assert(executionCount == count) + } + + override suspend fun execute(pollStartId: EventId): Result { + executionCount++ + return Result.success(Unit) + } +} diff --git a/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeSendPollResponseAction.kt b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeSendPollResponseAction.kt new file mode 100644 index 0000000000..f8fa3316d9 --- /dev/null +++ b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/actions/FakeSendPollResponseAction.kt @@ -0,0 +1,34 @@ +/* + * 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.poll.test.actions + +import io.element.android.features.poll.api.actions.SendPollResponseAction +import io.element.android.libraries.matrix.api.core.EventId + +class FakeSendPollResponseAction : SendPollResponseAction { + + private var executionCount = 0 + + fun verifyExecutionCount(count: Int) { + assert(executionCount == count) + } + + override suspend fun execute(pollStartId: EventId, answerId: String): Result { + executionCount++ + return Result.success(Unit) + } +} diff --git a/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt new file mode 100644 index 0000000000..626843f370 --- /dev/null +++ b/features/poll/test/src/main/kotlin/io/element/android/features/poll/test/pollcontent/FakePollContentStateFactory.kt @@ -0,0 +1,39 @@ +/* + * 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.poll.test.pollcontent + +import io.element.android.features.poll.api.pollcontent.PollAnswerItem +import io.element.android.features.poll.api.pollcontent.PollContentState +import io.element.android.features.poll.api.pollcontent.PollContentStateFactory +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import kotlinx.collections.immutable.toImmutableList + +class FakePollContentStateFactory : PollContentStateFactory { + + override suspend fun create(event: EventTimelineItem, content: PollContent): PollContentState { + return PollContentState( + eventId = event.eventId, + isMine = event.isOwn, + question = content.question, + answerItems = emptyList().toImmutableList(), + pollKind = content.kind, + isPollEditable = event.isEditable, + isPollEnded = content.endTime != null, + ) + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index f16fdfbe98..db263fee94 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -431,7 +431,8 @@ class FakeMatrixRoom( ): Result = generateWidgetWebViewUrlResult override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result = getWidgetDriverResult - override suspend fun pollHistory(): MatrixTimeline { + + override fun pollHistory(): MatrixTimeline { return FakeMatrixTimeline() } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 2ff8ef1745..79d3acb58b 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -18,35 +18,17 @@ package io.element.android.libraries.matrix.test.room import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.poll.PollAnswer -import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.message.RoomMessage import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails -import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo -import io.element.android.libraries.matrix.api.timeline.item.event.EventContent -import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem -import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo -import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState -import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent -import io.element.android.libraries.matrix.api.timeline.item.event.MessageType -import io.element.android.libraries.matrix.api.timeline.item.event.PollContent -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent -import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails -import io.element.android.libraries.matrix.api.timeline.item.event.Receipt -import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.A_USER_NAME -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentMapOf +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem fun aRoomSummaryFilled( roomId: RoomId = A_ROOM_ID, @@ -101,95 +83,3 @@ fun aRoomMessage( sender = userId, originServerTs = timestamp, ) - -fun anEventTimelineItem( - eventId: EventId = AN_EVENT_ID, - transactionId: TransactionId? = null, - isEditable: Boolean = false, - isLocal: Boolean = false, - isOwn: Boolean = false, - isRemote: Boolean = false, - localSendState: LocalEventSendState? = null, - reactions: ImmutableList = persistentListOf(), - receipts: ImmutableList = persistentListOf(), - sender: UserId = A_USER_ID, - senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), - timestamp: Long = 0L, - content: EventContent = aProfileChangeMessageContent(), - debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), -) = EventTimelineItem( - eventId = eventId, - transactionId = transactionId, - isEditable = isEditable, - isLocal = isLocal, - isOwn = isOwn, - isRemote = isRemote, - localSendState = localSendState, - reactions = reactions, - receipts = receipts, - sender = sender, - senderProfile = senderProfile, - timestamp = timestamp, - content = content, - debugInfo = debugInfo, - origin = null, -) - -fun aProfileTimelineDetails( - displayName: String? = A_USER_NAME, - displayNameAmbiguous: Boolean = false, - avatarUrl: String? = null -): ProfileTimelineDetails = ProfileTimelineDetails.Ready( - displayName = displayName, - displayNameAmbiguous = displayNameAmbiguous, - avatarUrl = avatarUrl, -) - -fun aProfileChangeMessageContent( - displayName: String? = null, - prevDisplayName: String? = null, - avatarUrl: String? = null, - prevAvatarUrl: String? = null, -) = ProfileChangeContent( - displayName = displayName, - prevDisplayName = prevDisplayName, - avatarUrl = avatarUrl, - prevAvatarUrl = prevAvatarUrl, -) - -fun aMessageContent( - body: String = "body", - inReplyTo: InReplyTo? = null, - isEdited: Boolean = false, - isThreaded: Boolean = false, - messageType: MessageType = TextMessageType( - body = body, - formatted = null - ) -) = MessageContent( - body = body, - inReplyTo = inReplyTo, - isEdited = isEdited, - isThreaded = isThreaded, - type = messageType -) - -fun aTimelineItemDebugInfo( - model: String = "Rust(Model())", - originalJson: String? = null, - latestEditedJson: String? = null, -) = TimelineItemDebugInfo( - model, originalJson, latestEditedJson -) - -fun aPollContent( - question: String = "Do you like polls?", - answers: ImmutableList = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")), -) = PollContent( - question = question, - kind = PollKind.Disclosed, - maxSelections = 1u, - answers = answers, - votes = persistentMapOf(), - endTime = null -) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt new file mode 100644 index 0000000000..606aade962 --- /dev/null +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt @@ -0,0 +1,139 @@ +/* + * 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.test.timeline + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.TransactionId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.poll.PollAnswer +import io.element.android.libraries.matrix.api.poll.PollKind +import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo +import io.element.android.libraries.matrix.api.timeline.item.event.EventContent +import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction +import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo +import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState +import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.MessageType +import io.element.android.libraries.matrix.api.timeline.item.event.PollContent +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent +import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails +import io.element.android.libraries.matrix.api.timeline.item.event.Receipt +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_NAME +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentMapOf + +fun anEventTimelineItem( + eventId: EventId = AN_EVENT_ID, + transactionId: TransactionId? = null, + isEditable: Boolean = false, + isLocal: Boolean = false, + isOwn: Boolean = false, + isRemote: Boolean = false, + localSendState: LocalEventSendState? = null, + reactions: ImmutableList = persistentListOf(), + receipts: ImmutableList = persistentListOf(), + sender: UserId = A_USER_ID, + senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(), + timestamp: Long = 0L, + content: EventContent = aProfileChangeMessageContent(), + debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), +) = EventTimelineItem( + eventId = eventId, + transactionId = transactionId, + isEditable = isEditable, + isLocal = isLocal, + isOwn = isOwn, + isRemote = isRemote, + localSendState = localSendState, + reactions = reactions, + receipts = receipts, + sender = sender, + senderProfile = senderProfile, + timestamp = timestamp, + content = content, + debugInfo = debugInfo, + origin = null, +) + +fun aProfileTimelineDetails( + displayName: String? = A_USER_NAME, + displayNameAmbiguous: Boolean = false, + avatarUrl: String? = null +): ProfileTimelineDetails = ProfileTimelineDetails.Ready( + displayName = displayName, + displayNameAmbiguous = displayNameAmbiguous, + avatarUrl = avatarUrl, +) + +fun aProfileChangeMessageContent( + displayName: String? = null, + prevDisplayName: String? = null, + avatarUrl: String? = null, + prevAvatarUrl: String? = null, +) = ProfileChangeContent( + displayName = displayName, + prevDisplayName = prevDisplayName, + avatarUrl = avatarUrl, + prevAvatarUrl = prevAvatarUrl, +) + +fun aMessageContent( + body: String = "body", + inReplyTo: InReplyTo? = null, + isEdited: Boolean = false, + isThreaded: Boolean = false, + messageType: MessageType = TextMessageType( + body = body, + formatted = null + ) +) = MessageContent( + body = body, + inReplyTo = inReplyTo, + isEdited = isEdited, + isThreaded = isThreaded, + type = messageType +) + +fun aTimelineItemDebugInfo( + model: String = "Rust(Model())", + originalJson: String? = null, + latestEditedJson: String? = null, +) = TimelineItemDebugInfo( + model, originalJson, latestEditedJson +) + +fun aPollContent( + question: String = "Do you like polls?", + answers: ImmutableList = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")), + kind: PollKind = PollKind.Disclosed, + maxSelections: ULong = 1u, + votes: ImmutableMap> = persistentMapOf(), + endTime: ULong? = null, +) = PollContent( + question = question, + kind = kind, + maxSelections = maxSelections, + answers = answers, + votes = votes, + endTime = endTime, +) From 6aac8f33e34f405c0ed2ec6519af4963fe3c4652 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 13 Dec 2023 16:34:07 +0000 Subject: [PATCH 14/24] Update screenshots --- ...neItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...neItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...eItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png} | 0 ...eItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png} | 0 ...ItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...ItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...temPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png} | 0 ...temPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png} | 0 ..._TimelineItemPollView-Day-38_38_null_2,NEXUS_5,1.0,en].png | 3 +++ ..._TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png | 3 +++ ...imelineItemPollView-Night-38_39_null_2,NEXUS_5,1.0,en].png | 3 +++ ...imelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png | 3 +++ ...swerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png} | 0 ...erDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png} | 0 ...lAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png} | 0 ...nswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png} | 0 ..._PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png} | 0 ...ollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png} | 0 ...erEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png} | 0 ...EndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png} | 0 ...nswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png} | 0 ...werEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png} | 0 ...erUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png} | 0 ...UndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png} | 0 ...nswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png} | 0 ...werUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png} | 0 ...ContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png} | 0 ...ntentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png} | 0 ...ollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png} | 0 ...lContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png} | 0 ...null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png | 3 +++ ...ll_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png | 3 +++ ...null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png | 3 +++ ...l_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png | 3 +++ ...d_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png} | 0 ...null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png} | 0 ...l_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png} | 0 ...PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png} | 0 ...ew_null_PollHistoryView-Day-1_1_null_0,NEXUS_5,1.0,en].png | 3 +++ ...ew_null_PollHistoryView-Day-1_1_null_1,NEXUS_5,1.0,en].png | 3 +++ ..._null_PollHistoryView-Night-1_2_null_0,NEXUS_5,1.0,en].png | 3 +++ ..._null_PollHistoryView-Night-1_2_null_1,NEXUS_5,1.0,en].png | 3 +++ ...sDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...sDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...sDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...sDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...sDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en].png | 4 ++-- ...omDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en].png | 4 ++-- ...omDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...omDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en].png | 4 ++-- ...omDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en].png | 4 ++-- ...omDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en].png | 4 ++-- 52 files changed, 64 insertions(+), 28 deletions(-) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png} (100%) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_2,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png} (100%) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png => ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png} (100%) create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_1,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_0,NEXUS_5,1.0,en].png create mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png index efff51686d..338b81a12b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8209a79e5d20ef58a2e947617b308386d4868799c87039d40fe7c89a68925f2b -size 51842 +oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 +size 49025 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png index a92aa23d0e..9a087a954c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea0b049a734767b1d68f75f808e398357772f37e80a8ad866280c74fc4671251 -size 54035 +oid sha256:0435109c519a31d671bd5cf85425574a10909733e21dcc46ae17e2a53d748b11 +size 50938 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png index 33f25a7736..378fa05efd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2f174ed9f51808a295fd8b748faa0709fb3ef45ebe9cb7cb093f971edbb11e0 -size 48291 +oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e +size 46059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png index 33692c96aa..6cdba0f6ce 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2551e11572c82720ddde2909c03d00d3503dadbd0d26e5525cdf9801d61ccc9 -size 50371 +oid sha256:2d320451b7608100f093bb140331fd1fcdecea6c0dc1e721acb0be9045a6b4df +size 48238 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..efff51686d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8209a79e5d20ef58a2e947617b308386d4868799c87039d40fe7c89a68925f2b +size 51842 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..338b81a12b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 +size 49025 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_2,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..33f25a7736 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_2,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2f174ed9f51808a295fd8b748faa0709fb3ef45ebe9cb7cb093f971edbb11e0 +size 48291 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..378fa05efd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e +size 46059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Day-0_1_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedNotSelected_null_PollAnswerDisclosedNotSelected-Night-0_2_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Day-1_2_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerDisclosedSelected_null_PollAnswerDisclosedSelected-Night-1_3_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Day-6_7_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedSelected_null_PollAnswerEndedSelected-Night-6_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Day-4_5_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerNotSelected_null_PollAnswerEndedWinnerNotSelected-Night-4_6_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Day-5_6_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerEndedWinnerSelected_null_PollAnswerEndedWinnerSelected-Night-5_7_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Day-2_3_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedNotSelected_null_PollAnswerUndisclosedNotSelected-Night-2_4_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Day-3_4_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollAnswerUndisclosedSelected_null_PollAnswerUndisclosedSelected-Night-3_5_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Day-10_11_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEditable_null_PollContentCreatorEditable-Night-10_12_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Day-12_13_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreatorEnded_null_PollContentCreatorEnded-Night-12_14_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..efff51686d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Day-11_12_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8209a79e5d20ef58a2e947617b308386d4868799c87039d40fe7c89a68925f2b +size 51842 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..33f25a7736 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentCreator_null_PollContentCreator-Night-11_13_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2f174ed9f51808a295fd8b748faa0709fb3ef45ebe9cb7cb093f971edbb11e0 +size 48291 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..338b81a12b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Day-8_9_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 +size 49025 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..378fa05efd --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentDisclosed_null_PollContentDisclosed-Night-8_10_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e +size 46059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Day-9_10_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentEnded_null_PollContentEnded-Night-9_11_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Day-7_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.api.pollcontent_PollContentUndisclosed_null_PollContentUndisclosed-Night-7_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..fd4b70813f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9900ded970610627436437fbbfa40ec41dba86edc8f8876f769870995156b995 +size 59859 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..03bcfda09a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Day-1_1_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c003aa7b3cf6d48cb33a8c33011293cb218b7c9cc4673613c9dedb58e5b3eb13 +size 64090 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_0,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..87f6d2838a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_0,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d82750e7225b54b68b409e0a02281cbf2ca8832db0b2378cfde79d13aa406ad +size 55862 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..483cb3715c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.poll.impl.history_PollHistoryView_null_PollHistoryView-Night-1_2_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25634fb44c842072f72a677d5f5de6e961090da3a06e84d1e5744508ccf22029 +size 59677 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en].png index f2aceaa87f..e4e301ae45 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:008e30d76413aa72b197df8fa48f767b36e4cff96665a341574fc201a9fba60f -size 49401 +oid sha256:55ffd8384b2b9bb21530512b0794afae3312a3344522973c200009f22b319a1b +size 48550 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en].png index 4e842b552c..c0a735b901 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51661a97bf10bab74eb34e8d81dcd11c1abd99d79ab34c6362fd4d47d15961e4 -size 37030 +oid sha256:998426a2ef42b3fcba4d833a94192ff84cdfca078e4e4beae76054677a517a20 +size 32722 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en].png index ebcff74062..429e87b82f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:373eb9b26c2cef0989a81b8b7a0a4339a61deb44d8e8c4cdc6ac84da2c185535 -size 50660 +oid sha256:4bf9b92e7f604738b91e09975c5ebfaee171a1c5aee7dce9f1b0a21ddac5cbc4 +size 50201 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en].png index 1b49e419ee..7d584650e5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41dd2f57b6ccb7b97265b5a0612eb1f2ded0afe5c3e23d985249430070bce448 -size 47490 +oid sha256:fda8d3e0eb21cb9754f93699569acbfc79de6c5ba187528601342a0311f20aa1 +size 47079 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en].png index 1b49e419ee..7d584650e5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetailsDark_null_RoomDetailsDark--1_3_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:41dd2f57b6ccb7b97265b5a0612eb1f2ded0afe5c3e23d985249430070bce448 -size 47490 +oid sha256:fda8d3e0eb21cb9754f93699569acbfc79de6c5ba187528601342a0311f20aa1 +size 47079 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en].png index 4400764ff6..88c9263e98 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2c730c7d431735a4a061eeebdb965078cbc024df6320817d6f370b6218fb615 -size 52195 +oid sha256:4f32621601d9acf2db4072cc990e655b2c6733a0429107e0c3525ceaa5ef18a4 +size 51222 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en].png index a82d12d069..b1894d9d16 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7f69b590dc167a2d397c675b690c2af80405062926cf50eb77487143887d239 -size 39221 +oid sha256:47df27bc44852fbf357b45b995365edc29d3d8ecebf1d5c93149416835b71b9a +size 34381 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en].png index 34e1113489..9832639e4c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b9764ee82c4d8cc88b9bdbc406baa52e7a7e2ce03cf207efde3dc5fad115557 -size 52136 +oid sha256:2b59de4767530724d5d4bf6e38f6b198db7fe1c88863efaae28933536de6e13c +size 51552 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en].png index 97d73ec016..37d9e41a98 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3ac6155aadacad8bb1bdc9119f1e9e26bea34407d4abacbd7b5c6a685e88462 -size 48566 +oid sha256:29e8f90bfa5518b8ee35f88a9c40e3cfbd58b3b15e7cf4d94515a50a41ca98fe +size 48050 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en].png index 97d73ec016..37d9e41a98 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl_RoomDetails_null_RoomDetails--0_2_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3ac6155aadacad8bb1bdc9119f1e9e26bea34407d4abacbd7b5c6a685e88462 -size 48566 +oid sha256:29e8f90bfa5518b8ee35f88a9c40e3cfbd58b3b15e7cf4d94515a50a41ca98fe +size 48050 From d3e1fea3e4b117213350ce1871d6b49c56937fc1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Dec 2023 17:44:53 +0100 Subject: [PATCH 15/24] Poll history : add changelog. --- changelog.d/2014.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/2014.feature diff --git a/changelog.d/2014.feature b/changelog.d/2014.feature new file mode 100644 index 0000000000..a53efee89c --- /dev/null +++ b/changelog.d/2014.feature @@ -0,0 +1 @@ +Poll history of a room is now accessible from the room details screen. From bb7123afbd279edee4969d75a122623d45b4a6e6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 14 Dec 2023 13:13:11 +0100 Subject: [PATCH 16/24] Fix tests and warnings --- .../impl/timeline/TimelinePresenterTest.kt | 4 ++-- .../features/poll/impl/history/PollHistoryView.kt | 4 ++-- .../matrix/api/timeline/MatrixTimeline.kt | 14 +++++++++++--- .../matrix/impl/timeline/AsyncMatrixTimeline.kt | 2 +- .../matrix/impl/timeline/RustMatrixTimeline.kt | 2 +- .../TimelineEncryptedHistoryPostProcessorTest.kt | 2 +- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index c07286dddc..4316750a6a 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -43,9 +43,9 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom -import io.element.android.libraries.matrix.test.room.aMessageContent -import io.element.android.libraries.matrix.test.room.anEventTimelineItem import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline +import io.element.android.libraries.matrix.test.timeline.aMessageContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.tests.testutils.WarmUpRule diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt index 3b22eed41a..19ca239725 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryView.kt @@ -64,9 +64,9 @@ import kotlinx.collections.immutable.ImmutableList @Composable fun PollHistoryView( state: PollHistoryState, - modifier: Modifier = Modifier, onEditPoll: (EventId) -> Unit, goBack: () -> Unit, + modifier: Modifier = Modifier, ) { fun onLoadMore() { @@ -118,7 +118,7 @@ fun PollHistoryView( HorizontalPager( state = pagerState, userScrollEnabled = false, - modifier = modifier.fillMaxSize() + modifier = Modifier.fillMaxSize() ) { page -> val filter = PollHistoryFilter.entries[page] val pollHistoryItems = state.pollHistoryForFilter(filter) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt index 7a43d1079f..6c1433027b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimeline.kt @@ -23,11 +23,19 @@ import kotlinx.coroutines.flow.StateFlow interface MatrixTimeline : AutoCloseable { data class PaginationState( - val isBackPaginating: Boolean = false, - val hasMoreToLoadBackwards: Boolean = true, - val beginningOfRoomReached: Boolean = false, + val isBackPaginating: Boolean, + val hasMoreToLoadBackwards: Boolean, + val beginningOfRoomReached: Boolean, ) { val canBackPaginate = !isBackPaginating && hasMoreToLoadBackwards + + companion object { + val Initial = PaginationState( + isBackPaginating = false, + hasMoreToLoadBackwards = true, + beginningOfRoomReached = false + ) + } } val paginationState: StateFlow diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt index 5f7636eaa9..fcc9a2a257 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt @@ -47,7 +47,7 @@ class AsyncMatrixTimeline( MutableStateFlow(emptyList()) private val _paginationState = MutableStateFlow( - MatrixTimeline.PaginationState() + MatrixTimeline.PaginationState.Initial ) private val timeline = coroutineScope.async(context = dispatcher, start = CoroutineStart.LAZY) { timelineProvider() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 3995392cbc..ebe6cfccfb 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -72,7 +72,7 @@ class RustMatrixTimeline( MutableStateFlow(emptyList()) private val _paginationState = MutableStateFlow( - MatrixTimeline.PaginationState() + MatrixTimeline.PaginationState.Initial ) private val encryptedHistoryPostProcessor = TimelineEncryptedHistoryPostProcessor( diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt index cf5c3682c2..029ae2336a 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt @@ -20,7 +20,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem -import io.element.android.libraries.matrix.test.room.anEventTimelineItem +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope From ac7dd355aaa901738ea96619c170ba82bf9a51e0 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 14 Dec 2023 16:08:22 +0100 Subject: [PATCH 17/24] Fix test compilation again. --- .../android/libraries/matrix/test/timeline/TimelineFixture.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt index 606aade962..0cbbe81eef 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/TimelineFixture.kt @@ -129,6 +129,7 @@ fun aPollContent( maxSelections: ULong = 1u, votes: ImmutableMap> = persistentMapOf(), endTime: ULong? = null, + isEdited: Boolean = false, ) = PollContent( question = question, kind = kind, @@ -136,4 +137,5 @@ fun aPollContent( answers = answers, votes = votes, endTime = endTime, + isEdited = isEdited, ) From ecf974334ed1a448aeade6e0a96220e72406153a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Dec 2023 16:56:20 +0100 Subject: [PATCH 18/24] Remove duplicated preview, but add editable case (isMine must be true) --- .../timeline/components/event/TimelineItemPollView.kt | 10 ---------- .../model/event/TimelineItemPollContentProvider.kt | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt index 4754bf6298..91dd5b99d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/event/TimelineItemPollView.kt @@ -70,13 +70,3 @@ internal fun TimelineItemPollViewPreview(@PreviewParameter(TimelineItemPollConte eventSink = {}, ) } - -@PreviewsDayNight -@Composable -internal fun TimelineItemPollCreatorViewPreview(@PreviewParameter(TimelineItemPollContentProvider::class) content: TimelineItemPollContent) = - ElementPreview { - TimelineItemPollView( - content = content, - eventSink = {}, - ) - } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt index 4e3639e652..26f545fd5f 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemPollContentProvider.kt @@ -17,9 +17,9 @@ package io.element.android.features.messages.impl.timeline.model.event import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.poll.api.pollcontent.PollAnswerItem import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList import io.element.android.features.poll.api.pollcontent.aPollQuestion -import io.element.android.features.poll.api.pollcontent.PollAnswerItem import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind @@ -29,7 +29,7 @@ open class TimelineItemPollContentProvider : PreviewParameterProvider Date: Thu, 14 Dec 2023 16:56:31 +0100 Subject: [PATCH 19/24] Format --- .../features/poll/impl/history/PollHistoryStateProvider.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt index 6771e034bf..9628a8e137 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryStateProvider.kt @@ -54,7 +54,8 @@ private fun aPollHistoryState( activeFilter = activeFilter, pollHistoryItems = PollHistoryItems( ongoing = currentItems, - past = currentItems,), + past = currentItems, + ), eventSink = {}, ) From 949d57bd41282b603c47f698a15fedefed43e795 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Dec 2023 17:36:35 +0100 Subject: [PATCH 20/24] Fix compilation issue after merging develop --- .../libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt index fcc9a2a257..9be6d3e3bd 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/AsyncMatrixTimeline.kt @@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.impl.timeline import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.ReceiptType import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -89,8 +90,8 @@ class AsyncMatrixTimeline( return timeline.await().fetchDetailsForEvent(eventId) } - override suspend fun sendReadReceipt(eventId: EventId): Result { - return timeline.await().sendReadReceipt(eventId) + override suspend fun sendReadReceipt(eventId: EventId, receiptType: ReceiptType): Result { + return timeline.await().sendReadReceipt(eventId, receiptType) } override fun close() { From 723fb123f11909b3c88c909af5a835f70738a40f Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 14 Dec 2023 16:48:04 +0000 Subject: [PATCH 21/24] Update screenshots --- ...on_null_ProgressButton-Day-46_46_null,NEXUS_5,1.0,en].png} | 0 ..._null_ProgressButton-Night-46_47_null,NEXUS_5,1.0,en].png} | 0 ...neItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png | 3 --- ...neItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png | 3 --- ...neItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png | 3 --- ...neItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png | 3 --- ...ItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png | 3 --- ...ItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png | 3 --- ...ItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png | 3 --- ...ItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png | 3 --- ..._TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...imelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png | 4 ++-- ...melineItemRedactedView-Day-39_39_null,NEXUS_5,1.0,en].png} | 0 ...lineItemRedactedView-Night-39_40_null,NEXUS_5,1.0,en].png} | 0 ..._TimelineItemStateView-Day-40_40_null,NEXUS_5,1.0,en].png} | 0 ...imelineItemStateView-Night-40_41_null,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_0,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_1,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_2,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_3,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_4,NEXUS_5,1.0,en].png} | 0 ...TimelineItemTextView-Day-41_41_null_5,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_0,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_1,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_2,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_3,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_4,NEXUS_5,1.0,en].png} | 0 ...melineItemTextView-Night-41_42_null_5,NEXUS_5,1.0,en].png} | 0 ...imelineItemUnknownView-Day-42_42_null,NEXUS_5,1.0,en].png} | 0 ...elineItemUnknownView-Night-42_43_null,NEXUS_5,1.0,en].png} | 0 ...imelineItemVideoView-Day-43_43_null_0,NEXUS_5,1.0,en].png} | 0 ...imelineItemVideoView-Day-43_43_null_1,NEXUS_5,1.0,en].png} | 0 ...imelineItemVideoView-Day-43_43_null_2,NEXUS_5,1.0,en].png} | 0 ...elineItemVideoView-Night-43_44_null_0,NEXUS_5,1.0,en].png} | 0 ...elineItemVideoView-Night-43_44_null_1,NEXUS_5,1.0,en].png} | 0 ...elineItemVideoView-Night-43_44_null_2,NEXUS_5,1.0,en].png} | 0 ...neItemVoiceViewUnified-Day-45_45_null,NEXUS_5,1.0,en].png} | 0 ...ItemVoiceViewUnified-Night-45_46_null,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_0,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_1,NEXUS_5,1.0,en].png} | 0 ...melineItemVoiceView-Day-44_44_null_10,NEXUS_5,1.0,en].png} | 0 ...melineItemVoiceView-Day-44_44_null_11,NEXUS_5,1.0,en].png} | 0 ...melineItemVoiceView-Day-44_44_null_12,NEXUS_5,1.0,en].png} | 0 ...melineItemVoiceView-Day-44_44_null_13,NEXUS_5,1.0,en].png} | 0 ...melineItemVoiceView-Day-44_44_null_14,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_2,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_3,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_4,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_5,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_6,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_7,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_8,NEXUS_5,1.0,en].png} | 0 ...imelineItemVoiceView-Day-44_44_null_9,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_0,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_1,NEXUS_5,1.0,en].png} | 0 ...lineItemVoiceView-Night-44_45_null_10,NEXUS_5,1.0,en].png} | 0 ...lineItemVoiceView-Night-44_45_null_11,NEXUS_5,1.0,en].png} | 0 ...lineItemVoiceView-Night-44_45_null_12,NEXUS_5,1.0,en].png} | 0 ...lineItemVoiceView-Night-44_45_null_13,NEXUS_5,1.0,en].png} | 0 ...lineItemVoiceView-Night-44_45_null_14,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_2,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_3,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_4,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_5,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_6,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_7,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_8,NEXUS_5,1.0,en].png} | 0 ...elineItemVoiceView-Night-44_45_null_9,NEXUS_5,1.0,en].png} | 0 ...w_null_GroupHeaderView-Day-47_47_null,NEXUS_5,1.0,en].png} | 0 ...null_GroupHeaderView-Night-47_48_null,NEXUS_5,1.0,en].png} | 0 ...nt_null_SheetContent-Day-48_48_null_0,NEXUS_5,1.0,en].png} | 0 ..._null_SheetContent-Night-48_49_null_0,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_0,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_1,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_2,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_3,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_4,NEXUS_5,1.0,en].png} | 0 ...adReceiptBottomSheet-Day-50_50_null_5,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_0,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_1,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_2,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_3,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_4,NEXUS_5,1.0,en].png} | 0 ...ReceiptBottomSheet-Night-50_51_null_5,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_0,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_1,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_2,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_3,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_4,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_5,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_6,NEXUS_5,1.0,en].png} | 0 ...ineItemReactionsView-Day-49_49_null_7,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_0,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_1,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_2,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_3,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_4,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_5,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_6,NEXUS_5,1.0,en].png} | 0 ...eItemReactionsView-Night-49_50_null_7,NEXUS_5,1.0,en].png} | 0 ...RetrySendMessageMenu-Day-51_51_null_0,NEXUS_5,1.0,en].png} | 0 ...RetrySendMessageMenu-Day-51_51_null_1,NEXUS_5,1.0,en].png} | 0 ...trySendMessageMenu-Night-51_52_null_0,NEXUS_5,1.0,en].png} | 0 ...trySendMessageMenu-Night-51_52_null_1,NEXUS_5,1.0,en].png} | 0 ...tedHistoryBannerView-Day-52_52_null_0,NEXUS_5,1.0,en].png} | 0 ...tedHistoryBannerView-Day-52_52_null_1,NEXUS_5,1.0,en].png} | 0 ...tedHistoryBannerView-Day-52_52_null_2,NEXUS_5,1.0,en].png} | 0 ...dHistoryBannerView-Night-52_53_null_0,NEXUS_5,1.0,en].png} | 0 ...dHistoryBannerView-Night-52_53_null_1,NEXUS_5,1.0,en].png} | 0 ...dHistoryBannerView-Night-52_53_null_2,NEXUS_5,1.0,en].png} | 0 ...ItemDaySeparatorView-Day-53_53_null_0,NEXUS_5,1.0,en].png} | 0 ...ItemDaySeparatorView-Day-53_53_null_1,NEXUS_5,1.0,en].png} | 0 ...emDaySeparatorView-Night-53_54_null_0,NEXUS_5,1.0,en].png} | 0 ...emDaySeparatorView-Night-53_54_null_1,NEXUS_5,1.0,en].png} | 0 ...lineItemReadMarkerView-Day-54_54_null,NEXUS_5,1.0,en].png} | 0 ...neItemReadMarkerView-Night-54_55_null,NEXUS_5,1.0,en].png} | 0 ...eItemRoomBeginningView-Day-55_55_null,NEXUS_5,1.0,en].png} | 0 ...temRoomBeginningView-Night-55_56_null,NEXUS_5,1.0,en].png} | 0 ...neLoadingMoreIndicator-Day-56_56_null,NEXUS_5,1.0,en].png} | 0 ...LoadingMoreIndicator-Night-56_57_null,NEXUS_5,1.0,en].png} | 0 ...ull_EventDebugInfoView-Day-57_57_null,NEXUS_5,1.0,en].png} | 0 ...l_EventDebugInfoView-Night-57_58_null,NEXUS_5,1.0,en].png} | 0 122 files changed, 4 insertions(+), 28 deletions(-) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-47_47_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-46_46_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-47_48_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-46_47_null,NEXUS_5,1.0,en].png} (100%) delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png delete mode 100644 tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-40_40_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-39_39_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-40_41_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-39_40_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-41_41_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-40_40_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-41_42_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-40_41_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-43_43_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-42_42_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-43_44_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-42_43_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-46_46_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-45_45_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-46_47_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-45_46_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_10,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_10,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_11,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_11,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_12,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_12,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_13,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_13,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_14,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_14,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_6,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_6,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_7,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_7,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_8,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_8,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_9,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_9,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_10,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_10,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_11,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_11,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_12,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_12,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_13,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_13,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_14,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_14,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_6,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_6,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_7,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_7,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_8,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_8,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_9,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_9,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-48_48_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-47_47_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-48_49_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-47_48_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-49_49_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-48_48_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-49_50_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-48_49_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_6,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_6,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_7,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_7,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_3,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_3,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_4,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_4,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_5,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_5,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_6,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_6,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_7,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_7,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_2,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_2,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_0,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_0,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_1,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_1,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-55_55_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-54_54_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-55_56_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-54_55_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-56_56_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-55_55_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-56_57_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-55_56_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-57_57_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-56_56_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-57_58_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-56_57_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-58_58_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-57_57_null,NEXUS_5,1.0,en].png} (100%) rename tests/uitests/src/test/snapshots/images/{ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-58_59_null,NEXUS_5,1.0,en].png => ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-57_58_null,NEXUS_5,1.0,en].png} (100%) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-47_47_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-46_46_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-47_47_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Day-46_46_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-47_48_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-46_47_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-47_48_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_ProgressButton_null_ProgressButton-Night-46_47_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index 338b81a12b..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 -size 49025 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png deleted file mode 100644 index 9a087a954c..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_1,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0435109c519a31d671bd5cf85425574a10909733e21dcc46ae17e2a53d748b11 -size 50938 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png deleted file mode 100644 index efff51686d..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_2,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8209a79e5d20ef58a2e947617b308386d4868799c87039d40fe7c89a68925f2b -size 51842 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png deleted file mode 100644 index 338b81a12b..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Day-39_39_null_3,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 -size 49025 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index 378fa05efd..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e -size 46059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png deleted file mode 100644 index 6cdba0f6ce..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_1,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d320451b7608100f093bb140331fd1fcdecea6c0dc1e721acb0be9045a6b4df -size 48238 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png deleted file mode 100644 index 33f25a7736..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_2,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2f174ed9f51808a295fd8b748faa0709fb3ef45ebe9cb7cb093f971edbb11e0 -size 48291 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png deleted file mode 100644 index 378fa05efd..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollCreatorView_null_TimelineItemPollCreatorView-Night-39_40_null_3,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e -size 46059 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png index 338b81a12b..19c589c630 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Day-38_38_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27550a0227e993f13e343219973e50ad6902737416e90c41b7a1916723c32e08 -size 49025 +oid sha256:cb71e2b69f31bdc3ee7bf17175f099c3838e311978bfed78ce40e6ad98c871e1 +size 51991 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png index 378fa05efd..029948fca4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemPollView_null_TimelineItemPollView-Night-38_39_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c73a0f3bc8127e9d1491a1056975fa381a0a29aa84f338e14d3c67a8e734918e -size 46059 +oid sha256:e7ff7a9241609b8990ad3353947e550607eca4d8809c0ace796a3cd3dd2ff079 +size 48382 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-40_40_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-39_39_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-40_40_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Day-39_39_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-40_41_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-39_40_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-40_41_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemRedactedView_null_TimelineItemRedactedView-Night-39_40_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-41_41_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-40_40_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-41_41_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Day-40_40_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-41_42_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-40_41_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-41_42_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemStateView_null_TimelineItemStateView-Night-40_41_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-42_42_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Day-41_41_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-42_43_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemTextView_null_TimelineItemTextView-Night-41_42_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-43_43_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-42_42_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-43_43_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Day-42_42_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-43_44_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-42_43_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-43_44_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemUnknownView_null_TimelineItemUnknownView-Night-42_43_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-44_44_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Day-43_43_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-44_45_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVideoView_null_TimelineItemVideoView-Night-43_44_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-46_46_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-45_45_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-46_46_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Day-45_45_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-46_47_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-45_46_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-46_47_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceViewUnified_null_TimelineItemVoiceViewUnified-Night-45_46_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_10,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_10,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_10,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_11,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_11,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_11,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_12,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_12,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_12,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_13,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_13,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_13,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_14,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_14,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_14,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_8,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_8,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_8,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_9,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-45_45_null_9,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Day-44_44_null_9,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_10,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_10,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_10,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_11,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_11,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_11,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_12,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_12,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_12,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_13,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_13,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_13,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_14,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_14,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_14,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_8,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_8,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_8,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_9,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-45_46_null_9,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.event_TimelineItemVoiceView_null_TimelineItemVoiceView-Night-44_45_null_9,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-48_48_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-47_47_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-48_48_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Day-47_47_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-48_49_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-47_48_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-48_49_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.group_GroupHeaderView_null_GroupHeaderView-Night-47_48_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-49_49_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-48_48_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-49_49_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Day-48_48_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-49_50_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-48_49_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-49_50_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.reactionsummary_SheetContent_null_SheetContent-Night-48_49_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-51_51_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Day-50_50_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-51_52_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt.bottomsheet_ReadReceiptBottomSheet_null_ReadReceiptBottomSheet-Night-50_51_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-50_50_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Day-49_49_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-50_51_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.receipt_TimelineItemReactionsView_null_TimelineItemReactionsView-Night-49_50_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-52_52_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Day-51_51_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-52_53_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.retrysendmenu_RetrySendMessageMenu_null_RetrySendMessageMenu-Night-51_52_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-53_53_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-52_52_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-53_54_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-52_53_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-54_54_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Day-53_53_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-54_55_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemDaySeparatorView_null_TimelineItemDaySeparatorView-Night-53_54_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-55_55_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-54_54_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-55_55_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Day-54_54_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-55_56_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-54_55_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-55_56_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemReadMarkerView_null_TimelineItemReadMarkerView-Night-54_55_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-56_56_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-55_55_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-56_56_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Day-55_55_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-56_57_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-55_56_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-56_57_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineItemRoomBeginningView_null_TimelineItemRoomBeginningView-Night-55_56_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-57_57_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-56_56_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-57_57_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Day-56_56_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-57_58_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-56_57_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-57_58_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_TimelineLoadingMoreIndicator_null_TimelineLoadingMoreIndicator-Night-56_57_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-58_58_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-57_57_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-58_58_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Day-57_57_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-58_59_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-57_58_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-58_59_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.debug_EventDebugInfoView_null_EventDebugInfoView-Night-57_58_null,NEXUS_5,1.0,en].png From 5dfd64a23b9d7e5a8f3e2510b11fe85ad257f305 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 14 Dec 2023 18:33:59 +0100 Subject: [PATCH 22/24] Fix androidTest compilation --- .../android/features/messages/impl/fixtures/aMessageEvent.kt | 2 +- .../messages/impl/timeline/groups/TimelineItemGrouperTest.kt | 2 +- .../messages/impl/timeline/model/InReplyToMetadataKtTest.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/aMessageEvent.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/aMessageEvent.kt index 3c94a8782e..f700ed34c3 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/aMessageEvent.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/fixtures/aMessageEvent.kt @@ -16,6 +16,7 @@ package io.element.android.features.messages.impl.fixtures +import io.element.android.features.messages.impl.timeline.aTimelineItemDebugInfo import io.element.android.features.messages.impl.timeline.aTimelineItemReactions import io.element.android.features.messages.impl.timeline.model.InReplyToDetails import io.element.android.features.messages.impl.timeline.model.ReadReceiptData @@ -32,7 +33,6 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME -import io.element.android.libraries.matrix.test.room.aTimelineItemDebugInfo import kotlinx.collections.immutable.toImmutableList internal fun aMessageEvent( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt index 1f111f248c..42d4b3388a 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouperTest.kt @@ -18,6 +18,7 @@ package io.element.android.features.messages.impl.timeline.groups import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.fixtures.aMessageEvent +import io.element.android.features.messages.impl.timeline.aTimelineItemDebugInfo import io.element.android.features.messages.impl.timeline.aTimelineItemReactions import io.element.android.features.messages.impl.timeline.model.ReadReceiptData import io.element.android.features.messages.impl.timeline.model.TimelineItem @@ -28,7 +29,6 @@ import io.element.android.libraries.designsystem.components.avatar.anAvatarData import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.room.aTimelineItemDebugInfo import kotlinx.collections.immutable.toImmutableList import org.junit.Test diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt index 646a6e372f..cb79f5cd08 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadataKtTest.kt @@ -43,8 +43,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageT import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.media.aMediaSource -import io.element.android.libraries.matrix.test.room.aMessageContent -import io.element.android.libraries.matrix.test.room.aPollContent +import io.element.android.libraries.matrix.test.timeline.aMessageContent +import io.element.android.libraries.matrix.test.timeline.aPollContent import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType import kotlinx.coroutines.test.runTest From 9bdb388d9ed4f6762639cf65354556d61d17498a Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 14 Dec 2023 19:00:06 +0100 Subject: [PATCH 23/24] MessagesPresenter : remove useless test --- .../messages/impl/MessagesPresenterTest.kt | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 9f8089efd3..6eba26ad4b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -21,7 +21,6 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import im.vector.app.features.analytics.plan.PollEnd import io.element.android.features.messages.impl.actionlist.ActionListPresenter import io.element.android.features.messages.impl.actionlist.ActionListState import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction @@ -93,7 +92,6 @@ import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.consumeItemsUntilTimeout import io.element.android.tests.testutils.testCoroutineDispatchers -import io.element.android.tests.testutils.waitForPredicate import io.mockk.mockk import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.TestScope @@ -621,29 +619,6 @@ class MessagesPresenterTest { } } - @Test - fun `present - handle poll end`() = runTest { - val room = FakeMatrixRoom() - val analyticsService = FakeAnalyticsService() - val presenter = createMessagesPresenter( - matrixRoom = room, - analyticsService = analyticsService, - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitItem() - initialState.eventSink(MessagesEvents.HandleAction(TimelineItemAction.EndPoll, aMessageEvent())) - waitForPredicate { room.endPollInvocations.size == 1 } - cancelAndIgnoreRemainingEvents() - assertThat(room.endPollInvocations.size).isEqualTo(1) - assertThat(room.endPollInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID) - assertThat(room.endPollInvocations.first().text).isEqualTo("The poll with event id: \$anEventId has ended.") - assertThat(analyticsService.capturedEvents.size).isEqualTo(1) - assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollEnd()) - } - } - @Test fun `present - handle action reply to a poll`() = runTest { val presenter = createMessagesPresenter() @@ -715,7 +690,7 @@ class MessagesPresenterTest { endPollAction = FakeEndPollAction(), sendPollResponseAction = FakeSendPollResponseAction(), ) - val timelinePresenterFactory = object: TimelinePresenter.Factory { + val timelinePresenterFactory = object : TimelinePresenter.Factory { override fun create(navigator: MessagesNavigator): TimelinePresenter { return timelinePresenter } From dfec3abbd691615673312bee567bd9ce795e2ab2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Dec 2023 20:53:20 +0100 Subject: [PATCH 24/24] Fix test compilation --- .../impl/DefaultRoomLastMessageFormatterTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 6b7d52118d..a6d0f2e776 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 @@ -50,9 +50,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageT import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType 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.room.aPollContent -import io.element.android.libraries.matrix.test.room.aProfileChangeMessageContent -import io.element.android.libraries.matrix.test.room.anEventTimelineItem +import io.element.android.libraries.matrix.test.timeline.aPollContent +import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.services.toolbox.impl.strings.AndroidStringProvider import org.junit.Before import org.junit.Test