Introduce ViewEvents in ViewModel and code harmonization

This commit is contained in:
Benoit Marty 2020-01-21 12:45:38 +01:00
parent d672313649
commit be371f9279
51 changed files with 411 additions and 159 deletions

View File

@ -126,6 +126,14 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
mUnBinder = ButterKnife.bind(this, view)
}
open fun showLoading(message: CharSequence?) {
showLoadingDialog(message)
}
open fun showFailure(throwable: Throwable) {
displayErrorDialog(throwable)
}
@CallSuper
override fun onDestroyView() {
super.onDestroyView()
@ -188,10 +196,10 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
}
}
protected fun showLoadingDialog(message: CharSequence, cancelable: Boolean = false) {
protected fun showLoadingDialog(message: CharSequence? = null, cancelable: Boolean = false) {
progress = ProgressDialog(requireContext()).apply {
setCancelable(cancelable)
setMessage(message)
setMessage(message ?: getString(R.string.please_wait))
setProgressStyle(ProgressDialog.STYLE_SPINNER)
show()
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2020 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.riotx.core.platform
/**
* Interface for View Events
*/
interface VectorViewEvents
/**
* To use when no view events is associated to the ViewModel
*/
object EmptyViewEvents : VectorViewEvents

View File

@ -16,20 +16,23 @@
package im.vector.riotx.core.platform
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.*
import im.vector.riotx.core.utils.LiveEvent
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.Success
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import io.reactivex.Observable
import io.reactivex.Single
abstract class VectorViewModel<S : MvRxState, A : VectorViewModelAction>(initialState: S)
abstract class VectorViewModel<S : MvRxState, VA : VectorViewModelAction, VE : VectorViewEvents>(initialState: S)
: BaseMvRxViewModel<S>(initialState, false) {
// Generic handling of any request error
protected val _requestErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
val requestErrorLiveData: LiveData<LiveEvent<Throwable>>
get() = _requestErrorLiveData
// Used to post transient events to the View
protected val _viewEvents = PublishDataSource<VE>()
val viewEvents: DataSource<VE> = _viewEvents
/**
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
@ -53,5 +56,5 @@ abstract class VectorViewModel<S : MvRxState, A : VectorViewModelAction>(initial
.doOnNext { setState { stateReducer(it) } }
}
abstract fun handle(action: A)
abstract fun handle(action: VA)
}

View File

@ -23,7 +23,11 @@ import com.airbnb.mvrx.withState
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.extensions.*
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.setupAsSearch
import im.vector.riotx.core.extensions.showKeyboard
import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.*
import javax.inject.Inject

View File

@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.user.model.User
import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.rx.rx
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.LiveEvent
import io.reactivex.Single
@ -51,7 +52,7 @@ data class SelectUserAction(
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
initialState: CreateDirectRoomViewState,
private val session: Session)
: VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction>(initialState) {
: VectorViewModel<CreateDirectRoomViewState, CreateDirectRoomAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -24,11 +24,12 @@ import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupStateListener
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialState: KeysBackupSettingViewState,
session: Session
) : VectorViewModel<KeysBackupSettingViewState, KeyBackupSettingsAction>(initialState),
) : VectorViewModel<KeysBackupSettingViewState, KeyBackupSettingsAction, EmptyViewEvents>(initialState),
KeysBackupStateListener {
@AssistedInject.Factory

View File

@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.rx.rx
import im.vector.riotx.R
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.LiveEvent
@ -45,7 +46,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
private val selectedGroupStore: SelectedGroupDataSource,
private val session: Session,
private val stringProvider: StringProvider
) : VectorViewModel<GroupListViewState, GroupListAction>(initialState) {
) : VectorViewModel<GroupListViewState, GroupListAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -24,6 +24,7 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.rx.rx
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.grouplist.SelectedGroupDataSource
@ -40,7 +41,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
private val selectedGroupStore: SelectedGroupDataSource,
private val homeRoomListStore: HomeRoomListDataSource,
private val stringProvider: StringProvider)
: VectorViewModel<HomeDetailViewState, HomeDetailAction>(initialState) {
: VectorViewModel<HomeDetailViewState, HomeDetailAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -24,12 +24,13 @@ import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.rx.rx
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import io.reactivex.schedulers.Schedulers
class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: BreadcrumbsViewState,
private val session: Session)
: VectorViewModel<BreadcrumbsViewState, EmptyAction>(initialState) {
: VectorViewModel<BreadcrumbsViewState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -16,9 +16,11 @@
package im.vector.riotx.features.home.room.detail
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for RoomDetail
*/
sealed class RoomDetailViewEvents {
sealed class RoomDetailViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable) : RoomDetailViewEvents()
}

View File

@ -20,7 +20,12 @@ import android.net.Uri
import androidx.annotation.IdRes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import com.jakewharton.rxrelay2.PublishRelay
import com.squareup.inject.assisted.Assisted
@ -55,9 +60,7 @@ import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.resources.UserPreferencesProvider
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.LiveEvent
import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.core.utils.subscribeLogError
import im.vector.riotx.features.command.CommandParser
import im.vector.riotx.features.command.ParsedCommand
@ -81,7 +84,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
private val stringProvider: StringProvider,
private val typingHelper: TypingHelper,
private val session: Session
) : VectorViewModel<RoomDetailViewState, RoomDetailAction>(initialState), Timeline.Listener {
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
private val room = session.getRoom(initialState.roomId)!!
private val eventId = initialState.eventId
@ -104,9 +107,6 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
var timeline = room.createTimeline(eventId, timelineSettings)
private set
private val _viewEvents = PublishDataSource<RoomDetailViewEvents>()
val viewEvents: DataSource<RoomDetailViewEvents> = _viewEvents
// Can be used for several actions, for a one shot result
private val _requestLiveData = MutableLiveData<LiveEvent<Async<RoomDetailAction>>>()
val requestLiveData: LiveData<LiveEvent<Async<RoomDetailAction>>>
@ -290,6 +290,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
}
}
// TODO Cleanup this and use ViewEvents
private val _nonBlockingPopAlert = MutableLiveData<LiveEvent<Pair<Int, List<Any>>>>()
val nonBlockingPopAlert: LiveData<LiveEvent<Pair<Int, List<Any>>>>
get() = _nonBlockingPopAlert

View File

@ -35,6 +35,7 @@ import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.R
import im.vector.riotx.core.extensions.canReact
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter
@ -89,7 +90,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
private val noticeEventFormatter: NoticeEventFormatter,
private val stringProvider: StringProvider,
private val vectorPreferences: VectorPreferences
) : VectorViewModel<MessageActionState, MessageActionsAction>(initialState) {
) : VectorViewModel<MessageActionState, MessageActionsAction, EmptyViewEvents>(initialState) {
private val eventId = initialState.eventId
private val informationData = initialState.informationData

View File

@ -15,7 +15,15 @@
*/
package im.vector.riotx.features.home.room.detail.timeline.edithistory
import com.airbnb.mvrx.*
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.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
@ -28,10 +36,11 @@ import im.vector.matrix.android.api.session.room.model.message.isReply
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import timber.log.Timber
import java.util.*
import java.util.UUID
data class ViewEditHistoryViewState(
val eventId: String,
@ -47,7 +56,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted
initialState: ViewEditHistoryViewState,
val session: Session,
val dateFormatter: VectorDateFormatter
) : VectorViewModel<ViewEditHistoryViewState, EmptyAction>(initialState) {
) : VectorViewModel<ViewEditHistoryViewState, EmptyAction, EmptyViewEvents>(initialState) {
private val roomId = initialState.roomId
private val eventId = initialState.eventId

View File

@ -16,7 +16,12 @@
package im.vector.riotx.features.home.room.detail.timeline.reactions
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
@ -25,6 +30,7 @@ import im.vector.matrix.rx.RxRoom
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import io.reactivex.Observable
@ -54,7 +60,7 @@ class ViewReactionsViewModel @AssistedInject constructor(@Assisted
initialState: DisplayReactionsViewState,
private val session: Session,
private val dateFormatter: VectorDateFormatter
) : VectorViewModel<DisplayReactionsViewState, EmptyAction>(initialState) {
) : VectorViewModel<DisplayReactionsViewState, EmptyAction, EmptyViewEvents>(initialState) {
private val roomId = initialState.roomId
private val eventId = initialState.eventId

View File

@ -27,7 +27,11 @@ import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.OnModelBuildFinishedListener
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary
@ -102,9 +106,11 @@ class RoomListFragment @Inject constructor(
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is RoomListViewEvents.Loading -> showLoading(it.message)
is RoomListViewEvents.Failure -> showFailure(it.throwable)
is RoomListViewEvents.SelectRoom -> openSelectedRoom(it)
is RoomListViewEvents.Failure -> showErrorInSnackbar(it.throwable)
}
}
.disposeOnDestroyView()
@ -117,6 +123,10 @@ class RoomListFragment @Inject constructor(
.disposeOnDestroyView()
}
override fun showFailure(throwable: Throwable) {
showErrorInSnackbar(throwable)
}
override fun onDestroyView() {
roomController.removeModelBuildListener(modelBuildListener)
modelBuildListener = null

View File

@ -17,10 +17,14 @@
package im.vector.riotx.features.home.room.list
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for RoomList
*/
sealed class RoomListViewEvents {
sealed class RoomListViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : RoomListViewEvents()
data class Failure(val throwable: Throwable) : RoomListViewEvents()
data class SelectRoom(val roomId: String) : RoomListViewEvents()
}

View File

@ -26,7 +26,6 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import javax.inject.Inject
@ -34,7 +33,7 @@ import javax.inject.Inject
class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
private val session: Session,
private val roomSummariesSource: DataSource<List<RoomSummary>>)
: VectorViewModel<RoomListViewState, RoomListAction>(initialState) {
: VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
interface Factory {
fun create(initialState: RoomListViewState): RoomListViewModel
@ -52,9 +51,6 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
private val displayMode = initialState.displayMode
private val roomListDisplayModeFilter = RoomListDisplayModeFilter(displayMode)
private val _viewEvents = PublishDataSource<RoomListViewEvents>()
val viewEvents: DataSource<RoomListViewEvents> = _viewEvents
init {
observeRoomSummaries()
}
@ -197,6 +193,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
}
private fun handleLeaveRoom(action: RoomListAction.LeaveRoom) {
_viewEvents.post(RoomListViewEvents.Loading(null))
session.getRoom(action.roomId)?.leave(null, object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(RoomListViewEvents.Failure(failure))

View File

@ -24,11 +24,12 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
class RoomListQuickActionsViewModel @AssistedInject constructor(@Assisted initialState: RoomListQuickActionsState,
session: Session
) : VectorViewModel<RoomListQuickActionsState, EmptyAction>(initialState) {
) : VectorViewModel<RoomListQuickActionsState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -70,14 +70,14 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) {
when (loginViewEvents) {
is LoginViewEvents.Error -> showError(loginViewEvents.throwable)
else ->
is LoginViewEvents.Failure -> showFailure(loginViewEvents.throwable)
else ->
// This is handled by the Activity
Unit
}
}
private fun showError(throwable: Throwable) {
override fun showFailure(throwable: Throwable) {
when (throwable) {
is Failure.ServerError -> {
if (throwable.error.code == MatrixError.M_FORBIDDEN
@ -96,11 +96,7 @@ abstract class AbstractLoginFragment : VectorBaseFragment(), OnBackPressed {
}
open fun onError(throwable: Throwable) {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.dialog_title_error)
.setMessage(errorFormatter.toHumanReadable(throwable))
.setPositiveButton(R.string.ok, null)
.show()
super.showFailure(throwable)
}
override fun onBackPressed(toolbarButton: Boolean): Boolean {

View File

@ -209,7 +209,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
.setMessage(R.string.login_error_outdated_homeserver_content)
.setPositiveButton(R.string.ok, null)
.show()
is LoginViewEvents.Error ->
is LoginViewEvents.Failure ->
// This is handled by the Fragments
Unit
}

View File

@ -18,12 +18,15 @@
package im.vector.riotx.features.login
import im.vector.matrix.android.api.auth.registration.FlowResult
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for Login
*/
sealed class LoginViewEvents {
sealed class LoginViewEvents: VectorViewEvents {
data class Loading(val message: CharSequence? = null) : LoginViewEvents()
data class Failure(val throwable: Throwable) : LoginViewEvents()
data class RegistrationFlowResult(val flowResult: FlowResult, val isRegistrationStarted: Boolean) : LoginViewEvents()
data class Error(val throwable: Throwable) : LoginViewEvents()
object OutdatedHomeserver : LoginViewEvents()
}

View File

@ -41,8 +41,6 @@ import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.extensions.configureAndStart
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.session.SessionListener
import im.vector.riotx.features.signout.soft.SoftLogoutActivity
@ -59,7 +57,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
private val pushRuleTriggerListener: PushRuleTriggerListener,
private val homeServerConnectionConfigFactory: HomeServerConnectionConfigFactory,
private val sessionListener: SessionListener)
: VectorViewModel<LoginViewState, LoginAction>(initialState) {
: VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -95,9 +93,6 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
private var currentTask: Cancelable? = null
private val _viewEvents = PublishDataSource<LoginViewEvents>()
val viewEvents: DataSource<LoginViewEvents> = _viewEvents
override fun handle(action: LoginAction) {
when (action) {
is LoginAction.UpdateServerType -> handleUpdateServerType(action)
@ -179,7 +174,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
override fun onFailure(failure: Throwable) {
if (failure !is CancellationException) {
_viewEvents.post(LoginViewEvents.Error(failure))
_viewEvents.post(LoginViewEvents.Failure(failure))
}
setState {
copy(
@ -201,7 +196,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
}
override fun onFailure(failure: Throwable) {
_viewEvents.post(LoginViewEvents.Error(failure))
_viewEvents.post(LoginViewEvents.Failure(failure))
setState {
copy(
asyncRegistration = Uninitialized
@ -223,7 +218,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
}
override fun onFailure(failure: Throwable) {
_viewEvents.post(LoginViewEvents.Error(failure))
_viewEvents.post(LoginViewEvents.Failure(failure))
setState {
copy(
asyncRegistration = Uninitialized
@ -526,7 +521,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
if (homeServerConnectionConfig == null) {
// This is invalid
_viewEvents.post(LoginViewEvents.Error(Throwable("Unable to create a HomeServerConnectionConfig")))
_viewEvents.post(LoginViewEvents.Failure(Throwable("Unable to create a HomeServerConnectionConfig")))
} else {
currentTask?.cancel()
currentTask = null
@ -540,7 +535,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
currentTask = authenticationService.getLoginFlow(homeServerConnectionConfig, object : MatrixCallback<LoginFlowResult> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(LoginViewEvents.Error(failure))
_viewEvents.post(LoginViewEvents.Failure(failure))
setState {
copy(
asyncHomeServerLoginFlowRequest = Uninitialized

View File

@ -21,6 +21,7 @@ import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.reactions.data.EmojiDataSource
import im.vector.riotx.features.reactions.data.EmojiItem
@ -33,7 +34,7 @@ data class EmojiSearchResultViewState(
class EmojiSearchResultViewModel @AssistedInject constructor(
@Assisted initialState: EmojiSearchResultViewState,
private val dataSource: EmojiDataSource)
: VectorViewModel<EmojiSearchResultViewState, EmojiSearchAction>(initialState) {
: VectorViewModel<EmojiSearchResultViewState, EmojiSearchAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -75,6 +75,7 @@ class PublicRoomsFragment @Inject constructor(
sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom)
}
// TODO remove this, replace by ViewEvents
viewModel.joinRoomErrorLiveData.observeEvent(this) { throwable ->
Snackbar.make(publicRoomsCoordinator, errorFormatter.toHumanReadable(throwable), Snackbar.LENGTH_SHORT)
.show()

View File

@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.rx.rx
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.LiveEvent
import timber.log.Timber
@ -41,7 +42,7 @@ private const val PUBLIC_ROOMS_LIMIT = 20
class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: PublicRoomsViewState,
private val session: Session)
: VectorViewModel<PublicRoomsViewState, RoomDirectoryAction>(initialState) {
: VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -17,7 +17,12 @@
package im.vector.riotx.features.roomdirectory.createroom
import androidx.fragment.app.FragmentActivity
import com.airbnb.mvrx.*
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
@ -25,12 +30,13 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState,
private val session: Session
) : VectorViewModel<CreateRoomViewState, CreateRoomAction>(initialState) {
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -16,17 +16,22 @@
package im.vector.riotx.features.roomdirectory.picker
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
class RoomDirectoryPickerViewModel @AssistedInject constructor(@Assisted initialState: RoomDirectoryPickerViewState,
private val session: Session)
: VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction>(initialState) {
: VectorViewModel<RoomDirectoryPickerViewState, RoomDirectoryPickerAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -26,13 +26,14 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
import im.vector.matrix.rx.rx
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.roomdirectory.JoinState
import timber.log.Timber
class RoomPreviewViewModel @AssistedInject constructor(@Assisted initialState: RoomPreviewViewState,
private val session: Session)
: VectorViewModel<RoomPreviewViewState, RoomPreviewAction>(initialState) {
: VectorViewModel<RoomPreviewViewState, RoomPreviewAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -20,7 +20,12 @@ package im.vector.riotx.features.roommemberprofile
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.util.MatrixItem
import im.vector.riotx.R
import im.vector.riotx.core.animations.AppBarStateChangeListener
@ -31,6 +36,7 @@ import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.core.platform.StateView
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.AvatarRenderer
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
@ -75,11 +81,13 @@ class RoomMemberProfileFragment @Inject constructor(
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
viewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is RoomMemberProfileViewEvents.Loading -> showLoadingDialog(it.message)
is RoomMemberProfileViewEvents.Failure -> showErrorInSnackbar(it.throwable)
is RoomMemberProfileViewEvents.Loading -> showLoading(it.message)
is RoomMemberProfileViewEvents.Failure -> showFailure(it.throwable)
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
}
}
.disposeOnDestroyView()

View File

@ -16,11 +16,14 @@
package im.vector.riotx.features.roommemberprofile
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for RoomMemberProfile
*/
sealed class RoomMemberProfileViewEvents {
data class Loading(val message: CharSequence) : RoomMemberProfileViewEvents()
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
sealed class RoomMemberProfileViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : RoomMemberProfileViewEvents()
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
}

View File

@ -44,8 +44,6 @@ import im.vector.matrix.rx.unwrap
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import kotlinx.coroutines.Dispatchers
@ -55,7 +53,7 @@ import kotlinx.coroutines.withContext
class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private val initialState: RoomMemberProfileViewState,
private val stringProvider: StringProvider,
private val session: Session)
: VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction>(initialState) {
: VectorViewModel<RoomMemberProfileViewState, RoomMemberProfileAction, RoomMemberProfileViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -71,9 +69,6 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
}
}
private val _viewEvents = PublishDataSource<RoomMemberProfileViewEvents>()
val viewEvents: DataSource<RoomMemberProfileViewEvents> = _viewEvents
private val room = if (initialState.roomId != null) {
session.getRoom(initialState.roomId)
} else {
@ -183,7 +178,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
private fun handleIgnoreAction() = withState { state ->
val isIgnored = state.isIgnored() ?: return@withState
_viewEvents.post(RoomMemberProfileViewEvents.Loading(stringProvider.getString(R.string.please_wait)))
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
val ignoreActionCallback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
_viewEvents.post(RoomMemberProfileViewEvents.OnIgnoreActionSuccess)

View File

@ -38,6 +38,7 @@ import im.vector.riotx.features.home.room.list.actions.RoomListActionsArgs
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
@ -79,12 +80,13 @@ class RoomProfileFragment @Inject constructor(
matrixProfileAppBarLayout.addOnOffsetChangedListener(appBarStateChangeListener)
roomProfileViewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is RoomProfileViewEvents.Loading -> showLoadingDialog(it.message)
RoomProfileViewEvents.OnLeaveRoomSuccess -> onLeaveRoom()
is RoomProfileViewEvents.Failure -> showError(it.throwable)
is RoomProfileViewEvents.Loading -> showLoading(it.message)
is RoomProfileViewEvents.Failure -> showFailure(it.throwable)
is RoomProfileViewEvents.OnLeaveRoomSuccess -> onLeaveRoom()
}
}
.disposeOnDestroyView()

View File

@ -15,11 +15,15 @@
*/
package im.vector.riotx.features.roomprofile
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for RoomProfile
*/
sealed class RoomProfileViewEvents {
data class Loading(val message: CharSequence): RoomProfileViewEvents()
object OnLeaveRoomSuccess: RoomProfileViewEvents()
sealed class RoomProfileViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : RoomProfileViewEvents()
data class Failure(val throwable: Throwable) : RoomProfileViewEvents()
object OnLeaveRoomSuccess : RoomProfileViewEvents()
}

View File

@ -29,13 +29,11 @@ import im.vector.matrix.rx.unwrap
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: RoomProfileViewState,
private val stringProvider: StringProvider,
private val session: Session)
: VectorViewModel<RoomProfileViewState, RoomProfileAction>(initialState) {
: VectorViewModel<RoomProfileViewState, RoomProfileAction, RoomProfileViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -51,9 +49,6 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: R
}
}
private val _viewEvents = PublishDataSource<RoomProfileViewEvents>()
val viewEvents: DataSource<RoomProfileViewEvents> = _viewEvents
private val room = session.getRoom(initialState.roomId)!!
init {

View File

@ -34,13 +34,14 @@ import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
import im.vector.matrix.rx.mapOptional
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState: RoomMemberListViewState,
private val session: Session)
: VectorViewModel<RoomMemberListViewState, RoomMemberListAction>(initialState) {
: VectorViewModel<RoomMemberListViewState, RoomMemberListAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -27,10 +27,10 @@ import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.R
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.roomprofile.RoomProfileArgs
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_room_setting_generic.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import javax.inject.Inject
@ -54,9 +54,16 @@ class RoomSettingsFragment @Inject constructor(
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
viewModel.requestErrorLiveData.observeEvent(this) {
displayErrorDialog(it)
}
viewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is RoomSettingsViewEvents.Failure -> showFailure(it.throwable)
}
}
.disposeOnDestroyView()
}
override fun onDestroyView() {

View File

@ -0,0 +1,28 @@
/*
* Copyright 2020 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.riotx.features.roomprofile.settings
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for room settings screen
*/
sealed class RoomSettingsViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : RoomSettingsViewEvents()
data class Failure(val throwable: Throwable) : RoomSettingsViewEvents()
}

View File

@ -17,9 +17,7 @@
package im.vector.riotx.features.roomprofile.settings
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
@ -28,12 +26,11 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel
class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState,
private val session: Session)
: VectorViewModel<RoomSettingsViewState, RoomSettingsAction>(initialState) {
: VectorViewModel<RoomSettingsViewState, RoomSettingsAction, RoomSettingsViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -80,7 +77,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
copy(isLoading = false)
}
_requestErrorLiveData.postLiveEvent(failure)
_viewEvents.post(RoomSettingsViewEvents.Failure(failure))
}
override fun onSuccess(data: Unit) {

View File

@ -0,0 +1,28 @@
/*
* Copyright 2020 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.riotx.features.settings.devices
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.riotx.core.platform.VectorViewModelAction
sealed class DevicesAction : VectorViewModelAction {
object Retry : DevicesAction()
data class Delete(val deviceInfo: DeviceInfo) : DevicesAction()
data class Password(val password: String) : DevicesAction()
data class Rename(val deviceInfo: DeviceInfo, val newName: String) : DevicesAction()
data class ToggleDevice(val deviceInfo: DeviceInfo) : DevicesAction()
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2020 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.riotx.features.settings.devices
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for Ignored users screen
*/
sealed class DevicesViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : DevicesViewEvents()
data class Failure(val throwable: Throwable) : DevicesViewEvents()
}

View File

@ -18,7 +18,15 @@ package im.vector.riotx.features.settings.devices
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.*
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.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
@ -29,7 +37,6 @@ import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.platform.VectorViewModelAction
import im.vector.riotx.core.utils.LiveEvent
import timber.log.Timber
@ -37,20 +44,13 @@ data class DevicesViewState(
val myDeviceId: String = "",
val devices: Async<List<DeviceInfo>> = Uninitialized,
val currentExpandedDeviceId: String? = null,
// TODO Replace by isLoading boolean
val request: Async<Unit> = Uninitialized
) : MvRxState
sealed class DevicesAction : VectorViewModelAction {
object Retry : DevicesAction()
data class Delete(val deviceInfo: DeviceInfo) : DevicesAction()
data class Password(val password: String) : DevicesAction()
data class Rename(val deviceInfo: DeviceInfo, val newName: String) : DevicesAction()
data class ToggleDevice(val deviceInfo: DeviceInfo) : DevicesAction()
}
class DevicesViewModel @AssistedInject constructor(@Assisted initialState: DevicesViewState,
private val session: Session)
: VectorViewModel<DevicesViewState, DevicesAction>(initialState) {
: VectorViewModel<DevicesViewState, DevicesAction, DevicesViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -153,7 +153,7 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic
)
}
_requestErrorLiveData.postLiveEvent(failure)
_viewEvents.post(DevicesViewEvents.Failure(failure))
}
})
}
@ -207,7 +207,7 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic
)
}
_requestErrorLiveData.postLiveEvent(failure)
_viewEvents.post(DevicesViewEvents.Failure(failure))
}
}
@ -261,7 +261,7 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic
)
}
_requestErrorLiveData.postLiveEvent(failure)
_viewEvents.post(DevicesViewEvents.Failure(failure))
}
})
}

View File

@ -35,6 +35,7 @@ import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.toast
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import javax.inject.Inject
@ -52,7 +53,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
override fun getLayoutResId() = R.layout.fragment_generic_recycler
private val devicesViewModel: DevicesViewModel by fragmentViewModel()
private val viewModel: DevicesViewModel by fragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -61,16 +62,29 @@ class VectorSettingsDevicesFragment @Inject constructor(
waiting_view_status_text.isVisible = true
devicesController.callback = this
recyclerView.configureWith(devicesController, showDivider = true)
devicesViewModel.requestErrorLiveData.observeEvent(this) {
displayErrorDialog(it)
// Password is maybe not good, for safety measure, reset it here
mAccountPassword = ""
}
devicesViewModel.requestPasswordLiveData.observeEvent(this) {
viewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is DevicesViewEvents.Loading -> showLoading(it.message)
is DevicesViewEvents.Failure -> showFailure(it.throwable)
}
}
.disposeOnDestroyView()
viewModel.requestPasswordLiveData.observeEvent(this) {
maybeShowDeleteDeviceWithPasswordDialog()
}
}
override fun showFailure(throwable: Throwable) {
super.showFailure(throwable)
// Password is maybe not good, for safety measure, reset it here
mAccountPassword = ""
}
override fun onDestroyView() {
devicesController.callback = null
recyclerView.cleanup()
@ -84,11 +98,11 @@ class VectorSettingsDevicesFragment @Inject constructor(
}
override fun onDeviceClicked(deviceInfo: DeviceInfo) {
devicesViewModel.handle(DevicesAction.ToggleDevice(deviceInfo))
viewModel.handle(DevicesAction.ToggleDevice(deviceInfo))
}
override fun onDeleteDevice(deviceInfo: DeviceInfo) {
devicesViewModel.handle(DevicesAction.Delete(deviceInfo))
viewModel.handle(DevicesAction.Delete(deviceInfo))
}
override fun onRenameDevice(deviceInfo: DeviceInfo) {
@ -96,7 +110,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
}
override fun retry() {
devicesViewModel.handle(DevicesAction.Retry)
viewModel.handle(DevicesAction.Retry)
}
/**
@ -117,7 +131,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
.setPositiveButton(R.string.ok) { _, _ ->
val newName = input.text.toString()
devicesViewModel.handle(DevicesAction.Rename(deviceInfo, newName))
viewModel.handle(DevicesAction.Rename(deviceInfo, newName))
}
.setNegativeButton(R.string.cancel, null)
.show()
@ -128,7 +142,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
*/
private fun maybeShowDeleteDeviceWithPasswordDialog() {
if (mAccountPassword.isNotEmpty()) {
devicesViewModel.handle(DevicesAction.Password(mAccountPassword))
viewModel.handle(DevicesAction.Password(mAccountPassword))
} else {
val inflater = requireActivity().layoutInflater
val layout = inflater.inflate(R.layout.dialog_device_delete, null)
@ -144,7 +158,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
return@OnClickListener
}
mAccountPassword = passwordEditText.text.toString()
devicesViewModel.handle(DevicesAction.Password(mAccountPassword))
viewModel.handle(DevicesAction.Password(mAccountPassword))
})
.setNegativeButton(R.string.cancel, null)
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
@ -158,7 +172,7 @@ class VectorSettingsDevicesFragment @Inject constructor(
}
}
override fun invalidate() = withState(devicesViewModel) { state ->
override fun invalidate() = withState(viewModel) { state ->
devicesController.update(state)
handleRequestStatus(state.request)

View File

@ -0,0 +1,28 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.features.settings.ignored
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for Ignored users screen
*/
sealed class IgnoredUsersViewEvents : VectorViewEvents {
data class Loading(val message: CharSequence? = null) : IgnoredUsersViewEvents()
data class Failure(val throwable: Throwable) : IgnoredUsersViewEvents()
}

View File

@ -16,14 +16,21 @@
package im.vector.riotx.features.settings.ignored
import com.airbnb.mvrx.*
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.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.user.model.User
import im.vector.matrix.rx.rx
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.platform.VectorViewModelAction
@ -38,7 +45,7 @@ sealed class IgnoredUsersAction : VectorViewModelAction {
class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState,
private val session: Session)
: VectorViewModel<IgnoredUsersViewState, IgnoredUsersAction>(initialState) {
: VectorViewModel<IgnoredUsersViewState, IgnoredUsersAction, IgnoredUsersViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -89,7 +96,7 @@ class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState:
)
}
_requestErrorLiveData.postLiveEvent(failure)
_viewEvents.post(IgnoredUsersViewEvents.Failure(failure))
}
override fun onSuccess(data: Unit) {

View File

@ -27,9 +27,9 @@ import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import javax.inject.Inject
@ -41,7 +41,7 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
override fun getLayoutResId() = R.layout.fragment_generic_recycler
private val ignoredUsersViewModel: IgnoredUsersViewModel by fragmentViewModel()
private val viewModel: IgnoredUsersViewModel by fragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -50,9 +50,17 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
waiting_view_status_text.isVisible = true
ignoredUsersController.callback = this
recyclerView.configureWith(ignoredUsersController)
ignoredUsersViewModel.requestErrorLiveData.observeEvent(this) {
displayErrorDialog(it)
}
viewModel.viewEvents
.observe()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
dismissLoadingDialog()
when (it) {
is IgnoredUsersViewEvents.Loading -> showLoading(it.message)
is IgnoredUsersViewEvents.Failure -> showFailure(it.throwable)
}
}
.disposeOnDestroyView()
}
override fun onDestroyView() {
@ -71,7 +79,7 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
AlertDialog.Builder(requireActivity())
.setMessage(getString(R.string.settings_unignore_user, userId))
.setPositiveButton(R.string.yes) { _, _ ->
ignoredUsersViewModel.handle(IgnoredUsersAction.UnIgnore(userId))
viewModel.handle(IgnoredUsersAction.UnIgnore(userId))
}
.setNegativeButton(R.string.no, null)
.show()
@ -81,7 +89,7 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
// ignored users list management
// ==============================================================================================================
override fun invalidate() = withState(ignoredUsersViewModel) { state ->
override fun invalidate() = withState(viewModel) { state ->
ignoredUsersController.update(state)
handleUnIgnoreRequestStatus(state.unIgnoreRequest)

View File

@ -16,13 +16,19 @@
package im.vector.riotx.features.settings.push
import com.airbnb.mvrx.*
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.pushers.Pusher
import im.vector.matrix.rx.RxSession
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
data class PushGatewayViewState(
@ -31,7 +37,7 @@ data class PushGatewayViewState(
class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: PushGatewayViewState,
private val session: Session)
: VectorViewModel<PushGatewayViewState, EmptyAction>(initialState) {
: VectorViewModel<PushGatewayViewState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -21,6 +21,7 @@ import com.airbnb.mvrx.ViewModelContext
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.riotx.core.di.HasScreenInjector
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
data class PushRulesViewState(
@ -28,7 +29,7 @@ data class PushRulesViewState(
) : MvRxState
class PushRulesViewModel(initialState: PushRulesViewState)
: VectorViewModel<PushRulesViewState, EmptyAction>(initialState) {
: VectorViewModel<PushRulesViewState, EmptyAction, EmptyViewEvents>(initialState) {
companion object : MvRxViewModelFactory<PushRulesViewModel, PushRulesViewState> {

View File

@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
import im.vector.matrix.rx.rx
import im.vector.riotx.ActiveSessionDataSource
import im.vector.riotx.core.platform.EmptyAction
import im.vector.riotx.core.platform.EmptyViewEvents
import im.vector.riotx.core.platform.VectorViewModel
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
@ -39,7 +40,7 @@ data class IncomingShareState(private val dummy: Boolean = false) : MvRxState
class IncomingShareViewModel @AssistedInject constructor(@Assisted initialState: IncomingShareState,
private val sessionObservableStore: ActiveSessionDataSource,
private val shareRoomListObservableStore: ShareRoomListDataSource)
: VectorViewModel<IncomingShareState, EmptyAction>(initialState) {
: VectorViewModel<IncomingShareState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {

View File

@ -73,7 +73,7 @@ class SoftLogoutActivity : LoginActivity() {
private fun handleSoftLogoutViewEvents(softLogoutViewEvents: SoftLogoutViewEvents) {
when (softLogoutViewEvents) {
is SoftLogoutViewEvents.Error ->
is SoftLogoutViewEvents.Failure ->
showError(errorFormatter.toHumanReadable(softLogoutViewEvents.throwable))
is SoftLogoutViewEvents.ErrorNotSameUser -> {
// Pop the backstack

View File

@ -17,11 +17,14 @@
package im.vector.riotx.features.signout.soft
import im.vector.riotx.core.platform.VectorViewEvents
/**
* Transient events for SoftLogout
*/
sealed class SoftLogoutViewEvents {
sealed class SoftLogoutViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable) : SoftLogoutViewEvents()
data class ErrorNotSameUser(val currentUserId: String, val newUserId: String) : SoftLogoutViewEvents()
data class Error(val throwable: Throwable) : SoftLogoutViewEvents()
object ClearData : SoftLogoutViewEvents()
}

View File

@ -16,7 +16,13 @@
package im.vector.riotx.features.signout.soft
import com.airbnb.mvrx.*
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.Uninitialized
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
@ -28,8 +34,6 @@ import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.extensions.hasUnsavedKeys
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.utils.DataSource
import im.vector.riotx.core.utils.PublishDataSource
import im.vector.riotx.features.login.LoginMode
import timber.log.Timber
@ -41,7 +45,7 @@ class SoftLogoutViewModel @AssistedInject constructor(
private val session: Session,
private val activeSessionHolder: ActiveSessionHolder,
private val authenticationService: AuthenticationService
) : VectorViewModel<SoftLogoutViewState, SoftLogoutAction>(initialState) {
) : VectorViewModel<SoftLogoutViewState, SoftLogoutAction, SoftLogoutViewEvents>(initialState) {
@AssistedInject.Factory
interface Factory {
@ -71,9 +75,6 @@ class SoftLogoutViewModel @AssistedInject constructor(
private var currentTask: Cancelable? = null
private val _viewEvents = PublishDataSource<SoftLogoutViewEvents>()
val viewEvents: DataSource<SoftLogoutViewEvents> = _viewEvents
init {
// Get the supported login flow
getSupportedLoginFlow()
@ -192,7 +193,7 @@ class SoftLogoutViewModel @AssistedInject constructor(
currentTask = session.updateCredentials(action.credentials,
object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(SoftLogoutViewEvents.Error(failure))
_viewEvents.post(SoftLogoutViewEvents.Failure(failure))
setState {
copy(
asyncLoginAction = Uninitialized