Flow migration: update after PR reviews

This commit is contained in:
ganfra 2021-10-28 19:19:59 +02:00
parent 16e4a7f653
commit bb4a820c31
9 changed files with 52 additions and 78 deletions

41
docs/rx_flow_migration.md Normal file
View file

@ -0,0 +1,41 @@
Useful links:
- https://github.com/ReactiveCircus/FlowBinding
- https://ivanisidrowu.github.io/kotlin/2020/08/09/Kotlin-Flow-Migration-And-Testing.html
Rx is now completely removed from Element dependencies.
Some examples of the changes:
```
sharedActionViewModel
.observe()
.subscribe { handleQuickActions(it) }
.disposeOnDestroyView()
```
became
```
sharedActionViewModel
.stream()
.onEach { handleQuickActions(it) }
.launchIn(viewLifecycleOwner.lifecycleScope)
```
Inside fragment use
```
launchIn(viewLifecycleOwner.lifecycleScope)
```
Inside activity use
```
launchIn(lifecycleScope)
```
Inside viewModel use
```
launchIn(viewModelScope)
```
Also be aware that when using these scopes the coroutine is launched on Dispatchers.Main by default.

View file

@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.session.group.GroupSummaryQueryParams
import org.matrix.android.sdk.api.session.group.model.GroupSummary import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.pushers.Pusher import org.matrix.android.sdk.api.session.pushers.Pusher
import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
@ -44,10 +45,10 @@ import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo
class FlowSession(private val session: Session) { class FlowSession(private val session: Session) {
fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Flow<List<RoomSummary>> { fun liveRoomSummaries(queryParams: RoomSummaryQueryParams, sortOrder: RoomSortOrder = RoomSortOrder.NONE): Flow<List<RoomSummary>> {
return session.getRoomSummariesLive(queryParams).asFlow() return session.getRoomSummariesLive(queryParams, sortOrder).asFlow()
.startWith(session.coroutineDispatchers.io) { .startWith(session.coroutineDispatchers.io) {
session.getRoomSummaries(queryParams) session.getRoomSummaries(queryParams, sortOrder)
} }
} }

View file

@ -43,7 +43,6 @@ import dagger.hilt.android.HiltAndroidApp
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.extensions.configureAndStart
import im.vector.app.core.extensions.startSyncing import im.vector.app.core.extensions.startSyncing
import im.vector.app.core.rx.RxConfig
import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.configuration.VectorConfiguration
import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
@ -93,7 +92,6 @@ class VectorApplication :
@Inject lateinit var versionProvider: VersionProvider @Inject lateinit var versionProvider: VersionProvider
@Inject lateinit var notificationUtils: NotificationUtils @Inject lateinit var notificationUtils: NotificationUtils
@Inject lateinit var appStateHandler: AppStateHandler @Inject lateinit var appStateHandler: AppStateHandler
@Inject lateinit var rxConfig: RxConfig
@Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var popupAlertManager: PopupAlertManager
@Inject lateinit var pinLocker: PinLocker @Inject lateinit var pinLocker: PinLocker
@Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var callManager: WebRtcCallManager
@ -118,7 +116,6 @@ class VectorApplication :
appContext = this appContext = this
invitesAcceptor.initialize() invitesAcceptor.initialize()
vectorUncaughtExceptionHandler.activate(this) vectorUncaughtExceptionHandler.activate(this)
rxConfig.setupRxPlugin()
// Remove Log handler statically added by Jitsi // Remove Log handler statically added by Jitsi
Timber.forest() Timber.forest()

View file

@ -1,28 +0,0 @@
/*
* Copyright 2019 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 im.vector.app.core.rx
import javax.inject.Inject
class RxConfig @Inject constructor() {
/**
* Make sure unhandled Rx error does not crash the app in production
*/
fun setupRxPlugin() {
}
}

View file

@ -27,6 +27,7 @@ import im.vector.app.RoomGroupingMethod
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.flow.throttleFirst
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.call.dialpad.DialPadLookup import im.vector.app.features.call.dialpad.DialPadLookup
import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.lookup.CallProtocolsChecker
@ -43,7 +44,6 @@ import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter
@ -214,7 +214,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
sortOrder = RoomSortOrder.NONE sortOrder = RoomSortOrder.NONE
).asFlow() ).asFlow()
} }
.sample(300) .throttleFirst(300)
.onEach { .onEach {
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) { when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
is RoomGroupingMethod.ByLegacyGroup -> { is RoomGroupingMethod.ByLegacyGroup -> {

View file

@ -21,7 +21,6 @@ import android.content.pm.ShortcutManager
import android.os.Build import android.os.Build
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.lifecycle.asFlow
import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.dispatchers.CoroutineDispatchers import im.vector.app.core.dispatchers.CoroutineDispatchers
import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinCodeStore
@ -37,6 +36,7 @@ import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.flow.flow
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
@ -61,13 +61,12 @@ class ShortcutsHandler @Inject constructor(
} }
hasPinCode.set(pinCodeStore.getEncodedPin() != null) hasPinCode.set(pinCodeStore.getEncodedPin() != null)
val session = activeSessionHolder.getSafeActiveSession() ?: return Job() val session = activeSessionHolder.getSafeActiveSession() ?: return Job()
return session.getRoomSummariesLive( return session.flow().liveRoomSummaries(
roomSummaryQueryParams { roomSummaryQueryParams {
memberships = listOf(Membership.JOIN) memberships = listOf(Membership.JOIN)
}, },
sortOrder = RoomSortOrder.PRIORITY_AND_ACTIVITY sortOrder = RoomSortOrder.PRIORITY_AND_ACTIVITY
) )
.asFlow()
.onStart { pinCodeStore.addListener(this@ShortcutsHandler) } .onStart { pinCodeStore.addListener(this@ShortcutsHandler) }
.onCompletion { pinCodeStore.removeListener(this@ShortcutsHandler) } .onCompletion { pinCodeStore.removeListener(this@ShortcutsHandler) }
.onEach { rooms -> .onEach { rooms ->

View file

@ -26,6 +26,7 @@ import im.vector.app.AppStateHandler
import im.vector.app.RoomGroupingMethod import im.vector.app.RoomGroupingMethod
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.flow.throttleFirst
import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
@ -36,7 +37,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.sample
import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSortOrder
@ -79,7 +79,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null) this.activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
}, sortOrder = RoomSortOrder.NONE }, sortOrder = RoomSortOrder.NONE
).asFlow() ).asFlow()
.sample(300) .throttleFirst(300)
.execute { .execute {
val counts = session.getNotificationCountForRooms( val counts = session.getNotificationCountForRooms(
roomSummaryQueryParams { roomSummaryQueryParams {
@ -114,7 +114,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
this.memberships = Membership.activeMemberships() this.memberships = Membership.activeMemberships()
}, sortOrder = RoomSortOrder.NONE }, sortOrder = RoomSortOrder.NONE
).asFlow() ).asFlow()
.sample(300) .throttleFirst(300)
} }
) { groupingMethod, _ -> ) { groupingMethod, _ ->
when (groupingMethod.orNull()) { when (groupingMethod.orNull()) {

View file

@ -18,7 +18,6 @@ package im.vector.app.features.crypto.quads
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.test.MvRxTestRule import com.airbnb.mvrx.test.MvRxTestRule
import im.vector.app.test.InstantRxRule
import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fakes.FakeStringProvider import im.vector.app.test.fakes.FakeStringProvider
import im.vector.app.test.test import im.vector.app.test.test
@ -40,9 +39,6 @@ private val KEY_INFO_WITHOUT_PASSPHRASE = KeyInfo(id = "id", content = SecretSto
class SharedSecureStorageViewModelTest { class SharedSecureStorageViewModelTest {
@get:Rule
val instantRx = InstantRxRule()
@get:Rule @get:Rule
val mvrxTestRule = MvRxTestRule() val mvrxTestRule = MvRxTestRule()

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2021 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 im.vector.app.test
import io.reactivex.android.plugins.RxAndroidPlugins
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.schedulers.Schedulers
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
class InstantRxRule : TestRule {
override fun apply(base: Statement, description: Description?): Statement {
RxJavaPlugins.setInitNewThreadSchedulerHandler { Schedulers.trampoline() }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
return base
}
}