mirror of
https://github.com/tuskyapp/Tusky
synced 2025-02-07 17:08:43 +01:00
improve local status updates (#3480)
The idea here is: Everytime we get hold of a new version of a post, we update everything about that post everywhere. This makes the distincion between different event types unnecessary, as everythng is just a `StatusChangedEvent`. The main benefit is that posts should be up-to-date more often, which is important considering there is now editing and #3413
This commit is contained in:
parent
2f39f87cc7
commit
54e92b2156
@ -26,12 +26,14 @@ class CacheUpdater @Inject constructor(
|
||||
eventHub.events.collect { event ->
|
||||
val accountId = accountManager.activeAccount?.id ?: return@collect
|
||||
when (event) {
|
||||
is FavoriteEvent ->
|
||||
timelineDao.setFavourited(accountId, event.statusId, event.favourite)
|
||||
is ReblogEvent ->
|
||||
timelineDao.setReblogged(accountId, event.statusId, event.reblog)
|
||||
is BookmarkEvent ->
|
||||
timelineDao.setBookmarked(accountId, event.statusId, event.bookmark)
|
||||
is StatusChangedEvent -> {
|
||||
val status = event.status
|
||||
timelineDao.update(
|
||||
accountId = accountId,
|
||||
status = status,
|
||||
gson = gson
|
||||
)
|
||||
}
|
||||
is UnfollowEvent ->
|
||||
timelineDao.removeAllByUser(accountId, event.accountId)
|
||||
is StatusDeletedEvent ->
|
||||
@ -40,8 +42,6 @@ class CacheUpdater @Inject constructor(
|
||||
val pollString = gson.toJson(event.poll)
|
||||
timelineDao.setVoted(accountId, event.statusId, pollString)
|
||||
}
|
||||
is PinEvent ->
|
||||
timelineDao.setPinned(accountId, event.statusId, event.pinned)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,7 @@ import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Poll
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
|
||||
data class FavoriteEvent(val statusId: String, val favourite: Boolean) : Event
|
||||
data class ReblogEvent(val statusId: String, val reblog: Boolean) : Event
|
||||
data class BookmarkEvent(val statusId: String, val bookmark: Boolean) : Event
|
||||
data class StatusChangedEvent(val status: Status) : Event
|
||||
data class MuteConversationEvent(val statusId: String, val mute: Boolean) : Event
|
||||
data class UnfollowEvent(val accountId: String) : Event
|
||||
data class BlockEvent(val accountId: String) : Event
|
||||
@ -15,11 +13,9 @@ data class MuteEvent(val accountId: String) : Event
|
||||
data class StatusDeletedEvent(val statusId: String) : Event
|
||||
data class StatusComposedEvent(val status: Status) : Event
|
||||
data class StatusScheduledEvent(val status: Status) : Event
|
||||
data class StatusEditedEvent(val originalId: String, val status: Status) : Event
|
||||
data class ProfileEditedEvent(val newProfileData: Account) : Event
|
||||
data class PreferenceChangedEvent(val preferenceKey: String) : Event
|
||||
data class MainTabsChangedEvent(val newTabs: List<TabData>) : Event
|
||||
data class PollVoteEvent(val statusId: String, val poll: Poll) : Event
|
||||
data class DomainMuteEvent(val instance: String) : Event
|
||||
data class AnnouncementReadEvent(val announcementId: String) : Event
|
||||
data class PinEvent(val statusId: String, val pinned: Boolean) : Event
|
||||
|
@ -45,7 +45,6 @@ import com.keylesspalace.tusky.adapter.StatusBaseViewHolder
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusComposedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusEditedEvent
|
||||
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
|
||||
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Companion.newIntent
|
||||
import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder
|
||||
@ -306,9 +305,6 @@ class TimelineFragment :
|
||||
val status = event.status
|
||||
handleStatusComposeEvent(status)
|
||||
}
|
||||
is StatusEditedEvent -> {
|
||||
handleStatusComposeEvent(event.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,11 +27,7 @@ import androidx.paging.filter
|
||||
import androidx.paging.map
|
||||
import androidx.room.withTransaction
|
||||
import com.google.gson.Gson
|
||||
import com.keylesspalace.tusky.appstore.BookmarkEvent
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder.NEWEST_FIRST
|
||||
import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder.OLDEST_FIRST
|
||||
import com.keylesspalace.tusky.components.timeline.Placeholder
|
||||
@ -43,6 +39,7 @@ import com.keylesspalace.tusky.db.AppDatabase
|
||||
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
|
||||
import com.keylesspalace.tusky.entity.Filter
|
||||
import com.keylesspalace.tusky.entity.Poll
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.FilterModel
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.usecase.TimelineCases
|
||||
@ -253,19 +250,7 @@ class CachedTimelineViewModel @Inject constructor(
|
||||
.insertStatus(Placeholder(placeholderId, loading = false).toEntity(activeAccount.id))
|
||||
}
|
||||
|
||||
override fun handleReblogEvent(reblogEvent: ReblogEvent) {
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun handleFavEvent(favEvent: FavoriteEvent) {
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun handleBookmarkEvent(bookmarkEvent: BookmarkEvent) {
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun handlePinEvent(pinEvent: PinEvent) {
|
||||
override fun handleStatusChangedEvent(status: Status) {
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,7 @@ import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.filter
|
||||
import com.keylesspalace.tusky.appstore.BookmarkEvent
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.components.timeline.util.ifExpected
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.entity.Filter
|
||||
@ -219,27 +215,13 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
currentSource?.invalidate()
|
||||
}
|
||||
|
||||
override fun handleReblogEvent(reblogEvent: ReblogEvent) {
|
||||
updateStatusById(reblogEvent.statusId) {
|
||||
it.copy(status = it.status.copy(reblogged = reblogEvent.reblog))
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleFavEvent(favEvent: FavoriteEvent) {
|
||||
updateActionableStatusById(favEvent.statusId) {
|
||||
it.copy(favourited = favEvent.favourite)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleBookmarkEvent(bookmarkEvent: BookmarkEvent) {
|
||||
updateActionableStatusById(bookmarkEvent.statusId) {
|
||||
it.copy(bookmarked = bookmarkEvent.bookmark)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handlePinEvent(pinEvent: PinEvent) {
|
||||
updateActionableStatusById(pinEvent.statusId) {
|
||||
it.copy(pinned = pinEvent.pinned)
|
||||
override fun handleStatusChangedEvent(status: Status) {
|
||||
updateStatusById(status.id) { oldViewData ->
|
||||
status.toViewData(
|
||||
isShowingContent = oldViewData.isShowingContent,
|
||||
isExpanded = oldViewData.isExpanded,
|
||||
isCollapsed = oldViewData.isCollapsed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,16 +24,13 @@ 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
|
||||
import com.keylesspalace.tusky.appstore.Event
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.MuteConversationEvent
|
||||
import com.keylesspalace.tusky.appstore.MuteEvent
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent
|
||||
import com.keylesspalace.tusky.appstore.UnfollowEvent
|
||||
import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder
|
||||
@ -42,6 +39,7 @@ import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.entity.Filter
|
||||
import com.keylesspalace.tusky.entity.FilterV1
|
||||
import com.keylesspalace.tusky.entity.Poll
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.FilterModel
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
@ -170,13 +168,7 @@ abstract class TimelineViewModel(
|
||||
|
||||
abstract fun loadMore(placeholderId: String)
|
||||
|
||||
abstract fun handleReblogEvent(reblogEvent: ReblogEvent)
|
||||
|
||||
abstract fun handleFavEvent(favEvent: FavoriteEvent)
|
||||
|
||||
abstract fun handleBookmarkEvent(bookmarkEvent: BookmarkEvent)
|
||||
|
||||
abstract fun handlePinEvent(pinEvent: PinEvent)
|
||||
abstract fun handleStatusChangedEvent(status: Status)
|
||||
|
||||
abstract fun fullReload()
|
||||
|
||||
@ -237,10 +229,7 @@ abstract class TimelineViewModel(
|
||||
|
||||
private fun handleEvent(event: Event) {
|
||||
when (event) {
|
||||
is FavoriteEvent -> handleFavEvent(event)
|
||||
is ReblogEvent -> handleReblogEvent(event)
|
||||
is BookmarkEvent -> handleBookmarkEvent(event)
|
||||
is PinEvent -> handlePinEvent(event)
|
||||
is StatusChangedEvent -> handleStatusChangedEvent(event.status)
|
||||
is MuteConversationEvent -> fullReload()
|
||||
is UnfollowEvent -> {
|
||||
if (kind == Kind.HOME) {
|
||||
|
@ -23,14 +23,10 @@ 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
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusComposedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusEditedEvent
|
||||
import com.keylesspalace.tusky.components.timeline.toViewData
|
||||
import com.keylesspalace.tusky.components.timeline.util.ifExpected
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
@ -59,7 +55,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
private val filterModel: FilterModel,
|
||||
private val timelineCases: TimelineCases,
|
||||
eventHub: EventHub,
|
||||
accountManager: AccountManager,
|
||||
private val accountManager: AccountManager,
|
||||
private val db: AppDatabase,
|
||||
private val gson: Gson
|
||||
) : ViewModel() {
|
||||
@ -86,14 +82,10 @@ class ViewThreadViewModel @Inject constructor(
|
||||
eventHub.events
|
||||
.collect { event ->
|
||||
when (event) {
|
||||
is FavoriteEvent -> handleFavEvent(event)
|
||||
is ReblogEvent -> handleReblogEvent(event)
|
||||
is BookmarkEvent -> handleBookmarkEvent(event)
|
||||
is PinEvent -> handlePinEvent(event)
|
||||
is StatusChangedEvent -> handleStatusChangedEvent(event.status)
|
||||
is BlockEvent -> removeAllByAccountId(event.accountId)
|
||||
is StatusComposedEvent -> handleStatusComposedEvent(event)
|
||||
is StatusDeletedEvent -> handleStatusDeletedEvent(event)
|
||||
is StatusEditedEvent -> handleStatusEditedEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,7 +99,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
Log.d(TAG, "Finding status with: $id")
|
||||
val contextCall = async { api.statusContext(id) }
|
||||
val timelineStatus = db.timelineDao().getStatus(id)
|
||||
val timelineStatus = db.timelineDao().getStatus(accountManager.activeAccount!!.id, id)
|
||||
|
||||
var detailedStatus = if (timelineStatus != null) {
|
||||
Log.d(TAG, "Loaded status from local timeline")
|
||||
@ -144,8 +136,14 @@ class ViewThreadViewModel @Inject constructor(
|
||||
// for the status. Ignore errors, the user still has a functioning UI if the fetch
|
||||
// failed.
|
||||
if (timelineStatus != null) {
|
||||
val viewData = api.status(id).getOrNull()?.toViewData(isDetailed = true)
|
||||
if (viewData != null) { detailedStatus = viewData }
|
||||
api.status(id).getOrNull()?.let { result ->
|
||||
db.timelineDao().update(
|
||||
accountId = accountManager.activeAccount!!.id,
|
||||
status = result,
|
||||
gson = gson
|
||||
)
|
||||
detailedStatus = result.toViewData(isDetailed = true)
|
||||
}
|
||||
}
|
||||
|
||||
val contextResult = contextCall.await()
|
||||
@ -277,27 +275,14 @@ class ViewThreadViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFavEvent(event: FavoriteEvent) {
|
||||
updateStatus(event.statusId) { status ->
|
||||
status.copy(favourited = event.favourite)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleReblogEvent(event: ReblogEvent) {
|
||||
updateStatus(event.statusId) { status ->
|
||||
status.copy(reblogged = event.reblog)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBookmarkEvent(event: BookmarkEvent) {
|
||||
updateStatus(event.statusId) { status ->
|
||||
status.copy(bookmarked = event.bookmark)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePinEvent(event: PinEvent) {
|
||||
updateStatus(event.statusId) { status ->
|
||||
status.copy(pinned = event.pinned)
|
||||
private fun handleStatusChangedEvent(status: Status) {
|
||||
updateStatusViewData(status.id) { viewData ->
|
||||
status.toViewData(
|
||||
isShowingContent = viewData.isShowingContent,
|
||||
isExpanded = viewData.isExpanded,
|
||||
isCollapsed = viewData.isCollapsed,
|
||||
isDetailed = viewData.isDetailed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,20 +314,6 @@ class ViewThreadViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleStatusEditedEvent(event: StatusEditedEvent) {
|
||||
updateSuccess { uiState ->
|
||||
uiState.copy(
|
||||
statusViewData = uiState.statusViewData.map { status ->
|
||||
if (status.actionableId == event.originalId) {
|
||||
event.status.toViewData()
|
||||
} else {
|
||||
status
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleStatusDeletedEvent(event: StatusDeletedEvent) {
|
||||
updateSuccess { uiState ->
|
||||
uiState.copy(
|
||||
|
@ -20,6 +20,10 @@ import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.Companion.REPLACE
|
||||
import androidx.room.Query
|
||||
import androidx.room.TypeConverters
|
||||
import com.google.gson.Gson
|
||||
import com.keylesspalace.tusky.entity.FilterResult
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
|
||||
@Dao
|
||||
abstract class TimelineDao {
|
||||
@ -72,9 +76,10 @@ FROM TimelineStatusEntity s
|
||||
LEFT JOIN TimelineAccountEntity a ON (s.timelineUserId = a.timelineUserId AND s.authorServerId = a.serverId)
|
||||
LEFT JOIN TimelineAccountEntity rb ON (s.timelineUserId = rb.timelineUserId AND s.reblogAccountId = rb.serverId)
|
||||
WHERE (s.serverId = :statusId OR s.reblogServerId = :statusId)
|
||||
AND s.authorServerId IS NOT NULL"""
|
||||
AND s.authorServerId IS NOT NULL
|
||||
AND s.timelineUserId = :accountId"""
|
||||
)
|
||||
abstract suspend fun getStatus(statusId: String): TimelineStatusWithAccount?
|
||||
abstract suspend fun getStatus(accountId: Long, statusId: String): TimelineStatusWithAccount?
|
||||
|
||||
@Query(
|
||||
"""DELETE FROM TimelineStatusEntity WHERE timelineUserId = :accountId AND
|
||||
@ -85,11 +90,85 @@ AND
|
||||
)
|
||||
abstract suspend fun deleteRange(accountId: Long, minId: String, maxId: String): Int
|
||||
|
||||
suspend fun update(accountId: Long, status: Status, gson: Gson) {
|
||||
update(
|
||||
accountId = accountId,
|
||||
statusId = status.id,
|
||||
content = status.content,
|
||||
editedAt = status.editedAt?.time,
|
||||
emojis = gson.toJson(status.emojis),
|
||||
reblogsCount = status.reblogsCount,
|
||||
favouritesCount = status.favouritesCount,
|
||||
repliesCount = status.repliesCount,
|
||||
reblogged = status.reblogged,
|
||||
bookmarked = status.bookmarked,
|
||||
favourited = status.favourited,
|
||||
sensitive = status.sensitive,
|
||||
spoilerText = status.spoilerText,
|
||||
visibility = status.visibility,
|
||||
attachments = gson.toJson(status.attachments),
|
||||
mentions = gson.toJson(status.mentions),
|
||||
tags = gson.toJson(status.tags),
|
||||
poll = gson.toJson(status.poll),
|
||||
muted = status.muted,
|
||||
pinned = status.pinned ?: false,
|
||||
card = gson.toJson(status.card),
|
||||
language = status.language,
|
||||
filtered = status.filtered
|
||||
)
|
||||
}
|
||||
|
||||
@Query(
|
||||
"""UPDATE TimelineStatusEntity SET favourited = :favourited
|
||||
WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)"""
|
||||
"""UPDATE TimelineStatusEntity
|
||||
SET content = :content,
|
||||
editedAt = :editedAt,
|
||||
emojis = :emojis,
|
||||
reblogsCount = :reblogsCount,
|
||||
favouritesCount = :favouritesCount,
|
||||
repliesCount = :repliesCount,
|
||||
reblogged = :reblogged,
|
||||
bookmarked = :bookmarked,
|
||||
favourited = :favourited,
|
||||
sensitive = :sensitive,
|
||||
spoilerText = :spoilerText,
|
||||
visibility = :visibility,
|
||||
attachments = :attachments,
|
||||
mentions = :mentions,
|
||||
tags = :tags,
|
||||
poll = :poll,
|
||||
muted = :muted,
|
||||
pinned = :pinned,
|
||||
card = :card,
|
||||
language = :language,
|
||||
filtered = :filtered
|
||||
WHERE timelineUserId = :accountId AND (serverId = :statusId OR reblogServerId = :statusId)"""
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract suspend fun update(
|
||||
accountId: Long,
|
||||
statusId: String,
|
||||
content: String?,
|
||||
editedAt: Long?,
|
||||
emojis: String?,
|
||||
reblogsCount: Int,
|
||||
favouritesCount: Int,
|
||||
repliesCount: Int,
|
||||
reblogged: Boolean,
|
||||
bookmarked: Boolean,
|
||||
favourited: Boolean,
|
||||
sensitive: Boolean,
|
||||
spoilerText: String,
|
||||
visibility: Status.Visibility,
|
||||
attachments: String?,
|
||||
mentions: String?,
|
||||
tags: String?,
|
||||
poll: String?,
|
||||
muted: Boolean?,
|
||||
pinned: Boolean,
|
||||
card: String?,
|
||||
language: String?,
|
||||
filtered: List<FilterResult>?
|
||||
)
|
||||
abstract suspend fun setFavourited(accountId: Long, statusId: String, favourited: Boolean)
|
||||
|
||||
@Query(
|
||||
"""UPDATE TimelineStatusEntity SET bookmarked = :bookmarked
|
||||
|
@ -21,8 +21,8 @@ import at.connyduck.calladapter.networkresult.fold
|
||||
import com.keylesspalace.tusky.MainActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusComposedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusEditedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusScheduledEvent
|
||||
import com.keylesspalace.tusky.components.compose.MediaUploader
|
||||
import com.keylesspalace.tusky.components.compose.UploadEvent
|
||||
@ -253,7 +253,7 @@ class SendStatusService : Service(), Injectable {
|
||||
if (scheduled) {
|
||||
eventHub.dispatch(StatusScheduledEvent(sentStatus))
|
||||
} else if (!isNew) {
|
||||
eventHub.dispatch(StatusEditedEvent(statusToSend.statusId!!, sentStatus))
|
||||
eventHub.dispatch(StatusChangedEvent(sentStatus))
|
||||
} else {
|
||||
eventHub.dispatch(StatusComposedEvent(sentStatus))
|
||||
}
|
||||
|
@ -21,14 +21,11 @@ import at.connyduck.calladapter.networkresult.fold
|
||||
import at.connyduck.calladapter.networkresult.onFailure
|
||||
import at.connyduck.calladapter.networkresult.onSuccess
|
||||
import com.keylesspalace.tusky.appstore.BlockEvent
|
||||
import com.keylesspalace.tusky.appstore.BookmarkEvent
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.MuteConversationEvent
|
||||
import com.keylesspalace.tusky.appstore.MuteEvent
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.PollVoteEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent
|
||||
import com.keylesspalace.tusky.entity.DeletedStatus
|
||||
import com.keylesspalace.tusky.entity.Poll
|
||||
@ -53,8 +50,8 @@ class TimelineCases @Inject constructor(
|
||||
mastodonApi.reblogStatus(statusId)
|
||||
} else {
|
||||
mastodonApi.unreblogStatus(statusId)
|
||||
}.onSuccess {
|
||||
eventHub.dispatch(ReblogEvent(statusId, reblog))
|
||||
}.onSuccess { status ->
|
||||
eventHub.dispatch(StatusChangedEvent(status))
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,8 +60,8 @@ class TimelineCases @Inject constructor(
|
||||
mastodonApi.favouriteStatus(statusId)
|
||||
} else {
|
||||
mastodonApi.unfavouriteStatus(statusId)
|
||||
}.onSuccess {
|
||||
eventHub.dispatch(FavoriteEvent(statusId, favourite))
|
||||
}.onSuccess { status ->
|
||||
eventHub.dispatch(StatusChangedEvent(status))
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,8 +70,8 @@ class TimelineCases @Inject constructor(
|
||||
mastodonApi.bookmarkStatus(statusId)
|
||||
} else {
|
||||
mastodonApi.unbookmarkStatus(statusId)
|
||||
}.onSuccess {
|
||||
eventHub.dispatch(BookmarkEvent(statusId, bookmark))
|
||||
}.onSuccess { status ->
|
||||
eventHub.dispatch(StatusChangedEvent(status))
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +159,7 @@ class TimelineCases @Inject constructor(
|
||||
} else {
|
||||
mastodonApi.unpinStatus(statusId)
|
||||
}.fold({ status ->
|
||||
eventHub.dispatch(PinEvent(statusId, pin))
|
||||
eventHub.dispatch(StatusChangedEvent(status))
|
||||
NetworkResult.success(status)
|
||||
}, { e ->
|
||||
Log.w(TAG, "Failed to change pin state", e)
|
||||
|
@ -7,10 +7,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
import com.google.gson.Gson
|
||||
import com.keylesspalace.tusky.appstore.BookmarkEvent
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.components.timeline.mockStatus
|
||||
import com.keylesspalace.tusky.components.timeline.mockStatusViewData
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
@ -216,13 +214,13 @@ class ViewThreadViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle favorite event`() {
|
||||
fun `should handle status changed event`() {
|
||||
mockSuccessResponses()
|
||||
|
||||
viewModel.loadThread(threadId)
|
||||
|
||||
runBlocking {
|
||||
eventHub.dispatch(FavoriteEvent(statusId = "1", false))
|
||||
eventHub.dispatch(StatusChangedEvent(mockStatus(id = "1", spoilerText = "Test", favourited = false)))
|
||||
|
||||
assertEquals(
|
||||
ThreadUiState.Success(
|
||||
@ -239,54 +237,6 @@ class ViewThreadViewModelTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle reblog event`() {
|
||||
mockSuccessResponses()
|
||||
|
||||
viewModel.loadThread(threadId)
|
||||
|
||||
runBlocking {
|
||||
eventHub.dispatch(ReblogEvent(statusId = "2", true))
|
||||
|
||||
assertEquals(
|
||||
ThreadUiState.Success(
|
||||
statusViewData = listOf(
|
||||
mockStatusViewData(id = "1", spoilerText = "Test"),
|
||||
mockStatusViewData(id = "2", inReplyToId = "1", inReplyToAccountId = "1", isDetailed = true, spoilerText = "Test", reblogged = true),
|
||||
mockStatusViewData(id = "3", inReplyToId = "2", inReplyToAccountId = "1", spoilerText = "Test")
|
||||
),
|
||||
detailedStatusPosition = 1,
|
||||
revealButton = RevealButtonState.REVEAL
|
||||
),
|
||||
viewModel.uiState.first()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle bookmark event`() {
|
||||
mockSuccessResponses()
|
||||
|
||||
viewModel.loadThread(threadId)
|
||||
|
||||
runBlocking {
|
||||
eventHub.dispatch(BookmarkEvent(statusId = "3", false))
|
||||
|
||||
assertEquals(
|
||||
ThreadUiState.Success(
|
||||
statusViewData = listOf(
|
||||
mockStatusViewData(id = "1", spoilerText = "Test"),
|
||||
mockStatusViewData(id = "2", inReplyToId = "1", inReplyToAccountId = "1", isDetailed = true, spoilerText = "Test"),
|
||||
mockStatusViewData(id = "3", inReplyToId = "2", inReplyToAccountId = "1", spoilerText = "Test", bookmarked = false)
|
||||
),
|
||||
detailedStatusPosition = 1,
|
||||
revealButton = RevealButtonState.REVEAL
|
||||
),
|
||||
viewModel.uiState.first()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should remove status`() {
|
||||
mockSuccessResponses()
|
||||
|
@ -4,7 +4,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import app.cash.turbine.test
|
||||
import at.connyduck.calladapter.networkresult.NetworkResult
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PinEvent
|
||||
import com.keylesspalace.tusky.appstore.StatusChangedEvent
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@ -39,15 +39,17 @@ class TimelineCasesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pin success emits PinEvent`() {
|
||||
fun `pin success emits StatusChangedEvent`() {
|
||||
val pinnedStatus = mockStatus(pinned = true)
|
||||
|
||||
api.stub {
|
||||
onBlocking { pinStatus(statusId) } doReturn NetworkResult.success(mockStatus(pinned = true))
|
||||
onBlocking { pinStatus(statusId) } doReturn NetworkResult.success(pinnedStatus)
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
eventHub.events.test {
|
||||
timelineCases.pin(statusId, true)
|
||||
assertEquals(PinEvent(statusId, true), awaitItem())
|
||||
assertEquals(StatusChangedEvent(pinnedStatus), awaitItem())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user