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:
parent
66eadabd44
commit
321d17f5de
25 changed files with 264 additions and 330 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue