Skip to content
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

Migrate TimelineFragment and dependencies to new architecture #3436

Closed
wants to merge 196 commits into from
Closed

Migrate TimelineFragment and dependencies to new architecture #3436

wants to merge 196 commits into from

Conversation

nikclayton
Copy link
Contributor

@nikclayton nikclayton commented Mar 11, 2023

Follow the same architecture as Notifications:

  • Loading statuses for cached and non-cached timelines uses the Paging3 library.
  • Fix the issue where chunks could be missing from a timeline
  • Failures during loading are shown in the status list, and the user can retry
  • The "Load more" option between pages of statuses is gone, pages of statuses are automatically loaded as the user scrolls
    • The user must still trigger an explicit refresh once they get to the "top" of a timeline
  • The architecture is strictly Fragment -> View Model -> Repository, with the Repository managing the PagingSource and RemoteMediator
  • The Fragment communicates with the View Models by sending actions
    • The View Models communicate with the Fragment with flows for status data, overall UI state, and success/failure of the different actions
    • The View Models communicates with the network/disk via a Repository
      • There are separate repositories for Cached and Network timelines, and Filters
    • The Fragment and View Models do not access the API or database directly
  • If an action fails the error is surfaced to the user, with an option to retry
  • Delete the "Reading order" preference, it's unnecessary
  • Add unit tests for the functionality, updated existing tests as necessary

Other code changes to make this easier:

  • Move TimelineKind to a separate type outside the view model, to prevent circular dependencies (e.g., view model depending on a repository and the repository depending on the view model). Implement as a sealed class, and carry kind-specific information in the class instead of passing as additional intent extras.
  • Update the "Developer tools" menu to include options for experimenting with missing statuses

Fixes #3195, #3632, #3433, #3320, #3317, #3269, #2831, #2702, #3505, #3461, #3818

Nik Clayton added 5 commits March 11, 2023 14:39
The layering of this code was weird. There's paging sources and remote
mediators making calls "up" in to the viewmodel, so they had a cyclic
dependency on each other.

And there's a remote mediator when there's no local database to cache to,
which made things more complicated.

So:

1. Remove the remote mediator
2. Put the code to fetch statuses in to the paging source
3. Push the a variant of the "TimelineKind" type in to the paging source
   (probably not its final location), as this needs to be as low down the
   dependency tree as possible to avoid cycle.
   - Implement it as a sealed class instead of an enum, so that the
     subclasses can hold non-null Strings where necessary, instead of relying
     on `!!`
4. Comment out some code that either needs to be deleted or refactored, I'm
   not sure which yet.

This builds and runs, and shows network timelines (local, federated, etc).
Some functionality it lost (e.g., retaining state about whether or not the
user has expanded a status) but that will be restored in future commits.
# Conflicts:
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/CachedTimelineViewModel.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/TimelineViewModel.kt
Move it from TimelineFragment to TimelinewViewModel.

Update StatusDisplayOptions.kt to handle SHOW_CARDS_IN_TIMELINES pref
@nikclayton nikclayton changed the title Remove NetworkTimelineRemoteMediator Migrate TimelineFragment and dependencies to new architecture Mar 12, 2023
Nik Clayton added 4 commits March 12, 2023 16:04
The old type was an enum, the new type is a hierarchy of sealed classes.

This allows each class to carry with it the information necessary for that
timeline.

For example, the PublicFederated timeline needs no additional data. But a
timeline for a hashtag does.

This simplifies TimelineFragment.newInstance(). Before the called had to
know which optional parameters to pass in, or whether they should actually
call newHashtagInstance.

Now they just construct a timeline of the appropriate kind, with the correct
data, and pass that in.

This also means that initialisation of TimelineFragment does not need to
unpack data from multiple extras in the launch intent, everything is in the
parcelized TimelineKind.
# Conflicts:
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelinePagingSource.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineRemoteMediator.kt
#	app/src/main/java/com/keylesspalace/tusky/components/timeline/viewmodel/NetworkTimelineViewModel.kt
Nik Clayton added 19 commits April 10, 2023 13:56
- Add CachedTimelineRepository between CachedTimelineViewModel and CachedTimelineRemoteMediator
- Update CachedTimelineViewModel to use the repository
- Modify TImelineFragment to be closer to NotificationsFragment (easier to figure out what code can be reused)
- Add DeveloperTools to clear the DB, and remove the most recent 40 statuses
- Add many TODOs marking code to refactor or remove
- Remove StatusViewData.Placeholder
- Move StatusViewData.Concrete into StatusViewData
- Delete the class
- Update instantiation locations
- Remove obsolete string resource
CachedTimelineViewModel no longer needs an injected AppDatabase.

To do this:

- Extend what was `NotificationWorkerFactory` to `WorkerFactory`. This can construct arbitrary Workers as long as they provide their own Factory for construction.

The per-Worker factory contains any injected components just for that worker type, keeping `WorkerFactory` clean.

- Move `NotificationWorkerFactory` to the new model.

- Implement `PruneCacheWorker`, and remove the code from `CachedTimelineViewModel`.

- Create the periodic worker in `TuskyApplication`, ensuring that the database is only pruned when the device is idle.
This pushes the last of the EventHub responsibility out of TimelineFragment in to TimelineViewModel
Doesn't actually save it (is consistent with current behaviour) but provides the hook from which to hang the future code.
@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

I'd need to see a video showing the difference, or a clear list of reproduction steps that demonstrate the problem.

I will take a video. Perhaps the reason I'm having so much trouble with this is what I'm seeing is not how the patch is supposed to work.

@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

… okay, this video came out very confusing , one second

@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

Here is a demo video. It shows two things:

  1. I am seeing something very weird in my day-to-day-use copy of v23, which could indicate a bug in the v23 Paging3 usage as well as possibly the PR Paging3 usage.
  2. A demonstration of the rotaty-reload icon behavior I described above as confusing me

In this video, I show three separate copies of Tusky:

  1. Vanilla v23.0 (blue)
  2. "Andi-hacks" v23.0 (black), which is the shipping v23.0 plus a small group of commits. See: https://github.com/mcclure/Tusky/releases/tag/v23.0-andi-hacks-r0
    • These commits shouldn't have an impact on the behavior of paging3. They are: A change to the display of alt tags; a change to tab-swipe speed; a new button in notifications tab (notification related but should[?] have no effect unless the new button is pressed); a change to bio display in notifications (notification related but should[?] be XML-only); several build-related nikclayton commits (Upgrade AGP to 8.0.2] etc)
  3. This PR (green)

I made this video because @nikclayton said "The Notifications tab has been using this code, or a version of it, since v22.0, with no user complaints" [including from me], which is confusing because I noticed no change in the notifications tab when going from v21 to v23+andihacks whereas I see a very large difference going from v23+andihacks to this PR. What I found in the video was that the notification tab behavior of this PR is the same as vanilla v23.0, but that v23+andihacks has a notification tab behavior different from either, which should not be possible.

Here is the video: https://www.youtube.com/watch?v=YvWRoj_LuiM

0:04: Boot Tusky v23.0.
0:09-0:47: Enter Tusky v23.0 notifications tab. The content is 185 days old. I try to get to the top by a combination of scrolling up and tapping the tab. Progress is very slow and over 30 seconds I am unable to reach the top or even escape day 185. (This is very, very bad. If v23 had been behaving like this for me on my day-to-day use install, I would have stayed on v21.)
0:49: Boot Tusky v23.0+andihacks.
0:50-1:07: I attempt to scroll to the top of the notifications tab. It takes longer than I would have expected (notice an interesting moment where I freeze on the reload-icon box, then switch tabs) but I do eventually get to the top. How is this possible when I could not do it in v23.0? I investigate:
1:15: I scroll down, then up. At 1:15 what I find is there is a gap in my notifications between 6 minutes ago and 20 hours ago. Nothing appears in between. There is no indicator of missing content.
1:32: Re-enter Tusky v23.0. I try to replicate what I just saw in v23.0+andihacks. No success. (I do try tab swiping while the reload button is up but maybe my timing was wrong.)
2:06: Scroll down to confirm Tusky v23.0 is a Google Play Tusky v23.0.
2:13: Boot Tusky [this PR].
2:14-End: Without success, I attempt to scroll to the top of the notifications tab. This is where I got a good view of the reload icon behavior:
2:21: The notification tab first displays after a long delay. The reload icon is visible up top, indicating that more posts are being loaded (good)
2:40: I double tap. It scrolls to the top, showing a reload icon.
3:01: I tap once. I got to the top. I am 17 hours in the past. Although more posts are being loaded, no reload icon shows.
3:05: I scroll down. It scrolls smoothly indicating nothing new is being drawn in. There has been a reload icon up there all along, Tusky just wasn't showing it.
3:16: New content loads in. I tap once. I get a reload icon; we've scrolled above it. (I can't explain this? Possibly it's a timing thing or possibly I double tapped and the double tap didn't show well in the video.)

Let's focus on 1:15. There are two possible explanations here. One is that this is about the difference between v23 and v23+andihacks— this is possible, but I don't think this could be it, due to the minor nature of the patches. The other explanation, which I think is what is happening, is that there is a bug (which I coincidentally managed to trigger in my v23-andihacks test but not my v23-vanilla test) which can cause the notifications tab to "skip" a large amount of content. In other words, it is as if the "Show More" behavior was retained, but with a less consistent trigger condition, and without any "Show More" button. Although this bug is bad (losing user content without indication is very, very wrong!), this bug was what made it possible for me to use v23 at all, because apparently whenever I got too far behind in the feed I would just fiddle with it until I accidentally triggered the bug. I really want to stress this: If the behavior I saw in my vanilla v23 test above had been the behavior I had seen on first installing v23, I would not have switched from v21 to v23 at all, I would have stayed on v21. If we have not seen user complaints about the v23 behavior, it could be that users who get "too far behind" in the notifications tab are accidentally triggering this bug.

(A third possibility is that changing filters, which I do pretty frequently, resets you to the top of the feed automatically. I haven't specifically tested this.)

@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

Meanwhile, this idea of "will not silently attempt to load any more unless the user takes an action"… I don't understand why this is a hard rule.
It is not necessarily a hard rule, but it is Tusky's current behaviour, which this PR preserves.
"quitting and reopening the application" is an example of action where the list is refreshed, because the fragment will be destroyed and recreated when you do this (simply putting Tusky in to the background is not sufficient to do this, because Android might keep the fragment running).

You are correct that switching from tab-to-tab does not currently refresh the list. This is true in Tusky v23.0, and at least true back to v19.0.

We could refresh the list whenever the fragment is resumed. However, I think that is an orthogonal behaviour change to this PR.

I think that because this patch changes the user model so significantly, we need to change more things to fit the new user model or the new user model is incoherent. (In other words I don't like the patch, but I think it could be usable as long as we take it significantly further.) I feel confident one of those the further changes should be "Invalidate the loaded-to position when Tusky is backgrounded and de-backgrounded". I think also probably the scrolled-to position should be invalidated when you change tabs/panes [including going to say, the preferences], and probably even it should be invalidated on a timer, say when ten seconds pass without user input. I also think that regardless of where the tab-tab scrolls you to, if that tab tap would result in a post load, tab-tapping should scroll you above the reload icon.

That is correct -- the operations supported on a list of pages by the Paging3 library are [Prepend to head, append to tail, discard]
Pages must be complete and contiguous. There is no support for a gap of unknown size between pages[1].

Okay, I don't think this is a very good library then :/

I assume there's some fourth operation that allows us to do in-situ post edits and post deletion on the timeline? Like, I assume the content isn't immutable, only the page structure?

Can you elaborate on what the "discard" operation entails? How disruptive of it? Does it entail a screen flash? Does it require flushing our caches of data (I assume no, we are maintaining the cache of content and Paging3 is maintaining the cache of constructed UI objects and it is the cache of UI objects that clears on a "discard"/invalidate?)

@nikclayton
Copy link
Contributor Author

The bug you note on your andihacks branch at 1:15 -- unless you can reproduce that on v23 or this PR I'm not going to investigate. Given that your branch changes how filters are handled it's possible that gap is due to misconfigured filters. I've never seen it in v23 or on this PR, and no one has reported anything like it elsewhere.

To the contrary, what this PR does do is fix an existing bug caused by the "Load more" behaviour where posts are missing from the timeline (Home, Local, Federated, etc), and there are external user complaints about that behaviour.

The rest of the behaviour in the video on v23 this PR looks as intended.

I do note two changes that might make some things more obvious to users.

  1. The rows that show if the previous/next page is loading (in your video they show at the top of the list with non-moving progress spinned) should not rely on just the animation to inform the user that something is happening, because the animation may be disabled. They should also have explicit "Loading..." text so the user is aware that something is happening.

  2. If there's an active (prepend) page load happening then ignore refresh operations (swipe-refresh and Menu > refresh), since the prepend operation will do the same thing as the refresh.


I think that because this patch changes the user model so significantly, [...]

  • Automatically refreshing when the user resumes[1]? That should be straightforward. I'm not 100% sold on the idea, but it's a reasonable experiment. The idea that "The user has just switched to this tab, they want to be able to see new content with the minimum of fuss" is defendable.

  • Refreshing on a timer, however, is not. Consider, for a moment, the impact that would have on the load experienced by the users' servers.

I assume there's some fourth operation that allows us to do in-situ post edits and post deletion on the timeline

No. The data is supposed to be immutable. Not all the existing Tusky code honours this (e.g., by sneaking in mutable data structures where the libraries expect immutable ones).

Fixing this is also on my todo list, I suspect it's the source of subtle bugs.

Can you elaborate on what the "discard" operation entails? How disruptive of it? Does it entail a screen flash? Does it require flushing our caches of data (I assume no, we are maintaining the cache of content and Paging3 is maintaining the cache of constructed UI objects and it is the cache of UI objects that clears on a "discard"/invalidate?)

A refresh or reload operation[2] discards the existing data (from memory, and from the backing database if there is one), and new data is fetched and cached.

Then the new data is applied to the list via the list adapter. The adapter contains code to diff the old list and the new list, figure out what's changed, and perform the minimum number of screen updates to show the new data.

There is no screen flash. Those changes either appear directly, or smoothly animate in (e.g., see what happens when you view a thread).

For much more on this see https://developer.android.com/codelabs/android-paging#0.

[1] Resume occurs both when Tusky returns to the foreground, or if the user switches tabs.

[2] "refresh" is just "reload, but remember and restore my reading position". Think of them as "My local cache of the data is out of date, it must be replaced by up to date content from the remote server".

@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

The bug you note on your andihacks branch at 1:15 -- unless you can reproduce that on v23 or this PR I'm not going to investigate. Given that your branch changes how filters are handled it's possible that gap is due to misconfigured filters.

Possible D:

@mcclure
Copy link
Collaborator

mcclure commented Aug 9, 2023

Emphasis mine:

A refresh or reload operation[2] discards the existing data (from memory, and from the backing database if there is one), and new data is fetched and cached.

Then the new data is applied to the list via the list adapter.

Fetched from where? Like… all the way from the server? Could it be fetched from a secondary data store Tusky hosts (so that if we wanted to do "correct" post edits or "load more" page inserts, we could simply change the Tusky device-side store, invalidate, and let paging3 redraw with amended content)? Or is the idea that having switched to paging3, "the data store" is now hosted entirely by paging3 and we no longer have a post store it could be drawn from?

@nikclayton
Copy link
Contributor Author

Fetched from where? Like… all the way from the server?

Yes. The on-device copy is treated as a local cache that can be discarded when necessary.

Could it be fetched from a secondary data store Tusky hosts (so that if we wanted to do "correct" post edits or "load more" page inserts, we could simply change the Tusky device-side store, invalidate, and let paging3 redraw with amended content)?

The word "simply" in that sentence is doing an awful lot of work.

In practice, the answer is no.

https://developer.android.com/topic/libraries/architecture/paging/v3-overview has more information on how the library is supposed to be use.

Or is the idea that having switched to paging3, "the data store" is now hosted entirely by paging3 and we no longer have a post store it could be drawn from?

No.

The data store (e.g., the local database) is still managed by the app. But on receipt of a "refresh" operation the local copy of the data is cleared, and a fresh copy fetched from the server.

This does not mean all the local data is cleared, only the data that the server hosts.

So information like "The user has clicked 'show more' on this status" and it should be rendered like that the next time it's displayed, or "This status has a content warning and the user has clicked to show the content of the post" is local view state that the app should maintain and not delete when the user refreshes.

Tusky is currently inconsistent about doing that, as I think I mentioned earlier. I've got ideas about how to fix that, but they're orthogonal to this PR.

@mcclure
Copy link
Collaborator

mcclure commented Aug 10, 2023

Okay. Thank you for all your detailed explanations. However,

I assume there's some fourth operation that allows us to do in-situ post edits and post deletion on the timeline

No. The data is supposed to be immutable. Not all the existing Tusky code honours this (e.g., by sneaking in mutable data structures where the libraries expect immutable ones).

Fixing this is also on my todo list, I suspect it's the source of subtle bugs.

Based on a few of your comments but particularly this one, my personal opinion at this point is that paging3 is not appropriate for our use case and we should not be using it, possibly not even for notifications.

@nikclayton
Copy link
Contributor Author

Based on a few of your comments but particularly this one, my personal opinion at this point is that paging3 is not appropriate or our use case and we should not be using it, possibly not even for notifications.

@mcclure That ship sailed in Jan 2021, with #2238

Reading that PR, I'm somewhat amused to note that @charlag identified the mutable data problem and suggested a cleaner way to implement it in #2238 (comment). The approach that was used (#2238 (comment)) is some of the technical debt that needs to be cleaned up.

@nikclayton
Copy link
Contributor Author

@mcclure

Although more posts are being loaded, no reload icon shows

This is because the progress spinner that indicates if a previous or next page is being loaded is a ContentLoadingProgressBar (https://developer.android.com/reference/androidx/core/widget/ContentLoadingProgressBar).

When being shown, this will wait 500ms before appearing. If there's a "hide" in the intervening 500ms then it won't show at all, preventing brief UI adjustments.

Similarly, once it's showing it will stay shown for at least 500ms even if it's told to "hide" before then. Again, to avoid very brief UI adjustments.

So if the load and processing of the previous (or next) page takes < ~500ms you'll not see a progress spinner. If it takes longer you will, and the spinner will be visible for at least 500ms.

This is similar behaviour to what happens when viewing a thread. If you open a thread there's a network request to fetch the status you're viewing, and a second request to fetch the statuses above/below it. If those requests complete in < ~500ms you'll never see the loading indicator, they'll smoothly animate in. If those requests take longer you'll see a loading indicator, so you know there's something to wait for.

…agment-arch

# Conflicts:
#	app/build.gradle
@nikclayton
Copy link
Contributor Author

@mcclure

Automatically refreshing when the user resumes[1]? That should be straightforward. I'm not 100% sold on the idea, but it's a reasonable experiment. The idea that "The user has just switched to this tab, they want to be able to see new content with the minimum of fuss" is defendable.

I've been trying a build with that for the last 24 hours or so.

I think it's too disruptive, as things that you would not expect to cause a refresh do.

For example, tapping a message to view its thread and then pressing back will trigger a refresh. So will tapping media in a status to view it full screen (image, video, or audio).

This means:

  1. The "swipe-refresh" progress spinner appears, which is good, because it tells the user that something has happened, but bad because it's not obvious why it's happened.
  2. Any changes to the user's timeline that affect the presentation of that timeline will cause it to adjust, potentially shifting content up or down, or removing it entirely. This happens (approx.) whenever a post in the timeline is edited, or a filter now matches it, or a link preview that wasn't there before is there now.
  3. If there is new content then the "scroll by 30dp to show there's new content" logic triggers, so the user's scroll position in the list is changed.

I think the user can expect this if they explicitly triggered a refresh -- reopening the app, swiping, choosing "refresh" from the menu.

But I don't think that activities like "viewing a thread" or "opening an image" (or "swiping to this tab") have this expectation.

I'll look and see if it's possible to do this only when the user is resuming the fragment because they've clicked on the tab to switch to it.

@mcclure
Copy link
Collaborator

mcclure commented Aug 11, 2023

Automatically refreshing when the user resumes[1]? That should be straightforward. I'm not 100% sold on the idea, but it's a reasonable experiment.

I think it's too disruptive, as things that you would not expect to cause a refresh do.

I'm sorry, I think I was unclear. I was not trying to suggest we should refresh on returning to the program, which probably would be disruptive, but rather that the "water line" above which we do not load further data without user input (assuming I understand correctly and this "water line" exists) should be invalidated, and if the user is already scrolled close enough to the top of the newest page we would (in the absence of the "water line") begin loading in newer data (but not scrolling toward it, which would indeed be disruptive).

@nikclayton
Copy link
Contributor Author

nikclayton commented Aug 12, 2023

rather that the "water line" above which we do not load further data without user input (assuming I understand correctly and this "water line" exists) should be invalidated

The "waterline" your describing is only created when Tusky has requested the page and the server has returned an empty page (which is how the server says "This page you have requested does not exist").

Then, and only then, is a "waterline" created.

To get Tusky to ask the server again you have to "refresh".

That's exactly the same behaviour as the current code -- when you refresh in Tusky at the moment the newest page is explicitly loaded. You can not scroll up past this page without performing a refresh.

Let's say you left Tusky reading page 90 of your home timeline, and have returned. In the intervening time pages 91-100 have been created on the server.

In Tusky 23.0

  • You open the timeline
  • It refreshes
  • Page 100 is loaded
  • Your reading position is page 90
  • A "Load more" placeholder is shown between pages 100 and 90.
  • You cannot scroll up past page 100 without explicitly refreshing
  • To load pages 91-99 you must repeatedly tap the "Load more" placeholder. When you do that (and depending on your reading order preference) pages are loaded in order, either 91, 92, 93, ... or 99, 98, 97, ...

In this PR

  • You open the timeline
  • It refreshes
  • Pages 91-94 are loaded
  • Your reading position is page 90
  • You scroll up to read. As you read, pages 95, 96, 97, 98, 99, and 100 are loaded for you.
  • Assuming there is nothing past page 100 you stop
  • Now, you cannot scroll up past page 100 without explicitly refresehing

In both cases what happens when the user reaches the top of page 100 is the same -- the user can't scroll without a refresh.

This PR improves things in the case where new pages become available while you're scrolling and haven't reached the top.

Consider this slight change in the same scenario, where the server is adding new pages to the top of the timeline.

In Tusky 23.0

  • You open the timeline
  • It refreshes
  • Page 100 is loaded
  • Your reading position is page 90
  • A "Load more" placeholder is shown between pages 100 and 90.
  • You cannot scroll up past page 100 without explicitly refreshing
  • To load pages 91-99 you must repeatedly tap the "Load more" placeholder. When you do that (and depending on your reading order preference) pages are loaded in order, either 91, 92, 93, ... or 99, 98, 97, ...
  • While you are doing the server adds pages 101, 102, and 103.
  • You scroll up and reach the top of page 100. You must refresh to see the new pages.

In this PR

  • You open the timeline
  • It refreshes
  • Pages 91-94 are loaded
  • Your reading position is page 90
  • You scroll up to read. As you read, pages 95, 96, 97, 98, 99, and 100 are loaded as you get closer to them.
  • While you are doing the server adds pages 101, 102, and 103.
  • If these pages are added on the server before Tusky has loaded page 100 then page 100 won't be set as the "waterline". So you can continue scrolling past page 100 without needing to "refresh"

So typically, with this PR you will:

  1. See more content before you need to explicitly refresh
  2. Will have to tap less, because you never need to tap a "Load more" placeholder

Nik Clayton added 14 commits August 13, 2023 20:33
- Calculate itemsBefore and itemsAfter, get correct anchorPosition
- Updating peeking and "show / hide the progress indicators" algorithm
…aded in to the adapter at the time of the check"

This reverts commit 5f8e8a9.

This seems to work better with the new prepend/refresh code
Previous code started/stopped on the fragment lifecycle.

So if you left the fragment the UI code would continue running (collecting from flows, ticking to update an invisible UI, etc).
…agment-arch

# Conflicts:
#	app/lint-baseline.xml
#	app/schemas/com.keylesspalace.tusky.db.AppDatabase/53.json
#	app/src/main/java/com/keylesspalace/tusky/TabData.kt
#	app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt
#	app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
#	app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
#	app/src/main/java/com/keylesspalace/tusky/settings/SettingsConstants.kt
@nikclayton nikclayton closed this by deleting the head repository Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Don't pass StatusDisplayOptions when creating view holders
9 participants