-
-
Notifications
You must be signed in to change notification settings - Fork 389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improve local status updates #3480
Conversation
if (viewData != null) { detailedStatus = viewData } | ||
val result = api.status(id).getOrNull() | ||
if (result != null) { | ||
eventHub.dispatch(StatusChangedEvent(result)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not ideal since ViewThreadViewModel
is both sending and observing StatusChangedEvent
, but I don't have a better idea :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered a bit why this case here stands out.
And maybe it doesn't: What happens if I refresh a timeline and one of the status there did change?
(A status that might as well be shown on the bookmark timeline for example?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes maybe we should send the event for all statuses 🤔
Still there is a problem that this ViewModel is both sending and receiving
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few ideas from thinking about this (and maybe questions). The concept(s) are still blurry in my mind:
If this "UpdateEvent" informs about updates (only) then there should be an actual check if there was an update.
That in turn needs a sort of central instance which stores every status that every activity in the running instance has seen. Only this instance/thing/repository would compare and if needed send a changed event.
Otherwise one would need quite a few locations which would need to send every status they see as "change", because they might have been changed somewhere else?
(Is that actually a wide-spread problem: activities remaining active even when another one is in the foreground and then their ui must be refreshed for every change/data received everywhere else?)
And specifically for the thread view: It receives the event to update its ui (on these status)?
Maybe it should then receive all the data to display as event - esp. the events it sends itself?
(It sounds too complex when it should simply "load things and then display them" but maybe that is because of the discussion above).
Sorry for writing so long but maybe it helps a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not ideal since
ViewThreadViewModel
is both sending and observingStatusChangedEvent
, but I don't have a better idea :/
https://developer.android.com/topic/architecture/data-layer
Tell the data layer to update the data, and the data layer content should be exposed as a Flow
, so that consumers of the content observe changes as they happen.
See e.g., https://developer.android.com/codelabs/android-room-with-a-view-kotlin#6, https://developer.android.com/topic/architecture/data-layer/offline-first#reads, https://developer.android.com/topic/architecture/data-layer/offline-first#writes
That'll be a lot easier when #3436 is complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kinda agree that observing the DB is kind of the best thing but also what's the problem with both sending and receiving?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a layering violation, and a source of bugs. With this approach every view model has to emit events, and if that's missed, or one of them has the wrong logic, then you have a bug.
By putting it in the data layer you guarantee that it doesn't matter what is updating the data, every update will generate the correct event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this, model and persistence should be the source of truth. I was referring to @connyduck 's comment what's the problem with both sending and receiving the event
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes basically what Nik says.
Problem is, we don't have a data layer for non-cached timelines so I'll fix it for cached ones only for now, still better than before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's coming in #3436. I'm in the "Cleanup up the TODOs and update the tests" phase in that PR.
app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt
Show resolved
Hide resolved
timelineDao.setReblogged(accountId, event.statusId, event.reblog) | ||
is BookmarkEvent -> | ||
timelineDao.setBookmarked(accountId, event.statusId, event.bookmark) | ||
is StatusChangedEvent -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an observation: "status changed" has much less (specific) information than for example "fav clicked". I would immediately ask "what changed?".
I see that these events are normally not used in their specific sense. But maybe they could?
Is it possible to have an event hierarchy? BookmarkEvent extends StatusChangedEvent? Or is that bad style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is the idea that there is less info. We need to update everything anyway. If the post has been bookmarked, the fav count could have changed as well. Or it was favourited on another device.
app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt
Show resolved
Hide resolved
if (viewData != null) { detailedStatus = viewData } | ||
val result = api.status(id).getOrNull() | ||
if (result != null) { | ||
eventHub.dispatch(StatusChangedEvent(result)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe one could compare the two if there was actually a change?
if (viewData != null) { detailedStatus = viewData } | ||
val result = api.status(id).getOrNull() | ||
if (result != null) { | ||
eventHub.dispatch(StatusChangedEvent(result)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondered a bit why this case here stands out.
And maybe it doesn't: What happens if I refresh a timeline and one of the status there did change?
(A status that might as well be shown on the bookmark timeline for example?)
How about instead of sending events in ViewThreadFragments, we update the database directly? This way at least cached timelines get updated (which is better than before) and we avoid redundant updates in the ViewThreadFragment itself. Still not ideal but my best idea right now. |
I think once the request is successful it's fairly safe to update the db and listen to db everywhere, like @nikclayton said |
@@ -144,8 +136,15 @@ 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 } | |||
val result = api.status(id).getOrNull() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val result = api.status(id).getOrNull() | |
api.status(id).getOrNull?.let { ... } |
?
isExpanded = viewData.isExpanded, | ||
isCollapsed = viewData.isCollapsed, | ||
isDetailed = viewData.isDetailed | ||
) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to update handleStatusComposedEvent()
as well?
Specifically, if the status that was composed is a reply, the status it was replying to needs to be updated so that the reply count is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that should probably be done, but I don't see it in the scope of this PR
# Conflicts: # app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt
This reverts commit 54e92b2.
Ugh, I didn't notice that #3480 was affected by the notification fragment rollback
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