Skip to content

Commit

Permalink
improve local status updates (tuskyapp#3480)
Browse files Browse the repository at this point in the history
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 tuskyapp#3413
  • Loading branch information
connyduck authored Sep 26, 2023
1 parent 2f39f87 commit 54e92b2
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 198 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand All @@ -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)
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions app/src/main/java/com/keylesspalace/tusky/appstore/Events.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,17 @@ 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
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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -306,9 +305,6 @@ class TimelineFragment :
val status = event.status
handleStatusComposeEvent(status)
}
is StatusEditedEvent -> {
handleStatusComposeEvent(event.status)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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() {
Expand All @@ -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)
}
}
}
Expand All @@ -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")
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
)
}
}

Expand Down Expand Up @@ -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(
Expand Down
Loading

0 comments on commit 54e92b2

Please sign in to comment.