Browse Source

Merge pull request #997 from vector-im/feature/fga/remove_from_main_thread

Feature/fga/remove from main thread
pull/1003/head
ganfra 1 year ago committed by GitHub
parent
commit
f1d438e701
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt
  2. 8
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt
  3. 2
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt
  4. 1
      libraries/matrix/impl/build.gradle.kts
  5. 2
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  6. 9
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt
  7. 1
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt
  8. 11
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt
  9. 20
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt
  10. 2
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt

14
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt

@ -21,7 +21,6 @@ import androidx.compose.runtime.Composable @@ -21,7 +21,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
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
@ -124,17 +123,12 @@ class MessagesPresenter @AssistedInject constructor( @@ -124,17 +123,12 @@ class MessagesPresenter @AssistedInject constructor(
}
val inviteProgress = remember { mutableStateOf<Async<Unit>>(Async.Uninitialized) }
val showReinvitePrompt by remember(
hasDismissedInviteDialog,
composerState.hasFocus,
syncUpdateFlow,
) {
derivedStateOf {
!hasDismissedInviteDialog && composerState.hasFocus && room.isDirect && room.activeMemberCount == 1L
var showReinvitePrompt by remember { mutableStateOf(false) }
LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow) {
withContext(dispatchers.io) {
showReinvitePrompt = !hasDismissedInviteDialog && composerState.hasFocus && room.isDirect && room.activeMemberCount == 1L
}
}
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()

8
features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt

@ -371,11 +371,15 @@ class MessagesPresenterTest { @@ -371,11 +371,15 @@ class MessagesPresenterTest {
assertThat(initialState.showReinvitePrompt).isFalse()
// When the input field is focused we show the alert
initialState.composerState.eventSink(MessageComposerEvents.FocusChanged(true))
val focusedState = awaitItem()
val focusedState = consumeItemsUntilPredicate { state ->
state.showReinvitePrompt
}.last()
assertThat(focusedState.showReinvitePrompt).isTrue()
// If it's dismissed then we stop showing the alert
initialState.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Cancel))
val dismissedState = awaitItem()
val dismissedState = consumeItemsUntilPredicate { state ->
!state.showReinvitePrompt
}.last()
assertThat(dismissedState.showReinvitePrompt).isFalse()
}
}

2
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt

@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.RoomId @@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
interface NotificationService {
fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId, filterByPushRules: Boolean): Result<NotificationData?>
suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId, filterByPushRules: Boolean): Result<NotificationData?>
}

1
libraries/matrix/impl/build.gradle.kts

@ -45,4 +45,5 @@ dependencies { @@ -45,4 +45,5 @@ dependencies {
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
testImplementation(projects.libraries.matrix.test)
testImplementation(libs.coroutines.test)
}

2
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

@ -103,7 +103,7 @@ class RustMatrixClient constructor( @@ -103,7 +103,7 @@ class RustMatrixClient constructor(
builder.finish()
}
private val notificationService = RustNotificationService(sessionId, notificationClient, clock)
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
private val isLoggingOut = AtomicBoolean(false)

9
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt

@ -16,29 +16,32 @@ @@ -16,29 +16,32 @@
package io.element.android.libraries.matrix.impl.notification
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.notification.NotificationService
import io.element.android.services.toolbox.api.systemclock.SystemClock
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.NotificationClient
import org.matrix.rustcomponents.sdk.use
class RustNotificationService(
sessionId: SessionId,
private val notificationClient: NotificationClient,
private val dispatchers: CoroutineDispatchers,
clock: SystemClock,
) : NotificationService {
private val notificationMapper: NotificationMapper = NotificationMapper(sessionId, clock)
override fun getNotification(
override suspend fun getNotification(
userId: SessionId,
roomId: RoomId,
eventId: EventId,
filterByPushRules: Boolean,
): Result<NotificationData?> {
return runCatching {
): Result<NotificationData?> = withContext(dispatchers.io) {
runCatching {
val item = notificationClient.getNotificationWithSlidingSync(roomId.value, eventId.value)
item?.use {
notificationMapper.map(eventId, roomId, it)

1
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt

@ -81,6 +81,7 @@ class RustMatrixTimeline( @@ -81,6 +81,7 @@ class RustMatrixTimeline(
lastLoginTimestamp = lastLoginTimestamp,
isRoomEncrypted = matrixRoom.isEncrypted,
paginationStateFlow = _paginationState,
dispatcher = dispatcher,
)
private val timelineItemFactory = MatrixTimelineItemMapper(

11
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessor.kt

@ -19,18 +19,23 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor @@ -19,18 +19,23 @@ package io.element.android.libraries.matrix.impl.timeline.postprocessor
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 kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.util.Date
class TimelineEncryptedHistoryPostProcessor(
private val dispatcher: CoroutineDispatcher,
private val lastLoginTimestamp: Date?,
private val isRoomEncrypted: Boolean,
private val paginationStateFlow: MutableStateFlow<MatrixTimeline.PaginationState>,
) {
fun process(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> {
if (!isRoomEncrypted || lastLoginTimestamp == null) return items
suspend fun process(items: List<MatrixTimelineItem>): List<MatrixTimelineItem> = withContext(dispatcher) {
Timber.d("Process on Thread=${Thread.currentThread()}")
if (!isRoomEncrypted || lastLoginTimestamp == null) return@withContext items
val filteredItems = replaceWithEncryptionHistoryBannerIfNeeded(items)
// Disable back pagination
@ -43,7 +48,7 @@ class TimelineEncryptedHistoryPostProcessor( @@ -43,7 +48,7 @@ class TimelineEncryptedHistoryPostProcessor(
)
}
}
return filteredItems
filteredItems
}
private fun replaceWithEncryptionHistoryBannerIfNeeded(list: List<MatrixTimelineItem>): List<MatrixTimelineItem> {

20
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/postprocessor/TimelineEncryptedHistoryPostProcessorTest.kt

@ -22,6 +22,9 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem @@ -22,6 +22,9 @@ 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 kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import java.util.Date
@ -30,7 +33,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -30,7 +33,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
private val defaultLastLoginTimestamp = Date(1_689_061_264L)
@Test
fun `given an unencrypted room, nothing is done`() {
fun `given an unencrypted room, nothing is done`() = runTest {
val processor = createPostProcessor(isRoomEncrypted = false)
val items = listOf(
MatrixTimelineItem.Event(0L, anEventTimelineItem())
@ -39,7 +42,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -39,7 +42,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
}
@Test
fun `given a null lastLoginTimestamp, nothing is done`() {
fun `given a null lastLoginTimestamp, nothing is done`() = runTest {
val processor = createPostProcessor(lastLoginTimestamp = null)
val items = listOf(
MatrixTimelineItem.Event(0L, anEventTimelineItem())
@ -48,14 +51,14 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -48,14 +51,14 @@ class TimelineEncryptedHistoryPostProcessorTest {
}
@Test
fun `given an empty list, nothing is done`() {
fun `given an empty list, nothing is done`() = runTest {
val processor = createPostProcessor()
val items = emptyList<MatrixTimelineItem>()
assertThat(processor.process(items)).isSameInstanceAs(items)
}
@Test
fun `given a list with no items before lastLoginTimestamp, nothing is done`() {
fun `given a list with no items before lastLoginTimestamp, nothing is done`() = runTest {
val processor = createPostProcessor()
val items = listOf(
MatrixTimelineItem.Event(0L, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time + 1))
@ -64,7 +67,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -64,7 +67,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
}
@Test
fun `given a list with an item with equal timestamp as lastLoginTimestamp, it's replaced`() {
fun `given a list with an item with equal timestamp as lastLoginTimestamp, it's replaced`() = runTest {
val processor = createPostProcessor()
val items = listOf(
MatrixTimelineItem.Event(0L, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time))
@ -74,7 +77,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -74,7 +77,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
}
@Test
fun `given a list with an item with a lower timestamp than lastLoginTimestamp, it's replaced`() {
fun `given a list with an item with a lower timestamp than lastLoginTimestamp, it's replaced`() = runTest {
val processor = createPostProcessor()
val items = listOf(
MatrixTimelineItem.Event(0L, anEventTimelineItem(timestamp = defaultLastLoginTimestamp.time - 1))
@ -85,7 +88,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -85,7 +88,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
}
@Test
fun `given a list with several with lower or equal timestamps than lastLoginTimestamp, they're replaced and the user can't back paginate`() {
fun `given a list with several with lower or equal timestamps than lastLoginTimestamp, they're replaced and the user can't back paginate`() = runTest {
val paginationStateFlow = MutableStateFlow(MatrixTimeline.PaginationState(hasMoreToLoadBackwards = true, isBackPaginating = false))
val processor = createPostProcessor(paginationStateFlow = paginationStateFlow)
val items = listOf(
@ -102,7 +105,7 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -102,7 +105,7 @@ class TimelineEncryptedHistoryPostProcessorTest {
assertThat(paginationStateFlow.value).isEqualTo(MatrixTimeline.PaginationState(hasMoreToLoadBackwards = false, isBackPaginating = false))
}
private fun createPostProcessor(
private fun TestScope.createPostProcessor(
lastLoginTimestamp: Date? = defaultLastLoginTimestamp,
isRoomEncrypted: Boolean = true,
paginationStateFlow: MutableStateFlow<MatrixTimeline.PaginationState> =
@ -111,5 +114,6 @@ class TimelineEncryptedHistoryPostProcessorTest { @@ -111,5 +114,6 @@ class TimelineEncryptedHistoryPostProcessorTest {
lastLoginTimestamp = lastLoginTimestamp,
isRoomEncrypted = isRoomEncrypted,
paginationStateFlow = paginationStateFlow,
dispatcher = StandardTestDispatcher(testScheduler)
)
}

2
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt

@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationData @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.notification.NotificationService
class FakeNotificationService : NotificationService {
override fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId, filterByPushRules: Boolean): Result<NotificationData?> {
override suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId, filterByPushRules: Boolean): Result<NotificationData?> {
return Result.success(null)
}
}

Loading…
Cancel
Save