Skip to content

perf: shared skeleton animation, image cache, bandwidth timer guards#9994

Open
qoole wants to merge 1 commit into
nextcloud:masterfrom
qoole:perf/animations-and-bandwidth
Open

perf: shared skeleton animation, image cache, bandwidth timer guards#9994
qoole wants to merge 1 commit into
nextcloud:masterfrom
qoole:perf/animations-and-bandwidth

Conversation

@qoole
Copy link
Copy Markdown
Contributor

@qoole qoole commented May 7, 2026

Summary

Several perf improvements to the tray UI and bandwidth manager.

Skeleton animation consolidation (UnifiedSearchResultItemSkeleton*.qml)

Each skeleton row was driving its own independent NumberAnimation to slide its gradient. With a list of N skeletons there were N independent timers running off-phase. Replaced with a single shared animation driver in the container: each row reads a bound x-offset from the container instead of running its own animation. One timer drives the whole stack, all rows stay in phase, and tray opening becomes noticeably cheaper on first paint.

Image caching for avatars (UserLine.qml, CurrentAccountHeaderButton.qml)

Both files set cache: false on the avatar and status Image elements, which forced Qt to re-decode the avatar PNG on every model update. The avatar source is the same URL for the lifetime of the user; removing cache: false lets Qt's image cache serve repeated requests.

Bandwidth timer guards (bandwidthmanager.cpp/.h)

Two related changes:

  1. Conditional start: absoluteLimitTimer and the measuring timer were started unconditionally in the constructor. They now only start when bandwidth limits are actually configured. On accounts with no limits these timers were ticking once per second forever, doing work that was always discarded.
  2. Dirty flag: switchingTimerExpired and absoluteLimitTimerExpired recompute per-device quotas on every 1s tick. When no upload/download device has been registered or unregistered since the previous tick, that recomputation is a no-op. Added a _dirty flag that is set on (un)register and cleared in the timer callbacks; the callbacks now early-return when nothing has changed.

VFS kernel transition batching (cfapiwrapper.cpp)

setPinState was calling findPlaceholderInfo to resolve the parent placeholder inside its per-file loop. Hoisted the parent lookup outside the loop so it runs once per batch instead of once per file.

Thread safety (syncjournaldb.cpp)

keyValueStoreDelete was missing a QMutexLocker while peer functions held one. Added it.

Checklist

  • Sign-off message is added to all commits.
  • The commit history is clean with no merge commits.
  • Uploaded screenshots from before and after for UI changes (tray skeleton appearance is unchanged; only the animation driver differs).
  • Documentation has been updated or is not required.
  • Backports requested where applicable (critical bugfixes).
  • Labels added where applicable (bug/enhancement).
  • Milestone added for target version.

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

- Skeleton animation consolidation: a single shared animation driver
  in the container drives all skeleton items via a bound x-offset,
  replacing the per-item independent NumberAnimation timers that were
  kicked off for every skeleton row.
- Image caching: remove cache:false from avatar and status Image
  elements in UserLine and CurrentAccountHeaderButton so that Qt's
  image cache can serve repeated avatar requests instead of decoding
  the same PNG on every model update.
- Bandwidth timer guard: only start absoluteLimitTimer and the
  measuring timer when bandwidth limits are actually configured.
  Previously they ticked unconditionally even on accounts with no
  limits set, doing per-tick work that was always discarded.
- Bandwidth dirty flag: short-circuit switchingTimerExpired and
  absoluteLimitTimerExpired when no upload/download device has been
  registered or unregistered since the last tick. The timers run on
  a 1s cadence and recompute per-device quotas; with no device churn
  the recomputation is a no-op.
- VFS kernel transition batching: hoist findPlaceholderInfo parent
  lookup outside the per-file loop in cfapiwrapper setPinState so
  the parent placeholder is only resolved once per batch.
- Thread-safety: add missing QMutexLocker to keyValueStoreDelete.

Signed-off-by: Qoole <2862661+qoole@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant