diff --git a/changelog.d/3890.misc b/changelog.d/3890.misc new file mode 100644 index 0000000000..3bace80fa7 --- /dev/null +++ b/changelog.d/3890.misc @@ -0,0 +1 @@ +Migrate to MvRx2 (Mavericks) \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index 882a4fde09..1e3c492149 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -19,6 +19,7 @@ def moshi = "1.12.0" def lifecycle = "2.2.0" def rxBinding = "3.1.0" def epoxy = "4.6.2" +def mavericks = "2.4.0" def glide = "4.12.0" def bigImageViewer = "1.8.1" def jjwt = "0.11.2" @@ -98,7 +99,9 @@ ext.libs = [ 'epoxyGlide' : "com.airbnb.android:epoxy-glide-preloading:$epoxy", 'epoxyProcessor' : "com.airbnb.android:epoxy-processor:$epoxy", 'epoxyPaging' : "com.airbnb.android:epoxy-paging:$epoxy", - 'mvrx' : "com.airbnb.android:mvrx:1.5.1" + 'mavericks' : "com.airbnb.android:mavericks:$mavericks", + 'mavericksRx' : "com.airbnb.android:mavericks-rxjava2:$mavericks", + 'mavericksTesting' : "com.airbnb.android:mavericks-testing:$mavericks" ], mockk : [ 'mockk' : "io.mockk:mockk:$mockk", diff --git a/docs/mavericks_migration.md b/docs/mavericks_migration.md new file mode 100644 index 0000000000..a36ae8261a --- /dev/null +++ b/docs/mavericks_migration.md @@ -0,0 +1,11 @@ +Useful links: +- https://airbnb.io/mavericks/#/new-2x + +Mavericks 2 is replacing MvRx, by removing usage of Rx by Flow, both internally and in the API. +See the link ^ to have more intel, but basically, the changes are: + +session.rx() => session.flow() +room.rx() => room.flow() +subscribe { }.disposeOnClear() => onEach { }.launchIn(viewModelScope) + +Only using manually onEach requires to add launchIn,any other methods provided by Mavericks on viewModel and activity/fragment are already taking care of lifecycle. \ No newline at end of file diff --git a/matrix-sdk-android-flow/.gitignore b/matrix-sdk-android-flow/.gitignore new file mode 100644 index 0000000000..42afabfd2a --- /dev/null +++ b/matrix-sdk-android-flow/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/matrix-sdk-android-flow/build.gradle b/matrix-sdk-android-flow/build.gradle new file mode 100644 index 0000000000..fd2e2e0824 --- /dev/null +++ b/matrix-sdk-android-flow/build.gradle @@ -0,0 +1,48 @@ + +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + + implementation project(":matrix-sdk-android") + implementation libs.androidx.appCompat + + implementation libs.jetbrains.kotlinStdlibJdk7 + implementation libs.jetbrains.coroutinesCore + implementation libs.jetbrains.coroutinesAndroid + implementation libs.androidx.lifecycleLivedata + + // Paging + implementation libs.androidx.pagingRuntimeKtx + + // Logging + implementation libs.jakewharton.timber +} diff --git a/matrix-sdk-android-flow/consumer-rules.pro b/matrix-sdk-android-flow/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/matrix-sdk-android-flow/proguard-rules.pro b/matrix-sdk-android-flow/proguard-rules.pro new file mode 100644 index 0000000000..481bb43481 --- /dev/null +++ b/matrix-sdk-android-flow/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/matrix-sdk-android-flow/src/main/AndroidManifest.xml b/matrix-sdk-android-flow/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..2392c0bfcb --- /dev/null +++ b/matrix-sdk-android-flow/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowExt.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowExt.kt new file mode 100644 index 0000000000..72493325c3 --- /dev/null +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowExt.kt @@ -0,0 +1,31 @@ +/* + * 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 org.matrix.android.sdk.flow + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.withContext + +internal fun Flow.startWith(dispatcher: CoroutineDispatcher, supplier: suspend () -> T): Flow { + return onStart { + val value = withContext(dispatcher) { + supplier() + } + emit(value) + } +} diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt new file mode 100644 index 0000000000..42c1476b79 --- /dev/null +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowRoom.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.flow + +import androidx.lifecycle.asFlow +import kotlinx.coroutines.flow.Flow +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams +import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary +import org.matrix.android.sdk.api.session.room.model.ReadReceipt +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState +import org.matrix.android.sdk.api.session.room.send.UserDraft +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.api.util.toOptional + +class FlowRoom(private val room: Room) { + + fun liveRoomSummary(): Flow> { + return room.getRoomSummaryLive().asFlow() + .startWith(room.coroutineDispatchers.io) { + room.roomSummary().toOptional() + } + } + + fun liveRoomMembers(queryParams: RoomMemberQueryParams): Flow> { + return room.getRoomMembersLive(queryParams).asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getRoomMembers(queryParams) + } + } + + fun liveAnnotationSummary(eventId: String): Flow> { + return room.getEventAnnotationsSummaryLive(eventId).asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getEventAnnotationsSummary(eventId).toOptional() + } + } + + fun liveTimelineEvent(eventId: String): Flow> { + return room.getTimeLineEventLive(eventId).asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getTimeLineEvent(eventId).toOptional() + } + } + + fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow> { + return room.getStateEventLive(eventType, stateKey).asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getStateEvent(eventType, stateKey).toOptional() + } + } + + fun liveStateEvents(eventTypes: Set): Flow> { + return room.getStateEventsLive(eventTypes).asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getStateEvents(eventTypes) + } + } + + fun liveReadMarker(): Flow> { + return room.getReadMarkerLive().asFlow() + } + + fun liveReadReceipt(): Flow> { + return room.getMyReadReceiptLive().asFlow() + } + + fun liveEventReadReceipts(eventId: String): Flow> { + return room.getEventReadReceiptsLive(eventId).asFlow() + } + + fun liveDraft(): Flow> { + return room.getDraftLive().asFlow() + .startWith(room.coroutineDispatchers.io) { + room.getDraft().toOptional() + } + } + + fun liveNotificationState(): Flow { + return room.getLiveRoomNotificationState().asFlow() + } +} + +fun Room.flow(): FlowRoom { + return FlowRoom(this) +} diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt new file mode 100644 index 0000000000..13fd097bcd --- /dev/null +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/FlowSession.kt @@ -0,0 +1,180 @@ +/* + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.flow + +import androidx.lifecycle.asFlow +import androidx.paging.PagedList +import kotlinx.coroutines.flow.Flow +import org.matrix.android.sdk.api.query.QueryStringValue +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent +import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo +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.identity.ThreePid +import org.matrix.android.sdk.api.session.pushers.Pusher +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.members.ChangeMembershipState +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams +import org.matrix.android.sdk.api.session.sync.SyncState +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.api.session.widgets.model.Widget +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo +import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo + +class FlowSession(private val session: Session) { + + fun liveRoomSummaries(queryParams: RoomSummaryQueryParams): Flow> { + return session.getRoomSummariesLive(queryParams).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.getRoomSummaries(queryParams) + } + } + + fun liveGroupSummaries(queryParams: GroupSummaryQueryParams): Flow> { + return session.getGroupSummariesLive(queryParams).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.getGroupSummaries(queryParams) + } + } + + fun liveSpaceSummaries(queryParams: SpaceSummaryQueryParams): Flow> { + return session.spaceService().getSpaceSummariesLive(queryParams).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.spaceService().getSpaceSummaries(queryParams) + } + } + + fun liveBreadcrumbs(queryParams: RoomSummaryQueryParams): Flow> { + return session.getBreadcrumbsLive(queryParams).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.getBreadcrumbs(queryParams) + } + } + + fun liveMyDevicesInfo(): Flow> { + return session.cryptoService().getLiveMyDevicesInfo().asFlow() + .startWith(session.coroutineDispatchers.io) { + session.cryptoService().getMyDevicesInfo() + } + } + + fun liveSyncState(): Flow { + return session.getSyncStateLive().asFlow() + } + + fun livePushers(): Flow> { + return session.getPushersLive().asFlow() + } + + fun liveUser(userId: String): Flow> { + return session.getUserLive(userId).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.getUser(userId).toOptional() + } + } + + fun liveRoomMember(userId: String, roomId: String): Flow> { + return session.getRoomMemberLive(userId, roomId).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.getRoomMember(userId, roomId).toOptional() + } + } + + fun liveUsers(): Flow> { + return session.getUsersLive().asFlow() + } + + fun liveIgnoredUsers(): Flow> { + return session.getIgnoredUsersLive().asFlow() + } + + fun livePagedUsers(filter: String? = null, excludedUserIds: Set? = null): Flow> { + return session.getPagedUsersLive(filter, excludedUserIds).asFlow() + } + + fun liveThreePIds(refreshData: Boolean): Flow> { + return session.getThreePidsLive(refreshData).asFlow() + .startWith(session.coroutineDispatchers.io) { session.getThreePids() } + } + + fun livePendingThreePIds(): Flow> { + return session.getPendingThreePidsLive().asFlow() + .startWith(session.coroutineDispatchers.io) { session.getPendingThreePids() } + } + + fun liveUserCryptoDevices(userId: String): Flow> { + return session.cryptoService().getLiveCryptoDeviceInfo(userId).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.cryptoService().getCryptoDeviceInfo(userId) + } + } + + fun liveCrossSigningInfo(userId: String): Flow> { + return session.cryptoService().crossSigningService().getLiveCrossSigningKeys(userId).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.cryptoService().crossSigningService().getUserCrossSigningKeys(userId).toOptional() + } + } + + fun liveCrossSigningPrivateKeys(): Flow> { + return session.cryptoService().crossSigningService().getLiveCrossSigningPrivateKeys().asFlow() + .startWith(session.coroutineDispatchers.io) { + session.cryptoService().crossSigningService().getCrossSigningPrivateKeys().toOptional() + } + } + + fun liveUserAccountData(types: Set): Flow> { + return session.accountDataService().getLiveUserAccountDataEvents(types).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.accountDataService().getUserAccountDataEvents(types) + } + } + + fun liveRoomAccountData(types: Set): Flow> { + return session.accountDataService().getLiveRoomAccountDataEvents(types).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.accountDataService().getRoomAccountDataEvents(types) + } + } + + fun liveRoomWidgets( + roomId: String, + widgetId: QueryStringValue, + widgetTypes: Set? = null, + excludedTypes: Set? = null + ): Flow> { + return session.widgetService().getRoomWidgetsLive(roomId, widgetId, widgetTypes, excludedTypes).asFlow() + .startWith(session.coroutineDispatchers.io) { + session.widgetService().getRoomWidgets(roomId, widgetId, widgetTypes, excludedTypes) + } + } + + fun liveRoomChangeMembershipState(): Flow> { + return session.getChangeMembershipsLive().asFlow() + } +} + +fun Session.flow(): FlowSession { + return FlowSession(this) +} diff --git a/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/OptionalFlow.kt b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/OptionalFlow.kt new file mode 100644 index 0000000000..a9f062f379 --- /dev/null +++ b/matrix-sdk-android-flow/src/main/java/org/matrix/android/sdk/flow/OptionalFlow.kt @@ -0,0 +1,32 @@ +/* + * 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 org.matrix.android.sdk.flow + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import org.matrix.android.sdk.api.util.Optional + +fun Flow>.unwrap(): Flow { + return filter { it.hasValue() }.map { it.get() } +} + +fun Flow>.mapOptional(fn: (T) -> U?): Flow> { + return map { + it.map(fn) + } +} diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt index 192f6442b2..3e3af10799 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/SingleThreadCoroutineDispatcher.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.asCoroutineDispatcher -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import java.util.concurrent.Executors internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/MatrixCoroutineDispatchers.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCoroutineDispatchers.kt similarity index 85% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/MatrixCoroutineDispatchers.kt rename to matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCoroutineDispatchers.kt index b44a543c1c..592974be74 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/MatrixCoroutineDispatchers.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixCoroutineDispatchers.kt @@ -5,7 +5,7 @@ * 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 + * 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, @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.matrix.android.sdk.internal.util +package org.matrix.android.sdk.api import kotlinx.coroutines.CoroutineDispatcher -internal data class MatrixCoroutineDispatchers( +data class MatrixCoroutineDispatchers( val io: CoroutineDispatcher, val computation: CoroutineDispatcher, val main: CoroutineDispatcher, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index bde68da9d7..124d7d9dae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -20,6 +20,7 @@ import androidx.annotation.MainThread import androidx.lifecycle.LiveData import kotlinx.coroutines.flow.SharedFlow import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.federation.FederationService @@ -82,6 +83,8 @@ interface Session : SecureStorageService, AccountService { + val coroutineDispatchers: MatrixCoroutineDispatchers + /** * The params associated to the session */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt index ebe96b6382..6c0e730499 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/Room.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.api.session.room import androidx.lifecycle.LiveData +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.call.RoomCallService @@ -61,6 +62,8 @@ interface Room : RoomAccountDataService, RoomVersionService { + val coroutineDispatchers: MatrixCoroutineDispatchers + /** * The roomId of this room */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 7115ff5db2..7b96148e2e 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.crypto.MXCryptoConfig @@ -93,7 +94,6 @@ import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.util.JsonCanonicalizer -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.olm.OlmManager import timber.log.Timber import java.util.concurrent.atomic.AtomicBoolean diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt index 8a91376b60..494e6d7cc7 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel @@ -29,7 +30,6 @@ import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.sync.SyncTokenStore import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.logLimit import timber.log.Timber import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt index fe17dd08e4..70081ebdd7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -33,7 +34,6 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.extensions.foldToCallback import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber import javax.inject.Inject import kotlin.jvm.Throws diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt index 3825a5dab2..e7a46750b0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/InboundGroupSessionStore.kt @@ -19,10 +19,10 @@ package org.matrix.android.sdk.internal.crypto import android.util.LruCache import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.crypto.model.OlmInboundGroupSessionWrapper2 import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber import java.util.Timer import java.util.TimerTask diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt index e8640d5011..220f25ec80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/IncomingGossipingRequestManager.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.crypto.MXCryptoConfig import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME @@ -38,7 +39,6 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import timber.log.Timber import java.util.concurrent.Executors diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt index 6fc7103668..fd60e43260 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OutgoingGossipingRequestManager.kt @@ -19,13 +19,13 @@ package org.matrix.android.sdk.internal.crypto import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.createUniqueTxnId import org.matrix.android.sdk.internal.crypto.util.RequestIdHelper import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import timber.log.Timber import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index d2f6bd0382..d7411ad0be 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -41,7 +42,6 @@ import org.matrix.android.sdk.internal.crypto.model.rest.ForwardedRoomKeyContent import org.matrix.android.sdk.internal.crypto.model.rest.RoomKeyRequestBody import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber internal class MXMegolmDecryption(private val userId: String, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt index 91640523fc..29f9d193f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryptionFactory.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm import kotlinx.coroutines.CoroutineScope +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.OutgoingGossipingRequestManager @@ -25,7 +26,6 @@ import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.di.UserId -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class MXMegolmDecryptionFactory @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt index 63fe678229..031bb4e194 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryption.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event @@ -39,7 +40,6 @@ import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepo import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.util.JsonCanonicalizer -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.convertToUTF8 import timber.log.Timber diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt index 9f6312ea97..238d7eed88 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmEncryptionFactory.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm import kotlinx.coroutines.CoroutineScope +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction @@ -27,7 +28,6 @@ import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.tasks.SendToDeviceTask import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.UserId -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class MXMegolmEncryptionFactory @Inject constructor( diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt index 68a95e395b..50ce2d2bf3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmEncryptionFactory.kt @@ -16,12 +16,12 @@ package org.matrix.android.sdk.internal.crypto.algorithms.olm +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.crypto.DeviceListManager import org.matrix.android.sdk.internal.crypto.MXOlmDevice import org.matrix.android.sdk.internal.crypto.actions.EnsureOlmSessionsForUsersAction import org.matrix.android.sdk.internal.crypto.actions.MessageEncrypter import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class MXOlmEncryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt index 113255bb7e..b470ab34bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/ComputeTrustTask.kt @@ -16,13 +16,13 @@ package org.matrix.android.sdk.internal.crypto.crosssigning import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.task.Task -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal interface ComputeTrustTask : Task { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt index 8a851b1267..83de06a668 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt @@ -22,6 +22,7 @@ import androidx.work.ExistingWorkPolicy import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService @@ -42,7 +43,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.util.JsonCanonicalizer -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.logLimit import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.olm.OlmPkSigning diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt index c6e2c1217f..fe2de6aa9c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.Credentials import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.MatrixError @@ -83,7 +84,6 @@ import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskThread import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.util.JsonCanonicalizer -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.awaitCallback import org.matrix.olm.OlmException import org.matrix.olm.OlmPkDecryption diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt index ad3bc012df..e6d8b5e84f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/secrets/DefaultSharedSecretStorageService.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.secrets import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService @@ -44,7 +45,6 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.util.computeRecoveryKey import org.matrix.android.sdk.internal.crypto.tools.HkdfSha256 import org.matrix.android.sdk.internal.crypto.tools.withOlmDecryption import org.matrix.android.sdk.internal.di.UserId -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.olm.OlmPkMessage import java.security.SecureRandom import javax.crypto.Cipher diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt index 768109979d..388ecb9659 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/DefaultVerificationService.kt @@ -21,6 +21,7 @@ import android.os.Looper import dagger.Lazy import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.crosssigning.CrossSigningService import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME @@ -83,7 +84,6 @@ import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber import java.util.UUID import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt index 5bc519e960..81a067f2c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixComponent.kt @@ -24,6 +24,7 @@ import dagger.Component import okhttp3.OkHttpClient import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.HomeServerHistoryService import org.matrix.android.sdk.api.raw.RawService @@ -35,7 +36,6 @@ import org.matrix.android.sdk.internal.session.MockHttpInterceptor import org.matrix.android.sdk.internal.session.TestInterceptor import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.system.SystemModule import org.matrix.olm.OlmManager import java.io.File diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt index 4cd960f426..9cab307c61 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/MatrixModule.kt @@ -23,7 +23,7 @@ import dagger.Provides import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.android.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.createBackgroundHandler import org.matrix.olm.OlmManager import java.io.File diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt index 414c018074..46c5967876 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.completeWith import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.session.file.FileService @@ -33,7 +34,6 @@ import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments import org.matrix.android.sdk.internal.di.SessionDownloadsDirectory import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificateWithProgress import org.matrix.android.sdk.internal.session.download.DownloadProgressInterceptor.Companion.DOWNLOAD_PROGRESS_INTERCEPTOR_HEADER -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.file.AtomicFileCreator import org.matrix.android.sdk.internal.util.md5 import org.matrix.android.sdk.internal.util.writeToFile diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index d41bf8a702..7260517ec5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -22,6 +22,7 @@ import io.realm.RealmConfiguration import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.withContext import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.failure.GlobalError import org.matrix.android.sdk.api.federation.FederationService @@ -86,6 +87,7 @@ internal class DefaultSession @Inject constructor( private val globalErrorHandler: GlobalErrorHandler, @SessionId override val sessionId: String, + override val coroutineDispatchers: MatrixCoroutineDispatchers, @SessionDatabase private val realmConfiguration: RealmConfiguration, private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>, private val sessionListeners: SessionListeners, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt index 71031a4614..8ee3f44f20 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionComponent.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session import dagger.BindsInstance import dagger.Component +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.internal.crypto.CancelGossipRequestWorker @@ -62,7 +63,6 @@ import org.matrix.android.sdk.internal.session.user.UserModule import org.matrix.android.sdk.internal.session.user.accountdata.AccountDataModule import org.matrix.android.sdk.internal.session.widgets.WidgetModule import org.matrix.android.sdk.internal.task.TaskExecutor -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.system.SystemModule @Component(dependencies = [MatrixComponent::class], diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt index da37948cd4..37d9a4e74f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.LifecycleRegistry import dagger.Lazy import kotlinx.coroutines.withContext import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull @@ -51,7 +52,6 @@ import org.matrix.android.sdk.internal.session.profile.UnbindThreePidsTask import org.matrix.android.sdk.internal.session.sync.model.accountdata.IdentityServerContent import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask import org.matrix.android.sdk.internal.session.user.accountdata.UserAccountDataDataSource -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.ensureProtocol import timber.log.Timber import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index 386fec8256..a19832c523 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.LiveData import com.zhuinden.monarchy.Monarchy import io.realm.kotlin.where import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.profile.ProfileService @@ -35,7 +36,6 @@ import org.matrix.android.sdk.internal.session.content.FileUploader import org.matrix.android.sdk.internal.session.user.UserStore import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import javax.inject.Inject internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt index 8afd690f64..cb4bcdb606 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/DefaultRoom.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room import androidx.lifecycle.LiveData +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.Room @@ -71,7 +72,8 @@ internal class DefaultRoom(override val roomId: String, private val roomVersionService: RoomVersionService, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask + private val searchTask: SearchTask, + override val coroutineDispatchers: MatrixCoroutineDispatchers ) : Room, TimelineService by timelineService, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt index d44eb32529..4ab06338a2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomFactory.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.room +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.internal.session.SessionScope @@ -66,7 +67,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, private val sendStateTask: SendStateTask, private val viaParameterFinder: ViaParameterFinder, - private val searchTask: SearchTask) : + private val searchTask: SearchTask, + private val coroutineDispatchers: MatrixCoroutineDispatchers) : RoomFactory { override fun create(roomId: String): Room { @@ -92,7 +94,8 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService: roomVersionService = roomVersionServiceFactory.create(roomId), sendStateTask = sendStateTask, searchTask = searchTask, - viaParameterFinder = viaParameterFinder + viaParameterFinder = viaParameterFinder, + coroutineDispatchers = coroutineDispatchers ) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt index 046f8ba8ba..3867e0dc8d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/draft/DefaultDraftService.kt @@ -21,10 +21,10 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.room.send.DraftService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers internal class DefaultDraftService @AssistedInject constructor(@Assisted private val roomId: String, private val draftRepository: DraftRepository, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt index cce169c246..9480cc73f1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncService.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.launch import org.matrix.android.sdk.api.Matrix +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isTokenError import org.matrix.android.sdk.api.session.Session @@ -34,7 +35,6 @@ import org.matrix.android.sdk.internal.session.sync.SyncPresence import org.matrix.android.sdk.internal.session.sync.SyncTask import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import timber.log.Timber import java.net.SocketTimeoutException import java.util.concurrent.atomic.AtomicBoolean diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt index 86848d1018..57574a96fa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/task/TaskExecutor.kt @@ -21,10 +21,10 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.internal.di.MatrixScope import org.matrix.android.sdk.internal.extensions.foldToCallback -import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers import org.matrix.android.sdk.internal.util.toCancelable import timber.log.Timber import javax.inject.Inject diff --git a/settings.gradle b/settings.gradle index b88ea99b05..e3b84b4733 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,3 +5,4 @@ include ':diff-match-patch' include ':attachment-viewer' include ':multipicker' include ':library:ui-styles' +include ':matrix-sdk-android-flow' diff --git a/tools/templates/ElementFeature/root/src/app_package/ViewModel.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/ViewModel.kt.ftl index 8c25f9f9a8..64e6a0f83f 100644 --- a/tools/templates/ElementFeature/root/src/app_package/ViewModel.kt.ftl +++ b/tools/templates/ElementFeature/root/src/app_package/ViewModel.kt.ftl @@ -2,7 +2,7 @@ package ${escapeKotlinIdentifiers(packageName)} import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -27,7 +27,7 @@ class ${viewModelClass} @AssistedInject constructor(@Assisted initialState: ${vi fun create(initialState: ${viewStateClass}): ${viewModelClass} } - companion object : MvRxViewModelFactory<${viewModelClass}, ${viewStateClass}> { + companion object : MavericksViewModelFactory<${viewModelClass}, ${viewStateClass}> { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ${viewStateClass}): ${viewModelClass}? { diff --git a/tools/templates/ElementFeature/root/src/app_package/ViewState.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/ViewState.kt.ftl index 55e1f5f549..0acb3f78da 100644 --- a/tools/templates/ElementFeature/root/src/app_package/ViewState.kt.ftl +++ b/tools/templates/ElementFeature/root/src/app_package/ViewState.kt.ftl @@ -1,5 +1,5 @@ package ${escapeKotlinIdentifiers(packageName)} -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState -data class ${viewStateClass}() : MvRxState \ No newline at end of file +data class ${viewStateClass}() : MavericksState \ No newline at end of file diff --git a/vector/build.gradle b/vector/build.gradle index c6350a2812..a26de28099 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -298,6 +298,16 @@ android { kotlinOptions { jvmTarget = "11" + freeCompilerArgs += [ + "-Xopt-in=kotlin.RequiresOptIn", + // Fixes false positive "This is an internal Mavericks API. It is not intended for external use." + // of MvRx `by viewModel()` calls. Maybe due to the inlining of code... This is a temporary fix... + "-Xopt-in=com.airbnb.mvrx.InternalMavericksApi", + // Opt in for kotlinx.coroutines.FlowPreview too + "-Xopt-in=kotlinx.coroutines.FlowPreview", + // Opt in for kotlinx.coroutines.ExperimentalCoroutinesApi too + "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + ] } sourceSets { @@ -323,6 +333,7 @@ dependencies { implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android-rx") + implementation project(":matrix-sdk-android-flow") implementation project(":diff-match-patch") implementation project(":multipicker") implementation project(":attachment-viewer") @@ -376,7 +387,10 @@ dependencies { implementation libs.airbnb.epoxyGlide kapt libs.airbnb.epoxyProcessor implementation libs.airbnb.epoxyPaging - implementation libs.airbnb.mvrx + implementation libs.airbnb.mavericks + //TODO: remove when entirely migrated to Flow + implementation libs.airbnb.mavericksRx + // Work implementation libs.androidx.work @@ -458,7 +472,9 @@ dependencies { implementation "androidx.emoji:emoji-appcompat:1.1.0" - implementation 'com.github.BillCarsonFr:JsonViewer:0.6' + implementation ('com.github.BillCarsonFr:JsonViewer:0.6'){ + exclude group: 'com.airbnb.android' + } // WebRTC // org.webrtc:google-webrtc is for development purposes only @@ -498,6 +514,7 @@ dependencies { testImplementation libs.mockk.mockk // Plant Timber tree for test testImplementation libs.tests.timberJunitRule + testImplementation libs.airbnb.mavericksTesting // Activate when you want to check for leaks, from time to time. //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3' diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 240bbca908..090d1668a9 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -34,6 +34,7 @@ import androidx.lifecycle.ProcessLifecycleOwner import androidx.multidex.MultiDex import com.airbnb.epoxy.EpoxyAsyncUtil import com.airbnb.epoxy.EpoxyController +import com.airbnb.mvrx.Mavericks import com.facebook.stetho.Stetho import com.gabrielittner.threetenbp.LazyThreeTen import com.vanniktech.emoji.EmojiManager @@ -137,7 +138,7 @@ class VectorApplication : } logInfo() LazyThreeTen.init(this) - + Mavericks.initialize(debugMode = false) EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager)) diff --git a/vector/src/main/java/im/vector/app/core/extensions/Parcelable.kt b/vector/src/main/java/im/vector/app/core/extensions/Parcelable.kt index 6ca0144601..65f59f7b73 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Parcelable.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Parcelable.kt @@ -18,8 +18,8 @@ package im.vector.app.core.extensions import android.os.Bundle import android.os.Parcelable -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks fun Parcelable?.toMvRxBundle(): Bundle? { - return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } } + return this?.let { Bundle().apply { putParcelable(Mavericks.KEY_ARG, it) } } } diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index dc19520865..fbfba10d21 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -40,6 +40,7 @@ import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentManager import androidx.lifecycle.ViewModelProvider import androidx.viewbinding.ViewBinding +import com.airbnb.mvrx.MavericksView import com.bumptech.glide.util.Util import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.snackbar.Snackbar @@ -88,7 +89,7 @@ import timber.log.Timber import java.util.concurrent.TimeUnit import kotlin.system.measureTimeMillis -abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { +abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector, MavericksView { /* ========================================================================================== * View * ========================================================================================== */ @@ -576,6 +577,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasSc open fun initUiAndData() = Unit + override fun invalidate() = Unit + @StringRes open fun getTitleRes() = -1 diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt index b9b5bc8ca5..68765d615e 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -27,9 +27,8 @@ import android.widget.FrameLayout import androidx.annotation.CallSuper import androidx.lifecycle.ViewModelProvider import androidx.viewbinding.ViewBinding -import com.airbnb.mvrx.MvRx -import com.airbnb.mvrx.MvRxView -import com.airbnb.mvrx.MvRxViewId +import com.airbnb.mvrx.Mavericks +import com.airbnb.mvrx.MavericksView import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -44,12 +43,10 @@ import timber.log.Timber import java.util.concurrent.TimeUnit /** - * Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment) + * Add Mavericks capabilities, handle DI and bindings. */ -abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView { +abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MavericksView { - private val mvrxViewIdProperty = MvRxViewId() - final override val mvrxViewId: String by mvrxViewIdProperty private lateinit var screenComponent: ScreenComponent /* ========================================================================================== @@ -133,11 +130,6 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShe protected open fun injectWith(injector: ScreenComponent) = Unit - override fun onCreate(savedInstanceState: Bundle?) { - mvrxViewIdProperty.restoreFrom(savedInstanceState) - super.onCreate(savedInstanceState) - } - override fun onResume() { super.onResume() Timber.i("onResume BottomSheet ${javaClass.simpleName}") @@ -154,11 +146,6 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShe } } - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - mvrxViewIdProperty.saveTo(outState) - } - override fun onStart() { super.onStart() // This ensures that invalidate() is called for static screens that don't @@ -179,7 +166,7 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShe } protected fun setArguments(args: Parcelable? = null) { - arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } } + arguments = args?.let { Bundle().apply { putParcelable(Mavericks.KEY_ARG, it) } } } /* ========================================================================================== diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt index 2c9452c4fd..64b55291fb 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt @@ -27,9 +27,10 @@ import android.view.ViewGroup import androidx.annotation.CallSuper import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.viewbinding.ViewBinding -import com.airbnb.mvrx.BaseMvRxFragment +import com.airbnb.mvrx.MavericksView import com.bumptech.glide.util.Util.assertMainThread import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -49,7 +50,7 @@ import io.reactivex.disposables.Disposable import timber.log.Timber import java.util.concurrent.TimeUnit -abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector { +abstract class VectorBaseFragment : Fragment(), MavericksView, HasScreenInjector { protected val vectorBaseActivity: VectorBaseActivity<*> by lazy { activity as VectorBaseActivity<*> diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt b/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt index bca462a92b..6e7c24d4e9 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt @@ -20,17 +20,17 @@ import com.airbnb.mvrx.Async import com.airbnb.mvrx.BaseMvRxViewModel import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Success import im.vector.app.core.utils.DataSource import im.vector.app.core.utils.PublishDataSource import io.reactivex.Observable import io.reactivex.Single -abstract class VectorViewModel(initialState: S) : - BaseMvRxViewModel(initialState, false) { +abstract class VectorViewModel(initialState: S) : + BaseMvRxViewModel(initialState) { - interface Factory { + interface Factory { fun create(state: S): BaseMvRxViewModel } diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index bda32e528b..5e07bb76c6 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -25,7 +25,7 @@ import android.view.KeyEvent import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import androidx.media.session.MediaButtonReceiver -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import im.vector.app.core.extensions.vectorComponent import im.vector.app.features.call.CallArgs import im.vector.app.features.call.VectorCallActivity @@ -166,7 +166,7 @@ class CallService : VectorService() { val incomingCallAlert = IncomingCallAlert(callId, shouldBeDisplayedIn = { activity -> if (activity is VectorCallActivity) { - activity.intent.getParcelableExtra(MvRx.KEY_ARG)?.callId != call.callId + activity.intent.getParcelableExtra(Mavericks.KEY_ARG)?.callId != call.callId } else true } ).apply { diff --git a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericState.kt b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericState.kt index 38c81a7ef6..0f57600b13 100644 --- a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericState.kt +++ b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericState.kt @@ -16,6 +16,6 @@ package im.vector.app.core.ui.bottomsheet -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState -abstract class BottomSheetGenericState : MvRxState +abstract class BottomSheetGenericState : MavericksState diff --git a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericViewModel.kt b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericViewModel.kt index 6cc2c4c981..bde87a5588 100644 --- a/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericViewModel.kt +++ b/vector/src/main/java/im/vector/app/core/ui/bottomsheet/BottomSheetGenericViewModel.kt @@ -16,12 +16,12 @@ package im.vector.app.core.ui.bottomsheet -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -abstract class BottomSheetGenericViewModel(initialState: State) : +abstract class BottomSheetGenericViewModel(initialState: State) : VectorViewModel(initialState) { override fun handle(action: EmptyAction) { diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewViewState.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewViewState.kt index cee2a7ddd7..8b8208fc4f 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewViewState.kt @@ -17,14 +17,14 @@ package im.vector.app.features.attachments.preview -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.content.ContentAttachmentData data class AttachmentsPreviewViewState( val attachments: List, val currentAttachmentIndex: Int = 0, val sendImagesWithOriginalSize: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: AttachmentsPreviewArgs) : this(attachments = args.attachments) } diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt index ce23111a95..b7f570672b 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt @@ -26,7 +26,7 @@ import androidx.browser.customtabs.CustomTabsCallback import androidx.browser.customtabs.CustomTabsClient import androidx.browser.customtabs.CustomTabsServiceConnection import androidx.browser.customtabs.CustomTabsSession -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -78,7 +78,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { val title = intent.extras?.getString(EXTRA_REASON_TITLE) ?: getString(R.string.re_authentication_activity_title) supportActionBar?.setTitle(title) ?: run { setTitle(title) } -// val authArgs = intent.getParcelableExtra(MvRx.KEY_ARG) +// val authArgs = intent.getParcelableExtra(Mavericks.KEY_ARG) // For the sso flow we can for now only rely on the fallback flow, that handles all // the UI, due to the sandbox nature of CCT (chrome custom tab) we cannot get much information @@ -221,7 +221,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { } } return Intent(context, ReAuthActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode, resultKeyStoreAlias)) + putExtra(Mavericks.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode, resultKeyStoreAlias)) } } } diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt index 075ef758b8..733516c691 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.auth -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState data class ReAuthState( val title: String? = null, @@ -25,7 +25,7 @@ data class ReAuthState( val ssoFallbackPageWasShown: Boolean = false, val lastErrorCode: String? = null, val resultKeyStoreAlias: String = "" -) : MvRxState { +) : MavericksState { constructor(args: ReAuthActivity.Args) : this( args.title, args.session, diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt index edbceae20f..449270644e 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.auth import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -39,7 +39,7 @@ class ReAuthViewModel @AssistedInject constructor( fun create(initialState: ReAuthState): ReAuthViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: ReAuthState): ReAuthViewModel? { val factory = when (viewModelContext) { diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 42e14efad3..0654942d4b 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -36,7 +36,7 @@ import androidx.core.content.getSystemService import androidx.core.view.isInvisible import androidx.core.view.isVisible import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState import com.google.android.material.card.MaterialCardView @@ -139,7 +139,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro renderState(it) } - callViewModel.asyncSubscribe(this, VectorCallViewState::callState) { + callViewModel.onAsync(VectorCallViewState::callState) { if (it is CallState.Ended) { handleCallEnded(it) } @@ -153,7 +153,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } .disposeOnDestroy() - callViewModel.selectSubscribe(this, VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall -> + callViewModel.onEach(VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall -> if (isVideoCall) { if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_camera_and_audio)) { setupRenderersIfNeeded() @@ -168,8 +168,8 @@ class VectorCallActivity : VectorBaseActivity(), CallContro override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) - intent?.takeIf { it.hasExtra(MvRx.KEY_ARG) } - ?.let { intent.getParcelableExtra(MvRx.KEY_ARG) } + intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) } + ?.let { intent.getParcelableExtra(Mavericks.KEY_ARG) } ?.let { callViewModel.handle(VectorCallViewActions.SwitchCall(it)) } @@ -631,10 +631,11 @@ class VectorCallActivity : VectorBaseActivity(), CallContro const val INCOMING_ACCEPT = "INCOMING_ACCEPT" fun newIntent(context: Context, call: WebRtcCall, mode: String?): Intent { + val callArgs = CallArgs(call.nativeRoomId, call.callId, call.mxCall.opponentUserId, !call.mxCall.isOutgoing, call.mxCall.isVideoCall) return Intent(context, VectorCallActivity::class.java).apply { // what could be the best flags? flags = Intent.FLAG_ACTIVITY_NEW_TASK - putExtra(MvRx.KEY_ARG, CallArgs(call.nativeRoomId, call.callId, call.mxCall.opponentUserId, !call.mxCall.isOutgoing, call.mxCall.isVideoCall)) + putExtra(Mavericks.KEY_ARG, callArgs) putExtra(EXTRA_MODE, mode) } } @@ -646,10 +647,11 @@ class VectorCallActivity : VectorBaseActivity(), CallContro isIncomingCall: Boolean, isVideoCall: Boolean, mode: String?): Intent { + val callArgs = CallArgs(signalingRoomId, callId, otherUserId, isIncomingCall, isVideoCall) return Intent(context, VectorCallActivity::class.java).apply { // what could be the best flags? flags = Intent.FLAG_ACTIVITY_NEW_TASK - putExtra(MvRx.KEY_ARG, CallArgs(signalingRoomId, callId, otherUserId, isIncomingCall, isVideoCall)) + putExtra(Mavericks.KEY_ARG, callArgs) putExtra(EXTRA_MODE, mode) } } diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 90df595f8f..d8aaca9bd8 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -19,7 +19,7 @@ package im.vector.app.features.call import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -345,7 +345,7 @@ class VectorCallViewModel @AssistedInject constructor( fun create(initialState: VectorCallViewState): VectorCallViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: VectorCallViewState): VectorCallViewModel { diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt index a351806e1a..2d33cbf9b9 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.call import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.call.audio.CallAudioManager import org.matrix.android.sdk.api.session.call.CallState @@ -43,7 +43,7 @@ data class VectorCallViewState( val formattedDuration: String = "", val canOpponentBeTransferred: Boolean = false, val transferee: TransfereeState = TransfereeState.NoTransferee -) : MvRxState { +) : MavericksState { sealed class TransfereeState { object NoTransferee : TransfereeState() diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt index 0b86114f6c..c46b4e459d 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewModel.kt @@ -16,9 +16,10 @@ package im.vector.app.features.call.conference +import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -27,14 +28,16 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.widgets.model.Widget import org.matrix.android.sdk.api.session.widgets.model.WidgetType -import org.matrix.android.sdk.rx.asObservable class JitsiCallViewModel @AssistedInject constructor( @Assisted initialState: JitsiCallViewState, @@ -47,7 +50,7 @@ class JitsiCallViewModel @AssistedInject constructor( fun create(initialState: JitsiCallViewState): JitsiCallViewModel } - private var currentWidgetObserver: Disposable? = null + private var currentWidgetObserver: Job? = null private val widgetService = session.widgetService() private var confIsJoined = false @@ -59,11 +62,11 @@ class JitsiCallViewModel @AssistedInject constructor( private fun observeWidget(roomId: String, widgetId: String) { confIsJoined = false - currentWidgetObserver?.dispose() + currentWidgetObserver?.cancel() currentWidgetObserver = widgetService.getRoomWidgetsLive(roomId, QueryStringValue.Equals(widgetId), WidgetType.Jitsi.values()) - .asObservable() + .asFlow() .distinctUntilChanged() - .subscribe { + .onEach { val jitsiWidget = it.firstOrNull() if (jitsiWidget != null) { setState { @@ -81,7 +84,7 @@ class JitsiCallViewModel @AssistedInject constructor( } } } - .disposeOnClear() + .launchIn(viewModelScope) } private fun joinConference(jitsiWidget: Widget) = withState { state -> @@ -140,7 +143,7 @@ class JitsiCallViewModel @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { const val ENABLE_VIDEO_OPTION = "ENABLE_VIDEO_OPTION" diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt index 1fd04542e0..d4c70d7333 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiCallViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.call.conference import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -26,4 +26,4 @@ data class JitsiCallViewState( val widgetId: String = "", val enableVideo: Boolean = false, val widget: Async = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index e7fd541f3d..62d017467f 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -28,7 +28,7 @@ import android.widget.Toast import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import com.airbnb.mvrx.Fail -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Success import com.airbnb.mvrx.viewModel import com.facebook.react.modules.core.PermissionListener @@ -205,8 +205,8 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee JitsiMeetActivityDelegate.onNewIntent(intent) // Is it a switch to another conf? - intent?.takeIf { it.hasExtra(MvRx.KEY_ARG) } - ?.let { intent.getParcelableExtra(MvRx.KEY_ARG) } + intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) } + ?.let { intent.getParcelableExtra(Mavericks.KEY_ARG) } ?.let { jitsiViewModel.handle(JitsiCallViewActions.SwitchTo(it, true)) } @@ -242,7 +242,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee companion object { fun newIntent(context: Context, roomId: String, widgetId: String, enableVideo: Boolean): Intent { return Intent(context, VectorJitsiActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, Args(roomId, widgetId, enableVideo)) + putExtra(Mavericks.KEY_ARG, Args(roomId, widgetId, enableVideo)) } } } diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt index c80b21334a..2a50dc85f9 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt @@ -20,7 +20,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.tabs.TabLayoutMediator import im.vector.app.R @@ -121,7 +121,7 @@ class CallTransferActivity : VectorBaseActivity(), fun newIntent(context: Context, callId: String): Intent { return Intent(context, CallTransferActivity::class.java).also { - it.putExtra(MvRx.KEY_ARG, CallTransferArgs(callId)) + it.putExtra(Mavericks.KEY_ARG, CallTransferArgs(callId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt index ceb2682ca8..a26b03a3aa 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.call.transfer import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -45,7 +45,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState: fun create(initialState: CallTransferViewState): CallTransferViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CallTransferViewState): CallTransferViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewState.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewState.kt index 2b29d9f6f2..babda1dd19 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewState.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewState.kt @@ -16,11 +16,11 @@ package im.vector.app.features.call.transfer -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState data class CallTransferViewState( val callId: String -) : MvRxState { +) : MavericksState { constructor(args: CallTransferArgs) : this(callId = args.callId) } diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt index e3d996c33b..6b5a6465a6 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -49,7 +49,7 @@ class ContactsBookViewModel @AssistedInject constructor(@Assisted fun create(initialState: ContactsBookViewState): ContactsBookViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: ContactsBookViewState): ContactsBookViewModel? { val factory = when (viewModelContext) { @@ -66,7 +66,7 @@ class ContactsBookViewModel @AssistedInject constructor(@Assisted init { loadContacts() - selectSubscribe(ContactsBookViewState::searchTerm, ContactsBookViewState::onlyBoundContacts) { _, _ -> + onEach(ContactsBookViewState::searchTerm, ContactsBookViewState::onlyBoundContacts) { _, _ -> updateFilteredMappedContacts() } } diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewState.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewState.kt index d2ee684c4d..d4f279787d 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewState.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.contactsbook import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import im.vector.app.core.contacts.MappedContact data class ContactsBookViewState( @@ -36,4 +36,4 @@ data class ContactsBookViewState( val identityServerUrl: String? = null, // User consent to perform lookup (send emails to the identity server) val userConsent: Boolean = false -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index b91ecf0cfe..ae3af4b3e9 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -102,7 +102,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac ) ) } - viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) { + viewModel.onEach(CreateDirectRoomViewState::createAndInviteState) { renderCreateAndInviteState(it) } } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt index f192ea3019..347dcdc410 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -49,7 +49,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted fun create(initialState: CreateDirectRoomViewState): CreateDirectRoomViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CreateDirectRoomViewState): CreateDirectRoomViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewState.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewState.kt index 27a8cc0a97..41366a7110 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomViewState.kt @@ -17,9 +17,9 @@ package im.vector.app.features.createdirect import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class CreateDirectRoomViewState( val createAndInviteState: Async = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt index d78fa37d62..716f02369a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt @@ -55,7 +55,7 @@ class KeysBackupManageActivity : SimpleFragmentActivity() { } // Observe the deletion of keys backup - viewModel.selectSubscribe(this, KeysBackupSettingViewState::deleteBackupRequest) { asyncDelete -> + viewModel.onEach(KeysBackupSettingViewState::deleteBackupRequest) { asyncDelete -> when (asyncDelete) { is Fail -> { updateWaitingView(null) diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingViewState.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingViewState.kt index fa701f2810..438b502b42 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.crypto.keysbackup.settings import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.internal.crypto.keysbackup.model.KeysBackupVersionTrust @@ -27,4 +27,4 @@ data class KeysBackupSettingViewState(val keysBackupVersionTrust: Async = Uninitialized) : - MvRxState + MavericksState diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt index d47416dd38..6814b376c2 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.crypto.keysbackup.settings import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -45,7 +45,7 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS fun create(initialState: KeysBackupSettingViewState): KeysBackupSettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: KeysBackupSettingViewState): KeysBackupSettingsViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt index 51159e62bf..bd7195ad1e 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt @@ -25,7 +25,7 @@ import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentOnAttachListener -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R @@ -159,7 +159,7 @@ class SharedSecureStorageActivity : resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent { require(requestedSecrets.isNotEmpty()) return Intent(context, SharedSecureStorageActivity::class.java).also { - it.putExtra(MvRx.KEY_ARG, Args( + it.putExtra(Mavericks.KEY_ARG, Args( keyId, requestedSecrets, resultKeyStoreAlias diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt index e3258c40ec..bb4d4ce99a 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt @@ -16,13 +16,12 @@ package im.vector.app.features.crypto.quads -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRx -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Mavericks +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -35,6 +34,7 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.resources.StringProvider import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.listeners.ProgressListener @@ -42,8 +42,8 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.securestorage.IntegrityResult import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding -import org.matrix.android.sdk.rx.rx import timber.log.Timber import java.io.ByteArrayOutputStream @@ -55,7 +55,7 @@ data class SharedSecureStorageViewState( val activeDeviceCount: Int = 0, val showResetAllAction: Boolean = false, val userId: String = "" -) : MvRxState { +) : MavericksState { enum class Step { EnterPassphrase, EnterKey, @@ -114,7 +114,7 @@ class SharedSecureStorageViewModel @AssistedInject constructor( } } - session.rx() + session.flow() .liveUserCryptoDevices(session.myUserId) .distinctUntilChanged() .execute { @@ -320,12 +320,12 @@ class SharedSecureStorageViewModel @AssistedInject constructor( _viewEvents.post(SharedSecureStorageViewEvent.Dismiss) } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: SharedSecureStorageViewState): SharedSecureStorageViewModel? { val activity: SharedSecureStorageActivity = viewModelContext.activity() - val args: SharedSecureStorageActivity.Args = activity.intent.getParcelableExtra(MvRx.KEY_ARG) ?: error("Missing args") + val args: SharedSecureStorageActivity.Args = activity.intent.getParcelableExtra(Mavericks.KEY_ARG) ?: error("Missing args") return activity.viewModelFactory.create(state, args) } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index 17a1359ea6..d208a92545 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -552,7 +552,7 @@ class BootstrapSharedViewModel @AssistedInject constructor( // Companion, view model assisted creation // ====================================== - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: BootstrapViewState): BootstrapSharedViewModel? { val fragment: BootstrapBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt index 4e94ddf0bf..b8c9f10b49 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.crypto.recover import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import com.nulabinc.zxcvbn.Strength import im.vector.app.core.platform.WaitingViewData @@ -34,4 +34,4 @@ data class BootstrapViewState( val recoveryKeyCreationInfo: SsssKeyCreationInfo? = null, val initializationWaitingViewData: WaitingViewData? = null, val recoverySaveFileProcess: Async = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt index 3b392780ef..e6abf13f8d 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt @@ -24,7 +24,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -185,7 +185,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment { showFragment(VerificationEmojiCodeFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationArgs( + putParcelable(Mavericks.KEY_ARG, VerificationArgs( state.otherUserMxItem?.id ?: "", // If it was outgoing it.transaction id would be null, but the pending request // would be updated (from localId to txId) @@ -245,12 +245,12 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment { showFragment(VerificationConclusionFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe)) + putParcelable(Mavericks.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe)) }) } is VerificationTxState.Cancelled -> { showFragment(VerificationConclusionFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(false, state.sasTransactionState.cancelCode.value, state.isMe)) + putParcelable(Mavericks.KEY_ARG, VerificationConclusionFragment.Args(false, state.sasTransactionState.cancelCode.value, state.isMe)) }) } } @@ -266,7 +266,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment { showFragment(VerificationQRWaitingFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationQRWaitingFragment.Args( + putParcelable(Mavericks.KEY_ARG, VerificationQRWaitingFragment.Args( isMe = state.isMe, otherUserName = state.otherUserMxItem?.getBestName() ?: "" )) @@ -275,13 +275,13 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment { showFragment(VerificationConclusionFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe)) + putParcelable(Mavericks.KEY_ARG, VerificationConclusionFragment.Args(true, null, state.isMe)) }) return@withState } is VerificationTxState.Cancelled -> { showFragment(VerificationConclusionFragment::class, Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationConclusionFragment.Args(false, state.qrTransactionState.cancelCode.value, state.isMe)) + putParcelable(Mavericks.KEY_ARG, VerificationConclusionFragment.Args(false, state.qrTransactionState.cancelCode.value, state.isMe)) }) return@withState } @@ -295,7 +295,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: VerificationBottomSheetViewState): VerificationBottomSheetViewModel? { val fragment: VerificationBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt index a6825348e9..990a204bc1 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt @@ -16,8 +16,8 @@ package im.vector.app.features.crypto.verification.choose import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -43,7 +43,7 @@ data class VerificationChooseMethodViewState( val sasModeAvailable: Boolean = false, val isMe: Boolean = false, val canCrossSign: Boolean = false -) : MvRxState +) : MavericksState class VerificationChooseMethodViewModel @AssistedInject constructor( @Assisted initialState: VerificationChooseMethodViewState, @@ -94,7 +94,7 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( super.onCleared() } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: VerificationChooseMethodViewState): VerificationChooseMethodViewModel? { val fragment: VerificationChooseMethodFragment = (viewModelContext as FragmentViewModelContext).fragment() return fragment.verificationChooseMethodViewModelFactory.create(state) diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt index 2708aa0961..82bdbccdb3 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/conclusion/VerificationConclusionViewModel.kt @@ -15,8 +15,8 @@ */ package im.vector.app.features.crypto.verification.conclusion -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents @@ -27,7 +27,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf data class VerificationConclusionViewState( val conclusionState: ConclusionState = ConclusionState.CANCELLED, val isSelfVerification: Boolean = false -) : MvRxState +) : MavericksState enum class ConclusionState { SUCCESS, @@ -38,7 +38,7 @@ enum class ConclusionState { class VerificationConclusionViewModel(initialState: VerificationConclusionViewState) : VectorViewModel(initialState) { - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun initialState(viewModelContext: ViewModelContext): VerificationConclusionViewState? { val args = viewModelContext.args() diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt index 1795d120f3..f1e3d1b805 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/emoji/VerificationEmojiCodeViewModel.kt @@ -19,8 +19,8 @@ import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -48,7 +48,7 @@ data class VerificationEmojiCodeViewState( val emojiDescription: Async> = Uninitialized, val decimalDescription: Async = Uninitialized, val isWaitingFromOther: Boolean = false -) : MvRxState +) : MavericksState class VerificationEmojiCodeViewModel @AssistedInject constructor( @Assisted initialState: VerificationEmojiCodeViewState, @@ -155,7 +155,7 @@ class VerificationEmojiCodeViewModel @AssistedInject constructor( fun create(initialState: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: VerificationEmojiCodeViewState): VerificationEmojiCodeViewModel? { val factory = (viewModelContext as FragmentViewModelContext).fragment().viewModelFactory diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt index 12a136f70c..441885dd10 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/qrconfirmation/VerificationQRWaitingFragment.kt @@ -21,7 +21,7 @@ import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.VectorBaseFragment @@ -46,7 +46,7 @@ class VerificationQRWaitingFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView() - (arguments?.getParcelable(MvRx.KEY_ARG) as? Args)?.let { + (arguments?.getParcelable(Mavericks.KEY_ARG) as? Args)?.let { controller.update(it) } } diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt index bcdcf5f719..2686722c6e 100644 --- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt +++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolActivity.kt @@ -27,7 +27,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.viewModel @@ -208,7 +208,7 @@ class RoomDevToolActivity : SimpleFragmentActivity(), RoomDevToolViewModel.Facto fun intent(context: Context, roomId: String): Intent { return Intent(context, RoomDevToolActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, Args(roomId)) + putExtra(Mavericks.KEY_ARG, Args(roomId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt index 9fffe70872..023d1976c9 100644 --- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.squareup.moshi.Types @@ -40,8 +40,8 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.di.MoshiProvider -import org.matrix.android.sdk.rx.rx class RoomDevToolViewModel @AssistedInject constructor( @Assisted val initialState: RoomDevToolViewState, @@ -55,7 +55,7 @@ class RoomDevToolViewModel @AssistedInject constructor( fun create(initialState: RoomDevToolViewState): RoomDevToolViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomDevToolViewState): RoomDevToolViewModel { @@ -69,7 +69,7 @@ class RoomDevToolViewModel @AssistedInject constructor( init { session.getRoom(initialState.roomId) - ?.rx() + ?.flow() ?.liveStateEvents(emptySet()) ?.execute { async -> copy(stateEvents = async) diff --git a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewState.kt b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewState.kt index 885de005b0..a5b7db9821 100644 --- a/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewState.kt +++ b/vector/src/main/java/im/vector/app/features/devtools/RoomDevToolViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.devtools import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.events.model.Event @@ -31,7 +31,7 @@ data class RoomDevToolViewState( val editedContent: String? = null, val modalLoading: Async = Uninitialized, val sendEventDraft: SendEventDraft? = null -) : MvRxState { +) : MavericksState { constructor(args: RoomDevToolActivity.Args) : this(roomId = args.roomId, displayMode = Mode.Root) diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsState.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsState.kt index 1d7346e463..3f5be60f2e 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsState.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.discovery import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class DiscoverySettingsState( @@ -28,7 +28,7 @@ data class DiscoverySettingsState( val termsNotSigned: Boolean = false, val userConsent: Boolean = false, val isIdentityPolicyUrlsExpanded: Boolean = false -) : MvRxState +) : MavericksState data class IdentityServerWithTerms( val serverUrl: String, diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt index 8b454607d5..66f38928a7 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt @@ -15,12 +15,11 @@ */ package im.vector.app.features.discovery -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -32,6 +31,8 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.ensureProtocol +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.identity.IdentityServiceError @@ -39,7 +40,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityServiceListener import org.matrix.android.sdk.api.session.identity.SharedState import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.terms.TermsService -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow class DiscoverySettingsViewModel @AssistedInject constructor( @Assisted initialState: DiscoverySettingsState, @@ -52,7 +53,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( fun create(initialState: DiscoverySettingsState): DiscoverySettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DiscoverySettingsState): DiscoverySettingsViewModel? { @@ -96,12 +97,12 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } private fun observeThreePids() { - session.rx() + session.flow() .liveThreePIds(true) - .subscribe { + .onEach { retrieveBinding(it) } - .disposeOnClear() + .launchIn(viewModelScope) } override fun onCleared() { diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerState.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerState.kt index 4c2f437e07..558cc4dcf7 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerState.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerState.kt @@ -16,10 +16,10 @@ package im.vector.app.features.discovery.change -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState data class SetIdentityServerState( val homeServerUrl: String = "", // Will contain the default identity server url if any val defaultIdentityServerUrl: String? = null -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt index a63ec22110..8921f0691d 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerViewModel.kt @@ -17,7 +17,7 @@ package im.vector.app.features.discovery.change import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -46,7 +46,7 @@ class SetIdentityServerViewModel @AssistedInject constructor( fun create(initialState: SetIdentityServerState): SetIdentityServerViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun initialState(viewModelContext: ViewModelContext): SetIdentityServerState? { val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession() diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 3d264104c3..ff1154acc3 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -29,7 +29,8 @@ import androidx.core.view.isVisible import androidx.drawerlayout.widget.DrawerLayout import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import com.airbnb.mvrx.MvRx +import androidx.lifecycle.lifecycleScope +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -73,7 +74,7 @@ import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import im.vector.app.features.workers.signout.ServerBackupStatusViewState import im.vector.app.push.fcm.FcmHelper -import io.reactivex.android.schedulers.AndroidSchedulers +import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.permalinks.PermalinkService @@ -248,7 +249,7 @@ class HomeActivity : } .disposeOnDestroy() - val args = intent.getParcelableExtra(MvRx.KEY_ARG) + val args = intent.getParcelableExtra(Mavericks.KEY_ARG) if (args?.clearNotification == true) { notificationDrawerManager.clearAllEvents() @@ -308,26 +309,24 @@ class HomeActivity : } else -> deepLink } - permalinkHandler.launch( - context = this, - deepLink = resolvedLink, - navigationInterceptor = this, - buildTask = true - ) - // .delay(500, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { isHandled -> - if (!isHandled) { - val isMatrixToLink = deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE) || - deepLink.startsWith(MATRIX_TO_CUSTOM_SCHEME_URL_BASE) - MaterialAlertDialogBuilder(this) - .setTitle(R.string.dialog_title_error) - .setMessage(if (isMatrixToLink) R.string.permalink_malformed else R.string.universal_link_malformed) - .setPositiveButton(R.string.ok, null) - .show() - } - } - .disposeOnDestroy() + + lifecycleScope.launch { + val isHandled = permalinkHandler.launch( + context = this@HomeActivity, + deepLink = resolvedLink, + navigationInterceptor = this@HomeActivity, + buildTask = true + ) + if (!isHandled) { + val isMatrixToLink = deepLink.startsWith(PermalinkService.MATRIX_TO_URL_BASE) || + deepLink.startsWith(MATRIX_TO_CUSTOM_SCHEME_URL_BASE) + MaterialAlertDialogBuilder(this@HomeActivity) + .setTitle(R.string.dialog_title_error) + .setMessage(if (isMatrixToLink) R.string.permalink_malformed else R.string.universal_link_malformed) + .setPositiveButton(R.string.ok, null) + .show() + } + } } } @@ -453,7 +452,7 @@ class HomeActivity : override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) - val parcelableExtra = intent?.getParcelableExtra(MvRx.KEY_ARG) + val parcelableExtra = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (parcelableExtra?.clearNotification == true) { notificationDrawerManager.clearAllEvents() } @@ -586,7 +585,7 @@ class HomeActivity : return Intent(context, HomeActivity::class.java) .apply { - putExtra(MvRx.KEY_ARG, args) + putExtra(Mavericks.KEY_ARG, args) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index be8b0cbc61..627ff4be12 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -16,9 +16,10 @@ package im.vector.app.features.home +import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope -import com.airbnb.mvrx.MvRx -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Mavericks +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -31,6 +32,8 @@ import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor @@ -44,11 +47,10 @@ import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.MXUsersDevicesMap import org.matrix.android.sdk.internal.util.awaitCallback -import org.matrix.android.sdk.rx.asObservable -import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -67,12 +69,12 @@ class HomeActivityViewModel @AssistedInject constructor( fun create(initialState: HomeActivityViewState, args: HomeActivityArgs): HomeActivityViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: HomeActivityViewState): HomeActivityViewModel? { val activity: HomeActivity = viewModelContext.activity() - val args: HomeActivityArgs? = activity.intent.getParcelableExtra(MvRx.KEY_ARG) + val args: HomeActivityArgs? = activity.intent.getParcelableExtra(Mavericks.KEY_ARG) return activity.viewModelFactory.create(state, args ?: HomeActivityArgs(clearNotification = false, accountCreation = false)) } } @@ -100,9 +102,9 @@ class HomeActivityViewModel @AssistedInject constructor( .crossSigningService().allPrivateKeysKnown() safeActiveSession - .rx() + .flow() .liveCrossSigningInfo(safeActiveSession.myUserId) - .subscribe { + .onEach { val isVerified = it.getOrNull()?.isTrusted() ?: false if (!isVerified && onceTrusted) { // cross signing keys have been reset @@ -116,15 +118,15 @@ class HomeActivityViewModel @AssistedInject constructor( } onceTrusted = isVerified } - .disposeOnClear() + .launchIn(viewModelScope) } private fun observeInitialSync() { val session = activeSessionHolder.getSafeActiveSession() ?: return session.getSyncStatusLive() - .asObservable() - .subscribe { status -> + .asFlow() + .onEach { status -> when (status) { is SyncStatusService.Status.Progressing -> { // Schedule a check of the bootstrap when the init sync will be finished @@ -145,7 +147,7 @@ class HomeActivityViewModel @AssistedInject constructor( ) } } - .disposeOnClear() + .launchIn(viewModelScope) } /** diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewState.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewState.kt index f3bddaf0d2..68131e8569 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewState.kt @@ -16,9 +16,9 @@ package im.vector.app.features.home -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.initsync.SyncStatusService data class HomeActivityViewState( val syncStatusServiceStatus: SyncStatusService.Status = SyncStatusService.Status.Idle -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 24677cf940..c8fff5605b 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -134,7 +134,7 @@ class HomeDetailFragment @Inject constructor( views.bottomNavigationView.selectedItemId = it.currentTab.toMenuId() } - viewModel.selectSubscribe(this, HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod -> + viewModel.onEach(HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod -> when (roomGroupingMethod) { is RoomGroupingMethod.ByLegacyGroup -> { onGroupChange(roomGroupingMethod.groupSummary) @@ -145,11 +145,11 @@ class HomeDetailFragment @Inject constructor( } } - viewModel.selectSubscribe(this, HomeDetailViewState::currentTab) { currentTab -> + viewModel.onEach(HomeDetailViewState::currentTab) { currentTab -> updateUIForTab(currentTab) } - viewModel.selectSubscribe(this, HomeDetailViewState::showDialPadTab) { showDialPadTab -> + viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab -> updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab) } @@ -161,7 +161,7 @@ class HomeDetailFragment @Inject constructor( } } - unknownDeviceDetectorSharedViewModel.subscribe { state -> + unknownDeviceDetectorSharedViewModel.onEach { state -> state.unknownSessions.invoke()?.let { unknownDevices -> // Timber.v("## Detector Triggerred in fragment - ${unknownDevices.firstOrNull()}") if (unknownDevices.firstOrNull()?.currentSessionTrust == true) { @@ -179,7 +179,7 @@ class HomeDetailFragment @Inject constructor( } } - unreadMessagesSharedViewModel.subscribe { state -> + unreadMessagesSharedViewModel.onEach { state -> views.drawerUnreadCounterBadgeView.render( UnreadCounterBadgeView.State( count = state.otherSpacesUnread.totalCount, diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt index 494a414832..d981a29fec 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewModel.kt @@ -16,9 +16,9 @@ package im.vector.app.features.home -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.asFlow import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -38,6 +38,7 @@ import im.vector.app.features.ui.UiStateRepository import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter @@ -47,8 +48,8 @@ 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.roomSummaryQueryParams import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.rx.asObservable -import org.matrix.android.sdk.rx.rx import timber.log.Timber import java.util.concurrent.TimeUnit @@ -72,7 +73,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho fun create(initialState: HomeDetailViewState): HomeDetailViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun initialState(viewModelContext: ViewModelContext): HomeDetailViewState? { val uiStateRepository = (viewModelContext.activity as HasScreenInjector).injector().uiStateRepository() @@ -95,7 +96,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho updateShowDialPadTab() observeDataStore() callManager.addProtocolsCheckerListener(this) - session.rx().liveUser(session.myUserId).execute { + session.flow().liveUser(session.myUserId).execute { copy( myMatrixItem = it.invoke()?.getOrNull()?.toMatrixItem() ) @@ -182,25 +183,18 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho } private fun observeSyncState() { - session.rx() + session.flow() .liveSyncState() - .subscribe { syncState -> - setState { - copy(syncState = syncState) - } + .setOnEach { syncState -> + copy(syncState = syncState) } - .disposeOnClear() session.getSyncStatusLive() - .asObservable() - .subscribe { - if (it is SyncStatusService.Status.IncrementalSyncStatus) { - setState { - copy(incrementalSyncStatus = it) - } - } + .asFlow() + .filterIsInstance() + .setOnEach { + copy(incrementalSyncStatus = it) } - .disposeOnClear() } private fun observeRoomGroupingMethod() { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt index 4022a0d9fb..7665dd41e5 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.home import androidx.annotation.StringRes import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.RoomGroupingMethod @@ -43,7 +43,7 @@ data class HomeDetailViewState( val incrementalSyncStatus: SyncStatusService.Status.IncrementalSyncStatus = SyncStatusService.Status.IncrementalSyncIdle, val pushCounter: Int = 0, val showDialPadTab: Boolean = false -) : MvRxState +) : MavericksState sealed class HomeTab(@StringRes val titleRes: Int) { data class RoomList(val displayMode: RoomListDisplayMode) : HomeTab(displayMode.titleRes) diff --git a/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt index ae7b495aa2..0c8c9e480c 100644 --- a/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/PromoteRestrictedViewModel.kt @@ -18,8 +18,8 @@ package im.vector.app.features.home import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -41,7 +41,7 @@ data class ActiveSpaceViewState( val isInSpaceMode: Boolean = false, val activeSpaceSummary: RoomSummary? = null, val canUserManageSpace: Boolean = false -) : MvRxState +) : MavericksState class PromoteRestrictedViewModel @AssistedInject constructor( @Assisted initialState: ActiveSpaceViewState, @@ -76,7 +76,7 @@ class PromoteRestrictedViewModel @AssistedInject constructor( fun create(initialState: ActiveSpaceViewState): PromoteRestrictedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ActiveSpaceViewState): PromoteRestrictedViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt index b88fe141ec..36e31770a9 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnknownDeviceDetectorSharedViewModel.kt @@ -19,8 +19,8 @@ package im.vector.app.features.home import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -31,24 +31,24 @@ import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.features.settings.VectorPreferences -import io.reactivex.Observable +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.sample import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.MatrixItem -import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo -import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo -import org.matrix.android.sdk.rx.rx import timber.log.Timber -import java.util.concurrent.TimeUnit data class UnknownDevicesState( val myMatrixItem: MatrixItem.UserItem? = null, val unknownSessions: Async> = Uninitialized -) : MvRxState +) : MavericksState data class DeviceDetectionInfo( val deviceInfo: DeviceInfo, @@ -70,7 +70,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted fun create(initialState: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: UnknownDevicesState): UnknownDeviceDetectorSharedViewModel? { @@ -98,31 +98,30 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted } ) - Observable.combineLatest, List, Optional, List>( - session.rx().liveUserCryptoDevices(session.myUserId), - session.rx().liveMyDevicesInfo(), - session.rx().liveCrossSigningPrivateKeys(), - { cryptoList, infoList, pInfo -> - // Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}") + combine( + session.flow().liveUserCryptoDevices(session.myUserId), + session.flow().liveMyDevicesInfo(), + session.flow().liveCrossSigningPrivateKeys() + ) { cryptoList, infoList, pInfo -> + // Timber.v("## Detector trigger ${cryptoList.map { "${it.deviceId} ${it.trustLevel}" }}") // Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}") - infoList - .filter { info -> - // filter verified session, by checking the crypto device info - cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse() - } - // filter out ignored devices - .filter { !ignoredDeviceList.contains(it.deviceId) } - .sortedByDescending { it.lastSeenTs } - .map { deviceInfo -> - val deviceKnownSince = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }?.firstTimeSeenLocalTs ?: 0 - DeviceDetectionInfo( - deviceInfo, - deviceKnownSince > currentSessionTs + 60_000, // short window to avoid false positive, - pInfo.getOrNull()?.selfSigned != null // adding this to pass distinct when cross sign change - ) - } - } - ) + infoList + .filter { info -> + // filter verified session, by checking the crypto device info + cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse() + } + // filter out ignored devices + .filter { !ignoredDeviceList.contains(it.deviceId) } + .sortedByDescending { it.lastSeenTs } + .map { deviceInfo -> + val deviceKnownSince = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId }?.firstTimeSeenLocalTs ?: 0 + DeviceDetectionInfo( + deviceInfo, + deviceKnownSince > currentSessionTs + 60_000, // short window to avoid false positive, + pInfo.getOrNull()?.selfSigned != null // adding this to pass distinct when cross sign change + ) + } + } .distinctUntilChanged() .execute { async -> // Timber.v("## Detector trigger passed distinct") @@ -132,14 +131,14 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted ) } - session.rx().liveUserCryptoDevices(session.myUserId) + session.flow().liveUserCryptoDevices(session.myUserId) .distinctUntilChanged() - .throttleLast(5_000, TimeUnit.MILLISECONDS) - .subscribe { + .sample(5_000) + .onEach { // If we have a new crypto device change, we might want to trigger refresh of device info session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) } - .disposeOnClear() + .launchIn(viewModelScope) // trigger a refresh of lastSeen / last Ip session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) diff --git a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt index 0ee7152cbb..cc209cd72c 100644 --- a/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/UnreadMessagesSharedViewModel.kt @@ -18,8 +18,8 @@ package im.vector.app.features.home import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -46,7 +46,7 @@ import java.util.concurrent.TimeUnit data class UnreadMessagesState( val homeSpaceUnread: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0), val otherSpacesUnread: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0) -) : MvRxState +) : MavericksState data class CountInfo( val homeCount: RoomAggregateNotificationCount, @@ -65,7 +65,7 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: UnreadMessagesState): UnreadMessagesSharedViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt index 39004f4ed4..8ed44053a1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.breadcrumbs import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -25,12 +25,11 @@ import dagger.assisted.AssistedInject import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import io.reactivex.schedulers.Schedulers import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: BreadcrumbsViewState, private val session: Session) : @@ -41,7 +40,7 @@ class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: B fun create(initialState: BreadcrumbsViewState): BreadcrumbsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: BreadcrumbsViewState): BreadcrumbsViewModel? { @@ -61,12 +60,11 @@ class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: B // PRIVATE METHODS ***************************************************************************** private fun observeBreadcrumbs() { - session.rx() + session.flow() .liveBreadcrumbs(roomSummaryQueryParams { displayName = QueryStringValue.NoCondition memberships = listOf(Membership.JOIN) }) - .observeOn(Schedulers.computation()) .execute { asyncBreadcrumbs -> copy(asyncBreadcrumbs = asyncBreadcrumbs) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewState.kt index f067591e83..f2971db093 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/breadcrumbs/BreadcrumbsViewState.kt @@ -17,10 +17,10 @@ package im.vector.app.features.home.room.breadcrumbs import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary data class BreadcrumbsViewState( val asyncBreadcrumbs: Async> = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt index 54681366e0..7159f7b33a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/JoinReplacementRoomBottomSheet.kt @@ -61,7 +61,7 @@ class JoinReplacementRoomBottomSheet : } } - viewModel.selectSubscribe(this, RoomDetailViewState::joinUpgradedRoomAsync) { joinState -> + viewModel.onEach(RoomDetailViewState::joinUpgradedRoomAsync) { joinState -> when (joinState) { // it should never be Uninitialized Uninitialized, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index b3fe6fcbf4..ed87f1b833 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -61,7 +61,7 @@ import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.OnModelBuildFinishedListener import com.airbnb.epoxy.addGlidePreloader import com.airbnb.epoxy.glidePreloader -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -184,8 +184,6 @@ import im.vector.app.features.widgets.WidgetActivity import im.vector.app.features.widgets.WidgetArgs import im.vector.app.features.widgets.WidgetKind import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import nl.dionsegijn.konfetti.models.Shape @@ -381,13 +379,13 @@ class RoomDetailFragment @Inject constructor( invalidateOptionsMenu() } - roomDetailViewModel.selectSubscribe(this, RoomDetailViewState::canShowJumpToReadMarker, RoomDetailViewState::unreadState) { _, _ -> + roomDetailViewModel.onEach(RoomDetailViewState::canShowJumpToReadMarker, RoomDetailViewState::unreadState) { _, _ -> updateJumpToReadMarkerViewVisibility() } - textComposerViewModel.selectSubscribe(this, TextComposerViewState::sendMode, TextComposerViewState::canSendMessage) { mode, canSend -> + textComposerViewModel.onEach(TextComposerViewState::sendMode, TextComposerViewState::canSendMessage) { mode, canSend -> if (!canSend) { - return@selectSubscribe + return@onEach } when (mode) { is SendMode.REGULAR -> renderRegularMode(mode.text) @@ -397,8 +395,7 @@ class RoomDetailFragment @Inject constructor( } } - roomDetailViewModel.selectSubscribe( - this, + roomDetailViewModel.onEach( RoomDetailViewState::syncState, RoomDetailViewState::incrementalSyncStatus, RoomDetailViewState::pushCounter @@ -1591,7 +1588,7 @@ class RoomDetailFragment @Inject constructor( val otherUserId = data.otherUserId ?: return VerificationBottomSheet().apply { arguments = Bundle().apply { - putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs( + putParcelable(Mavericks.KEY_ARG, VerificationBottomSheet.VerificationArgs( otherUserId, data.transactionId, roomId = roomDetailArgs.roomId)) } }.show(parentFragmentManager, "REQ") @@ -1599,57 +1596,54 @@ class RoomDetailFragment @Inject constructor( } } -// TimelineEventController.Callback ************************************************************ + // TimelineEventController.Callback ************************************************************ override fun onUrlClicked(url: String, title: String): Boolean { - permalinkHandler - .launch(requireActivity(), url, object : NavigationInterceptor { - override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { - // Same room? - if (roomId == roomDetailArgs.roomId) { - // Navigation to same room - if (eventId == null) { - showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room)) - } else { - // Highlight and scroll to this event - roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true)) + viewLifecycleOwner.lifecycleScope.launch { + val isManaged = permalinkHandler + .launch(requireActivity(), url, object : NavigationInterceptor { + override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { + // Same room? + if (roomId == roomDetailArgs.roomId) { + // Navigation to same room + if (eventId == null) { + showSnackWithMessage(getString(R.string.navigate_to_room_when_already_in_the_room)) + } else { + // Highlight and scroll to this event + roomDetailViewModel.handle(RoomDetailAction.NavigateToEvent(eventId, true)) + } + return true } + // Not handled + return false + } + + override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { + openRoomMemberProfile(userId) return true } - // Not handled - return false - } - - override fun navToMemberProfile(userId: String, deepLink: Uri): Boolean { - openRoomMemberProfile(userId) - return true - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { managed -> - if (!managed) { - if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) { - MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive) - .setTitle(R.string.external_link_confirmation_title) - .setMessage( - getString(R.string.external_link_confirmation_message, title, url) - .toSpannable() - .colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) - .colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) - ) - .setPositiveButton(R.string._continue) { _, _ -> - openUrlInExternalBrowser(requireContext(), url) - } - .setNegativeButton(R.string.cancel, null) - .show() - } else { - // Open in external browser, in a new Tab - openUrlInExternalBrowser(requireContext(), url) - } - } + }) + if (!isManaged) { + if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) { + MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_NegativeDestructive) + .setTitle(R.string.external_link_confirmation_title) + .setMessage( + getString(R.string.external_link_confirmation_message, title, url) + .toSpannable() + .colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) + .colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) + ) + .setPositiveButton(R.string._continue) { _, _ -> + openUrlInExternalBrowser(requireContext(), url) + } + .setNegativeButton(R.string.cancel, null) + .show() + } else { + // Open in external browser, in a new Tab + openUrlInExternalBrowser(requireContext(), url) } - .disposeOnDestroyView() + } + } // In fact it is always managed return true } @@ -1808,15 +1802,15 @@ class RoomDetailFragment @Inject constructor( } override fun onRoomCreateLinkClicked(url: String) { - permalinkHandler - .launch(requireContext(), url, object : NavigationInterceptor { - override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { - requireActivity().finish() - return false - } - }) - .subscribe() - .disposeOnDestroyView() + viewLifecycleOwner.lifecycleScope.launchWhenResumed { + permalinkHandler + .launch(requireContext(), url, object : NavigationInterceptor { + override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { + requireActivity().finish() + return false + } + }) + } } override fun onReadReceiptsClicked(readReceipts: List) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index bd11ec6718..73717b169a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -18,17 +18,16 @@ package im.vector.app.features.home.room.detail import android.net.Uri import androidx.annotation.IdRes -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.asFlow import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import com.jakewharton.rxrelay2.BehaviorRelay -import com.jakewharton.rxrelay2.PublishRelay import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -52,16 +51,21 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever import im.vector.app.features.home.room.typing.TypingHelper -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.voice.VoicePlayerHelper -import io.reactivex.Observable import io.reactivex.rxkotlin.subscribeBy -import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.MatrixPatterns @@ -90,10 +94,9 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.widgets.model.WidgetType import org.matrix.android.sdk.api.util.toOptional +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.internal.crypto.model.event.WithHeldCode -import org.matrix.android.sdk.rx.asObservable -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap import timber.log.Timber import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean @@ -122,7 +125,7 @@ class RoomDetailViewModel @AssistedInject constructor( private val eventId = initialState.eventId private val invisibleEventsObservable = BehaviorRelay.create() private val visibleEventsObservable = BehaviorRelay.create() - private var timelineEvents = PublishRelay.create>() + private var timelineEvents = MutableSharedFlow>(0) val timeline = timelineFactory.createTimeline(viewModelScope, room, eventId) // Same lifecycle than the ViewModel (survive to screen rotation) @@ -144,7 +147,7 @@ class RoomDetailViewModel @AssistedInject constructor( fun create(initialState: RoomDetailViewState): RoomDetailViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { const val PAGINATION_COUNT = 50 @@ -217,8 +220,8 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun observePowerLevel() { - PowerLevelsObservableFactory(room).createObservable() - .subscribe { + PowerLevelsFlowFactory(room).createFlow() + .onEach { val canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId) val isAllowedToManageWidgets = session.widgetService().hasPermissionsToHandleWidgets(room.roomId) val isAllowedToStartWebRTCCall = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.CALL_INVITE) @@ -229,12 +232,11 @@ class RoomDetailViewModel @AssistedInject constructor( isAllowedToStartWebRTCCall = isAllowedToStartWebRTCCall ) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } private fun observeActiveRoomWidgets() { - session.rx() + session.flow() .liveRoomWidgets( roomId = initialState.roomId, widgetId = QueryStringValue.NoCondition @@ -246,7 +248,7 @@ class RoomDetailViewModel @AssistedInject constructor( copy(activeRoomWidgets = widgets) } - asyncSubscribe(RoomDetailViewState::activeRoomWidgets) { widgets -> + onAsync(RoomDetailViewState::activeRoomWidgets) { widgets -> setState { val jitsiWidget = widgets.firstOrNull { it.type == WidgetType.Jitsi } val jitsiConfId = jitsiWidget?.let { @@ -267,7 +269,7 @@ class RoomDetailViewModel @AssistedInject constructor( val queryParams = roomMemberQueryParams { this.userId = QueryStringValue.Equals(session.myUserId, QueryStringValue.Case.SENSITIVE) } - room.rx() + room.flow() .liveRoomMembers(queryParams) .map { it.firstOrNull().toOptional() @@ -982,29 +984,22 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun observeSyncState() { - session.rx() + session.flow() .liveSyncState() - .subscribe { syncState -> - setState { - copy(syncState = syncState) - } + .setOnEach { syncState -> + copy(syncState = syncState) } - .disposeOnClear() session.getSyncStatusLive() - .asObservable() - .subscribe { it -> - if (it is SyncStatusService.Status.IncrementalSyncStatus) { - setState { - copy(incrementalSyncStatus = it) - } - } + .asFlow() + .filterIsInstance() + .setOnEach { + copy(incrementalSyncStatus = it) } - .disposeOnClear() } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy( @@ -1014,14 +1009,12 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun getUnreadState() { - Observable - .combineLatest, RoomSummary, UnreadState>( - timelineEvents.observeOn(Schedulers.computation()), - room.rx().liveRoomSummary().unwrap(), - { timelineEvents, roomSummary -> - computeUnreadState(timelineEvents, roomSummary) - } - ) + combine( + timelineEvents, + room.flow().liveRoomSummary().unwrap() + ) { timelineEvents, roomSummary -> + computeUnreadState(timelineEvents, roomSummary) + } // We don't want live update of unread so we skip when we already had a HasUnread or HasNoUnread .distinctUntilChanged { previous, current -> when { @@ -1030,10 +1023,9 @@ class RoomDetailViewModel @AssistedInject constructor( else -> false } } - .subscribe { - setState { copy(unreadState = it) } + .setOnEach { + copy(unreadState = it) } - .disposeOnClear() } private fun computeUnreadState(events: List, roomSummary: RoomSummary): UnreadState { @@ -1057,7 +1049,7 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun observeUnreadState() { - selectSubscribe(RoomDetailViewState::unreadState) { + onEach(RoomDetailViewState::unreadState) { Timber.v("Unread state: $it") if (it is UnreadState.HasNoUnread) { startTrackingUnreadMessages() @@ -1066,20 +1058,19 @@ class RoomDetailViewModel @AssistedInject constructor( } private fun observeMembershipChanges() { - session.rx() + session.flow() .liveRoomChangeMembershipState() .map { it[initialState.roomId] ?: ChangeMembershipState.Unknown } .distinctUntilChanged() - .subscribe { - setState { copy(changeMembershipState = it) } + .setOnEach { + copy(changeMembershipState = it) } - .disposeOnClear() } private fun observeSummaryState() { - asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> + onAsync(RoomDetailViewState::asyncRoomSummary) { summary -> setState { val typingMessage = typingHelper.getTypingMessage(summary.typingUsers) copy( @@ -1101,7 +1092,7 @@ class RoomDetailViewModel @AssistedInject constructor( } override fun onTimelineUpdated(snapshot: List) { - timelineEvents.accept(snapshot) + timelineEvents.tryEmit(snapshot) // PreviewUrl if (vectorPreferences.showUrlPreviews()) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt index 4c6e4ac3fe..042a415b47 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.Event @@ -66,7 +66,7 @@ data class RoomDetailViewState( val isAllowedToStartWebRTCCall: Boolean = true, val hasFailedSending: Boolean = false, val jitsiState: JitsiState = JitsiState() -) : MvRxState { +) : MavericksState { constructor(args: RoomDetailArgs) : this( roomId = args.roomId, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt index 35871611c0..742d2848a1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewModel.kt @@ -16,9 +16,8 @@ package im.vector.app.features.home.room.detail.composer -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -33,7 +32,7 @@ import im.vector.app.features.home.room.detail.ChatEffect import im.vector.app.features.home.room.detail.RoomDetailFragment import im.vector.app.features.home.room.detail.composer.rainbow.RainbowGenerator import im.vector.app.features.home.room.detail.toMessageType -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.Dispatchers @@ -130,14 +129,11 @@ class TextComposerViewModel @AssistedInject constructor( } private fun observePowerLevel() { - PowerLevelsObservableFactory(room).createObservable() - .subscribe { + PowerLevelsFlowFactory(room).createFlow() + .setOnEach { val canSendMessage = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE) - setState { - copy(canSendMessage = canSendMessage) - } + copy(canSendMessage = canSendMessage) } - .disposeOnClear() } private fun handleEnterQuoteMode(action: TextComposerAction.EnterQuoteMode) { @@ -711,7 +707,7 @@ class TextComposerViewModel @AssistedInject constructor( fun create(initialState: TextComposerViewState): TextComposerViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: TextComposerViewState): TextComposerViewModel { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt index fd1dd2d0ad..3110aa8dc3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerViewState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.home.room.detail.composer -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import im.vector.app.features.home.room.detail.RoomDetailArgs import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent @@ -47,7 +47,7 @@ data class TextComposerViewState( val isVoiceRecording: Boolean = false, val isSendButtonVisible: Boolean = false, val sendMode: SendMode = SendMode.REGULAR("", false) -) : MvRxState { +) : MavericksState { val isComposerVisible: Boolean get() = canSendMessage && !isVoiceRecording diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt index 95b2333b43..9f98d655cc 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/readreceipts/DisplayReadReceiptsBottomSheet.kt @@ -21,7 +21,7 @@ import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.args import im.vector.app.R import im.vector.app.core.di.ScreenComponent @@ -88,7 +88,7 @@ class DisplayReadReceiptsBottomSheet : val parcelableArgs = DisplayReadReceiptArgs( readReceipts ) - args.putParcelable(MvRx.KEY_ARG, parcelableArgs) + args.putParcelable(Mavericks.KEY_ARG, parcelableArgs) return DisplayReadReceiptsBottomSheet().apply { arguments = args } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt index d9a2f98e32..88ed101252 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt @@ -20,7 +20,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.widget.SearchView -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.addFragment @@ -49,7 +49,7 @@ class SearchActivity : VectorBaseActivity() { override fun initUiAndData() { if (isFirstCreation()) { - val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return addFragment(R.id.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG) } views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { @@ -73,7 +73,7 @@ class SearchActivity : VectorBaseActivity() { return Intent(context, SearchActivity::class.java).apply { // If we do that we will have the same room two times on the stack. Let's allow infinite stack for the moment. // flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT - putExtra(MvRx.KEY_ARG, args) + putExtra(Mavericks.KEY_ARG, args) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt index 26111e4f2b..e4832b3876 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -50,7 +50,7 @@ class SearchViewModel @AssistedInject constructor( fun create(initialState: SearchViewState): SearchViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: SearchViewState): SearchViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt index 41fecbb5e2..4b272b6c4c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail.search import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.search.EventAndSender @@ -32,7 +32,7 @@ data class SearchViewState( val roomId: String = "", // Current pagination request val asyncSearchRequest: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: SearchArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index 5a37a343e6..d320f0b6e0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -244,20 +244,22 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec interceptorHelper.intercept(models, partialState.unreadState, timeline, callback) } - fun update(viewState: RoomDetailViewState) = synchronized(modelCache) { - val newPartialState = PartialState(viewState) - if (partialState.highlightedEventId != newPartialState.highlightedEventId) { - // Clear cache to force a refresh - for (i in 0 until modelCache.size) { - if (modelCache[i]?.eventId == viewState.highlightedEventId || - modelCache[i]?.eventId == partialState.highlightedEventId) { - modelCache[i] = null + fun update(viewState: RoomDetailViewState) = backgroundHandler.post { + synchronized(modelCache) { + val newPartialState = PartialState(viewState) + if (partialState.highlightedEventId != newPartialState.highlightedEventId) { + // Clear cache to force a refresh + for (i in 0 until modelCache.size) { + if (modelCache[i]?.eventId == viewState.highlightedEventId || + modelCache[i]?.eventId == partialState.highlightedEventId) { + modelCache[i] = null + } } } - } - if (newPartialState != partialState) { - partialState = newPartialState - requestModelBuild() + if (newPartialState != partialState) { + partialState = newPartialState + requestModelBuild() + } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt index caee485aba..c1c145040e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail.timeline.action import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.core.extensions.canReact import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData @@ -50,7 +50,7 @@ data class MessageActionState( val actions: List = emptyList(), val expendedReportContentMenu: Boolean = false, val actionPermissions: ActionPermissions = ActionPermissions() -) : MvRxState { +) : MavericksState { constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId, informationData = args.informationData) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 275d37e295..b4fff6eb3d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -16,9 +16,8 @@ package im.vector.app.features.home.room.detail.timeline.action import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext -import com.jakewharton.rxrelay2.BehaviorRelay import dagger.Lazy import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -33,9 +32,14 @@ import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormat import im.vector.app.features.html.EventHtmlRenderer import im.vector.app.features.html.PillsPostProcessor import im.vector.app.features.html.VectorHtmlCompressor -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.reactions.data.EmojiDataSource import im.vector.app.features.settings.VectorPreferences +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState @@ -54,9 +58,8 @@ import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap -import java.util.ArrayList +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap /** * Information related to an event and used to display preview in contextual bottom sheet. @@ -79,14 +82,14 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted pillsPostProcessorFactory.create(initialState.roomId) } - private val eventIdObservable = BehaviorRelay.createDefault(initialState.eventId) + private val eventIdFlow = MutableStateFlow(initialState.eventId) @AssistedFactory interface Factory { fun create(initialState: MessageActionState): MessageActionsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: MessageActionState): MessageActionsViewModel? { val fragment: MessageActionsBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() @@ -119,8 +122,8 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted if (room == null) { return } - PowerLevelsObservableFactory(room).createObservable() - .subscribe { + PowerLevelsFlowFactory(room).createFlow() + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) val canReact = powerLevelsHelper.isUserAllowedToSend(session.myUserId, false, EventType.REACTION) val canRedact = powerLevelsHelper.isUserAbleToRedact(session.myUserId) @@ -129,13 +132,12 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted setState { copy(actionPermissions = permissions) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } private fun observeEvent() { if (room == null) return - room.rx() + room.flow() .liveTimelineEvent(initialState.eventId) .unwrap() .execute { @@ -145,9 +147,9 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted private fun observeReactions() { if (room == null) return - eventIdObservable - .switchMap { eventId -> - room.rx() + eventIdFlow + .flatMapLatest { eventId -> + room.flow() .liveAnnotationSummary(eventId) .map { annotations -> EmojiDataSource.quickEmojis.map { emoji -> @@ -161,9 +163,9 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted } private fun observeTimelineEventState() { - selectSubscribe(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions -> - val nonNullTimelineEvent = timelineEvent() ?: return@selectSubscribe - eventIdObservable.accept(nonNullTimelineEvent.eventId) + onEach(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions -> + val nonNullTimelineEvent = timelineEvent() ?: return@onEach + eventIdFlow.tryEmit(nonNullTimelineEvent.eventId) setState { copy( eventId = nonNullTimelineEvent.eventId, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt index d8ce6e3e7a..da3a7396fd 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryBottomSheet.kt @@ -19,7 +19,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -78,7 +78,7 @@ class ViewEditHistoryBottomSheet : roomId, informationData ) - args.putParcelable(MvRx.KEY_ARG, parcelableArgs) + args.putParcelable(Mavericks.KEY_ARG, parcelableArgs) return ViewEditHistoryBottomSheet().apply { arguments = args } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index 5732326f2e..699f3cf02d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -19,7 +19,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -51,7 +51,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor( fun create(initialState: ViewEditHistoryViewState): ViewEditHistoryViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ViewEditHistoryViewState): ViewEditHistoryViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt index ca80c29cb4..61a400d875 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail.timeline.edithistory import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import org.matrix.android.sdk.api.session.events.model.Event @@ -27,7 +27,7 @@ data class ViewEditHistoryViewState( val roomId: String, val isOriginalAReply: Boolean = false, val editList: Async> = Uninitialized) : - MvRxState { + MavericksState { constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt index ab15ace5cc..81ebd6d3de 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsBottomSheet.kt @@ -20,7 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -92,7 +92,7 @@ class ViewReactionsBottomSheet : roomId, informationData ) - args.putParcelable(MvRx.KEY_ARG, parcelableArgs) + args.putParcelable(Mavericks.KEY_ARG, parcelableArgs) return ViewReactionsBottomSheet().apply { arguments = args } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt index e9e7b471f3..5baab683cf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/reactions/ViewReactionsViewModel.kt @@ -18,8 +18,8 @@ package im.vector.app.features.home.room.detail.timeline.reactions import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -42,7 +42,7 @@ data class DisplayReactionsViewState( val eventId: String, val roomId: String, val mapReactionKeyToMemberList: Async> = Uninitialized) : - MvRxState { + MavericksState { constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId) } @@ -74,7 +74,7 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted fun create(initialState: DisplayReactionsViewState): ViewReactionsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DisplayReactionsViewState): ViewReactionsViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt index 71dc794cb0..bb28836cd3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewModel.kt @@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail.upgrade import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -55,7 +55,7 @@ class MigrateRoomViewModel @AssistedInject constructor( fun create(initialState: MigrateRoomViewState): MigrateRoomViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: MigrateRoomViewState): MigrateRoomViewModel? { val factory = when (viewModelContext) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt index e3ea98682b..6a155aa22a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/upgrade/MigrateRoomViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail.upgrade import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class MigrateRoomViewState( @@ -36,7 +36,7 @@ data class MigrateRoomViewState( val upgradingProgressIndeterminate: Boolean = true, val migrationReason: MigrateRoomBottomSheet.MigrationReason = MigrateRoomBottomSheet.MigrationReason.MANUAL, val autoMigrateMembersAndParents: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: MigrateRoomBottomSheet.Args) : this( roomId = args.roomId, newVersion = args.newVersion, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt index ab6eb2e658..42f613d60f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/RoomWidgetsBottomSheet.kt @@ -64,7 +64,7 @@ class RoomWidgetsBottomSheet : views.bottomSheetTitle.textSize = 20f views.bottomSheetTitle.setTextColor(colorProvider.getColorFromAttribute(R.attr.vctr_content_primary)) epoxyController.listener = this - roomDetailViewModel.asyncSubscribe(this, RoomDetailViewState::activeRoomWidgets) { + roomDetailViewModel.onAsync(RoomDetailViewState::activeRoomWidgets) { epoxyController.setData(it) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index f9ee303e1c..c36836c87f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -123,7 +123,7 @@ class RoomListFragment @Inject constructor( .subscribe { handleQuickActions(it) } .disposeOnDestroyView() - roomListViewModel.selectSubscribe(viewLifecycleOwner, RoomListViewState::roomMembershipChanges) { ms -> + roomListViewModel.onEach(RoomListViewState::roomMembershipChanges) { ms -> // it's for invites local echo adapterInfosList.filter { it.section.notifyOfLocalEcho } .onEach { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index b7a2d4e26b..345c33ec18 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -17,12 +17,11 @@ package im.vector.app.features.home.room.list import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import im.vector.app.AppStateHandler @@ -34,6 +33,8 @@ import im.vector.app.features.displayname.getBestName import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue @@ -43,7 +44,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.tag.RoomTag import org.matrix.android.sdk.api.session.room.state.isPublic import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.inject.Inject @@ -96,7 +97,7 @@ class RoomListViewModel @Inject constructor( ) } - session.rx().liveUser(session.myUserId) + session.flow().liveUser(session.myUserId) .map { it.getOrNull()?.toMatrixItem()?.getBestName() } .distinctUntilChanged() .execute { @@ -107,18 +108,17 @@ class RoomListViewModel @Inject constructor( } private fun observeMembershipChanges() { - session.rx() + session.flow() .liveRoomChangeMembershipState() - .subscribe { - setState { copy(roomMembershipChanges = it) } + .setOnEach { + copy(roomMembershipChanges = it) } - .disposeOnClear() } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic - override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? { + override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel { val fragment: RoomListFragment = (viewModelContext as FragmentViewModelContext).fragment() return fragment.roomListViewModelFactory.create(state) } @@ -324,7 +324,7 @@ class RoomListViewModel @Inject constructor( private fun String.otherTag(): String? { return when (this) { - RoomTag.ROOM_TAG_FAVOURITE -> RoomTag.ROOM_TAG_LOW_PRIORITY + RoomTag.ROOM_TAG_FAVOURITE -> RoomTag.ROOM_TAG_LOW_PRIORITY RoomTag.ROOM_TAG_LOW_PRIORITY -> RoomTag.ROOM_TAG_FAVOURITE else -> null } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt index 68a8b9e515..46ff6c242b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.list import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.RoomGroupingMethod import im.vector.app.features.home.RoomListDisplayMode @@ -31,7 +31,7 @@ data class RoomListViewState( val asyncSuggestedRooms: Async> = Uninitialized, val currentUserName: String? = null, val currentRoomGrouping: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: RoomListParams) : this(displayMode = args.displayMode) } diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt index 312e2766cc..deee0c4cf5 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.homeserver import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -48,7 +48,7 @@ class HomeServerCapabilitiesViewModel @AssistedInject constructor( fun create(initialState: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: HomeServerCapabilitiesViewState): HomeServerCapabilitiesViewModel? { val fragment: UserListFragment = (viewModelContext as FragmentViewModelContext).fragment() diff --git a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt index 14d19b2e6a..d7ced5e632 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/HomeServerCapabilitiesViewState.kt @@ -16,10 +16,10 @@ package im.vector.app.features.homeserver -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities data class HomeServerCapabilitiesViewState( val capabilities: HomeServerCapabilities = HomeServerCapabilities(), val isE2EByDefault: Boolean = true -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index 88998861bc..dd07319e9f 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -21,7 +21,7 @@ import android.content.Intent import android.os.Bundle import android.os.Parcelable import android.view.View -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R @@ -165,7 +165,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fa fun getIntent(context: Context, roomId: String): Intent { return Intent(context, InviteUsersToRoomActivity::class.java).also { - it.putExtra(MvRx.KEY_ARG, InviteUsersToRoomArgs(roomId)) + it.putExtra(Mavericks.KEY_ARG, InviteUsersToRoomArgs(roomId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt index 49ff8bde0d..fd06614950 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.invite import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -27,9 +27,12 @@ import im.vector.app.R import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.userdirectory.PendingSelection -import io.reactivex.Observable +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.rx.rx class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted initialState: InviteUsersToRoomViewState, @@ -44,7 +47,7 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted fun create(initialState: InviteUsersToRoomViewState): InviteUsersToRoomViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: InviteUsersToRoomViewState): InviteUsersToRoomViewModel? { @@ -63,32 +66,33 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted } private fun inviteUsersToRoom(selections: Set) { - _viewEvents.post(InviteUsersToRoomViewEvents.Loading) - - Observable.fromIterable(selections).flatMapCompletable { user -> - when (user) { - is PendingSelection.UserPendingSelection -> room.rx().invite(user.user.userId, null) - is PendingSelection.ThreePidPendingSelection -> room.rx().invite3pid(user.threePid) - } - }.subscribe( - { - val successMessage = when (selections.size) { - 1 -> stringProvider.getString(R.string.invitation_sent_to_one_user, - selections.first().getBestName()) - 2 -> stringProvider.getString(R.string.invitations_sent_to_two_users, - selections.first().getBestName(), - selections.last().getBestName()) - else -> stringProvider.getQuantityString(R.plurals.invitations_sent_to_one_and_more_users, - selections.size - 1, - selections.first().getBestName(), - selections.size - 1) + viewModelScope.launch { + _viewEvents.post(InviteUsersToRoomViewEvents.Loading) + selections.asFlow() + .map { user -> + when (user) { + is PendingSelection.UserPendingSelection -> room.invite(user.user.userId, null) + is PendingSelection.ThreePidPendingSelection -> room.invite3pid(user.threePid) + } } - _viewEvents.post(InviteUsersToRoomViewEvents.Success(successMessage)) - }, - { - _viewEvents.post(InviteUsersToRoomViewEvents.Failure(it)) - }) - .disposeOnClear() + .catch { cause -> + _viewEvents.post(InviteUsersToRoomViewEvents.Failure(cause)) + } + .collect { + val successMessage = when (selections.size) { + 1 -> stringProvider.getString(R.string.invitation_sent_to_one_user, + selections.first().getBestName()) + 2 -> stringProvider.getString(R.string.invitations_sent_to_two_users, + selections.first().getBestName(), + selections.last().getBestName()) + else -> stringProvider.getQuantityString(R.plurals.invitations_sent_to_one_and_more_users, + selections.size - 1, + selections.first().getBestName(), + selections.size - 1) + } + _viewEvents.post(InviteUsersToRoomViewEvents.Success(successMessage)) + } + } } fun getUserIdsOfRoomMembers(): Set { diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewState.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewState.kt index cd688f097b..37f0861a83 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomViewState.kt @@ -17,13 +17,13 @@ package im.vector.app.features.invite import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class InviteUsersToRoomViewState( val roomId: String, val inviteState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: InviteUsersToRoomArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt index 6e7de1c35b..09eff756d5 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InvitesAcceptor.kt @@ -18,10 +18,14 @@ package im.vector.app.features.invite import im.vector.app.ActiveSessionDataSource import im.vector.app.features.session.coroutineScope -import io.reactivex.Observable import io.reactivex.disposables.Disposable import kotlinx.coroutines.async -import kotlinx.coroutines.launch +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import org.matrix.android.sdk.api.extensions.orFalse @@ -31,9 +35,8 @@ import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber -import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton @@ -50,7 +53,7 @@ class InvitesAcceptor @Inject constructor( private lateinit var activeSessionDisposable: Disposable private val shouldRejectRoomIds = mutableSetOf() - private val invitedRoomDisposables = HashMap() + private val activeSessionIds = mutableSetOf() private val semaphore = Semaphore(1) fun initialize() { @@ -71,34 +74,32 @@ class InvitesAcceptor @Inject constructor( if (!autoAcceptInvites.isEnabled) { return } - if (invitedRoomDisposables.containsKey(session.sessionId)) { + if (activeSessionIds.contains(session.sessionId)) { return } + activeSessionIds.add(session.sessionId) session.addListener(this) val roomQueryParams = roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) } - val rxSession = session.rx() - Observable - .combineLatest( - rxSession.liveRoomSummaries(roomQueryParams), - rxSession.liveRoomChangeMembershipState().debounce(1, TimeUnit.SECONDS), - { invitedRooms, _ -> invitedRooms.map { it.roomId } } - ) + val flowSession = session.flow() + combine( + flowSession.liveRoomSummaries(roomQueryParams), + flowSession.liveRoomChangeMembershipState().debounce(1000) + ) { invitedRooms, _ -> invitedRooms.map { it.roomId } } .filter { it.isNotEmpty() } - .subscribe { invitedRoomIds -> - session.coroutineScope.launch { - semaphore.withPermit { - Timber.v("Invited roomIds: $invitedRoomIds") - for (roomId in invitedRoomIds) { - async { session.joinRoomSafely(roomId) }.start() - } - } - } - } - .also { - invitedRoomDisposables[session.sessionId] = it - } + .onEach { invitedRoomIds -> + joinInvitedRooms(session, invitedRoomIds) + }.launchIn(session.coroutineScope) + } + + private suspend fun joinInvitedRooms(session: Session, invitedRoomIds: List) = coroutineScope { + semaphore.withPermit { + Timber.v("Invited roomIds: $invitedRoomIds") + for (roomId in invitedRoomIds) { + async { session.joinRoomSafely(roomId) }.start() + } + } } private suspend fun Session.joinRoomSafely(roomId: String) { @@ -138,6 +139,6 @@ class InvitesAcceptor @Inject constructor( override fun onSessionStopped(session: Session) { session.removeListener(this) - invitedRoomDisposables.remove(session.sessionId)?.dispose() + activeSessionIds.remove(session.sessionId) } } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt index e941392e38..28a9fa46d1 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginViewModel.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -86,7 +86,7 @@ class LoginViewModel @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: LoginViewState): LoginViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/login/LoginViewState.kt b/vector/src/main/java/im/vector/app/features/login/LoginViewState.kt index d6f2c8f087..46b5052a38 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginViewState.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.login import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.PersistState import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized @@ -55,7 +55,7 @@ data class LoginViewState( @PersistState val loginModeSupportedTypes: List = emptyList(), val knownCustomHomeServersUrls: List = emptyList() -) : MvRxState { +) : MavericksState { fun isLoading(): Boolean { return asyncLoginAction is Loading || diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt index 0eee121854..daa97d732f 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt @@ -51,6 +51,8 @@ class LoginWebFragment @Inject constructor( private val assetReader: AssetReader ) : AbstractLoginFragment() { + val softLogoutViewModel: SoftLogoutViewModel by activityViewModel() + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginWebBinding { return FragmentLoginWebBinding.inflate(inflater, container, false) } @@ -232,7 +234,6 @@ class LoginWebFragment @Inject constructor( private fun notifyViewModel(credentials: Credentials) { if (isForSessionRecovery) { - val softLogoutViewModel: SoftLogoutViewModel by activityViewModel() softLogoutViewModel.handle(SoftLogoutAction.WebLoginSuccess(credentials)) } else { loginViewModel.handle(LoginAction.WebLoginSuccess(credentials)) diff --git a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsViewState.kt b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsViewState.kt index c09c76efc3..3641b443e3 100644 --- a/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/login/terms/LoginTermsViewState.kt @@ -16,12 +16,12 @@ package im.vector.app.features.login.terms -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.internal.auth.registration.LocalizedFlowDataLoginTerms data class LoginTermsViewState( val localizedFlowDataLoginTermsChecked: List -) : MvRxState { +) : MavericksState { fun check(data: LocalizedFlowDataLoginTerms) { localizedFlowDataLoginTermsChecked.find { it.localizedFlowDataLoginTerms == data }?.checked = true } diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt index 2c06352868..09ca979c6c 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt @@ -22,7 +22,7 @@ import androidx.fragment.app.FragmentActivity import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -86,7 +86,7 @@ class LoginViewModel2 @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: LoginViewState2): LoginViewModel2? { diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt index d629c6dfe7..276d1111bb 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt @@ -17,7 +17,7 @@ package im.vector.app.features.login2 import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.PersistState import com.airbnb.mvrx.Uninitialized import im.vector.app.core.extensions.toReducedUrl @@ -55,7 +55,7 @@ data class LoginViewState2( // From database val knownCustomHomeServersUrls: List = emptyList() -) : MvRxState { +) : MavericksState { // Pending user identifier fun userIdentifier(): String { diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginWebFragment2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginWebFragment2.kt index b0741f6520..080cce4958 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginWebFragment2.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginWebFragment2.kt @@ -56,6 +56,8 @@ class LoginWebFragment2 @Inject constructor( return FragmentLoginWebBinding.inflate(inflater, container, false) } + val softLogoutViewModel: SoftLogoutViewModel by activityViewModel() + private var isWebViewLoaded = false private var isForSessionRecovery = false @@ -233,7 +235,6 @@ class LoginWebFragment2 @Inject constructor( private fun notifyViewModel(credentials: Credentials) { if (isForSessionRecovery) { - val softLogoutViewModel: SoftLogoutViewModel by activityViewModel() softLogoutViewModel.handle(SoftLogoutAction.WebLoginSuccess(credentials)) } else { loginViewModel.handle(LoginAction2.WebLoginSuccess(credentials)) diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt index e3d25ef283..5668214b50 100644 --- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedFragment.kt @@ -72,7 +72,7 @@ class AccountCreatedFragment @Inject constructor( setupSubmitButton() observeViewEvents() - viewModel.subscribe { invalidateState(it) } + viewModel.onEach { invalidateState(it) } views.loginAccountCreatedTime.text = dateFormatter.format(System.currentTimeMillis(), DateFormatKind.MESSAGE_SIMPLE) } diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt index 1acec968b6..34957dd47b 100644 --- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewModel.kt @@ -18,19 +18,20 @@ package im.vector.app.features.login2.created import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap import timber.log.Timber class AccountCreatedViewModel @AssistedInject constructor( @@ -43,7 +44,7 @@ class AccountCreatedViewModel @AssistedInject constructor( fun create(initialState: AccountCreatedViewState): AccountCreatedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: AccountCreatedViewState): AccountCreatedViewModel? { @@ -62,7 +63,7 @@ class AccountCreatedViewModel @AssistedInject constructor( } private fun observeUser() { - session.rx() + session.flow() .liveUser(session.myUserId) .unwrap() .map { diff --git a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewState.kt b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewState.kt index 80211b3da2..0ae60e910c 100644 --- a/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewState.kt +++ b/vector/src/main/java/im/vector/app/features/login2/created/AccountCreatedViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.login2.created import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.util.MatrixItem @@ -26,4 +26,4 @@ data class AccountCreatedViewState( val isLoading: Boolean = false, val currentUser: Async = Uninitialized, val hasBeenModified: Boolean = false -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index bf3e7a5d78..aadabcb1b4 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -24,7 +24,7 @@ import android.view.ViewGroup import androidx.core.view.isVisible import androidx.fragment.app.Fragment import com.airbnb.mvrx.Incomplete -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -127,7 +127,7 @@ class MatrixToBottomSheet : fun withLink(matrixToLink: String): MatrixToBottomSheet { return MatrixToBottomSheet().apply { arguments = Bundle().apply { - putParcelable(MvRx.KEY_ARG, MatrixToArgs( + putParcelable(Mavericks.KEY_ARG, MatrixToArgs( matrixToLink = matrixToLink )) } diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt index 40213dc0ee..0fff2495f9 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.matrixto import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser @@ -31,7 +31,7 @@ data class MatrixToBottomSheetState( val startChattingState: Async = Uninitialized, val roomPeekResult: Async = Uninitialized, val peopleYouKnow: Async> = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: MatrixToBottomSheet.MatrixToArgs) : this( deepLink = args.matrixToLink, diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index f78724d454..327485a3b0 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -245,7 +245,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( return session.peekRoom(roomIdOrAlias) } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: MatrixToBottomSheetState): MatrixToBottomSheetViewModel? { val fragment: MatrixToBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt index 7469f44583..a02cfe7517 100644 --- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt +++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt @@ -23,91 +23,80 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.utils.toast import im.vector.app.features.navigation.Navigator import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData -import io.reactivex.Single -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomType -import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.rx.rx import javax.inject.Inject class PermalinkHandler @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, private val navigator: Navigator) { - fun launch( + suspend fun launch( context: Context, deepLink: String?, navigationInterceptor: NavigationInterceptor? = null, buildTask: Boolean = false - ): Single { + ): Boolean { val uri = deepLink?.let { Uri.parse(it) } return launch(context, uri, navigationInterceptor, buildTask) } - fun launch( + suspend fun launch( context: Context, deepLink: Uri?, navigationInterceptor: NavigationInterceptor? = null, buildTask: Boolean = false - ): Single { + ): Boolean { if (deepLink == null || !isPermalinkSupported(context, deepLink.toString())) { - return Single.just(false) + return false } - return Single - .fromCallable { - PermalinkParser.parse(deepLink) - } - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .flatMap { permalinkData -> - handlePermalink(permalinkData, deepLink, context, navigationInterceptor, buildTask) - } - .onErrorReturnItem(false) + return tryOrNull { + withContext(Dispatchers.Default) { + val permalinkData = PermalinkParser.parse(deepLink) + handlePermalink(permalinkData, deepLink, context, navigationInterceptor, buildTask) + } + } ?: false } - private fun handlePermalink( + private suspend fun handlePermalink( permalinkData: PermalinkData, rawLink: Uri, context: Context, navigationInterceptor: NavigationInterceptor?, buildTask: Boolean - ): Single { + ): Boolean { return when (permalinkData) { is PermalinkData.RoomLink -> { - permalinkData.getRoomId() - .observeOn(AndroidSchedulers.mainThread()) - .map { - val roomId = it.getOrNull() - if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink) != true) { - openRoom( - context = context, - roomId = roomId, - permalinkData = permalinkData, - rawLink = rawLink, - buildTask = buildTask - ) - } - true - } + val roomId = permalinkData.getRoomId() + if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId, rawLink) != true) { + openRoom( + context = context, + roomId = roomId, + permalinkData = permalinkData, + rawLink = rawLink, + buildTask = buildTask + ) + } + true } is PermalinkData.GroupLink -> { navigator.openGroupDetail(permalinkData.groupId, context, buildTask) - Single.just(true) + true } is PermalinkData.UserLink -> { if (navigationInterceptor?.navToMemberProfile(permalinkData.userId, rawLink) != true) { navigator.openRoomMemberProfile(userId = permalinkData.userId, roomId = null, context = context, buildTask = buildTask) } - Single.just(true) + true } is PermalinkData.FallbackLink -> { - Single.just(false) + false } is PermalinkData.RoomEmailInviteLink -> { val data = RoomPreviewData( @@ -118,7 +107,7 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti roomType = permalinkData.roomType ) navigator.openRoomPreview(context, data) - Single.just(true) + true } } } @@ -130,15 +119,13 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti } } - private fun PermalinkData.RoomLink.getRoomId(): Single> { + private suspend fun PermalinkData.RoomLink.getRoomId(): String? { val session = activeSessionHolder.getSafeActiveSession() return if (isRoomAlias && session != null) { - session.rx() - .getRoomIdByAlias(roomIdOrAlias, true) - .map { it.getOrNull()?.roomId.toOptional() } - .subscribeOn(Schedulers.io()) + val roomIdByAlias = session.getRoomIdByAlias(roomIdOrAlias, true) + roomIdByAlias.getOrNull()?.roomId } else { - Single.just(Optional.from(roomIdOrAlias)) + roomIdOrAlias } } diff --git a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt index a36e945699..430be6bc1f 100644 --- a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt +++ b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt @@ -18,7 +18,7 @@ package im.vector.app.features.pin import android.content.Context import android.content.Intent -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.google.android.material.appbar.MaterialToolbar import im.vector.app.R import im.vector.app.core.extensions.addFragment @@ -31,7 +31,7 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigur companion object { fun newIntent(context: Context, args: PinArgs): Intent { return Intent(context, PinActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, args) + putExtra(Mavericks.KEY_ARG, args) } } } @@ -42,7 +42,7 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigur override fun initUiAndData() { if (isFirstCreation()) { - val fragmentArgs: PinArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + val fragmentArgs: PinArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return addFragment(R.id.simpleFragmentContainer, PinFragment::class.java, fragmentArgs) } } diff --git a/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsObservableFactory.kt b/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt similarity index 73% rename from vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsObservableFactory.kt rename to vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt index a9d4578bf0..767d6f1ba7 100644 --- a/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsObservableFactory.kt +++ b/vector/src/main/java/im/vector/app/features/powerlevel/PowerLevelsFlowFactory.kt @@ -16,23 +16,24 @@ package im.vector.app.features.powerlevel -import io.reactivex.Observable -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap -class PowerLevelsObservableFactory(private val room: Room) { +class PowerLevelsFlowFactory(private val room: Room) { - fun createObservable(): Observable { - return room.rx() + fun createFlow(): Flow { + return room.flow() .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) - .observeOn(Schedulers.computation()) + .flowOn(Dispatchers.Default) .mapOptional { it.content.toModel() } .unwrap() } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportState.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportState.kt index a5019115fb..37a379104b 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportState.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportState.kt @@ -16,8 +16,8 @@ package im.vector.app.features.rageshake -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState data class BugReportState( val serverVersion: String = "" -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt index c71a89553e..a1ec6b2e76 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.rageshake import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -40,7 +40,7 @@ class BugReportViewModel @AssistedInject constructor( fun create(initialState: BugReportState): BugReportViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: BugReportState): BugReportViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt index 4d1d0adf23..ea04d6b25f 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiSearchResultViewModel.kt @@ -17,8 +17,8 @@ package im.vector.app.features.reactions import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -32,7 +32,7 @@ import kotlinx.coroutines.launch data class EmojiSearchResultViewState( val query: String = "", val results: List = emptyList() -) : MvRxState +) : MavericksState class EmojiSearchResultViewModel @AssistedInject constructor( @Assisted initialState: EmojiSearchResultViewState, @@ -44,7 +44,7 @@ class EmojiSearchResultViewModel @AssistedInject constructor( fun create(initialState: EmojiSearchResultViewState): EmojiSearchResultViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: EmojiSearchResultViewState): EmojiSearchResultViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt index ece953a185..44a6963a5d 100644 --- a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewModel.kt @@ -18,9 +18,8 @@ package im.vector.app.features.room import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext -import com.jakewharton.rxrelay2.BehaviorRelay import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -28,8 +27,14 @@ import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider -import io.reactivex.Observable -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType @@ -37,8 +42,8 @@ import org.matrix.android.sdk.api.session.room.Room 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.util.Optional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap /** * This ViewModel observe a room summary and notify when the room is left @@ -54,7 +59,7 @@ class RequireActiveMembershipViewModel @AssistedInject constructor( fun create(initialState: RequireActiveMembershipViewState): RequireActiveMembershipViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RequireActiveMembershipViewState): RequireActiveMembershipViewModel? { @@ -66,28 +71,31 @@ class RequireActiveMembershipViewModel @AssistedInject constructor( } } - private val roomIdObservable = BehaviorRelay.createDefault(Optional.from(initialState.roomId)) + private val roomIdFlow = MutableStateFlow(Optional.from(initialState.roomId)) init { observeRoomSummary() } private fun observeRoomSummary() { - roomIdObservable + roomIdFlow .unwrap() - .switchMap { roomId -> - val room = session.getRoom(roomId) ?: return@switchMap Observable.just(Optional.empty()) - room.rx() + .flatMapLatest { roomId -> + val room = session.getRoom(roomId) ?: return@flatMapLatest flow { + val emptyResult = Optional.empty() + emit(emptyResult) + } + room.flow() .liveRoomSummary() .unwrap() - .observeOn(Schedulers.computation()) + .flowOn(Dispatchers.Default) .map { mapToLeftViewEvent(room, it) } } .unwrap() - .subscribe { event -> + .onEach { event -> _viewEvents.post(event) } - .disposeOnClear() + .launchIn(viewModelScope) } private fun mapToLeftViewEvent(room: Room, roomSummary: RoomSummary): Optional { @@ -128,7 +136,7 @@ class RequireActiveMembershipViewModel @AssistedInject constructor( setState { copy(roomId = action.roomId) } - roomIdObservable.accept(Optional.from(action.roomId)) + roomIdFlow.tryEmit(Optional.from(action.roomId)) } }.exhaustive } diff --git a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt index 2ca68b5e8b..dbf399bdf2 100644 --- a/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt +++ b/vector/src/main/java/im/vector/app/features/room/RequireActiveMembershipViewState.kt @@ -16,13 +16,13 @@ package im.vector.app.features.room -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import im.vector.app.features.roommemberprofile.RoomMemberProfileArgs import im.vector.app.features.roomprofile.RoomProfileArgs data class RequireActiveMembershipViewState( val roomId: String? = null -) : MvRxState { +) : MavericksState { // No constructor for RoomDetailArgs because of intent for Shortcut diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt index 1ff8af1d7d..b61583df55 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt @@ -22,6 +22,7 @@ import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import com.jakewharton.rxbinding3.appcompat.queryTextChanges @@ -37,6 +38,7 @@ import im.vector.app.databinding.FragmentPublicRoomsBinding import im.vector.app.features.permalink.NavigationInterceptor import im.vector.app.features.permalink.PermalinkHandler import io.reactivex.rxkotlin.subscribeBy +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom import timber.log.Timber @@ -124,20 +126,20 @@ class PublicRoomsFragment @Inject constructor( } override fun onUnknownRoomClicked(roomIdOrAlias: String) { - val permalink = session.permalinkService().createPermalink(roomIdOrAlias) - permalinkHandler - .launch(requireContext(), permalink, object : NavigationInterceptor { - override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { - requireActivity().finish() - return false - } - }) - .subscribe { isSuccessful -> - if (!isSuccessful) { - requireContext().toast(R.string.room_error_not_found) - } - } - .disposeOnDestroyView() + viewLifecycleOwner.lifecycleScope.launch { + val permalink = session.permalinkService().createPermalink(roomIdOrAlias) + val isHandled = permalinkHandler + .launch(requireContext(), permalink, object : NavigationInterceptor { + override fun navToRoom(roomId: String?, eventId: String?, deepLink: Uri?): Boolean { + requireActivity().finish() + return false + } + }) + + if (!isHandled) { + requireContext().toast(R.string.room_error_not_found) + } + } } override fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt index fdab72caba..3b9995a13d 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomdirectory import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom @@ -36,4 +36,4 @@ data class PublicRoomsViewState( // keys are room alias or roomId val changeMembershipStates: Map = emptyMap(), val roomDirectoryData: RoomDirectoryData = RoomDirectoryData() -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt index dc1cbfc58d..a2089e6cd5 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt @@ -16,11 +16,10 @@ package im.vector.app.features.roomdirectory -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.appendAt @@ -31,6 +30,7 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session @@ -38,7 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsFilter import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoomsParams import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber class RoomDirectoryViewModel @AssistedInject constructor( @@ -53,7 +53,7 @@ class RoomDirectoryViewModel @AssistedInject constructor( fun create(initialState: PublicRoomsViewState): RoomDirectoryViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { private const val PUBLIC_ROOMS_LIMIT = 20 @JvmStatic @@ -80,28 +80,24 @@ class RoomDirectoryViewModel @AssistedInject constructor( memberships = listOf(Membership.JOIN) } session - .rx() + .flow() .liveRoomSummaries(queryParams) - .subscribe { list -> - val joinedRoomIds = list - ?.map { it.roomId } - ?.toSet() - .orEmpty() - - setState { - copy(joinedRoomsIds = joinedRoomIds) - } + .map { roomSummaries -> + roomSummaries + .map { it.roomId } + .toSet() + } + .setOnEach { + copy(joinedRoomsIds = it) } - .disposeOnClear() } private fun observeMembershipChanges() { - session.rx() + session.flow() .liveRoomChangeMembershipState() - .subscribe { - setState { copy(changeMembershipStates = it) } + .setOnEach { + copy(changeMembershipStates = it) } - .disposeOnClear() } override fun handle(action: RoomDirectoryAction) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 14789aabb5..e0a542dd68 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -21,7 +21,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -122,7 +122,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt index 46076edec6..389d365875 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roomdirectory.createroom import android.net.Uri import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -40,7 +40,7 @@ data class CreateRoomViewState( val supportsRestricted: Boolean = false, val aliasLocalPart: String? = null, val isSubSpace: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: CreateRoomArgs) : this( roomName = args.initialName, diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt index 2558715834..3f73b80bc6 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -50,7 +50,7 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor( fun create(initialState: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomDirectoryPickerViewState): RoomDirectoryPickerViewModel? { @@ -66,7 +66,7 @@ class RoomDirectoryPickerViewModel @AssistedInject constructor( } private fun observeAndCompute() { - selectSubscribe( + onEach( RoomDirectoryPickerViewState::asyncThirdPartyRequest, RoomDirectoryPickerViewState::customHomeservers ) { async, custom -> diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt index 5cdee862ab..56aa807e41 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomdirectory.picker import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomdirectory.RoomDirectoryServer import org.matrix.android.sdk.api.session.room.model.thirdparty.ThirdPartyProtocol @@ -30,4 +30,4 @@ data class RoomDirectoryPickerViewState( val addServerAsync: Async = Uninitialized, // computed val directories: List = emptyList() -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt index 04c4ea18bf..1df070d3d9 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt @@ -19,7 +19,7 @@ package im.vector.app.features.roomdirectory.roompreview import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -30,6 +30,8 @@ import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.roomdirectory.JoinState import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue @@ -40,7 +42,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.peeking.PeekResult import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val initialState: RoomPreviewViewState, @@ -52,7 +54,7 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini fun create(initialState: RoomPreviewViewState): RoomPreviewViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomPreviewViewState): RoomPreviewViewModel? { @@ -165,9 +167,9 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini excludeType = null } session - .rx() + .flow() .liveRoomSummaries(queryParams) - .subscribe { list -> + .onEach { list -> val isRoomJoined = list.any { it.membership == Membership.JOIN } @@ -180,13 +182,13 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini setState { copy(roomJoinState = JoinState.JOINED) } } } - .disposeOnClear() + .launchIn(viewModelScope) } private fun observeMembershipChanges() { - session.rx() + session.flow() .liveRoomChangeMembershipState() - .subscribe { + .onEach { val changeMembership = it[initialState.roomId] ?: ChangeMembershipState.Unknown val joinState = when (changeMembership) { is ChangeMembershipState.Joining -> JoinState.JOINING @@ -198,7 +200,7 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini setState { copy(roomJoinState = joinState) } } } - .disposeOnClear() + .launchIn(viewModelScope) } override fun handle(action: RoomPreviewAction) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt index 7af6e757ad..8488dd7267 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomdirectory.roompreview import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomdirectory.JoinState import org.matrix.android.sdk.api.session.permalinks.PermalinkData @@ -48,7 +48,7 @@ data class RoomPreviewViewState( val fromEmailInvite: PermalinkData.RoomEmailInviteLink? = null, // used only if it's an email invite val isEmailBoundToAccount: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomPreviewData) : this( roomId = args.roomId, diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt index 72122ff7fe..8c166e7715 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt @@ -20,7 +20,7 @@ package im.vector.app.features.roommemberprofile import android.content.Context import android.content.Intent import android.widget.Toast -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.appbar.MaterialToolbar import im.vector.app.R @@ -42,7 +42,7 @@ class RoomMemberProfileActivity : companion object { fun newIntent(context: Context, args: RoomMemberProfileArgs): Intent { return Intent(context, RoomMemberProfileActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, args) + putExtra(Mavericks.KEY_ARG, args) } } } @@ -66,7 +66,7 @@ class RoomMemberProfileActivity : override fun initUiAndData() { if (isFirstCreation()) { - val fragmentArgs: RoomMemberProfileArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + val fragmentArgs: RoomMemberProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return addFragment(R.id.simpleFragmentContainer, RoomMemberProfileFragment::class.java, fragmentArgs) } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt index dbddad87ca..e99c8dde64 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewModel.kt @@ -17,11 +17,10 @@ package im.vector.app.features.roommemberprofile -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -33,10 +32,12 @@ import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.displayname.getBestName -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory -import io.reactivex.Observable -import io.reactivex.functions.BiFunction +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.query.QueryStringValue @@ -47,16 +48,14 @@ import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.model.Membership -import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent -import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState, private val stringProvider: StringProvider, @@ -68,7 +67,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v fun create(initialState: RoomMemberProfileViewState): RoomMemberProfileViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomMemberProfileViewState): RoomMemberProfileViewModel? { @@ -109,7 +108,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v } } - session.rx().liveUserCryptoDevices(initialState.userId) + session.flow().liveUserCryptoDevices(initialState.userId) .map { Pair( it.fold(true, { prev, dev -> prev && dev.isVerified }), @@ -123,14 +122,14 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v ) } - session.rx().liveCrossSigningInfo(initialState.userId) + session.flow().liveCrossSigningInfo(initialState.userId) .execute { copy(userMXCrossSigningInfo = it.invoke()?.getOrNull()) } } private fun observeIgnoredState() { - session.rx().liveIgnoredUsers() + session.flow().liveIgnoredUsers() .map { ignored -> ignored.find { it.userId == initialState.userId @@ -247,7 +246,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v val queryParams = roomMemberQueryParams { this.userId = QueryStringValue.Equals(initialState.userId, QueryStringValue.Case.SENSITIVE) } - room.rx().liveRoomMembers(queryParams) + room.flow().liveRoomMembers(queryParams) .map { it.firstOrNull().toOptional() } .unwrap() .execute { @@ -287,11 +286,11 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v } private fun observeRoomSummaryAndPowerLevels(room: Room) { - val roomSummaryLive = room.rx().liveRoomSummary().unwrap() - val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable() + val roomSummaryLive = room.flow().liveRoomSummary().unwrap() + val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow() powerLevelsContentLive - .subscribe { + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) val permissions = ActionPermissions( canKick = powerLevelsHelper.isUserAbleToKick(session.myUserId), @@ -299,30 +298,26 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId), canEditPowerLevel = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_POWER_LEVELS) ) - setState { copy(powerLevelsContent = it, actionPermissions = permissions) } - } - .disposeOnClear() + setState { + copy(powerLevelsContent = it, actionPermissions = permissions) + } + }.launchIn(viewModelScope) roomSummaryLive.execute { copy(isRoomEncrypted = it.invoke()?.isEncrypted == true) } - Observable - .combineLatest( - roomSummaryLive, - powerLevelsContentLive, - BiFunction { roomSummary, powerLevelsContent -> - val roomName = roomSummary.toMatrixItem().getBestName() - val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent) - when (val userPowerLevel = powerLevelsHelper.getUserRole(initialState.userId)) { - Role.Admin -> stringProvider.getString(R.string.room_member_power_level_admin_in, roomName) - Role.Moderator -> stringProvider.getString(R.string.room_member_power_level_moderator_in, roomName) - Role.Default -> stringProvider.getString(R.string.room_member_power_level_default_in, roomName) - is Role.Custom -> stringProvider.getString(R.string.room_member_power_level_custom_in, userPowerLevel.value, roomName) - } - } - ).execute { - copy(userPowerLevelString = it) - } + roomSummaryLive.combine(powerLevelsContentLive) { roomSummary, powerLevelsContent -> + val roomName = roomSummary.toMatrixItem().getBestName() + val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent) + when (val userPowerLevel = powerLevelsHelper.getUserRole(initialState.userId)) { + Role.Admin -> stringProvider.getString(R.string.room_member_power_level_admin_in, roomName) + Role.Moderator -> stringProvider.getString(R.string.room_member_power_level_moderator_in, roomName) + Role.Default -> stringProvider.getString(R.string.room_member_power_level_default_in, roomName) + is Role.Custom -> stringProvider.getString(R.string.room_member_power_level_custom_in, userPowerLevel.value, roomName) + } + }.execute { + copy(userPowerLevelString = it) + } } private fun handleIgnoreAction() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewState.kt index 5c2751f0dc..a4730153c2 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roommemberprofile import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.room.model.Membership @@ -42,7 +42,7 @@ data class RoomMemberProfileViewState( val asyncMembership: Async = Uninitialized, val hasReadReceipt: Boolean = false, val actionPermissions: ActionPermissions = ActionPermissions() -) : MvRxState { +) : MavericksState { constructor(args: RoomMemberProfileArgs) : this(userId = args.userId, roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt index f0cdb1cdd1..05ccc57b10 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheet.kt @@ -24,7 +24,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -122,7 +122,7 @@ class DeviceListBottomSheet : companion object { fun newInstance(userId: String, allowDeviceAction: Boolean = true): DeviceListBottomSheet { val args = Bundle() - args.putParcelable(MvRx.KEY_ARG, Args(userId, allowDeviceAction)) + args.putParcelable(Mavericks.KEY_ARG, Args(userId, allowDeviceAction)) return DeviceListBottomSheet().apply { arguments = args } } } diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt index 386e0c98af..063f7b6188 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/devices/DeviceListBottomSheetViewModel.kt @@ -19,8 +19,8 @@ package im.vector.app.features.roommemberprofile.devices import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -33,8 +33,8 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo -import org.matrix.android.sdk.rx.rx data class DeviceListViewState( val userItem: MatrixItem? = null, @@ -42,7 +42,7 @@ data class DeviceListViewState( val memberCrossSigningKey: MXCrossSigningInfo? = null, val cryptoDevices: Async> = Loading(), val selectedDevice: CryptoDeviceInfo? = null -) : MvRxState +) : MavericksState class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted private val initialState: DeviceListViewState, @Assisted private val args: DeviceListBottomSheet.Args, @@ -55,14 +55,14 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } init { - session.rx().liveUserCryptoDevices(args.userId) + session.flow().liveUserCryptoDevices(args.userId) .execute { copy(cryptoDevices = it).also { refreshSelectedId() } } - session.rx().liveCrossSigningInfo(args.userId) + session.flow().liveCrossSigningInfo(args.userId) .execute { copy(memberCrossSigningKey = it.invoke()?.getOrNull()) } @@ -108,7 +108,7 @@ class DeviceListBottomSheetViewModel @AssistedInject constructor(@Assisted priva } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DeviceListViewState): DeviceListBottomSheetViewModel? { val fragment: DeviceListBottomSheet = (viewModelContext as FragmentViewModelContext).fragment() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt index ec9beda9d6..f9ba2f6810 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt @@ -20,7 +20,7 @@ package im.vector.app.features.roomprofile import android.content.Context import android.content.Intent import android.widget.Toast -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.appbar.MaterialToolbar import im.vector.app.R @@ -60,7 +60,7 @@ class RoomProfileActivity : fun newIntent(context: Context, roomId: String, directAccess: Int?): Intent { val roomProfileArgs = RoomProfileArgs(roomId) return Intent(context, RoomProfileActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, roomProfileArgs) + putExtra(Mavericks.KEY_ARG, roomProfileArgs) putExtra(EXTRA_DIRECT_ACCESS, directAccess) } } @@ -91,7 +91,7 @@ class RoomProfileActivity : override fun initUiAndData() { sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java) - roomProfileArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + roomProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return if (isFirstCreation()) { when (intent?.extras?.getInt(EXTRA_DIRECT_ACCESS, EXTRA_DIRECT_ACCESS_ROOM_ROOT)) { EXTRA_DIRECT_ACCESS_ROOM_SETTINGS -> { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index d35e8f3ad5..c4fc2bc7bb 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -17,9 +17,8 @@ package im.vector.app.features.roomprofile -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -29,7 +28,7 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.ShortcutCreator -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue @@ -41,10 +40,10 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.state.isPublic -import org.matrix.android.sdk.rx.RxRoom -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.FlowRoom +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap class RoomProfileViewModel @AssistedInject constructor( @Assisted private val initialState: RoomProfileViewState, @@ -58,7 +57,7 @@ class RoomProfileViewModel @AssistedInject constructor( fun create(initialState: RoomProfileViewState): RoomProfileViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomProfileViewState): RoomProfileViewModel? { @@ -70,15 +69,15 @@ class RoomProfileViewModel @AssistedInject constructor( private val room = session.getRoom(initialState.roomId)!! init { - val rxRoom = room.rx() - observeRoomSummary(rxRoom) - observeRoomCreateContent(rxRoom) - observeBannedRoomMembers(rxRoom) + val flowRoom = room.flow() + observeRoomSummary(flowRoom) + observeRoomCreateContent(flowRoom) + observeBannedRoomMembers(flowRoom) observePermissions() } - private fun observeRoomCreateContent(rxRoom: RxRoom) { - rxRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition) + private fun observeRoomCreateContent(flowRoom: FlowRoom) { + flowRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() .execute { async -> @@ -93,32 +92,31 @@ class RoomProfileViewModel @AssistedInject constructor( } } - private fun observeRoomSummary(rxRoom: RxRoom) { - rxRoom.liveRoomSummary() + private fun observeRoomSummary(flowRoom: FlowRoom) { + flowRoom.liveRoomSummary() .unwrap() .execute { copy(roomSummary = it) } } - private fun observeBannedRoomMembers(rxRoom: RxRoom) { - rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) }) + private fun observeBannedRoomMembers(flowRoom: FlowRoom) { + flowRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) }) .execute { copy(bannedMembership = it) } } private fun observePermissions() { - PowerLevelsObservableFactory(room) - .createObservable() - .subscribe { + PowerLevelsFlowFactory(room) + .createFlow() + .setOnEach { val powerLevelsHelper = PowerLevelsHelper(it) val permissions = RoomProfileViewState.ActionPermissions( canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION) ) - setState { copy(actionPermissions = permissions) } + copy(actionPermissions = permissions) } - .disposeOnClear() } override fun handle(action: RoomProfileAction) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index 999b6540bd..14b415c53a 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roomprofile import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -35,7 +35,7 @@ data class RoomProfileViewState( val recommendedRoomVersion: String? = null, val canUpgradeRoom: Boolean = false, val isTombstoned: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt index bb9a5c39d9..68cbfc6170 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewModel.kt @@ -16,11 +16,10 @@ package im.vector.app.features.roomprofile.alias -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -29,7 +28,9 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixPatterns.getDomain import org.matrix.android.sdk.api.query.QueryStringValue @@ -38,9 +39,9 @@ import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: RoomAliasViewState, private val session: Session) : @@ -51,7 +52,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo fun create(initialState: RoomAliasViewState): RoomAliasViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomAliasViewState): RoomAliasViewModel? { @@ -128,7 +129,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy( @@ -138,9 +139,9 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo } private fun observePowerLevel() { - PowerLevelsObservableFactory(room) - .createObservable() - .subscribe { + PowerLevelsFlowFactory(room) + .createFlow() + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) val permissions = RoomAliasViewState.ActionPermissions( canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend( @@ -163,27 +164,23 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo publishManuallyState = newPublishManuallyState ) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } /** * We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar. */ private fun observeRoomCanonicalAlias() { - room.rx() + room.flow() .liveStateEvent(EventType.STATE_ROOM_CANONICAL_ALIAS, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .subscribe { - setState { - copy( - canonicalAlias = it.canonicalAlias, - alternativeAliases = it.alternativeAliases.orEmpty().sorted() - ) - } + .setOnEach { + copy( + canonicalAlias = it.canonicalAlias, + alternativeAliases = it.alternativeAliases.orEmpty().sorted() + ) } - .disposeOnClear() } override fun handle(action: RoomAliasAction) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt index f6341f4f64..aabdb7530f 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/RoomAliasViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.alias import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomprofile.RoomProfileArgs import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility @@ -35,7 +35,7 @@ data class RoomAliasViewState( val publishManuallyState: AddAliasState = AddAliasState.Hidden, val localAliases: Async> = Uninitialized, val newLocalAliasState: AddAliasState = AddAliasState.Closed -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetState.kt index a61075cef6..1accc85e45 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.roomprofile.alias.detail -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState data class RoomAliasBottomSheetState( val alias: String, @@ -25,7 +25,7 @@ data class RoomAliasBottomSheetState( val isMainAlias: Boolean, val isLocal: Boolean, val canEditCanonicalAlias: Boolean -) : MvRxState { +) : MavericksState { constructor(args: RoomAliasBottomSheetArgs) : this( alias = args.alias, diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt index 2029491546..bc249fc746 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/alias/detail/RoomAliasBottomSheetViewModel.kt @@ -16,7 +16,7 @@ package im.vector.app.features.roomprofile.alias.detail import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -36,7 +36,7 @@ class RoomAliasBottomSheetViewModel @AssistedInject constructor( fun create(initialState: RoomAliasBottomSheetState): RoomAliasBottomSheetViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomAliasBottomSheetState): RoomAliasBottomSheetViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt index b5c10ec2fa..e3132c3cc5 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewModel.kt @@ -16,9 +16,8 @@ package im.vector.app.features.roomprofile.banned -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -27,7 +26,7 @@ import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue @@ -39,8 +38,8 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomBannedMemberListViewState, private val stringProvider: StringProvider, @@ -55,32 +54,30 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia private val room = session.getRoom(initialState.roomId)!! init { - val rxRoom = room.rx() - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy(roomSummary = async) } - rxRoom.liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) }) + room.flow().liveRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.BAN) }) .execute { copy( bannedMemberSummaries = it ) } - val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable() + val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow() powerLevelsContentLive - .subscribe { + .setOnEach { val powerLevelsHelper = PowerLevelsHelper(it) - setState { copy(canUserBan = powerLevelsHelper.isUserAbleToBan(session.myUserId)) } + copy(canUserBan = powerLevelsHelper.isUserAbleToBan(session.myUserId)) } - .disposeOnClear() } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomBannedMemberListViewState): RoomBannedMemberListViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt index 2861b30222..e36de58f97 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/banned/RoomBannedMemberListViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.banned import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomprofile.RoomProfileArgs import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary @@ -30,7 +30,7 @@ data class RoomBannedMemberListViewState( val filter: String = "", val onGoingModerationAction: List = emptyList(), val canUserBan: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt index 1e3a97a027..f16353353c 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewModel.kt @@ -16,10 +16,10 @@ package im.vector.app.features.roomprofile.members -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.asFlow import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -27,9 +27,15 @@ import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory -import io.reactivex.Observable -import io.reactivex.android.schedulers.AndroidSchedulers +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.extensions.orFalse @@ -43,10 +49,9 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.Role -import org.matrix.android.sdk.rx.asObservable -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap import timber.log.Timber class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberListViewState, @@ -59,7 +64,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState fun create(initialState: RoomMemberListViewState): RoomMemberListViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomMemberListViewState): RoomMemberListViewModel? { @@ -86,28 +91,26 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState memberships = Membership.activeMemberships() } - Observable - .combineLatest, PowerLevelsContent, RoomMemberSummaries>( - room.rx().liveRoomMembers(roomMemberQueryParams), - room.rx() - .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) - .mapOptional { it.content.toModel() } - .unwrap(), - { roomMembers, powerLevelsContent -> - buildRoomMemberSummaries(powerLevelsContent, roomMembers) - } - ) + combine( + room.flow().liveRoomMembers(roomMemberQueryParams), + room.flow() + .liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) + .mapOptional { it.content.toModel() } + .unwrap() + ) { roomMembers, powerLevelsContent -> + buildRoomMemberSummaries(powerLevelsContent, roomMembers) + } .execute { async -> copy(roomMemberSummaries = async) } if (room.isEncrypted()) { - room.rx().liveRoomMembers(roomMemberQueryParams) - .observeOn(AndroidSchedulers.mainThread()) - .switchMap { membersSummary -> + room.flow().liveRoomMembers(roomMemberQueryParams) + .flowOn(Dispatchers.Main) + .flatMapLatest { membersSummary -> session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId }) - .asObservable() - .doOnError { Timber.e(it) } + .asFlow() + .catch { Timber.e(it) } .map { deviceList -> // If any key change, emit the userIds list deviceList.groupBy { it.userId }.mapValues { @@ -129,8 +132,8 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState } private fun observePowerLevel() { - PowerLevelsObservableFactory(room).createObservable() - .subscribe { + PowerLevelsFlowFactory(room).createFlow() + .onEach { val permissions = ActionPermissions( canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId), canRevokeThreePidInvite = PowerLevelsHelper(it).isUserAllowedToSend( @@ -142,12 +145,11 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState setState { copy(actionsPermissions = permissions) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy(roomSummary = async) @@ -155,7 +157,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState } private fun observeThirdPartyInvites() { - room.rx().liveStateEvents(setOf(EventType.STATE_ROOM_THIRD_PARTY_INVITE)) + room.flow().liveStateEvents(setOf(EventType.STATE_ROOM_THIRD_PARTY_INVITE)) .execute { async -> copy(threePidInvites = async) } @@ -192,7 +194,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState override fun handle(action: RoomMemberListAction) { when (action) { is RoomMemberListAction.RevokeThreePidInvite -> handleRevokeThreePidInvite(action) - is RoomMemberListAction.FilterMemberList -> handleFilterMemberList(action) + is RoomMemberListAction.FilterMemberList -> handleFilterMemberList(action) }.exhaustive } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt index 63d07cc4dd..d736260f10 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roomprofile.members import androidx.annotation.StringRes import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.core.platform.GenericIdArgs @@ -36,7 +36,7 @@ data class RoomMemberListViewState( val threePidInvites: Async> = Uninitialized, val trustLevelMap: Async> = Uninitialized, val actionsPermissions: ActionPermissions = ActionPermissions() -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt index dd0535f51b..f91b482b13 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roomprofile.notifications import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -28,8 +28,8 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap class RoomNotificationSettingsViewModel @AssistedInject constructor( @Assisted initialState: RoomNotificationSettingsViewState, @@ -41,7 +41,7 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor( fun create(initialState: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomNotificationSettingsViewState): RoomNotificationSettingsViewModel { @@ -64,7 +64,7 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor( } private fun observeSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy(roomSummary = async) @@ -72,7 +72,7 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor( } private fun observeNotificationState() { - room.rx() + room.flow() .liveNotificationState() .execute { copy(notificationState = it) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt index 2e660eec05..832bb5036e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/notifications/RoomNotificationSettingsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.notifications import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import im.vector.app.features.home.room.list.actions.RoomListActionsArgs @@ -30,7 +30,7 @@ data class RoomNotificationSettingsViewState( val roomSummary: Async = Uninitialized, val isLoading: Boolean = false, val notificationState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) constructor(args: RoomListActionsArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt index c5c0c6c822..bf2f2134d6 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewModel.kt @@ -16,9 +16,8 @@ package im.vector.app.features.roomprofile.permissions -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -26,15 +25,17 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialState: RoomPermissionsViewState, private val session: Session) : @@ -45,7 +46,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat fun create(initialState: RoomPermissionsViewState): RoomPermissionsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomPermissionsViewState): RoomPermissionsViewModel? { @@ -62,7 +63,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy( @@ -72,9 +73,9 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat } private fun observePowerLevel() { - PowerLevelsObservableFactory(room) - .createObservable() - .subscribe { powerLevelContent -> + PowerLevelsFlowFactory(room) + .createFlow() + .onEach { powerLevelContent -> val powerLevelsHelper = PowerLevelsHelper(powerLevelContent) val permissions = RoomPermissionsViewState.ActionPermissions( canChangePowerLevels = powerLevelsHelper.isUserAllowedToSend( @@ -89,8 +90,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat currentPowerLevelsContent = Success(powerLevelContent) ) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } override fun handle(action: RoomPermissionsAction) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt index ce38ab87e5..9a5ac4c19f 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/permissions/RoomPermissionsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.permissions import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomprofile.RoomProfileArgs import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent @@ -30,7 +30,7 @@ data class RoomPermissionsViewState( val showAdvancedPermissions: Boolean = false, val currentPowerLevelsContent: Async = Uninitialized, val isLoading: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 5b0943906a..c3c8ca7e2f 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -19,17 +19,19 @@ package im.vector.app.features.roomprofile.settings import androidx.core.net.toFile import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.settings.VectorPreferences -import io.reactivex.Completable -import io.reactivex.Observable +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -41,9 +43,9 @@ import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState, private val vectorPreferences: VectorPreferences, @@ -55,7 +57,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: fun create(initialState: RoomSettingsViewState): RoomSettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomSettingsViewState): RoomSettingsViewModel? { @@ -97,7 +99,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: } private fun observeState() { - selectSubscribe( + onEach( RoomSettingsViewState::avatarAction, RoomSettingsViewState::newName, RoomSettingsViewState::newTopic, @@ -123,7 +125,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> val roomSummary = async.invoke() @@ -134,10 +136,10 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: ) } - val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable() + val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow() powerLevelsContentLive - .subscribe { + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) val permissions = RoomSettingsViewState.ActionPermissions( canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR), @@ -152,62 +154,56 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: canAddChildren = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD) ) - setState { copy(actionPermissions = permissions) } - } - .disposeOnClear() + setState { + copy(actionPermissions = permissions) + } + }.launchIn(viewModelScope) } private fun observeRoomHistoryVisibility() { - room.rx() + room.flow() .liveStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .subscribe { - it.historyVisibility?.let { - setState { copy(currentHistoryVisibility = it) } - } + .mapNotNull { it.historyVisibility } + .setOnEach { + copy(currentHistoryVisibility = it) } - .disposeOnClear() } private fun observeJoinRule() { - room.rx() + room.flow() .liveStateEvent(EventType.STATE_ROOM_JOIN_RULES, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .subscribe { - it.joinRules?.let { - setState { copy(currentRoomJoinRules = it) } - } + .mapNotNull { it.joinRules } + .setOnEach { + copy(currentRoomJoinRules = it) } - .disposeOnClear() } private fun observeGuestAccess() { - room.rx() + room.flow() .liveStateEvent(EventType.STATE_ROOM_GUEST_ACCESS, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .subscribe { - it.guestAccess?.let { - setState { copy(currentGuestAccess = it) } - } + .mapNotNull { it.guestAccess } + .setOnEach { + copy(currentGuestAccess = it) } - .disposeOnClear() } /** * We do not want to use the fallback avatar url, which can be the other user avatar, or the current user avatar. */ private fun observeRoomAvatar() { - room.rx() + room.flow() .liveStateEvent(EventType.STATE_ROOM_AVATAR, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() - .subscribe { - setState { copy(currentRoomAvatarUrl = it.avatarUrl) } + .setOnEach { + copy(currentRoomAvatarUrl = it.avatarUrl) } - .disposeOnClear() } override fun handle(action: RoomSettingsAction) { @@ -261,61 +257,57 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: } private fun saveSettings() = withState { state -> - postLoading(true) - - val operationList = mutableListOf() + val operationList = mutableListOf Unit>() val summary = state.roomSummary.invoke() when (val avatarAction = state.avatarAction) { RoomSettingsViewState.AvatarAction.None -> Unit RoomSettingsViewState.AvatarAction.DeleteAvatar -> { - operationList.add(room.rx().deleteAvatar()) + operationList.add { room.deleteAvatar() } } is RoomSettingsViewState.AvatarAction.UpdateAvatar -> { - operationList.add(room.rx().updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName)) + operationList.add { room.updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName) } } } if (summary?.name != state.newName) { - operationList.add(room.rx().updateName(state.newName ?: "")) + operationList.add { room.updateName(state.newName ?: "") } } if (summary?.topic != state.newTopic) { - operationList.add(room.rx().updateTopic(state.newTopic ?: "")) + operationList.add { room.updateTopic(state.newTopic ?: "") } } if (state.newHistoryVisibility != null) { - operationList.add(room.rx().updateHistoryReadability(state.newHistoryVisibility)) + operationList.add { room.updateHistoryReadability(state.newHistoryVisibility) } } if (state.newRoomJoinRules.hasChanged()) { - operationList.add(room.rx().updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess)) + operationList.add { room.updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess) } + } + viewModelScope.launch { + updateLoadingState(isLoading = true) + try { + for (operation in operationList) { + operation.invoke() + } + setState { + deletePendingAvatar(this) + copy( + avatarAction = RoomSettingsViewState.AvatarAction.None, + newHistoryVisibility = null, + newRoomJoinRules = RoomSettingsViewState.NewJoinRule() + ) + } + _viewEvents.post(RoomSettingsViewEvents.Success) + } catch (failure: Throwable) { + _viewEvents.post(RoomSettingsViewEvents.Failure(failure)) + } finally { + updateLoadingState(isLoading = false) + } } - - Observable - .fromIterable(operationList) - .concatMapCompletable { it } - .subscribe( - { - postLoading(false) - setState { - deletePendingAvatar(this) - copy( - avatarAction = RoomSettingsViewState.AvatarAction.None, - newHistoryVisibility = null, - newRoomJoinRules = RoomSettingsViewState.NewJoinRule() - ) - } - _viewEvents.post(RoomSettingsViewEvents.Success) - }, - { - postLoading(false) - _viewEvents.post(RoomSettingsViewEvents.Failure(it)) - } - ) - .disposeOnClear() } - private fun postLoading(isLoading: Boolean) { + private fun updateLoadingState(isLoading: Boolean) { setState { copy(isLoading = isLoading) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index 403836b268..122e0034c6 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.roomprofile.settings import android.net.Uri import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.R import im.vector.app.core.resources.StringProvider @@ -46,7 +46,7 @@ data class RoomSettingsViewState( val actionPermissions: ActionPermissions = ActionPermissions(), val supportsRestricted: Boolean = false, val canUpgradeToRestricted: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt index 21c39ad49d..dcce7b2384 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt @@ -22,7 +22,7 @@ import android.os.Bundle import androidx.core.view.isVisible import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.viewModel @@ -66,7 +66,7 @@ class RoomJoinRuleActivity : VectorBaseActivity(), } override fun initUiAndData() { - roomProfileArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return + roomProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return if (isFirstCreation()) { addFragment( R.id.simpleFragmentContainer, @@ -78,7 +78,7 @@ class RoomJoinRuleActivity : VectorBaseActivity(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel.selectSubscribe(this, RoomJoinRuleChooseRestrictedState::updatingStatus) { + viewModel.onEach(RoomJoinRuleChooseRestrictedState::updatingStatus) { when (it) { Uninitialized -> { // nop @@ -142,7 +142,7 @@ class RoomJoinRuleActivity : VectorBaseActivity(), fun newIntent(context: Context, roomId: String): Intent { val roomProfileArgs = RoomProfileArgs(roomId) return Intent(context, RoomJoinRuleActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, roomProfileArgs) + putExtra(Mavericks.KEY_ARG, roomProfileArgs) } } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedState.kt index 8a107ce8f1..157f53b56e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.settings.joinrule.advanced import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomprofile.RoomProfileArgs import im.vector.app.features.roomprofile.settings.joinrule.JoinRulesOptionSupport @@ -45,6 +45,6 @@ data class RoomJoinRuleChooseRestrictedState( val restrictedSupportedByThisVersion: Boolean = false, val restrictedVersionNeeded: String? = null, val didSwitchToReplacementRoom: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt index 9a9df700f8..1e7f1d2111 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/advanced/RoomJoinRuleChooseRestrictedViewModel.kt @@ -23,7 +23,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -391,7 +391,7 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: RoomJoinRuleChooseRestrictedState): RoomJoinRuleChooseRestrictedViewModel? { val factory = when (viewModelContext) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt index dfa3204d07..3d3ad375ea 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewModel.kt @@ -16,12 +16,11 @@ package im.vector.app.features.roomprofile.uploads -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -32,8 +31,8 @@ import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.model.message.MessageType -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap class RoomUploadsViewModel @AssistedInject constructor( @Assisted initialState: RoomUploadsViewState, @@ -45,7 +44,7 @@ class RoomUploadsViewModel @AssistedInject constructor( fun create(initialState: RoomUploadsViewState): RoomUploadsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomUploadsViewState): RoomUploadsViewModel? { @@ -66,7 +65,7 @@ class RoomUploadsViewModel @AssistedInject constructor( } private fun observeRoomSummary() { - room.rx().liveRoomSummary() + room.flow().liveRoomSummary() .unwrap() .execute { async -> copy(roomSummary = async) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewState.kt index b85e4f04de..a2b5aa99df 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.roomprofile.uploads import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.roomprofile.RoomProfileArgs import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -33,7 +33,7 @@ data class RoomUploadsViewState( val asyncEventsRequest: Async = Uninitialized, // True if more result are available server side val hasMore: Boolean = true -) : MvRxState { +) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt b/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt new file mode 100644 index 0000000000..5afcb77587 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/SecretsSynchronisationInfo.kt @@ -0,0 +1,71 @@ +/* + * 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.features.settings + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME +import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.rx.SecretsSynchronisationInfo + +data class SecretsSynchronisationInfo( + val isBackupSetup: Boolean, + val isCrossSigningEnabled: Boolean, + val isCrossSigningTrusted: Boolean, + val allPrivateKeysKnown: Boolean, + val megolmBackupAvailable: Boolean, + val megolmSecretKnown: Boolean, + val isMegolmKeyIn4S: Boolean +) + +fun Session.liveSecretSynchronisationInfo(): Flow { + val sessionFlow = flow() + return combine( + sessionFlow.liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME)), + sessionFlow.liveCrossSigningInfo(myUserId), + sessionFlow.liveCrossSigningPrivateKeys() + ) { _, crossSigningInfo, pInfo -> + // first check if 4S is already setup + val is4SSetup = sharedSecretStorageService.isRecoverySetup() + val isCrossSigningEnabled = crossSigningInfo.getOrNull() != null + val isCrossSigningTrusted = crossSigningInfo.getOrNull()?.isTrusted() == true + val allPrivateKeysKnown = pInfo.getOrNull()?.allKnown().orFalse() + + val keysBackupService = cryptoService().keysBackupService() + val currentBackupVersion = keysBackupService.currentBackupVersion + val megolmBackupAvailable = currentBackupVersion != null + val savedBackupKey = keysBackupService.getKeyBackupRecoveryKeyInfo() + + val megolmKeyKnown = savedBackupKey?.version == currentBackupVersion + SecretsSynchronisationInfo( + isBackupSetup = is4SSetup, + isCrossSigningEnabled = isCrossSigningEnabled, + isCrossSigningTrusted = isCrossSigningTrusted, + allPrivateKeysKnown = allPrivateKeysKnown, + megolmBackupAvailable = megolmBackupAvailable, + megolmSecretKnown = megolmKeyKnown, + isMegolmKeyIn4S = sharedSecretStorageService.isMegolmKeyInBackup() + ) + } + .distinctUntilChanged() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 1be0bb3f76..8d950b4e32 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -54,15 +54,19 @@ import im.vector.app.features.MainActivityArgs import im.vector.app.features.discovery.DiscoverySettingsFragment import im.vector.app.features.navigation.SettingsActivityPayload import im.vector.app.features.workers.signout.SignOutUiWorker -import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerConfig import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.unwrap import java.io.File import java.util.UUID import javax.inject.Inject @@ -121,29 +125,29 @@ class VectorSettingsGeneralFragment @Inject constructor( } private fun observeUserAvatar() { - session.rx() + session.flow() .liveUser(session.myUserId) .unwrap() - .distinctUntilChanged { user -> user.avatarUrl } - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { mUserAvatarPreference.refreshAvatar(it) } - .disposeOnDestroyView() + .distinctUntilChangedBy { user -> user.avatarUrl } + .onEach { + mUserAvatarPreference.refreshAvatar(it) + } + .launchIn(viewLifecycleOwner.lifecycleScope) } private fun observeUserDisplayName() { - session.rx() + session.flow() .liveUser(session.myUserId) .unwrap() .map { it.displayName ?: "" } .distinctUntilChanged() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { displayName -> + .onEach { displayName -> mDisplayNamePreference.let { it.summary = displayName it.text = displayName } } - .disposeOnDestroyView() + .launchIn(viewLifecycleOwner.lifecycleScope) } override fun bindPref() { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 0075be6e25..7e60e69379 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -58,8 +58,11 @@ import im.vector.app.features.pin.PinMode import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault import im.vector.app.features.themes.ThemeUtils -import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import me.gujun.android.span.span import org.matrix.android.sdk.api.MatrixCallback @@ -68,7 +71,6 @@ import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DevicesListResponse import org.matrix.android.sdk.rx.SecretsSynchronisationInfo -import org.matrix.android.sdk.rx.rx import javax.inject.Inject class VectorSettingsSecurityPrivacyFragment @Inject constructor( @@ -144,14 +146,12 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( // My device name may have been updated refreshMyDevice() refreshXSigningStatus() - session.rx().liveSecretSynchronisationInfo() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { + session.liveSecretSynchronisationInfo() + .flowOn(Dispatchers.Main) + .onEach { refresh4SSection(it) refreshXSigningStatus() - }.also { - disposables.add(it) - } + }.launchIn(viewLifecycleOwner.lifecycleScope) lifecycleScope.launchWhenResumed { findPreference(VectorPreferences.SETTINGS_CRYPTOGRAPHY_HS_ADMIN_DISABLED_E2E_DEFAULT)?.isVisible = diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index 91c6223505..5aaa0be13a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -17,8 +17,8 @@ package im.vector.app.features.settings.account.deactivation import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -42,7 +42,7 @@ import kotlin.coroutines.resumeWithException data class DeactivateAccountViewState( val dummy: Boolean = false -) : MvRxState +) : MavericksState class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private val initialState: DeactivateAccountViewState, private val session: Session) : @@ -114,7 +114,7 @@ class DeactivateAccountViewModel @AssistedInject constructor(@Assisted private v } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DeactivateAccountViewState): DeactivateAccountViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index 1bd498d1ab..033d9cf716 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -15,9 +15,8 @@ */ package im.vector.app.features.settings.crosssigning -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -28,8 +27,8 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper -import io.reactivex.Observable import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor @@ -38,14 +37,11 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.auth.registration.nextUncompletedStage import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo -import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth -import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.util.awaitCallback -import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -59,26 +55,25 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( ) : VectorViewModel(initialState) { init { - Observable.combineLatest, Optional, Pair, Optional>>( - session.rx().liveMyDevicesInfo(), - session.rx().liveCrossSigningInfo(session.myUserId), - { myDevicesInfo, mxCrossSigningInfo -> - myDevicesInfo to mxCrossSigningInfo - } - ) - .execute { data -> - val crossSigningKeys = data.invoke()?.second?.getOrNull() - val xSigningIsEnableInAccount = crossSigningKeys != null - val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified() - val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign() + combine( + session.flow().liveMyDevicesInfo(), + session.flow().liveCrossSigningInfo(session.myUserId) + ) { myDevicesInfo, mxCrossSigningInfo -> + myDevicesInfo to mxCrossSigningInfo + } + .execute { data -> + val crossSigningKeys = data.invoke()?.second?.getOrNull() + val xSigningIsEnableInAccount = crossSigningKeys != null + val xSigningKeysAreTrusted = session.cryptoService().crossSigningService().checkUserTrust(session.myUserId).isVerified() + val xSigningKeyCanSign = session.cryptoService().crossSigningService().canCrossSign() - copy( - crossSigningInfo = crossSigningKeys, - xSigningIsEnableInAccount = xSigningIsEnableInAccount, - xSigningKeysAreTrusted = xSigningKeysAreTrusted, - xSigningKeyCanSign = xSigningKeyCanSign - ) - } + copy( + crossSigningInfo = crossSigningKeys, + xSigningIsEnableInAccount = xSigningIsEnableInAccount, + xSigningKeysAreTrusted = xSigningKeysAreTrusted, + xSigningKeyCanSign = xSigningKeyCanSign + ) + } } var uiaContinuation: Continuation? = null @@ -126,7 +121,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( } Unit } - is CrossSigningSettingsAction.SsoAuthDone -> { + is CrossSigningSettingsAction.SsoAuthDone -> { Timber.d("## UIA - FallBack success") if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) @@ -134,7 +129,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( uiaContinuation?.resumeWithException(IllegalArgumentException()) } } - is CrossSigningSettingsAction.PasswordAuthDone -> { + is CrossSigningSettingsAction.PasswordAuthDone -> { val decryptedPass = session.loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) uiaContinuation?.resume( UserPasswordAuth( @@ -144,7 +139,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( ) ) } - CrossSigningSettingsAction.ReAuthCancelled -> { + CrossSigningSettingsAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") _viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView) uiaContinuation?.resumeWithException(Exception()) @@ -159,7 +154,7 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( _viewEvents.post(CrossSigningSettingsViewEvents.Failure(Exception(stringProvider.getString(R.string.failed_to_initialize_cross_signing)))) } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CrossSigningSettingsViewState): CrossSigningSettingsViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewState.kt index 8a371ada68..9e349253ca 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.settings.crosssigning -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo data class CrossSigningSettingsViewState( @@ -24,4 +24,4 @@ data class CrossSigningSettingsViewState( val xSigningIsEnableInAccount: Boolean = false, val xSigningKeysAreTrusted: Boolean = false, val xSigningKeyCanSign: Boolean = true -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt index 9bfd2df0d6..7ba6042027 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheet.kt @@ -21,7 +21,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState @@ -83,7 +83,7 @@ class DeviceVerificationInfoBottomSheet : fun newInstance(userId: String, deviceId: String): DeviceVerificationInfoBottomSheet { val args = Bundle() val parcelableArgs = DeviceVerificationInfoArgs(userId, deviceId) - args.putParcelable(MvRx.KEY_ARG, parcelableArgs) + args.putParcelable(Mavericks.KEY_ARG, parcelableArgs) return DeviceVerificationInfoBottomSheet().apply { arguments = args } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt index 5f903cf49d..e6cde74440 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewModel.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.devices import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -25,9 +25,10 @@ import dagger.assisted.AssistedInject import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.flow.map import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo -import org.matrix.android.sdk.rx.rx class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: DeviceVerificationInfoBottomSheetViewState, @Assisted val deviceId: String, @@ -48,7 +49,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As isRecoverySetup = session.sharedSecretStorageService.isRecoverySetup() ) } - session.rx().liveCrossSigningInfo(session.myUserId) + session.flow().liveCrossSigningInfo(session.myUserId) .execute { copy( hasAccountCrossSigning = it.invoke()?.getOrNull() != null, @@ -56,7 +57,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As ) } - session.rx().liveUserCryptoDevices(session.myUserId) + session.flow().liveUserCryptoDevices(session.myUserId) .map { list -> list.firstOrNull { it.deviceId == deviceId } } @@ -67,7 +68,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As ) } - session.rx().liveUserCryptoDevices(session.myUserId) + session.flow().liveUserCryptoDevices(session.myUserId) .map { it.size } .execute { copy( @@ -79,7 +80,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As copy(deviceInfo = Loading()) } - session.rx().liveMyDevicesInfo() + session.flow().liveMyDevicesInfo() .map { devices -> devices.firstOrNull { it.deviceId == deviceId } ?: DeviceInfo(deviceId = deviceId) } @@ -88,7 +89,7 @@ class DeviceVerificationInfoBottomSheetViewModel @AssistedInject constructor(@As } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DeviceVerificationInfoBottomSheetViewState): diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt index a736b0442c..e320642ed0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DeviceVerificationInfoBottomSheetViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.devices import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo @@ -30,7 +30,7 @@ data class DeviceVerificationInfoBottomSheetViewState( val isMine: Boolean = false, val hasOtherSessions: Boolean = false, val isRecoverySetup: Boolean = false -) : MvRxState { +) : MavericksState { val canVerifySession: Boolean get() = hasOtherSessions || isRecoverySetup diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 30342dbf2a..a8154c3e11 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -16,13 +16,12 @@ package im.vector.app.features.settings.devices -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -34,9 +33,14 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper -import io.reactivex.Observable import io.reactivex.subjects.PublishSubject import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback @@ -52,13 +56,13 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationMethod import org.matrix.android.sdk.api.session.crypto.verification.VerificationService import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo import org.matrix.android.sdk.internal.util.awaitCallback -import org.matrix.android.sdk.rx.rx import timber.log.Timber import java.util.concurrent.TimeUnit import javax.net.ssl.HttpsURLConnection @@ -75,7 +79,7 @@ data class DevicesViewState( val request: Async = Uninitialized, val hasAccountCrossSigning: Boolean = false, val accountCrossSigningIsTrusted: Boolean = false -) : MvRxState +) : MavericksState data class DeviceFullInfo( val deviceInfo: DeviceInfo, @@ -97,7 +101,7 @@ class DevicesViewModel @AssistedInject constructor( fun create(initialState: DevicesViewState): DevicesViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: DevicesViewState): DevicesViewModel? { @@ -118,18 +122,17 @@ class DevicesViewModel @AssistedInject constructor( ) } - Observable.combineLatest, List, List>( - session.rx().liveUserCryptoDevices(session.myUserId), - session.rx().liveMyDevicesInfo(), - { cryptoList, infoList -> - infoList - .sortedByDescending { it.lastSeenTs } - .map { deviceInfo -> - val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId } - DeviceFullInfo(deviceInfo, cryptoDeviceInfo) - } - } - ) + combine( + session.flow().liveUserCryptoDevices(session.myUserId), + session.flow().liveMyDevicesInfo() + ) { cryptoList, infoList -> + infoList + .sortedByDescending { it.lastSeenTs } + .map { deviceInfo -> + val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId } + DeviceFullInfo(deviceInfo, cryptoDeviceInfo) + } + } .distinctUntilChanged() .execute { async -> copy( @@ -137,7 +140,7 @@ class DevicesViewModel @AssistedInject constructor( ) } - session.rx().liveCrossSigningInfo(session.myUserId) + session.flow().liveCrossSigningInfo(session.myUserId) .execute { copy( hasAccountCrossSigning = it.invoke()?.getOrNull() != null, @@ -146,24 +149,24 @@ class DevicesViewModel @AssistedInject constructor( } session.cryptoService().verificationService().addListener(this) -// session.rx().liveMyDeviceInfo() +// session.flow().liveMyDeviceInfo() // .execute { // copy( // devices = it // ) // } - session.rx().liveUserCryptoDevices(session.myUserId) + session.flow().liveUserCryptoDevices(session.myUserId) .map { it.size } .distinctUntilChanged() - .throttleLast(5_000, TimeUnit.MILLISECONDS) - .subscribe { + .sample(5_000) + .onEach { // If we have a new crypto device change, we might want to trigger refresh of device info session.cryptoService().fetchDevicesList(NoOpMatrixCallback()) } - .disposeOnClear() + .launchIn(viewModelScope) -// session.rx().liveUserCryptoDevices(session.myUserId) +// session.flow().liveUserCryptoDevices(session.myUserId) // .execute { // copy( // cryptoDevices = it diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt index 7e5d690d8e..104ee71edc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataViewModel.kt @@ -16,11 +16,10 @@ package im.vector.app.features.settings.devtools -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -32,18 +31,18 @@ import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow data class AccountDataViewState( val accountData: Async> = Uninitialized -) : MvRxState +) : MavericksState class AccountDataViewModel @AssistedInject constructor(@Assisted initialState: AccountDataViewState, private val session: Session) : VectorViewModel(initialState) { init { - session.rx().liveUserAccountData(emptySet()) + session.flow().liveUserAccountData(emptySet()) .execute { copy(accountData = it) } @@ -66,7 +65,7 @@ class AccountDataViewModel @AssistedInject constructor(@Assisted initialState: A fun create(initialState: AccountDataViewState): AccountDataViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: AccountDataViewState): AccountDataViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt index 6d95255e70..fd09b38919 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/GossipingEventsPaperTrailViewModel.kt @@ -16,12 +16,13 @@ package im.vector.app.features.settings.devtools +import androidx.lifecycle.asFlow import androidx.paging.PagedList import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -32,11 +33,10 @@ import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.rx.asObservable data class GossipingEventsPaperTrailState( val events: Async> = Uninitialized -) : MvRxState +) : MavericksState class GossipingEventsPaperTrailViewModel @AssistedInject constructor(@Assisted initialState: GossipingEventsPaperTrailState, private val session: Session) : @@ -50,7 +50,8 @@ class GossipingEventsPaperTrailViewModel @AssistedInject constructor(@Assisted i setState { copy(events = Loading()) } - session.cryptoService().getGossipingEventsTrail().asObservable() + session.cryptoService().getGossipingEventsTrail() + .asFlow() .execute { copy(events = it) } @@ -63,7 +64,7 @@ class GossipingEventsPaperTrailViewModel @AssistedInject constructor(@Assisted i fun create(initialState: GossipingEventsPaperTrailState): GossipingEventsPaperTrailViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: GossipingEventsPaperTrailState): GossipingEventsPaperTrailViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt index 88cae8fac2..37decc4a12 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestListViewModel.kt @@ -16,12 +16,13 @@ package im.vector.app.features.settings.devtools +import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import androidx.paging.PagedList import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -34,12 +35,11 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.internal.crypto.IncomingRoomKeyRequest import org.matrix.android.sdk.internal.crypto.OutgoingRoomKeyRequest -import org.matrix.android.sdk.rx.asObservable data class KeyRequestListViewState( val incomingRequests: Async> = Uninitialized, val outgoingRoomKeyRequests: Async> = Uninitialized -) : MvRxState +) : MavericksState class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState: KeyRequestListViewState, private val session: Session) : @@ -51,13 +51,13 @@ class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState fun refresh() { viewModelScope.launch { - session.cryptoService().getOutgoingRoomKeyRequestsPaged().asObservable() + session.cryptoService().getOutgoingRoomKeyRequestsPaged().asFlow() .execute { copy(outgoingRoomKeyRequests = it) } session.cryptoService().getIncomingRoomKeyRequestsPaged() - .asObservable() + .asFlow() .execute { copy(incomingRequests = it) } @@ -71,7 +71,7 @@ class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState fun create(initialState: KeyRequestListViewState): KeyRequestListViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: KeyRequestListViewState): KeyRequestListViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt index f51c90ec5f..362502d7d8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devtools/KeyRequestViewModel.kt @@ -22,8 +22,8 @@ import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -48,7 +48,7 @@ sealed class KeyRequestEvents : VectorViewEvents { data class KeyRequestViewState( val exporting: Async = Uninitialized -) : MvRxState +) : MavericksState class KeyRequestViewModel @AssistedInject constructor( @Assisted initialState: KeyRequestViewState, @@ -60,7 +60,7 @@ class KeyRequestViewModel @AssistedInject constructor( fun create(initialState: KeyRequestViewState): KeyRequestViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: KeyRequestViewState): KeyRequestViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeServerSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeServerSettingsViewState.kt index 87ad637ca5..3acd79d768 100644 --- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeServerSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeServerSettingsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.homeserver import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.federation.FederationVersion import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities @@ -27,4 +27,4 @@ data class HomeServerSettingsViewState( val homeserverClientServerApiUrl: String = "", val homeServerCapabilities: HomeServerCapabilities = HomeServerCapabilities(), val federationVersion: Async = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt index 623ac37aa4..91ad34f1b6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsViewModel.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -41,7 +41,7 @@ class HomeserverSettingsViewModel @AssistedInject constructor( fun create(initialState: HomeServerSettingsViewState): HomeserverSettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: HomeServerSettingsViewState): HomeserverSettingsViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt index 6238885528..91213809de 100644 --- a/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/ignored/IgnoredUsersViewModel.kt @@ -16,13 +16,12 @@ package im.vector.app.features.settings.ignored -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -34,12 +33,12 @@ import im.vector.app.core.platform.VectorViewModelAction import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.user.model.User -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow data class IgnoredUsersViewState( val ignoredUsers: List = emptyList(), val unIgnoreRequest: Async = Uninitialized -) : MvRxState +) : MavericksState sealed class IgnoredUsersAction : VectorViewModelAction { data class UnIgnore(val userId: String) : IgnoredUsersAction() @@ -54,7 +53,7 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: IgnoredUsersViewState): IgnoredUsersViewModel? { @@ -68,7 +67,7 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: } private fun observeIgnoredUsers() { - session.rx() + session.flow() .liveIgnoredUsers() .execute { async -> copy( diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt index d0077eec66..83858dff6a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt @@ -19,7 +19,7 @@ package im.vector.app.features.settings.locale import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -53,7 +53,7 @@ class LocalePickerViewModel @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: LocalePickerViewState): LocalePickerViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt index 64c95468f0..8cb5978393 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.locale import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.settings.VectorLocale import java.util.Locale @@ -25,4 +25,4 @@ import java.util.Locale data class LocalePickerViewState( val currentLocale: Locale = VectorLocale.applicationLocale, val locales: Async> = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt index bcfb68387b..d8205aada9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushGatewaysViewModel.kt @@ -16,11 +16,10 @@ package im.vector.app.features.settings.push -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -31,11 +30,11 @@ import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.pushers.Pusher -import org.matrix.android.sdk.rx.RxSession +import org.matrix.android.sdk.flow.flow data class PushGatewayViewState( val pushGateways: Async> = Uninitialized -) : MvRxState +) : MavericksState class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: PushGatewayViewState, private val session: Session) : @@ -46,7 +45,7 @@ class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: fun create(initialState: PushGatewayViewState): PushGatewaysViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? { @@ -62,7 +61,7 @@ class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: } private fun observePushers() { - RxSession(session) + session.flow() .livePushers() .execute { copy(pushGateways = it) diff --git a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt index 645ddbb8f7..745d71fd41 100644 --- a/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/push/PushRulesViewModel.kt @@ -15,8 +15,8 @@ */ package im.vector.app.features.settings.push -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import im.vector.app.core.di.HasScreenInjector import im.vector.app.core.platform.EmptyAction @@ -26,12 +26,12 @@ import org.matrix.android.sdk.api.pushrules.rest.PushRule data class PushRulesViewState( val rules: List = emptyList() -) : MvRxState +) : MavericksState class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel(initialState) { - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? { val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession() diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt index 358436a7fc..cd0d74a288 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt @@ -16,12 +16,11 @@ package im.vector.app.features.settings.threepids -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -39,9 +38,9 @@ import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth -import org.matrix.android.sdk.rx.rx import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -84,7 +83,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( fun create(initialState: ThreePidsSettingsViewState): ThreePidsSettingsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ThreePidsSettingsViewState): ThreePidsSettingsViewModel? { @@ -102,7 +101,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( } private fun observeThreePids() { - session.rx() + session.flow() .liveThreePIds(true) .execute { copy( @@ -112,7 +111,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( } private fun observePendingThreePids() { - session.rx() + session.flow() .livePendingThreePIds() .execute { copy( @@ -131,13 +130,13 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( override fun handle(action: ThreePidsSettingsAction) { when (action) { - is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action) + is ThreePidsSettingsAction.AddThreePid -> handleAddThreePid(action) is ThreePidsSettingsAction.ContinueThreePid -> handleContinueThreePid(action) - is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action) - is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action) - is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action) - is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action) - ThreePidsSettingsAction.SsoAuthDone -> { + is ThreePidsSettingsAction.SubmitCode -> handleSubmitCode(action) + is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action) + is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action) + is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action) + ThreePidsSettingsAction.SsoAuthDone -> { Timber.d("## UIA - FallBack success") if (pendingAuth != null) { uiaContinuation?.resume(pendingAuth!!) @@ -155,7 +154,7 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( ) ) } - ThreePidsSettingsAction.ReAuthCancelled -> { + ThreePidsSettingsAction.ReAuthCancelled -> { Timber.d("## UIA - Reauth cancelled") uiaContinuation?.resumeWithException(Exception()) uiaContinuation = null diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewState.kt index b080c06cbd..dbc81fd8f3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.threepids import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.core.utils.ReadOnceTrue import org.matrix.android.sdk.api.session.identity.ThreePid @@ -30,4 +30,4 @@ data class ThreePidsSettingsViewState( val msisdnValidationRequests: Map> = emptyMap(), val editTextReinitiator: ReadOnceTrue = ReadOnceTrue(), val msisdnValidationReinitiator: Map = emptyMap() -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt index da1b20b4d1..b476065035 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewModel.kt @@ -17,9 +17,8 @@ package im.vector.app.features.share import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext -import com.jakewharton.rxrelay2.BehaviorRelay import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -29,13 +28,16 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.attachments.isPreviewable import im.vector.app.features.attachments.toGroupedContentAttachmentData import im.vector.app.features.home.room.list.BreadcrumbsRoomComparator +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.sample import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx -import java.util.concurrent.TimeUnit +import org.matrix.android.sdk.flow.flow class IncomingShareViewModel @AssistedInject constructor( @Assisted initialState: IncomingShareViewState, @@ -48,7 +50,7 @@ class IncomingShareViewModel @AssistedInject constructor( fun create(initialState: IncomingShareViewState): IncomingShareViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: IncomingShareViewState): IncomingShareViewModel? { @@ -57,7 +59,7 @@ class IncomingShareViewModel @AssistedInject constructor( } } - private val filterStream: BehaviorRelay = BehaviorRelay.createDefault("") + private val filterStream = MutableStateFlow("") init { observeRoomSummaries() @@ -68,13 +70,13 @@ class IncomingShareViewModel @AssistedInject constructor( memberships = listOf(Membership.JOIN) } session - .rx().liveRoomSummaries(queryParams) + .flow().liveRoomSummaries(queryParams) .execute { copy(roomSummaries = it) } filterStream - .switchMap { filter -> + .flatMapLatest { filter -> val displayNameQuery = if (filter.isEmpty()) { QueryStringValue.NoCondition } else { @@ -84,9 +86,9 @@ class IncomingShareViewModel @AssistedInject constructor( displayName = displayNameQuery memberships = listOf(Membership.JOIN) } - session.rx().liveRoomSummaries(filterQueryParams) + session.flow().liveRoomSummaries(filterQueryParams) } - .throttleLast(300, TimeUnit.MILLISECONDS) + .sample(300) .map { it.sortedWith(breadcrumbsRoomComparator) } .execute { copy(filteredRoomSummaries = it) @@ -109,7 +111,7 @@ class IncomingShareViewModel @AssistedInject constructor( } private fun handleFilter(action: IncomingShareAction.FilterWith) { - filterStream.accept(action.filter) + filterStream.tryEmit(action.filter) } private fun handleShareToSelectedRooms() = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewState.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewState.kt index 751dc999a2..620709a515 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareViewState.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.share import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -27,4 +27,4 @@ data class IncomingShareViewState( val filteredRoomSummaries: Async> = Uninitialized, val selectedRoomIds: Set = emptySet(), val isInMultiSelectionMode: Boolean = false -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt index 552d279fad..dfc483a813 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewModel.kt @@ -16,11 +16,10 @@ package im.vector.app.features.signout.soft -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -52,7 +51,7 @@ class SoftLogoutViewModel @AssistedInject constructor( fun create(initialState: SoftLogoutViewState): SoftLogoutViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun initialState(viewModelContext: ViewModelContext): SoftLogoutViewState? { val activity: SoftLogoutActivity = (viewModelContext as ActivityViewModelContext).activity() diff --git a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt index 4beb47c4a4..511711ab2f 100644 --- a/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt +++ b/vector/src/main/java/im/vector/app/features/signout/soft/SoftLogoutViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.signout.soft import com.airbnb.mvrx.Async import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import im.vector.app.features.login.LoginMode @@ -32,7 +32,7 @@ data class SoftLogoutViewState( val userDisplayName: String, val hasUnsavedKeys: Boolean, val enteredPassword: String = "" -) : MvRxState { +) : MavericksState { fun isLoading(): Boolean { return asyncLoginAction is Loading || diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt index 344559bc81..1844e8e9ca 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceCreationActivity.kt @@ -171,7 +171,7 @@ class SpaceCreationActivity : SimpleFragmentActivity(), CreateSpaceViewModel.Fac fun newIntent(context: Context): Intent { return Intent(context, SpaceCreationActivity::class.java).apply { - // putExtra(MvRx.KEY_ARG, SpaceDirectoryArgs(spaceId)) + // putExtra(Mavericks.KEY_ARG, SpaceDirectoryArgs(spaceId)) } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt index cee945e202..47e4c6420b 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt @@ -21,7 +21,7 @@ import android.content.Intent import android.os.Bundle import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import im.vector.app.R import im.vector.app.core.di.ScreenComponent @@ -73,12 +73,12 @@ class SpaceExploreActivity : VectorBaseActivity(), SpaceD if (isFirstCreation()) { val simpleName = SpaceDirectoryFragment::class.java.simpleName - val args = intent?.getParcelableExtra(MvRx.KEY_ARG) + val args = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (supportFragmentManager.findFragmentByTag(simpleName) == null) { supportFragmentManager.commitTransaction { replace(R.id.simpleFragmentContainer, SpaceDirectoryFragment::class.java, - Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) }, + Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, simpleName ) } @@ -108,7 +108,7 @@ class SpaceExploreActivity : VectorBaseActivity(), SpaceD companion object { fun newIntent(context: Context, spaceId: String): Intent { return Intent(context, SpaceExploreActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, SpaceDirectoryArgs(spaceId)) + putExtra(Mavericks.KEY_ARG, SpaceDirectoryArgs(spaceId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt index 795713152a..eafc6a241e 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.RoomGroupingMethod import org.matrix.android.sdk.api.session.group.model.GroupSummary @@ -35,4 +35,4 @@ data class SpaceListViewState( val legacyGroups: List? = null, val expandedStates: Map = emptyMap(), val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0) -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuState.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuState.kt index 395fcc9df1..7ac844d297 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -30,7 +30,7 @@ data class SpaceMenuState( val isLastAdmin: Boolean = false, val leaveMode: LeaveMode = LeaveMode.LEAVE_NONE, val leavingState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: SpaceBottomSheetSettingsArgs) : this(spaceId = args.spaceId) enum class LeaveMode { diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt index 24ca218942..887c93afd4 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceMenuViewModel.kt @@ -20,7 +20,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -30,8 +30,10 @@ import dagger.assisted.AssistedInject import im.vector.app.AppStateHandler import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import im.vector.app.features.session.coroutineScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.ActiveSpaceFilter import org.matrix.android.sdk.api.session.Session @@ -40,7 +42,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.Role import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber class SpaceMenuViewModel @AssistedInject constructor( @@ -54,7 +56,7 @@ class SpaceMenuViewModel @AssistedInject constructor( fun create(initialState: SpaceMenuState): SpaceMenuViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: SpaceMenuState): SpaceMenuViewModel? { @@ -75,7 +77,7 @@ class SpaceMenuViewModel @AssistedInject constructor( session.getRoom(initialState.spaceId)?.let { room -> - room.rx().liveRoomSummary().subscribe { + room.flow().liveRoomSummary().onEach { it.getOrNull()?.let { if (it.membership == Membership.LEAVE) { setState { copy(leavingState = Success(Unit)) } @@ -85,11 +87,11 @@ class SpaceMenuViewModel @AssistedInject constructor( } } } - }.disposeOnClear() + }.launchIn(viewModelScope) - PowerLevelsObservableFactory(room) - .createObservable() - .subscribe { + PowerLevelsFlowFactory(room) + .createFlow() + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId) @@ -114,8 +116,7 @@ class SpaceMenuViewModel @AssistedInject constructor( isLastAdmin = isLastAdmin ) } - } - .disposeOnClear() + }.launchIn(viewModelScope) } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt index 0dcaf9d754..59166529b9 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt @@ -19,7 +19,7 @@ package im.vector.app.features.spaces import android.content.Context import android.content.Intent import android.os.Bundle -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import im.vector.app.R import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.platform.VectorBaseActivity @@ -50,12 +50,12 @@ class SpacePreviewActivity : VectorBaseActivity() { if (isFirstCreation()) { val simpleName = SpacePreviewFragment::class.java.simpleName - val args = intent?.getParcelableExtra(MvRx.KEY_ARG) + val args = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (supportFragmentManager.findFragmentByTag(simpleName) == null) { supportFragmentManager.commitTransaction { replace(R.id.simpleFragmentContainer, SpacePreviewFragment::class.java, - Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) }, + Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, simpleName ) } @@ -66,7 +66,7 @@ class SpacePreviewActivity : VectorBaseActivity() { companion object { fun newIntent(context: Context, spaceIdOrAlias: String): Intent { return Intent(context, SpacePreviewActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, SpacePreviewArgs(spaceIdOrAlias)) + putExtra(Mavericks.KEY_ARG, SpacePreviewArgs(spaceIdOrAlias)) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt index 12c4ddbfc4..fbbaeafe72 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacesListViewModel.kt @@ -16,10 +16,10 @@ package im.vector.app.features.spaces -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.asFlow import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -33,8 +33,13 @@ import im.vector.app.features.session.coroutineScope import im.vector.app.features.settings.VectorPreferences import im.vector.app.group import im.vector.app.space -import io.reactivex.Observable -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.ActiveSpaceFilter @@ -44,20 +49,15 @@ import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams import org.matrix.android.sdk.api.session.room.RoomSortOrder -import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes 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.roomSummaryQueryParams import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import org.matrix.android.sdk.api.session.space.SpaceOrderUtils import org.matrix.android.sdk.api.session.space.model.SpaceOrderContent import org.matrix.android.sdk.api.session.space.model.TopLevelSpaceComparator -import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.rx.asObservable -import org.matrix.android.sdk.rx.rx -import java.util.concurrent.TimeUnit +import org.matrix.android.sdk.flow.flow class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: SpaceListViewState, private val appStateHandler: AppStateHandler, @@ -71,7 +71,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp fun create(initialState: SpaceListViewState): SpacesListViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: SpaceListViewState): SpacesListViewModel { @@ -84,14 +84,13 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp init { - session.getUserLive(session.myUserId).asObservable() - .subscribe { - setState { - copy( - myMxItem = it?.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading() - ) - } - }.disposeOnClear() + session.getUserLive(session.myUserId) + .asFlow() + .setOnEach { + copy( + myMxItem = it.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading() + ) + } observeSpaceSummaries() // observeSelectionState() @@ -107,14 +106,10 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp .disposeOnClear() session.getGroupSummariesLive(groupSummaryQueryParams {}) - .asObservable() - .subscribe { - setState { - copy( - legacyGroups = it - ) - } - }.disposeOnClear() + .asFlow() + .setOnEach { + copy(legacyGroups = it) + } // XXX there should be a way to refactor this and share it session.getPagedRoomSummariesLive( @@ -124,10 +119,10 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp !vectorPreferences.prefSpacesShowAllRoomInHome() } ?: ActiveSpaceFilter.None }, sortOrder = RoomSortOrder.NONE - ).asObservable() - .throttleFirst(300, TimeUnit.MILLISECONDS) - .observeOn(Schedulers.computation()) - .subscribe { + ).asFlow() + .sample(300) + .flowOn(Dispatchers.Default) + .onEach { val inviteCount = if (autoAcceptInvites.hideInvites) { 0 } else { @@ -152,7 +147,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp homeAggregateCount = counts ) } - }.disposeOnClear() + }.launchIn(viewModelScope) } override fun handle(action: SpaceListAction) { @@ -286,21 +281,23 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp null) } - val rxSession = session.rx() + val flowSession = session.flow() - Observable.combineLatest, List, List>( - rxSession + combine( + flowSession .liveUser(session.myUserId) .map { it.getOrNull() }, - rxSession + flowSession .liveSpaceSummaries(spaceSummaryQueryParams), - session.accountDataService().getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)).asObservable(), - { _, communityGroups, _ -> - communityGroups - } - ) + session + .accountDataService() + .getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)) + .asFlow() + ) { _, communityGroups, _ -> + communityGroups + } .execute { async -> val rootSpaces = session.spaceService().getRootSpaceSummaries() val orders = rootSpaces.map { @@ -319,7 +316,8 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp // clear local echos on update session.accountDataService() .getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)) - .asObservable().execute { + .asFlow() + .execute { copy( spaceOrderLocalEchos = emptyMap() ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/ChoosePrivateSpaceTypeFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/create/ChoosePrivateSpaceTypeFragment.kt index 4f079551eb..6d3003dfcf 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/create/ChoosePrivateSpaceTypeFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/create/ChoosePrivateSpaceTypeFragment.kt @@ -49,7 +49,7 @@ class ChoosePrivateSpaceTypeFragment @Inject constructor( sharedViewModel.handle(CreateSpaceAction.SetSpaceTopology(SpaceTopology.MeAndTeammates)) } - sharedViewModel.subscribe { state -> + sharedViewModel.onEach { state -> views.accessInfoHelpText.text = stringProvider.getString(R.string.create_spaces_make_sure_access, state.name ?: "") } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt index ab7fb0cc25..57782d9182 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.spaces.create import android.net.Uri import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class CreateSpaceState( @@ -38,7 +38,7 @@ data class CreateSpaceState( val emailValidationResult: Map? = null, val creationResult: Async = Uninitialized, val canInviteByMail: Boolean = false -) : MvRxState { +) : MavericksState { enum class Step { ChooseType, diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt index 4495ee31a1..34cc72b03f 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -93,7 +93,7 @@ class CreateSpaceViewModel @AssistedInject constructor( super.onCleared() } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: CreateSpaceState): CreateSpaceViewModel? { val factory = when (viewModelContext) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt index 3af66cbb6b..cd7d6a379a 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt @@ -25,6 +25,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.text.toSpannable import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope import com.airbnb.epoxy.EpoxyVisibilityTracker import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState @@ -46,8 +47,7 @@ import im.vector.app.features.permalink.PermalinkHandler import im.vector.app.features.spaces.manage.ManageType import im.vector.app.features.spaces.manage.SpaceAddRoomSpaceChooserBottomSheet import im.vector.app.features.spaces.manage.SpaceManageActivity -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import java.net.URL @@ -110,7 +110,7 @@ class SpaceDirectoryFragment @Inject constructor( views.spaceDirectoryList.configureWith(epoxyController) epoxyVisibilityTracker.attach(views.spaceDirectoryList) - viewModel.selectSubscribe(this, SpaceDirectoryState::canAddRooms) { + viewModel.onEach(SpaceDirectoryState::canAddRooms) { invalidateOptionsMenu() } @@ -200,33 +200,29 @@ class SpaceDirectoryFragment @Inject constructor( } override fun onUrlClicked(url: String, title: String): Boolean { - permalinkHandler - .launch(requireActivity(), url, null) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { managed -> - if (!managed) { - if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) { - MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive) - .setTitle(R.string.external_link_confirmation_title) - .setMessage( - getString(R.string.external_link_confirmation_message, title, url) - .toSpannable() - .colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) - .colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) - ) - .setPositiveButton(R.string._continue) { _, _ -> - openUrlInExternalBrowser(requireContext(), url) - } - .setNegativeButton(R.string.cancel, null) - .show() - } else { - // Open in external browser, in a new Tab - openUrlInExternalBrowser(requireContext(), url) - } - } + viewLifecycleOwner.lifecycleScope.launch { + val isHandled = permalinkHandler.launch(requireActivity(), url, null) + if (!isHandled) { + if (title.isValidUrl() && url.isValidUrl() && URL(title).host != URL(url).host) { + MaterialAlertDialogBuilder(requireActivity(), R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive) + .setTitle(R.string.external_link_confirmation_title) + .setMessage( + getString(R.string.external_link_confirmation_message, title, url) + .toSpannable() + .colorizeMatchingText(url, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) + .colorizeMatchingText(title, colorProvider.getColorFromAttribute(R.attr.vctr_content_tertiary)) + ) + .setPositiveButton(R.string._continue) { _, _ -> + openUrlInExternalBrowser(requireContext(), url) + } + .setNegativeButton(R.string.cancel, null) + .show() + } else { + // Open in external browser, in a new Tab + openUrlInExternalBrowser(requireContext(), url) } - .disposeOnDestroyView() + } + } // In fact it is always managed return true } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryState.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryState.kt index 33b494075d..1467b69659 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.explore import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo @@ -39,7 +39,7 @@ data class SpaceDirectoryState( // cached room summaries of known rooms, we use it because computed room name would be better using it val knownRoomSummaries: List = emptyList(), val paginationStatus: Map> = emptyMap() -) : MvRxState { +) : MavericksState { constructor(args: SpaceDirectoryArgs) : this( spaceId = args.spaceId ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt index 1006f5a570..5e2537f587 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt @@ -16,12 +16,11 @@ package im.vector.app.features.spaces.explore -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -29,8 +28,11 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType @@ -41,7 +43,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber class SpaceDirectoryViewModel @AssistedInject constructor( @@ -54,7 +56,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor( fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceDirectoryState): SpaceDirectoryViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory @@ -83,17 +85,17 @@ class SpaceDirectoryViewModel @AssistedInject constructor( private fun observePermissions() { val room = session.getRoom(initialState.spaceId) ?: return - val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable() + val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow() powerLevelsContentLive - .subscribe { + .onEach { val powerLevelsHelper = PowerLevelsHelper(it) setState { copy(canAddRooms = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)) } } - .disposeOnClear() + .launchIn(viewModelScope) } private fun refreshFromApi(rootId: String?) = withState { state -> @@ -146,7 +148,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor( excludeType = null } session - .rx() + .flow() .liveRoomSummaries(queryParams) .map { it.map { it.roomId }.toSet() @@ -157,12 +159,11 @@ class SpaceDirectoryViewModel @AssistedInject constructor( } private fun observeMembershipChanges() { - session.rx() + session.flow() .liveRoomChangeMembershipState() - .subscribe { - setState { copy(changeMembershipStates = it) } + .setOnEach { + copy(changeMembershipStates = it) } - .disposeOnClear() } override fun handle(action: SpaceDirectoryViewAction) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetState.kt b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetState.kt index d712cf9e8a..5963d491d5 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.invite import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.user.model.User @@ -29,7 +29,7 @@ data class SpaceInviteBottomSheetState( val peopleYouKnow: Async> = Uninitialized, val joinActionState: Async = Uninitialized, val rejectActionState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: SpaceInviteBottomSheet.Args) : this( spaceId = args.spaceId ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt index 55b265f244..00fb6c4054 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/invite/SpaceInviteBottomSheetViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -97,7 +97,7 @@ class SpaceInviteBottomSheetViewModel @AssistedInject constructor( fun create(initialState: SpaceInviteBottomSheetState): SpaceInviteBottomSheetViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceInviteBottomSheetState): SpaceInviteBottomSheetViewModel? { val factory = when (viewModelContext) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt index f7802d2a31..b8dcd3f7a2 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.leave import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.spaces.SpaceBottomSheetSettingsArgs import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -29,7 +29,7 @@ data class SpaceLeaveAdvanceViewState( val selectedRooms: List = emptyList(), val currentFilter: String = "", val leaveState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: SpaceBottomSheetSettingsArgs) : this( spaceId = args.spaceId ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt index cb66708324..762abf10cb 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt @@ -23,7 +23,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Success import com.airbnb.mvrx.viewModel import com.google.android.material.appbar.MaterialToolbar @@ -74,7 +74,7 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity(MvRx.KEY_ARG) + val args = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (isFirstCreation()) { val simpleName = SpaceLeaveAdvancedFragment::class.java.simpleName @@ -83,7 +83,7 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity - room.rx().liveRoomSummary().subscribe { - it.getOrNull()?.let { - if (it.membership == Membership.LEAVE) { - setState { copy(leaveState = Success(Unit)) } - if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) { - // switch to home? - appStateHandler.setCurrentSpace(null, session) + room.flow().liveRoomSummary() + .unwrap() + .onEach { + if (it.membership == Membership.LEAVE) { + setState { copy(leaveState = Success(Unit)) } + if (appStateHandler.safeActiveSpaceId() == initialState.spaceId) { + // switch to home? + appStateHandler.setCurrentSpace(null, session) + } } - } - } - } + }.launchIn(viewModelScope) } viewModelScope.launch { @@ -129,7 +131,7 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor( fun create(initialState: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceLeaveAdvanceViewState): SpaceLeaveAdvancedViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt index e192ec3c88..0512a478a1 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomFragment.kt @@ -91,35 +91,35 @@ class SpaceAddRoomFragment @Inject constructor( invalidateOptionsMenu() } - viewModel.selectSubscribe(this, SpaceAddRoomsState::spaceName) { + viewModel.onEach(SpaceAddRoomsState::spaceName) { views.appBarSpaceInfo.text = it - }.disposeOnDestroyView() + } - viewModel.selectSubscribe(this, SpaceAddRoomsState::ignoreRooms) { + viewModel.onEach(SpaceAddRoomsState::ignoreRooms) { spaceEpoxyController.ignoreRooms = it roomEpoxyController.ignoreRooms = it dmEpoxyController.ignoreRooms = it - }.disposeOnDestroyView() + } - viewModel.selectSubscribe(this, SpaceAddRoomsState::isSaving) { + viewModel.onEach(SpaceAddRoomsState::isSaving) { if (it is Loading) { sharedViewModel.handle(SpaceManagedSharedAction.ShowLoading) } else { sharedViewModel.handle(SpaceManagedSharedAction.HideLoading) } - }.disposeOnDestroyView() + } - viewModel.selectSubscribe(this, SpaceAddRoomsState::shouldShowDMs) { + viewModel.onEach(SpaceAddRoomsState::shouldShowDMs) { dmEpoxyController.disabled = !it - }.disposeOnDestroyView() + } - viewModel.selectSubscribe(this, SpaceAddRoomsState::onlyShowSpaces) { + viewModel.onEach(SpaceAddRoomsState::onlyShowSpaces) { spaceEpoxyController.disabled = !it roomEpoxyController.disabled = it views.createNewRoom.text = if (it) getString(R.string.create_space) else getString(R.string.create_new_room) val title = if (it) getString(R.string.space_add_existing_spaces) else getString(R.string.space_add_existing_rooms_only) views.appBarTitle.text = title - }.disposeOnDestroyView() + } views.createNewRoom.debouncedClicks { withState(viewModel) { state -> diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt index e941d04b22..bec8b905d8 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.manage import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class SpaceAddRoomsState( @@ -30,7 +30,7 @@ data class SpaceAddRoomsState( val shouldShowDMs: Boolean = false, val onlyShowSpaces: Boolean = false // val selectionList: Map = emptyMap() -) : MvRxState { +) : MavericksState { constructor(args: SpaceManageArgs) : this( spaceId = args.spaceId, onlyShowSpaces = args.manageType == ManageType.AddRoomsOnlySpaces diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt index 9f5cd7d35e..bf062ce0a8 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceAddRoomsViewModel.kt @@ -23,7 +23,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -132,7 +132,7 @@ class SpaceAddRoomsViewModel @AssistedInject constructor( } } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceAddRoomsState): SpaceAddRoomsViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt index 16a1e18da2..f45f9099bb 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageActivity.kt @@ -22,7 +22,7 @@ import android.os.Bundle import android.os.Parcelable import androidx.core.view.isGone import androidx.core.view.isVisible -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState import com.google.android.material.appbar.MaterialToolbar @@ -95,7 +95,7 @@ class SpaceManageActivity : VectorBaseActivity(), } .disposeOnDestroy() - val args = intent?.getParcelableExtra(MvRx.KEY_ARG) + val args = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (isFirstCreation()) { withState(sharedViewModel) { when (it.manageType) { @@ -106,7 +106,7 @@ class SpaceManageActivity : VectorBaseActivity(), supportFragmentManager.commitTransaction { replace(R.id.simpleFragmentContainer, SpaceAddRoomFragment::class.java, - Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) }, + Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, simpleName ) } @@ -118,7 +118,7 @@ class SpaceManageActivity : VectorBaseActivity(), supportFragmentManager.commitTransaction { replace(R.id.simpleFragmentContainer, SpaceSettingsFragment::class.java, - Bundle().apply { this.putParcelable(MvRx.KEY_ARG, RoomProfileArgs(args.spaceId)) }, + Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, RoomProfileArgs(args.spaceId)) }, simpleName ) } @@ -189,7 +189,7 @@ class SpaceManageActivity : VectorBaseActivity(), companion object { fun newIntent(context: Context, spaceId: String, manageType: ManageType): Intent { return Intent(context, SpaceManageActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, SpaceManageArgs(spaceId, manageType)) + putExtra(Mavericks.KEY_ARG, SpaceManageArgs(spaceId, manageType)) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomViewState.kt index 34173828a7..211d3645f5 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.manage import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.space.SpaceHierarchyData @@ -32,7 +32,7 @@ data class SpaceManageRoomViewState( val paginationStatus: Async = Uninitialized, // cached room summaries of known rooms, we use it because computed room name would be better using it val knownRoomSummaries: List = emptyList() -) : MvRxState { +) : MavericksState { constructor(args: SpaceManageArgs) : this( spaceId = args.spaceId ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt index 186d733982..8e16784a6d 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsFragment.kt @@ -80,7 +80,7 @@ class SpaceManageRoomsFragment @Inject constructor( } .disposeOnDestroyView() - viewModel.selectSubscribe(SpaceManageRoomViewState::actionState) { actionState -> + viewModel.onEach(SpaceManageRoomViewState::actionState) { actionState -> when (actionState) { is Loading -> { sharedViewModel.handle(SpaceManagedSharedAction.ShowLoading) diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt index b1f6d5c3c3..d36e62db13 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageRoomsViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -60,7 +60,7 @@ class SpaceManageRoomsViewModel @AssistedInject constructor( fun create(initialState: SpaceManageRoomViewState): SpaceManageRoomsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceManageRoomViewState): SpaceManageRoomsViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt index 8f23788d19..133054236e 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageSharedViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.spaces.manage import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -37,7 +37,7 @@ class SpaceManageSharedViewModel @AssistedInject constructor( fun create(initialState: SpaceManageViewState): SpaceManageSharedViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpaceManageViewState): SpaceManageSharedViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt index 35596f0884..82abc823c3 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/manage/SpaceManageViewState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.spaces.manage -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState enum class ManageType { AddRooms, @@ -27,7 +27,7 @@ enum class ManageType { data class SpaceManageViewState( val spaceId: String = "", val manageType: ManageType -) : MvRxState { +) : MavericksState { constructor(args: SpaceManageArgs) : this( spaceId = args.spaceId, manageType = args.manageType diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt index b4b48d7710..3b84a12bc1 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt @@ -21,7 +21,7 @@ import android.content.Intent import android.os.Bundle import androidx.core.view.isGone import androidx.core.view.isVisible -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import im.vector.app.R import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.hideKeyboard @@ -57,14 +57,14 @@ class SpacePeopleActivity : VectorBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val args = intent?.getParcelableExtra(MvRx.KEY_ARG) + val args = intent?.getParcelableExtra(Mavericks.KEY_ARG) if (isFirstCreation()) { val simpleName = SpacePeopleFragment::class.java.simpleName if (supportFragmentManager.findFragmentByTag(simpleName) == null) { supportFragmentManager.commitTransaction { replace(R.id.simpleFragmentContainer, SpacePeopleFragment::class.java, - Bundle().apply { this.putParcelable(MvRx.KEY_ARG, args) }, + Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, simpleName ) } @@ -97,7 +97,7 @@ class SpacePeopleActivity : VectorBaseActivity() { companion object { fun newIntent(context: Context, spaceId: String): Intent { return Intent(context, SpacePeopleActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, GenericIdArgs(spaceId)) + putExtra(Mavericks.KEY_ARG, GenericIdArgs(spaceId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt index 95cf5fb461..efa7d97e9c 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -48,7 +48,7 @@ class SpacePeopleViewModel @AssistedInject constructor( fun create(initialState: SpacePeopleViewState): SpacePeopleViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpacePeopleViewState): SpacePeopleViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewState.kt index ea322e3fbd..b24636a9d4 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleViewState.kt @@ -17,14 +17,14 @@ package im.vector.app.features.spaces.people import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.core.platform.GenericIdArgs data class SpacePeopleViewState( val spaceId: String, val createAndInviteState: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: GenericIdArgs) : this( spaceId = args.id ) diff --git a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewState.kt b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewState.kt index d31d05cf96..14f9a45d68 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.preview import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class SpacePreviewState( @@ -28,7 +28,7 @@ data class SpacePreviewState( val spaceInfo: Async = Uninitialized, val childInfoList: Async> = Uninitialized, val inviteTermination: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(args: SpacePreviewArgs) : this(idOrAlias = args.idOrAlias) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt index 0f1afd8371..d71a4bef46 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/preview/SpacePreviewViewModel.kt @@ -21,7 +21,7 @@ import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -62,7 +62,7 @@ class SpacePreviewViewModel @AssistedInject constructor( fun create(initialState: SpacePreviewState): SpacePreviewViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: SpacePreviewState): SpacePreviewViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt index dfce534a7a..d96cecbfbb 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.spaces.share import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -26,7 +26,9 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.PowerLevelsObservableFactory +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper @@ -40,7 +42,7 @@ class ShareSpaceViewModel @AssistedInject constructor( fun create(initialState: ShareSpaceViewState): ShareSpaceViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: ShareSpaceViewState): ShareSpaceViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory @@ -63,9 +65,9 @@ class ShareSpaceViewModel @AssistedInject constructor( private fun observePowerLevel() { val room = session.getRoom(initialState.spaceId) ?: return - PowerLevelsObservableFactory(room) - .createObservable() - .subscribe { powerLevelContent -> + PowerLevelsFlowFactory(room) + .createFlow() + .onEach { powerLevelContent -> val powerLevelsHelper = PowerLevelsHelper(powerLevelContent) setState { copy( @@ -73,7 +75,7 @@ class ShareSpaceViewModel @AssistedInject constructor( ) } } - .disposeOnClear() + .launchIn(viewModelScope) } override fun handle(action: ShareSpaceAction) { diff --git a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewState.kt index 97606e9506..826719b762 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/share/ShareSpaceViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.spaces.share import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -27,7 +27,7 @@ data class ShareSpaceViewState( val canInviteByMxId: Boolean = false, val canShareLink: Boolean = false, val postCreation: Boolean = false -) : MvRxState { +) : MavericksState { constructor(args: ShareSpaceBottomSheet.Args) : this( spaceId = args.spaceId, postCreation = args.postCreation diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt index db9e017473..6a46061a31 100644 --- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewModel.kt @@ -18,7 +18,7 @@ package im.vector.app.features.terms import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -41,7 +41,7 @@ class ReviewTermsViewModel @AssistedInject constructor( fun create(initialState: ReviewTermsViewState): ReviewTermsViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ReviewTermsViewState): ReviewTermsViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewState.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewState.kt index 20b09f0cd7..e87fd9620c 100644 --- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsViewState.kt @@ -17,9 +17,9 @@ package im.vector.app.features.terms import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized data class ReviewTermsViewState( val termsList: Async> = Uninitialized -) : MvRxState +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 5e8145168b..db1bc3056a 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -25,7 +25,7 @@ import androidx.core.app.ActivityCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -86,7 +86,7 @@ class UserCodeActivity : VectorBaseActivity(), showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) } - sharedViewModel.selectSubscribe(this, UserCodeState::mode) { mode -> + sharedViewModel.onEach(UserCodeState::mode) { mode -> when (mode) { UserCodeState.Mode.SHOW -> showFragment(ShowUserCodeFragment::class, Bundle.EMPTY) UserCodeState.Mode.SCAN -> showFragment(ScanUserCodeFragment::class, Bundle.EMPTY) @@ -153,7 +153,7 @@ class UserCodeActivity : VectorBaseActivity(), companion object { fun newIntent(context: Context, userId: String): Intent { return Intent(context, UserCodeActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, Args(userId)) + putExtra(Mavericks.KEY_ARG, Args(userId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt index 74da635787..2319eef6c4 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt @@ -19,7 +19,7 @@ package im.vector.app.features.usercode import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -45,7 +45,7 @@ class UserCodeSharedViewModel @AssistedInject constructor( private val directRoomHelper: DirectRoomHelper, private val rawService: RawService) : VectorViewModel(initialState) { - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: UserCodeState): UserCodeSharedViewModel? { val factory = when (viewModelContext) { is FragmentViewModelContext -> viewModelContext.fragment as? Factory diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt index c26da7c0a4..a323609344 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeState.kt @@ -16,7 +16,7 @@ package im.vector.app.features.usercode -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import org.matrix.android.sdk.api.util.MatrixItem data class UserCodeState( @@ -24,7 +24,7 @@ data class UserCodeState( val matrixItem: MatrixItem? = null, val shareLink: String? = null, val mode: Mode = Mode.SHOW -) : MvRxState { +) : MavericksState { sealed class Mode { object SHOW : Mode() object SCAN : Mode() diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt index e6d64c799f..daf5d73e8f 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListFragment.kt @@ -81,11 +81,11 @@ class UserListFragment @Inject constructor( setupRecyclerView() setupSearchView() - homeServerCapabilitiesViewModel.subscribe { + homeServerCapabilitiesViewModel.onEach { views.userListE2EbyDefaultDisabled.isVisible = !it.isE2EByDefault } - viewModel.selectSubscribe(this, UserListViewState::pendingSelections) { + viewModel.onEach(UserListViewState::pendingSelections) { renderSelectedUsers(it) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index fc0dbbfb73..457f8cbd9a 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -16,12 +16,12 @@ package im.vector.app.features.userdirectory +import androidx.lifecycle.asFlow import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext -import com.jakewharton.rxrelay2.BehaviorRelay import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -29,21 +29,23 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.toggle import im.vector.app.core.platform.VectorViewModel -import io.reactivex.Single -import io.reactivex.android.schedulers.AndroidSchedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.sample import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.identity.IdentityServiceListener import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.session.user.model.User import org.matrix.android.sdk.api.util.toMatrixItem -import org.matrix.android.sdk.api.util.toOptional -import org.matrix.android.sdk.rx.rx -import java.util.concurrent.TimeUnit - -private typealias KnownUsersSearch = String -private typealias DirectoryUsersSearch = String data class ThreePidUser( val email: String, @@ -54,16 +56,16 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User private val session: Session) : VectorViewModel(initialState) { - private val knownUsersSearch = BehaviorRelay.create() - private val directoryUsersSearch = BehaviorRelay.create() - private val identityServerUsersSearch = BehaviorRelay.create() + private val knownUsersSearch = MutableStateFlow("") + private val directoryUsersSearch = MutableStateFlow("") + private val identityServerUsersSearch = MutableStateFlow("") @AssistedFactory interface Factory { fun create(initialState: UserListViewState): UserListViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { override fun create(viewModelContext: ViewModelContext, state: UserListViewState): UserListViewModel? { val factory = when (viewModelContext) { @@ -77,11 +79,10 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User private val identityServerListener = object : IdentityServiceListener { override fun onIdentityServerChange() { withState { - identityServerUsersSearch.accept(it.searchTerm) + identityServerUsersSearch.tryEmit(it.searchTerm) + val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl()) setState { - copy( - configuredIdentityServer = cleanISURL(session.identityService().getCurrentIdentityServerUrl()) - ) + copy(configuredIdentityServer = identityServerURL) } } } @@ -120,7 +121,7 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) { session.identityService().setUserConsent(action.consent) withState { - identityServerUsersSearch.accept(it.searchTerm) + identityServerUsersSearch.tryEmit(it.searchTerm) } } @@ -139,9 +140,9 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User ) } } - identityServerUsersSearch.accept(searchTerm) - knownUsersSearch.accept(searchTerm) - directoryUsersSearch.accept(searchTerm) + identityServerUsersSearch.tryEmit(searchTerm) + knownUsersSearch.tryEmit(searchTerm) + directoryUsersSearch.tryEmit(searchTerm) } private fun handleShareMyMatrixToLink() { @@ -151,115 +152,93 @@ class UserListViewModel @AssistedInject constructor(@Assisted initialState: User } private fun handleClearSearchUsers() { - knownUsersSearch.accept("") - directoryUsersSearch.accept("") - identityServerUsersSearch.accept("") + knownUsersSearch.tryEmit("") + directoryUsersSearch.tryEmit("") + identityServerUsersSearch.tryEmit("") setState { copy(searchTerm = "") } } private fun observeUsers() = withState { state -> - identityServerUsersSearch .filter { it.isEmail() } - .throttleLast(300, TimeUnit.MILLISECONDS) - .switchMapSingle { search -> - val rx = session.rx() - val stream = - rx.lookupThreePid(ThreePid.Email(search)).flatMap { - it.getOrNull()?.let { foundThreePid -> - rx.getProfileInfo(foundThreePid.matrixId) - .map { json -> - ThreePidUser( - email = search, - user = User( - userId = foundThreePid.matrixId, - displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, - avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String - ) - ) - } - .onErrorResumeNext { - Single.just(ThreePidUser(email = search, user = User(foundThreePid.matrixId))) - } - } ?: Single.just(ThreePidUser(email = search, user = null)) - } - stream.toAsync { - copy(matchingEmail = it) - } - } - .subscribe() - .disposeOnClear() + .sample(300) + .onEach { search -> + executeSearchEmail(search) + }.launchIn(viewModelScope) knownUsersSearch - .throttleLast(300, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .switchMap { - session.rx().livePagedUsers(it, state.excludedUserIds) - } - .execute { async -> - copy(knownUsers = async) + .sample(300) + .flowOn(Dispatchers.Main) + .flatMapLatest { search -> + session.getPagedUsersLive(search, state.excludedUserIds).asFlow() + }.execute { + copy(knownUsers = it) } directoryUsersSearch - .debounce(300, TimeUnit.MILLISECONDS) - .switchMapSingle { search -> - val stream = if (search.isBlank()) { - Single.just(emptyList()) - } else { - val searchObservable = session.rx() - .searchUsersDirectory(search, 50, state.excludedUserIds.orEmpty()) - .map { users -> - users.sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } - } - // If it's a valid user id try to use Profile API - // because directory only returns users that are in public rooms or share a room with you, where as - // profile will work other federations - if (!MatrixPatterns.isUserId(search)) { - searchObservable - } else { - val profileObservable = session.rx().getProfileInfo(search) - .map { json -> - User( - userId = search, - displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, - avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String - ).toOptional() - } - .onErrorResumeNext { - // Profile API can be restricted and doesn't have to return result. - // In this case allow inviting valid user ids. - Single.just( - User( - userId = search, - displayName = null, - avatarUrl = null - ).toOptional() - ) - } + .debounce(300) + .onEach { search -> + executeSearchDirectory(state, search) + }.launchIn(viewModelScope) + } - Single.zip( - searchObservable, - profileObservable, - { searchResults, optionalProfile -> - val profile = optionalProfile.getOrNull() ?: return@zip searchResults - val searchContainsProfile = searchResults.any { it.userId == profile.userId } - if (searchContainsProfile) { - searchResults - } else { - listOf(profile) + searchResults - } - } + private suspend fun executeSearchEmail(search: String) { + suspend { + val params = listOf(ThreePid.Email(search)) + val foundThreePid = tryOrNull { + session.identityService().lookUp(params).firstOrNull() + } + if (foundThreePid == null) { + null + } else { + try { + val json = session.getProfile(foundThreePid.matrixId) + ThreePidUser( + email = search, + user = User( + userId = foundThreePid.matrixId, + displayName = json[ProfileService.DISPLAY_NAME_KEY] as? String, + avatarUrl = json[ProfileService.AVATAR_URL_KEY] as? String ) - } - } - stream.toAsync { - copy(directoryUsers = it) - } + ) + } catch (failure: Throwable) { + ThreePidUser(email = search, user = User(foundThreePid.matrixId)) } - .subscribe() - .disposeOnClear() + } + }.execute { + copy(matchingEmail = it) + } + } + + private suspend fun executeSearchDirectory(state: UserListViewState, search: String) { + suspend { + if (search.isBlank()) { + emptyList() + } else { + val searchResult = session + .searchUsersDirectory(search, 50, state.excludedUserIds.orEmpty()) + .sortedBy { it.toMatrixItem().firstLetterOfDisplayName() } + val userProfile = if (MatrixPatterns.isUserId(search)) { + val json = tryOrNull { session.getProfile(search) } + User( + userId = search, + displayName = json?.get(ProfileService.DISPLAY_NAME_KEY) as? String, + avatarUrl = json?.get(ProfileService.AVATAR_URL_KEY) as? String + ) + } else { + null + } + if (userProfile == null || searchResult.any { it.userId == userProfile.userId }) { + searchResult + } else { + listOf(userProfile) + searchResult + } + } + }.execute { + copy(directoryUsers = it) + } } private fun handleSelectUser(action: UserListAction.AddPendingSelection) = withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt index b66d36c5f0..e389bbefee 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.userdirectory import androidx.paging.PagedList import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.core.contacts.MappedContact import org.matrix.android.sdk.api.session.user.model.User @@ -35,7 +35,7 @@ data class UserListViewState( val configuredIdentityServer: String? = null, private val showInviteActions: Boolean, val showContactBookAction: Boolean -) : MvRxState { +) : MavericksState { constructor(args: UserListFragmentArgs) : this( excludedUserIds = args.excludedUserIds, diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt index c902b661c0..23f1cfe119 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt @@ -20,7 +20,7 @@ import android.app.Activity import android.content.Context import android.content.Intent import androidx.core.view.isVisible -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.appbar.MaterialToolbar import im.vector.app.R @@ -50,7 +50,7 @@ class WidgetActivity : VectorBaseActivity(), fun newIntent(context: Context, args: WidgetArgs): Intent { return Intent(context, WidgetActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, args) + putExtra(Mavericks.KEY_ARG, args) } } @@ -83,7 +83,7 @@ class WidgetActivity : VectorBaseActivity(), } override fun initUiAndData() { - val widgetArgs: WidgetArgs? = intent?.extras?.getParcelable(MvRx.KEY_ARG) + val widgetArgs: WidgetArgs? = intent?.extras?.getParcelable(Mavericks.KEY_ARG) if (widgetArgs == null) { finish() return @@ -102,14 +102,14 @@ class WidgetActivity : VectorBaseActivity(), } } - viewModel.selectSubscribe(this, WidgetViewState::status) { ws -> + viewModel.onEach(WidgetViewState::status) { ws -> when (ws) { WidgetStatus.UNKNOWN -> { } WidgetStatus.WIDGET_NOT_ALLOWED -> { val dFrag = supportFragmentManager.findFragmentByTag(WIDGET_PERMISSION_FRAGMENT_TAG) as? RoomWidgetPermissionBottomSheet if (dFrag != null && dFrag.dialog?.isShowing == true && !dFrag.isRemoving) { - return@selectSubscribe + return@onEach } else { RoomWidgetPermissionBottomSheet .newInstance(widgetArgs) @@ -124,11 +124,11 @@ class WidgetActivity : VectorBaseActivity(), } } - viewModel.selectSubscribe(this, WidgetViewState::widgetName) { name -> + viewModel.onEach(WidgetViewState::widgetName) { name -> supportActionBar?.title = name } - viewModel.selectSubscribe(this, WidgetViewState::canManageWidgets) { + viewModel.onEach(WidgetViewState::canManageWidgets) { invalidateOptionsMenu() } } diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt index 27a0be83e8..1cf3e367ea 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewModel.kt @@ -17,12 +17,11 @@ package im.vector.app.features.widgets import android.net.Uri -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -31,6 +30,8 @@ import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.widgets.permissions.WidgetPermissionsHelper +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -41,9 +42,9 @@ import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerS import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure -import org.matrix.android.sdk.rx.mapOptional -import org.matrix.android.sdk.rx.rx -import org.matrix.android.sdk.rx.unwrap +import org.matrix.android.sdk.flow.flow +import org.matrix.android.sdk.flow.mapOptional +import org.matrix.android.sdk.flow.unwrap import timber.log.Timber import javax.net.ssl.HttpsURLConnection @@ -60,7 +61,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi fun create(initialState: WidgetViewState): WidgetViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: WidgetViewState): WidgetViewModel? { @@ -101,7 +102,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi } private fun subscribeToWidget() { - asyncSubscribe(WidgetViewState::asyncWidget) { + onAsync(WidgetViewState::asyncWidget) { setState { copy(widgetName = it.name) } } } @@ -118,16 +119,15 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi if (room == null) { return } - room.rx().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) + room.flow().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition) .mapOptional { it.content.toModel() } .unwrap() .map { PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, null) } - .subscribe { - setState { copy(canManageWidgets = it) } + .setOnEach { + copy(canManageWidgets = it) } - .disposeOnClear() } private fun observeWidgetIfNeeded() { @@ -135,7 +135,7 @@ class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: Wi return } val widgetId = initialState.widgetId ?: return - session.rx() + session.flow() .liveRoomWidgets(initialState.roomId, QueryStringValue.Equals(widgetId)) .filter { it.isNotEmpty() } .map { it.first() } diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewState.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewState.kt index 845ee81a2d..2d98f734dd 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetViewState.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetViewState.kt @@ -18,7 +18,7 @@ package im.vector.app.features.widgets import androidx.annotation.StringRes import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.R import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -52,7 +52,7 @@ data class WidgetViewState( val widgetName: String = "", val canManageWidgets: Boolean = false, val asyncWidget: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(widgetArgs: WidgetArgs) : this( widgetKind = widgetArgs.kind, diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt index 68f55773a4..e7ee2aed1f 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionBottomSheet.kt @@ -23,7 +23,7 @@ import android.text.style.BulletSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import com.airbnb.mvrx.MvRx +import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.app.R @@ -115,7 +115,7 @@ class RoomWidgetPermissionBottomSheet : companion object { fun newInstance(widgetArgs: WidgetArgs) = RoomWidgetPermissionBottomSheet().withArgs { - putParcelable(MvRx.KEY_ARG, widgetArgs) + putParcelable(Mavericks.KEY_ARG, widgetArgs) } } } diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt index e156ad4087..71eaebbc91 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewModel.kt @@ -15,23 +15,24 @@ */ package im.vector.app.features.widgets.permissions -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.R import im.vector.app.core.platform.VectorViewModel +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.widgets.model.WidgetType -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber import java.net.URL @@ -48,7 +49,7 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in private fun observeWidget() { val widgetId = initialState.widgetId ?: return - session.rx() + session.flow() .liveRoomWidgets(initialState.roomId, QueryStringValue.Equals(widgetId)) .filter { it.isNotEmpty() } .map { @@ -144,7 +145,7 @@ class RoomWidgetPermissionViewModel @AssistedInject constructor(@Assisted val in fun create(initialState: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomWidgetPermissionViewState): RoomWidgetPermissionViewModel? { diff --git a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewState.kt b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewState.kt index 1cc14a91c2..79f9b8cee3 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewState.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/permissions/RoomWidgetPermissionViewState.kt @@ -17,7 +17,7 @@ package im.vector.app.features.widgets.permissions import com.airbnb.mvrx.Async -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized import im.vector.app.features.widgets.WidgetArgs import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -26,7 +26,7 @@ data class RoomWidgetPermissionViewState( val roomId: String, val widgetId: String?, val permissionData: Async = Uninitialized -) : MvRxState { +) : MavericksState { constructor(widgetArgs: WidgetArgs) : this( roomId = widgetArgs.roomId, diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt index 075d424f0a..9b9f3fe490 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt @@ -20,8 +20,8 @@ import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -30,26 +30,22 @@ import dagger.assisted.AssistedInject import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import io.reactivex.Observable -import io.reactivex.functions.Function4 -import io.reactivex.subjects.PublishSubject +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.sample import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME -import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener -import org.matrix.android.sdk.api.util.Optional -import org.matrix.android.sdk.internal.crypto.store.PrivateKeysInfo -import org.matrix.android.sdk.rx.rx -import java.util.concurrent.TimeUnit +import org.matrix.android.sdk.flow.flow data class ServerBackupStatusViewState( val bannerState: Async = Uninitialized -) : MvRxState +) : MavericksState /** * The state representing the view @@ -68,14 +64,14 @@ sealed class BannerState { class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialState: ServerBackupStatusViewState, private val session: Session) : - VectorViewModel(initialState), KeysBackupStateListener { + VectorViewModel(initialState), KeysBackupStateListener { @AssistedFactory interface Factory { fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: ServerBackupStatusViewState): ServerBackupStatusViewModel? { @@ -91,43 +87,37 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS val keysExportedToFile = MutableLiveData() val keysBackupState = MutableLiveData() - private val keyBackupPublishSubject: PublishSubject = PublishSubject.create() + private val keyBackupFlow = MutableSharedFlow(0) init { session.cryptoService().keysBackupService().addListener(this) - keysBackupState.value = session.cryptoService().keysBackupService().state - - Observable.combineLatest, Optional, KeysBackupState, Optional, BannerState>( - session.rx().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)), - session.rx().liveCrossSigningInfo(session.myUserId), - keyBackupPublishSubject, - session.rx().liveCrossSigningPrivateKeys(), - Function4 { _, crossSigningInfo, keyBackupState, pInfo -> - // first check if 4S is already setup - if (session.sharedSecretStorageService.isRecoverySetup()) { - // 4S is already setup sp we should not display anything - return@Function4 when (keyBackupState) { - KeysBackupState.BackingUp -> BannerState.BackingUp - else -> BannerState.Hidden - } - } - - // So recovery is not setup - // Check if cross signing is enabled and local secrets known - if ( - crossSigningInfo.getOrNull() == null || - (crossSigningInfo.getOrNull()?.isTrusted() == true && - pInfo.getOrNull()?.allKnown().orFalse()) - ) { - // So 4S is not setup and we have local secrets, - return@Function4 BannerState.Setup(numberOfKeys = getNumberOfKeysToBackup()) - } - - BannerState.Hidden + val liveUserAccountData = session.flow().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)) + val liveCrossSigningInfo = session.flow().liveCrossSigningInfo(session.myUserId) + val liveCrossSigningPrivateKeys = session.flow().liveCrossSigningPrivateKeys() + combine(liveUserAccountData, liveCrossSigningInfo, keyBackupFlow, liveCrossSigningPrivateKeys) { _, crossSigningInfo, keyBackupState, pInfo -> + // first check if 4S is already setup + if (session.sharedSecretStorageService.isRecoverySetup()) { + // 4S is already setup sp we should not display anything + return@combine when (keyBackupState) { + KeysBackupState.BackingUp -> BannerState.BackingUp + else -> BannerState.Hidden } - ) - .throttleLast(1000, TimeUnit.MILLISECONDS) // we don't want to flicker or catch transient states + } + + // So recovery is not setup + // Check if cross signing is enabled and local secrets known + if ( + crossSigningInfo.getOrNull() == null || + (crossSigningInfo.getOrNull()?.isTrusted() == true && + pInfo.getOrNull()?.allKnown().orFalse()) + ) { + // So 4S is not setup and we have local secrets, + return@combine BannerState.Setup(numberOfKeys = getNumberOfKeysToBackup()) + } + BannerState.Hidden + } + .sample(1000) // we don't want to flicker or catch transient states .distinctUntilChanged() .execute { async -> copy( @@ -135,7 +125,7 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS ) } - keyBackupPublishSubject.onNext(session.cryptoService().keysBackupService().state) + keyBackupFlow.tryEmit(session.cryptoService().keysBackupService().state) } /** @@ -165,7 +155,7 @@ class ServerBackupStatusViewModel @AssistedInject constructor(@Assisted initialS } override fun onStateChange(newState: KeysBackupState) { - keyBackupPublishSubject.onNext(session.cryptoService().keysBackupService().state) + keyBackupFlow.tryEmit(session.cryptoService().keysBackupService().state) keysBackupState.value = newState } diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt index df7a826b48..057d9e31f8 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignoutCheckViewModel.kt @@ -17,13 +17,12 @@ package im.vector.app.features.workers.signout import android.net.Uri -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext import com.airbnb.mvrx.Async import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState -import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.MavericksViewModelFactory import com.airbnb.mvrx.Success import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext @@ -35,6 +34,8 @@ import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction import im.vector.app.features.crypto.keys.KeysExporter +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME @@ -42,7 +43,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_S import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener -import org.matrix.android.sdk.rx.rx +import org.matrix.android.sdk.flow.flow import timber.log.Timber data class SignoutCheckViewState( @@ -51,7 +52,7 @@ data class SignoutCheckViewState( val crossSigningSetupAllKeysKnown: Boolean = false, val keysBackupState: KeysBackupState = KeysBackupState.Unknown, val hasBeenExportedToFile: Async = Uninitialized -) : MvRxState +) : MavericksState class SignoutCheckViewModel @AssistedInject constructor( @Assisted initialState: SignoutCheckViewState, @@ -69,7 +70,7 @@ class SignoutCheckViewModel @AssistedInject constructor( fun create(initialState: SignoutCheckViewState): SignoutCheckViewModel } - companion object : MvRxViewModelFactory { + companion object : MavericksViewModelFactory { @JvmStatic override fun create(viewModelContext: ViewModelContext, state: SignoutCheckViewState): SignoutCheckViewModel? { @@ -97,7 +98,7 @@ class SignoutCheckViewModel @AssistedInject constructor( ) } - session.rx().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)) + session.flow().liveUserAccountData(setOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME)) .map { session.sharedSecretStorageService.isRecoverySetup() } diff --git a/vector/src/test/java/androidx/lifecycle/LifecycleRegistry.kt b/vector/src/test/java/androidx/lifecycle/LifecycleRegistry.kt deleted file mode 100644 index 15a76f5e1e..0000000000 --- a/vector/src/test/java/androidx/lifecycle/LifecycleRegistry.kt +++ /dev/null @@ -1,44 +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 androidx.lifecycle - -/** - * Manual test override to stop BaseMvRxViewModel from interacting with the android looper/main thread - * Tests will run on their original test worker threads - * - * This has been fixed is newer versions of Mavericks via LifecycleRegistry.createUnsafe - * https://github.com/airbnb/mavericks/blob/master/mvrx-rxjava2/src/main/kotlin/com/airbnb/mvrx/BaseMvRxViewModel.kt#L61 - */ -@Suppress("UNUSED") -class LifecycleRegistry(@Suppress("UNUSED_PARAMETER") lifecycleOwner: LifecycleOwner) : Lifecycle() { - - private var state = State.INITIALIZED - - fun setCurrentState(state: State) { - this.state = state - } - - override fun addObserver(observer: LifecycleObserver) { - TODO("Not yet implemented") - } - - override fun removeObserver(observer: LifecycleObserver) { - TODO("Not yet implemented") - } - - override fun getCurrentState() = state -} diff --git a/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt b/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt index 8f48f10868..0fff663972 100644 --- a/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModelTest.kt @@ -17,6 +17,7 @@ package im.vector.app.features.crypto.quads import com.airbnb.mvrx.Uninitialized +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.FakeStringProvider @@ -40,6 +41,8 @@ class SharedSecureStorageViewModelTest { @get:Rule val instantRx = InstantRxRule() + @get:Rule + val mvrxTestRule = MvRxTestRule() private val stringProvider = FakeStringProvider() private val session = FakeSession() diff --git a/vector/src/test/java/im/vector/app/test/Extensions.kt b/vector/src/test/java/im/vector/app/test/Extensions.kt index 0d89208b2e..f2a087fd52 100644 --- a/vector/src/test/java/im/vector/app/test/Extensions.kt +++ b/vector/src/test/java/im/vector/app/test/Extensions.kt @@ -16,7 +16,7 @@ package im.vector.app.test -import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MavericksState import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModelAction @@ -25,7 +25,7 @@ import org.amshove.kluent.shouldBeEqualTo fun String.trimIndentOneLine() = trimIndent().replace("\n", "") -fun VectorViewModel.test(): ViewModelTest { +fun VectorViewModel.test(): ViewModelTest { val state = { com.airbnb.mvrx.withState(this) { it } } val viewEvents = viewEvents.observe().test() return ViewModelTest(state, viewEvents) diff --git a/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt b/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt new file mode 100644 index 0000000000..bf24d146e6 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/TestCoroutineDispatchers.kt @@ -0,0 +1,28 @@ +/* + * 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 kotlinx.coroutines.Dispatchers +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers + +internal val testCoroutineDispatchers = MatrixCoroutineDispatchers( + io = Dispatchers.Main, + computation = Dispatchers.Main, + main = Dispatchers.Main, + crypto = Dispatchers.Main, + dmVerif = Dispatchers.Main +) diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index f5ee51b020..91403b3b2c 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -16,6 +16,7 @@ package im.vector.app.test.fakes +import im.vector.app.test.testCoroutineDispatchers import io.mockk.mockk import org.matrix.android.sdk.api.session.Session @@ -23,6 +24,8 @@ class FakeSession( val fakeCryptoService: FakeCryptoService = FakeCryptoService(), val fakeSharedSecretStorageService: FakeSharedSecretStorageService = FakeSharedSecretStorageService() ) : Session by mockk(relaxed = true) { + override fun cryptoService() = fakeCryptoService override val sharedSecretStorageService = fakeSharedSecretStorageService + override val coroutineDispatchers = testCoroutineDispatchers }