use RxAwareViewModel for more ViewModels (#1613)

* use RxAwareViewModel for more ViewModels

* fix ReportViewModel
This commit is contained in:
Konrad Pozniak 2020-01-02 18:50:58 +01:00 committed by GitHub
parent 88d59da13c
commit cdb9d87f41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 115 deletions

View File

@ -4,15 +4,13 @@ import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.paging.PagedList
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.network.TimelineCases
import com.keylesspalace.tusky.util.Listing
import com.keylesspalace.tusky.util.NetworkState
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import com.keylesspalace.tusky.util.RxAwareViewModel
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
@ -21,7 +19,7 @@ class ConversationsViewModel @Inject constructor(
private val timelineCases: TimelineCases,
private val database: AppDatabase,
private val accountManager: AccountManager
) : ViewModel() {
) : RxAwareViewModel() {
private val repoResult = MutableLiveData<Listing<ConversationEntity>>()
@ -29,8 +27,6 @@ class ConversationsViewModel @Inject constructor(
val networkState: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.networkState }
val refreshState: LiveData<NetworkState> = Transformations.switchMap(repoResult) { it.refreshState }
private val disposables = CompositeDisposable()
fun load() {
val accountId = accountManager.activeAccount?.id ?: return
if (repoResult.value == null) {
@ -61,7 +57,7 @@ class ConversationsViewModel @Inject constructor(
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
.onErrorReturnItem(0)
.subscribe()
.addTo(disposables)
.autoDispose()
}
}
@ -79,7 +75,7 @@ class ConversationsViewModel @Inject constructor(
.subscribeOn(Schedulers.io())
.doOnError { t -> Log.w("ConversationViewModel", "Failed to bookmark conversation", t) }
.subscribe()
.addTo(disposables)
.autoDispose()
}
}
@ -98,7 +94,7 @@ class ConversationsViewModel @Inject constructor(
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
.onErrorReturnItem(0)
.subscribe()
.addTo(disposables)
.autoDispose()
}
}
@ -150,8 +146,4 @@ class ConversationsViewModel @Inject constructor(
.subscribe()
}
override fun onCleared() {
disposables.dispose()
}
}

View File

@ -18,7 +18,6 @@ package com.keylesspalace.tusky.components.report
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.paging.PagedList
import com.keylesspalace.tusky.components.report.adapter.StatusesRepository
import com.keylesspalace.tusky.components.report.model.StatusViewState
@ -26,16 +25,13 @@ import com.keylesspalace.tusky.entity.Relationship
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.*
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
class ReportViewModel @Inject constructor(
private val mastodonApi: MastodonApi,
private val statusesRepository: StatusesRepository) : ViewModel() {
private val disposables = CompositeDisposable()
private val statusesRepository: StatusesRepository) : RxAwareViewModel() {
private val navigationMutable = MutableLiveData<Screen>()
val navigation: LiveData<Screen> = navigationMutable
@ -87,11 +83,6 @@ class ReportViewModel @Inject constructor(
repoResult.value = statusesRepository.getStatuses(accountId, statusId, disposables)
}
override fun onCleared() {
super.onCleared()
disposables.clear()
}
fun navigateTo(screen: Screen) {
navigationMutable.value = screen
}
@ -105,19 +96,19 @@ class ReportViewModel @Inject constructor(
val ids = listOf(accountId)
muteStateMutable.value = Loading()
blockStateMutable.value = Loading()
disposables.add(
mastodonApi.relationshipsObservable(ids)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data ->
updateRelationship(data.getOrNull(0))
mastodonApi.relationshipsObservable(ids)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data ->
updateRelationship(data.getOrNull(0))
},
{
updateRelationship(null)
}
))
},
{
updateRelationship(null)
}
)
.autoDispose()
}
@ -132,62 +123,61 @@ class ReportViewModel @Inject constructor(
}
fun toggleMute() {
val single: Single<Relationship> = if (muteStateMutable.value?.data == true) {
if (muteStateMutable.value?.data == true) {
mastodonApi.unmuteAccountObservable(accountId)
} else {
mastodonApi.muteAccountObservable(accountId)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ relationship ->
muteStateMutable.value = Success(relationship?.muting == true)
},
{ error ->
muteStateMutable.value = Error(false, error.message)
}
).autoDispose()
muteStateMutable.value = Loading()
disposables.add(
single
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ relationship ->
muteStateMutable.value = Success(relationship?.muting == true)
},
{ error ->
muteStateMutable.value = Error(false, error.message)
}
))
}
fun toggleBlock() {
val single: Single<Relationship> = if (blockStateMutable.value?.data == true) {
if (blockStateMutable.value?.data == true) {
mastodonApi.unblockAccountObservable(accountId)
} else {
mastodonApi.blockAccountObservable(accountId)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ relationship ->
blockStateMutable.value = Success(relationship?.blocking == true)
},
{ error ->
blockStateMutable.value = Error(false, error.message)
}
)
.autoDispose()
blockStateMutable.value = Loading()
disposables.add(
single
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ relationship ->
blockStateMutable.value = Success(relationship?.blocking == true)
},
{ error ->
blockStateMutable.value = Error(false, error.message)
}
))
}
fun doReport() {
reportingStateMutable.value = Loading()
disposables.add(
mastodonApi.reportObservable(accountId, selectedIds.toList(), reportNote, if (isRemoteAccount) isRemoteNotify else null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
reportingStateMutable.value = Success(true)
},
{ error ->
reportingStateMutable.value = Error(cause = error)
}
)
)
mastodonApi.reportObservable(accountId, selectedIds.toList(), reportNote, if (isRemoteAccount) isRemoteNotify else null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
reportingStateMutable.value = Success(true)
},
{ error ->
reportingStateMutable.value = Error(cause = error)
}
)
.autoDispose()
}
fun retryStatusLoad() {

View File

@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.scheduled
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.paging.Config
import androidx.paging.toLiveData
import com.keylesspalace.tusky.appstore.EventHub
@ -25,8 +24,6 @@ import com.keylesspalace.tusky.entity.ScheduledStatus
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.RxAwareViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import javax.inject.Inject
class ScheduledTootViewModel @Inject constructor(

View File

@ -4,7 +4,6 @@ import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.paging.PagedList
import com.keylesspalace.tusky.components.search.adapter.SearchRepository
import com.keylesspalace.tusky.db.AccountEntity
@ -14,18 +13,17 @@ import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.network.TimelineCases
import com.keylesspalace.tusky.util.Listing
import com.keylesspalace.tusky.util.NetworkState
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.ViewDataUtils
import com.keylesspalace.tusky.viewdata.StatusViewData
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import javax.inject.Inject
class SearchViewModel @Inject constructor(
mastodonApi: MastodonApi,
private val timelineCases: TimelineCases,
private val accountManager: AccountManager) : ViewModel() {
private val accountManager: AccountManager) : RxAwareViewModel() {
var currentQuery: String = ""
@ -37,7 +35,6 @@ class SearchViewModel @Inject constructor(
val mediaPreviewEnabled: Boolean
get() = activeAccount?.mediaPreviewEnabled ?: false
private val disposables = CompositeDisposable()
private val statusesRepository = SearchRepository<Pair<Status, StatusViewData.Concrete>>(mastodonApi)
private val accountsRepository = SearchRepository<Account>(mastodonApi)
@ -83,11 +80,6 @@ class SearchViewModel @Inject constructor(
}
override fun onCleared() {
super.onCleared()
disposables.clear()
}
fun removeItem(status: Pair<Status, StatusViewData.Concrete>) {
timelineCases.delete(status.first.id)
.subscribe({
@ -96,7 +88,7 @@ class SearchViewModel @Inject constructor(
}, {
err -> Log.d(TAG, "Failed to delete status", err)
})
.addTo(disposables)
.autoDispose()
}
@ -110,13 +102,13 @@ class SearchViewModel @Inject constructor(
}
fun reblog(status: Pair<Status, StatusViewData.Concrete>, reblog: Boolean) {
disposables.add(timelineCases.reblog(status.first, reblog)
timelineCases.reblog(status.first, reblog)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ setRebloggedForStatus(status, reblog) },
{ err -> Log.d(TAG, "Failed to reblog status ${status.first.id}", err) }
)
)
.autoDispose()
}
private fun setRebloggedForStatus(status: Pair<Status, StatusViewData.Concrete>, reblog: Boolean) {
@ -152,7 +144,7 @@ class SearchViewModel @Inject constructor(
fun voteInPoll(status: Pair<Status, StatusViewData.Concrete>, choices: MutableList<Int>) {
val votedPoll = status.first.actionableStatus.poll!!.votedCopy(choices)
updateStatus(status, votedPoll)
disposables.add(timelineCases.voteInPoll(status.first, choices)
timelineCases.voteInPoll(status.first, choices)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ newPoll -> updateStatus(status, newPoll) },
@ -160,7 +152,8 @@ class SearchViewModel @Inject constructor(
Log.d(TAG,
"Failed to vote in poll: ${status.first.id}", t)
}
))
)
.autoDispose()
}
private fun updateStatus(status: Pair<Status, StatusViewData.Concrete>, newPoll: Poll) {
@ -182,9 +175,10 @@ class SearchViewModel @Inject constructor(
loadedStatuses[idx] = newPair
repoResultStatus.value?.refresh?.invoke()
}
disposables.add(timelineCases.favourite(status.first, isFavorited)
timelineCases.favourite(status.first, isFavorited)
.onErrorReturnItem(status.first)
.subscribe())
.subscribe()
.autoDispose()
}
fun bookmark(status: Pair<Status, StatusViewData.Concrete>, isBookmarked: Boolean) {
@ -194,9 +188,10 @@ class SearchViewModel @Inject constructor(
loadedStatuses[idx] = newPair
repoResultStatus.value?.refresh?.invoke()
}
disposables.add(timelineCases.favourite(status.first, isBookmarked)
timelineCases.favourite(status.first, isBookmarked)
.onErrorReturnItem(status.first)
.subscribe())
.subscribe()
.autoDispose()
}
fun getAllAccountsOrderedByActive(): List<AccountEntity> {

View File

@ -17,26 +17,23 @@
package com.keylesspalace.tusky.viewmodel
import android.util.Log
import androidx.lifecycle.ViewModel
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.Either
import com.keylesspalace.tusky.util.Either.Left
import com.keylesspalace.tusky.util.Either.Right
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.withoutFirstWhich
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import io.reactivex.subjects.BehaviorSubject
import javax.inject.Inject
data class State(val accounts: Either<Throwable, List<Account>>, val searchResult: List<Account>?)
class AccountsInListViewModel @Inject constructor(private val api: MastodonApi) : ViewModel() {
class AccountsInListViewModel @Inject constructor(private val api: MastodonApi) : RxAwareViewModel() {
val state: Observable<State> get() = _state
private val _state = BehaviorSubject.createDefault(State(Right(listOf()), null))
private val disposable = CompositeDisposable()
fun load(listId: String) {
val state = _state.value!!
@ -45,7 +42,7 @@ class AccountsInListViewModel @Inject constructor(private val api: MastodonApi)
updateState { copy(accounts = Right(accounts)) }
}, { e ->
updateState { copy(accounts = Left(e)) }
}).addTo(disposable)
}).autoDispose()
}
}
@ -59,7 +56,7 @@ class AccountsInListViewModel @Inject constructor(private val api: MastodonApi)
Log.i(javaClass.simpleName,
"Failed to add account to the list: ${account.username}")
})
.addTo(disposable)
.autoDispose()
}
fun deleteAccountFromList(listId: String, accountId: String) {
@ -73,7 +70,7 @@ class AccountsInListViewModel @Inject constructor(private val api: MastodonApi)
}, {
Log.i(javaClass.simpleName, "Failed to remove account from thelist: $accountId")
})
.addTo(disposable)
.autoDispose()
}
fun search(query: String) {
@ -85,7 +82,7 @@ class AccountsInListViewModel @Inject constructor(private val api: MastodonApi)
updateState { copy(searchResult = result) }
}, {
updateState { copy(searchResult = listOf()) }
}).addTo(disposable)
}).autoDispose()
}
}

View File

@ -16,14 +16,12 @@
package com.keylesspalace.tusky.viewmodel
import androidx.lifecycle.ViewModel
import com.keylesspalace.tusky.entity.MastoList
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.withoutFirstWhich
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.replacedFirstWhich
import com.keylesspalace.tusky.util.withoutFirstWhich
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.PublishSubject
import java.io.IOException
@ -31,7 +29,7 @@ import java.net.ConnectException
import javax.inject.Inject
internal class ListsViewModel @Inject constructor(private val api: MastodonApi) : ViewModel() {
internal class ListsViewModel @Inject constructor(private val api: MastodonApi) : RxAwareViewModel() {
enum class LoadingState {
INITIAL, LOADING, LOADED, ERROR_NETWORK, ERROR_OTHER
}
@ -46,7 +44,6 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
val events: Observable<Event> get() = _events
private val _state = BehaviorSubject.createDefault(State(listOf(), LoadingState.INITIAL))
private val _events = PublishSubject.create<Event>()
private val disposable = CompositeDisposable()
fun retryLoading() {
loadIfNeeded()
@ -71,7 +68,7 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
copy(loadingState = if (err is IOException || err is ConnectException)
LoadingState.ERROR_NETWORK else LoadingState.ERROR_OTHER)
}
}).addTo(disposable)
}).autoDispose()
}
fun createNewList(listName: String) {
@ -81,7 +78,7 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
}
}, {
sendEvent(Event.CREATE_ERROR)
}).addTo(disposable)
}).autoDispose()
}
fun renameList(listId: String, listName: String) {
@ -91,7 +88,7 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
}
}, {
sendEvent(Event.RENAME_ERROR)
}).addTo(disposable)
}).autoDispose()
}
fun deleteList(listId: String) {
@ -101,7 +98,7 @@ internal class ListsViewModel @Inject constructor(private val api: MastodonApi)
}
}, {
sendEvent(Event.DELETE_ERROR)
}).addTo(disposable)
}).autoDispose()
}
private inline fun updateState(crossinline fn: State.() -> State) {