Skip to content

speeding up the gallery, a bit#720

Open
krugerk wants to merge 11 commits intobeeminder:masterfrom
krugerk:bugfix/laggy-gallery
Open

speeding up the gallery, a bit#720
krugerk wants to merge 11 commits intobeeminder:masterfrom
krugerk:bugfix/laggy-gallery

Conversation

@krugerk
Copy link
Contributor

@krugerk krugerk commented Jan 11, 2026

Summary

Upon returning to the gallery, especially after bring the app back into the foreground, scrolling the gallery can be very choppy.
This PR reduces some of the lagginess by moving json serializing off of the main thread and by prefetching the gallery's thumbnails.
RequestManager was made an actor and it was made to implement protocols to make testing/mocking easier.

Validation

Used app in Simulator
logged out,
logged in,
browsed goal list (gallery),
opened goals (goal view),
edited and deleted datapoints from without the main app,
loaded settings

#588 mentioned a slow gallery.

@krugerk krugerk requested a review from a team as a code owner January 11, 2026 22:54
@krugerk krugerk requested review from theospears and removed request for a team January 11, 2026 22:54
Copy link
Collaborator

@theospears theospears left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is needed! Added a few questions, but also happy to merge as-is if you think this is the best approach.

case .success(let data):
let asJSON = try? JSONSerialization.jsonObject(with: data)
return asJSON
case .success(let data): return try await Task.detached { try JSONSerialization.jsonObject(with: data) }.value
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on this solution vs making RequestManager an actor so all its work is done on a background thread?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching it over to actor seems like a more complete solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on this solution vs making RequestManager an actor so all its work is done on a background thread?

I think the switch to RequestManager makes sense, and its public API is marked as asynchronous anyway already. Although it currently does not maintain much internal state, it does interact with AF.request.
Also, marking it as an actor I think does not make its work happen off of the main thread. Thus the CPU-intensive work of JSON parsing is moved onto a background thread, explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on this solution vs making RequestManager an actor so all its work is done on a background thread?

bumped RequestManager to an actor and introduced the protocols for signed and non-signed requests, which have been used on the testing side as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it is an actor do we still need this Task.detached?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so: we still want the work to not block.

@krugerk krugerk force-pushed the bugfix/laggy-gallery branch 4 times, most recently from 53fefad to d582c89 Compare February 2, 2026 07:44
@krugerk krugerk force-pushed the bugfix/laggy-gallery branch 2 times, most recently from e3f4fc2 to d844e4a Compare February 13, 2026 11:13
func addDatapoint(urtext: String, slug: String, requestId: String?) async throws -> Any?
}

extension RequestManaging {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what this is for? It seems like functions just calling themselves

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The protocol cannot have a default for the parameter and several places were calling them without specifying the parameter with a nil.

This here is a version that does (pass nil as a default) and allows then others to make calls without specifying also the parameters: nil for each and every call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made obsolete by #744

@krugerk krugerk force-pushed the bugfix/laggy-gallery branch from d844e4a to e3e8cf6 Compare February 14, 2026 09:19
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.

2 participants