Remove Rx from EventHub and TimelineCases (#3446)

* remove Rx from EventHub and TimelineCases

* fix tests

* fix AccountViewModel.unblockDomain

* remove debug logging
This commit is contained in:
Konrad Pozniak 2023-03-18 10:11:47 +01:00 committed by GitHub
commit 321d17f5de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 264 additions and 330 deletions

View file

@ -3,6 +3,7 @@ package com.keylesspalace.tusky.components.account
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import at.connyduck.calladapter.networkresult.fold
import com.keylesspalace.tusky.appstore.BlockEvent
import com.keylesspalace.tusky.appstore.DomainMuteEvent
import com.keylesspalace.tusky.appstore.EventHub
@ -21,9 +22,6 @@ import com.keylesspalace.tusky.util.Success
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -47,12 +45,13 @@ class AccountViewModel @Inject constructor(
private var noteDisposable: Disposable? = null
init {
eventHub.events
.subscribe { event ->
viewModelScope.launch {
eventHub.events.collect { event ->
if (event is ProfileEditedEvent && event.newProfileData.id == accountData.value?.data?.id) {
accountData.postValue(Success(event.newProfileData))
}
}.autoDispose()
}
}
}
private fun obtainAccount(reload: Boolean = false) {
@ -133,42 +132,30 @@ class AccountViewModel @Inject constructor(
}
fun blockDomain(instance: String) {
mastodonApi.blockDomain(instance).enqueue(object : Callback<Any> {
override fun onResponse(call: Call<Any>, response: Response<Any>) {
if (response.isSuccessful) {
eventHub.dispatch(DomainMuteEvent(instance))
val relation = relationshipData.value?.data
if (relation != null) {
relationshipData.postValue(Success(relation.copy(blockingDomain = true)))
}
} else {
Log.e(TAG, "Error muting %s".format(instance))
viewModelScope.launch {
mastodonApi.blockDomain(instance).fold({
eventHub.dispatch(DomainMuteEvent(instance))
val relation = relationshipData.value?.data
if (relation != null) {
relationshipData.postValue(Success(relation.copy(blockingDomain = true)))
}
}
override fun onFailure(call: Call<Any>, t: Throwable) {
Log.e(TAG, "Error muting %s".format(instance), t)
}
})
}, { e ->
Log.e(TAG, "Error muting $instance", e)
})
}
}
fun unblockDomain(instance: String) {
mastodonApi.unblockDomain(instance).enqueue(object : Callback<Any> {
override fun onResponse(call: Call<Any>, response: Response<Any>) {
if (response.isSuccessful) {
val relation = relationshipData.value?.data
if (relation != null) {
relationshipData.postValue(Success(relation.copy(blockingDomain = false)))
}
} else {
Log.e(TAG, "Error unmuting %s".format(instance))
viewModelScope.launch {
mastodonApi.unblockDomain(instance).fold({
val relation = relationshipData.value?.data
if (relation != null) {
relationshipData.postValue(Success(relation.copy(blockingDomain = false)))
}
}
override fun onFailure(call: Call<Any>, t: Throwable) {
Log.e(TAG, "Error unmuting %s".format(instance), t)
}
})
}, { e ->
Log.e(TAG, "Error unmuting $instance", e)
})
}
}
fun changeShowReblogsState() {

View file

@ -36,7 +36,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import at.connyduck.sparkbutton.helpers.Utils
import autodispose2.androidx.lifecycle.autoDispose
import com.google.android.material.color.MaterialColors
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.StatusListActivity
@ -62,7 +61,6 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@ -205,14 +203,13 @@ class ConversationsFragment :
}
}
eventHub.events
.observeOn(AndroidSchedulers.mainThread())
.autoDispose(this, Lifecycle.Event.ON_DESTROY)
.subscribe { event ->
lifecycleScope.launch {
eventHub.events.collect { event ->
if (event is PreferenceChangedEvent) {
onPreferenceChanged(event.preferenceKey)
}
}
}
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {

View file

@ -23,6 +23,7 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import androidx.paging.map
import at.connyduck.calladapter.networkresult.fold
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.db.AppDatabase
import com.keylesspalace.tusky.network.MastodonApi
@ -30,7 +31,6 @@ import com.keylesspalace.tusky.usecase.TimelineCases
import com.keylesspalace.tusky.util.EmptyPagingSource
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.await
import javax.inject.Inject
class ConversationsViewModel @Inject constructor(
@ -61,51 +61,47 @@ class ConversationsViewModel @Inject constructor(
fun favourite(favourite: Boolean, conversation: ConversationViewData) {
viewModelScope.launch {
try {
timelineCases.favourite(conversation.lastStatus.id, favourite).await()
timelineCases.favourite(conversation.lastStatus.id, favourite).fold({
val newConversation = conversation.toEntity(
accountId = accountManager.activeAccount!!.id,
favourited = favourite
)
saveConversationToDb(newConversation)
} catch (e: Exception) {
}, { e ->
Log.w(TAG, "failed to favourite status", e)
}
})
}
}
fun bookmark(bookmark: Boolean, conversation: ConversationViewData) {
viewModelScope.launch {
try {
timelineCases.bookmark(conversation.lastStatus.id, bookmark).await()
timelineCases.bookmark(conversation.lastStatus.id, bookmark).fold({
val newConversation = conversation.toEntity(
accountId = accountManager.activeAccount!!.id,
bookmarked = bookmark
)
saveConversationToDb(newConversation)
} catch (e: Exception) {
}, { e ->
Log.w(TAG, "failed to bookmark status", e)
}
})
}
}
fun voteInPoll(choices: List<Int>, conversation: ConversationViewData) {
viewModelScope.launch {
try {
val poll = timelineCases.voteInPoll(conversation.lastStatus.id, conversation.lastStatus.status.poll?.id!!, choices).await()
val newConversation = conversation.toEntity(
accountId = accountManager.activeAccount!!.id,
poll = poll
)
timelineCases.voteInPoll(conversation.lastStatus.id, conversation.lastStatus.status.poll?.id!!, choices)
.fold({ poll ->
val newConversation = conversation.toEntity(
accountId = accountManager.activeAccount!!.id,
poll = poll
)
saveConversationToDb(newConversation)
} catch (e: Exception) {
Log.w(TAG, "failed to vote in poll", e)
}
saveConversationToDb(newConversation)
}, { e ->
Log.w(TAG, "failed to vote in poll", e)
})
}
}
@ -160,7 +156,7 @@ class ConversationsViewModel @Inject constructor(
timelineCases.muteConversation(
conversation.lastStatus.id,
!(conversation.lastStatus.status.muted ?: false)
).await()
)
val newConversation = conversation.toEntity(
accountId = accountManager.activeAccount!!.id,

View file

@ -5,9 +5,11 @@ import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import at.connyduck.calladapter.networkresult.fold
import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider.from
import autodispose2.autoDispose
import com.google.android.material.snackbar.Snackbar
@ -23,9 +25,7 @@ import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.view.EndlessOnScrollListener
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlinx.coroutines.launch
import java.io.IOException
import javax.inject.Inject
@ -64,39 +64,25 @@ class InstanceListFragment : Fragment(R.layout.fragment_instance_list), Injectab
}
override fun mute(mute: Boolean, instance: String, position: Int) {
if (mute) {
api.blockDomain(instance).enqueue(object : Callback<Any> {
override fun onFailure(call: Call<Any>, t: Throwable) {
Log.e(TAG, "Error muting domain $instance")
}
override fun onResponse(call: Call<Any>, response: Response<Any>) {
if (response.isSuccessful) {
adapter.addItem(instance)
} else {
Log.e(TAG, "Error muting domain $instance")
}
}
})
} else {
api.unblockDomain(instance).enqueue(object : Callback<Any> {
override fun onFailure(call: Call<Any>, t: Throwable) {
Log.e(TAG, "Error unmuting domain $instance")
}
override fun onResponse(call: Call<Any>, response: Response<Any>) {
if (response.isSuccessful) {
adapter.removeItem(position)
Snackbar.make(binding.recyclerView, getString(R.string.confirmation_domain_unmuted, instance), Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo) {
mute(true, instance, position)
}
.show()
} else {
Log.e(TAG, "Error unmuting domain $instance")
}
}
})
viewLifecycleOwner.lifecycleScope.launch {
if (mute) {
api.blockDomain(instance).fold({
adapter.addItem(instance)
}, { e ->
Log.e(TAG, "Error muting domain $instance", e)
})
} else {
api.unblockDomain(instance).fold({
adapter.removeItem(position)
Snackbar.make(binding.recyclerView, getString(R.string.confirmation_domain_unmuted, instance), Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo) {
mute(true, instance, position)
}
.show()
}, { e ->
Log.e(TAG, "Error unmuting domain $instance", e)
})
}
}
}

View file

@ -62,7 +62,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow
import kotlinx.coroutines.rx3.await
import retrofit2.HttpException
import javax.inject.Inject
@ -357,7 +356,7 @@ class NotificationsViewModel @Inject constructor(
)
viewModelScope.launch {
eventHub.events.asFlow()
eventHub.events
.filterIsInstance<PreferenceChangedEvent>()
.filter { StatusDisplayOptions.prefKeys.contains(it.preferenceKey) }
.map {
@ -420,23 +419,23 @@ class NotificationsViewModel @Inject constructor(
timelineCases.bookmark(
action.statusViewData.actionableId,
action.state
).await()
)
is StatusAction.Favourite ->
timelineCases.favourite(
action.statusViewData.actionableId,
action.state
).await()
)
is StatusAction.Reblog ->
timelineCases.reblog(
action.statusViewData.actionableId,
action.state
).await()
)
is StatusAction.VoteInPoll ->
timelineCases.voteInPoll(
action.statusViewData.actionableId,
action.poll.id,
action.choices
).await()
)
}
uiSuccess.emit(StatusActionSuccess.from(action))
} catch (e: Exception) {
@ -447,7 +446,7 @@ class NotificationsViewModel @Inject constructor(
// Handle events that should refresh the list
viewModelScope.launch {
eventHub.events.asFlow().collectLatest {
eventHub.events.collectLatest {
when (it) {
is BlockEvent -> uiSuccess.emit(UiSuccess.Block)
is MuteEvent -> uiSuccess.emit(UiSuccess.Mute)
@ -504,7 +503,7 @@ class NotificationsViewModel @Inject constructor(
* @return Flow of relevant preferences that change the UI
*/
// TODO: Preferences should be in a repository
private fun getUiPrefs() = eventHub.events.asFlow()
private fun getUiPrefs() = eventHub.events
.filterIsInstance<PreferenceChangedEvent>()
.filter { UiPrefs.prefKeys.contains(it.preferenceKey) }
.map { toPrefs() }

View file

@ -21,6 +21,7 @@ import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.annotation.DrawableRes
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
@ -57,6 +58,7 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeRes
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
@ -198,7 +200,6 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
setOnPreferenceChangeListener { _, newValue ->
setIcon(getIconForVisibility(Status.Visibility.byString(newValue as String)))
syncWithServer(visibility = newValue)
eventHub.dispatch(PreferenceChangedEvent(key))
true
}
}
@ -221,7 +222,6 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
setOnPreferenceChangeListener { _, newValue ->
syncWithServer(language = (newValue as String))
eventHub.dispatch(PreferenceChangedEvent(key))
true
}
}
@ -237,7 +237,6 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
setOnPreferenceChangeListener { _, newValue ->
setIcon(getIconForSensitivity(newValue as Boolean))
syncWithServer(sensitive = newValue)
eventHub.dispatch(PreferenceChangedEvent(key))
true
}
}
@ -246,7 +245,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
preferenceCategory(R.string.pref_title_timelines) {
// TODO having no activeAccount in this fragment does not really make sense, enforce it?
// All other locations here make it optional, however.
val accountPreferenceHandler = AccountPreferenceHandler(accountManager.activeAccount!!, accountManager, eventHub)
val accountPreferenceHandler = AccountPreferenceHandler(accountManager.activeAccount!!, accountManager, ::dispatchEvent)
switchPreference {
key = PrefKeys.MEDIA_PREVIEW_ENABLED
@ -354,6 +353,12 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), Injectable {
activity?.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
}
private fun dispatchEvent(event: PreferenceChangedEvent) {
lifecycleScope.launch {
eventHub.dispatch(event)
}
}
companion object {
fun newInstance() = AccountPreferencesFragment()
}

View file

@ -23,6 +23,7 @@ import android.util.Log
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
@ -38,6 +39,7 @@ import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.setAppNightMode
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import kotlinx.coroutines.launch
import javax.inject.Inject
class PreferencesActivity :
@ -155,8 +157,9 @@ class PreferencesActivity :
restartActivitiesOnBackPressedCallback.isEnabled = true
}
}
eventHub.dispatch(PreferenceChangedEvent(key))
lifecycleScope.launch {
eventHub.dispatch(PreferenceChangedEvent(key))
}
}
private fun restartCurrentActivity() {

View file

@ -28,7 +28,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import autodispose2.androidx.lifecycle.autoDispose
import com.google.android.material.color.MaterialColors
import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R
@ -46,7 +45,6 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -119,14 +117,13 @@ class ScheduledStatusActivity :
}
}
eventHub.events
.observeOn(AndroidSchedulers.mainThread())
.autoDispose(this)
.subscribe { event ->
lifecycleScope.launch {
eventHub.events.collect { event ->
if (event is StatusScheduledEvent) {
adapter.refresh()
}
}
}
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {

View file

@ -16,11 +16,14 @@
package com.keylesspalace.tusky.components.search
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import at.connyduck.calladapter.networkresult.NetworkResult
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.onFailure
import com.keylesspalace.tusky.components.search.adapter.SearchPagingSourceFactory
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.AccountManager
@ -28,10 +31,8 @@ import com.keylesspalace.tusky.entity.DeletedStatus
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.usecase.TimelineCases
import com.keylesspalace.tusky.util.RxAwareViewModel
import com.keylesspalace.tusky.util.toViewData
import com.keylesspalace.tusky.viewdata.StatusViewData
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
@ -41,7 +42,7 @@ class SearchViewModel @Inject constructor(
mastodonApi: MastodonApi,
private val timelineCases: TimelineCases,
private val accountManager: AccountManager
) : RxAwareViewModel() {
) : ViewModel() {
var currentQuery: String = ""
@ -115,22 +116,18 @@ class SearchViewModel @Inject constructor(
}
fun reblog(statusViewData: StatusViewData.Concrete, reblog: Boolean) {
timelineCases.reblog(statusViewData.id, reblog)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ setRebloggedForStatus(statusViewData, reblog) },
{ t -> Log.d(TAG, "Failed to reblog status ${statusViewData.id}", t) }
)
.autoDispose()
}
private fun setRebloggedForStatus(statusViewData: StatusViewData.Concrete, reblog: Boolean) {
updateStatus(
statusViewData.status.copy(
reblogged = reblog,
reblog = statusViewData.status.reblog?.copy(reblogged = reblog)
)
)
viewModelScope.launch {
timelineCases.reblog(statusViewData.id, reblog).fold({
updateStatus(
statusViewData.status.copy(
reblogged = reblog,
reblog = statusViewData.status.reblog?.copy(reblogged = reblog)
)
)
}, { t ->
Log.d(TAG, "Failed to reblog status ${statusViewData.id}", t)
})
}
}
fun contentHiddenChange(statusViewData: StatusViewData.Concrete, isShowing: Boolean) {
@ -144,27 +141,24 @@ class SearchViewModel @Inject constructor(
fun voteInPoll(statusViewData: StatusViewData.Concrete, choices: MutableList<Int>) {
val votedPoll = statusViewData.status.actionableStatus.poll!!.votedCopy(choices)
updateStatus(statusViewData.status.copy(poll = votedPoll))
timelineCases.voteInPoll(statusViewData.id, votedPoll.id, choices)
.observeOn(AndroidSchedulers.mainThread())
.doOnError { t -> Log.d(TAG, "Failed to vote in poll: ${statusViewData.id}", t) }
.subscribe()
.autoDispose()
viewModelScope.launch {
timelineCases.voteInPoll(statusViewData.id, votedPoll.id, choices)
.onFailure { t -> Log.d(TAG, "Failed to vote in poll: ${statusViewData.id}", t) }
}
}
fun favorite(statusViewData: StatusViewData.Concrete, isFavorited: Boolean) {
updateStatus(statusViewData.status.copy(favourited = isFavorited))
timelineCases.favourite(statusViewData.id, isFavorited)
.onErrorReturnItem(statusViewData.status)
.subscribe()
.autoDispose()
viewModelScope.launch {
timelineCases.favourite(statusViewData.id, isFavorited)
}
}
fun bookmark(statusViewData: StatusViewData.Concrete, isBookmarked: Boolean) {
updateStatus(statusViewData.status.copy(bookmarked = isBookmarked))
timelineCases.bookmark(statusViewData.id, isBookmarked)
.onErrorReturnItem(statusViewData.status)
.subscribe()
.autoDispose()
viewModelScope.launch {
timelineCases.bookmark(statusViewData.id, isBookmarked)
}
}
fun muteAccount(accountId: String, notifications: Boolean, duration: Int?) {
@ -174,7 +168,9 @@ class SearchViewModel @Inject constructor(
}
fun pinAccount(status: Status, isPin: Boolean) {
timelineCases.pin(status.id, isPin)
viewModelScope.launch {
timelineCases.pin(status.id, isPin)
}
}
fun blockAccount(accountId: String) {
@ -191,10 +187,9 @@ class SearchViewModel @Inject constructor(
fun muteConversation(statusViewData: StatusViewData.Concrete, mute: Boolean) {
updateStatus(statusViewData.status.copy(muted = mute))
timelineCases.muteConversation(statusViewData.id, mute)
.onErrorReturnItem(statusViewData.status)
.subscribe()
.autoDispose()
viewModelScope.launch {
timelineCases.muteConversation(statusViewData.id, mute)
}
}
private fun updateStatusViewData(newStatusViewData: StatusViewData.Concrete) {

View file

@ -77,6 +77,7 @@ import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.io.IOException
@ -299,10 +300,8 @@ class TimelineFragment :
})
}
eventHub.events
.observeOn(AndroidSchedulers.mainThread())
.autoDispose(this, Lifecycle.Event.ON_DESTROY)
.subscribe { event ->
viewLifecycleOwner.lifecycleScope.launch {
eventHub.events.collect { event ->
when (event) {
is PreferenceChangedEvent -> {
onPreferenceChanged(event.preferenceKey)
@ -316,6 +315,7 @@ class TimelineFragment :
}
}
}
}
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {

View file

@ -22,6 +22,7 @@ import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.getOrElse
import at.connyduck.calladapter.networkresult.getOrThrow
import com.keylesspalace.tusky.appstore.BlockEvent
import com.keylesspalace.tusky.appstore.BookmarkEvent
import com.keylesspalace.tusky.appstore.DomainMuteEvent
@ -49,8 +50,6 @@ import com.keylesspalace.tusky.viewdata.StatusViewData
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow
import kotlinx.coroutines.rx3.await
import retrofit2.HttpException
abstract class TimelineViewModel(
@ -101,7 +100,6 @@ abstract class TimelineViewModel(
viewModelScope.launch {
eventHub.events
.asFlow()
.collect { event -> handleEvent(event) }
}
@ -110,7 +108,7 @@ abstract class TimelineViewModel(
fun reblog(reblog: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.reblog(status.actionableId, reblog).await()
timelineCases.reblog(status.actionableId, reblog).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to reblog status " + status.actionableId, t)
@ -120,7 +118,7 @@ abstract class TimelineViewModel(
fun favorite(favorite: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.favourite(status.actionableId, favorite).await()
timelineCases.favourite(status.actionableId, favorite).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to favourite status " + status.actionableId, t)
@ -130,7 +128,7 @@ abstract class TimelineViewModel(
fun bookmark(bookmark: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.bookmark(status.actionableId, bookmark).await()
timelineCases.bookmark(status.actionableId, bookmark).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to bookmark status " + status.actionableId, t)
@ -148,7 +146,7 @@ abstract class TimelineViewModel(
updatePoll(votedPoll, status)
try {
timelineCases.voteInPoll(status.actionableId, poll.id, choices).await()
timelineCases.voteInPoll(status.actionableId, poll.id, choices).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to vote in poll: " + status.actionableId, t)

View file

@ -28,7 +28,6 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow
import okio.IOException
import javax.inject.Inject
@ -55,7 +54,7 @@ class TrendingViewModel @Inject constructor(
// or deleted. Unfortunately, there's nothing in the event to determine if it's a filter
// that was modified, so refresh on every preference change.
viewModelScope.launch {
eventHub.events.asFlow()
eventHub.events
.filterIsInstance<PreferenceChangedEvent>()
.collect {
invalidate()

View file

@ -20,6 +20,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.connyduck.calladapter.networkresult.fold
import at.connyduck.calladapter.networkresult.getOrElse
import at.connyduck.calladapter.networkresult.getOrThrow
import com.google.gson.Gson
import com.keylesspalace.tusky.appstore.BlockEvent
import com.keylesspalace.tusky.appstore.BookmarkEvent
@ -50,8 +51,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlow
import kotlinx.coroutines.rx3.await
import retrofit2.HttpException
import javax.inject.Inject
@ -85,7 +84,6 @@ class ViewThreadViewModel @Inject constructor(
viewModelScope.launch {
eventHub.events
.asFlow()
.collect { event ->
when (event) {
is FavoriteEvent -> handleFavEvent(event)
@ -195,7 +193,7 @@ class ViewThreadViewModel @Inject constructor(
fun reblog(reblog: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.reblog(status.actionableId, reblog).await()
timelineCases.reblog(status.actionableId, reblog).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to reblog status " + status.actionableId, t)
@ -205,7 +203,7 @@ class ViewThreadViewModel @Inject constructor(
fun favorite(favorite: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.favourite(status.actionableId, favorite).await()
timelineCases.favourite(status.actionableId, favorite).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to favourite status " + status.actionableId, t)
@ -215,7 +213,7 @@ class ViewThreadViewModel @Inject constructor(
fun bookmark(bookmark: Boolean, status: StatusViewData.Concrete): Job = viewModelScope.launch {
try {
timelineCases.bookmark(status.actionableId, bookmark).await()
timelineCases.bookmark(status.actionableId, bookmark).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to bookmark status " + status.actionableId, t)
@ -235,7 +233,7 @@ class ViewThreadViewModel @Inject constructor(
}
try {
timelineCases.voteInPoll(status.actionableId, poll.id, choices).await()
timelineCases.voteInPoll(status.actionableId, poll.id, choices).getOrThrow()
} catch (t: Exception) {
ifExpected(t) {
Log.d(TAG, "Failed to vote in poll: " + status.actionableId, t)