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:
Konrad Pozniak 2023-09-26 09:08:58 +02:00 committed by GitHub
commit 54e92b2156
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 145 additions and 198 deletions

View file

@ -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)
}
}
}
}

View file

@ -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
}

View file

@ -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
)
}
}

View file

@ -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) {

View file

@ -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(