feat: Added smooth wallpaper fade-in and fixed the widget transparency delay on page load#217
feat: Added smooth wallpaper fade-in and fixed the widget transparency delay on page load#217prem-k-r wants to merge 3 commits into
Conversation
Replace CSS background-image with a fixed <img id="bg-img"> element for wallpapers. Adds the DOM element in index.html and styles it for full-viewport coverage and an opacity-based fade. Update wallpaper.js to set the image via URL.createObjectURL, handle load-based fade-in, revoke previous object URLs, and persist state with localStorage.hasWallpaper. Also remove the persisted flag on errors or when clearing the image and adjust toggle logic accordingly.
|
Caution Review failedFailed to post review comments 📝 WalkthroughWalkthroughThis PR refactors wallpaper rendering from direct CSS variable updates to a dedicated DOM element with opacity-based fade-in. The changes introduce a background image element with staged loading, revoke prior object URLs after transitions, clean up localStorage state consistently across initialization and clear workflows, and update release documentation. ChangesWallpaper Fade-In Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| }); | ||
| }); | ||
| }; | ||
| img.src = newUrl; |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/wallpaper.js`:
- Around line 24-43: The onload callback can fire after a clear and revive an
old wallpaper and leak object URLs; implement a token-based cancellation and
pending URL tracking: add a numeric bgLoadToken and pendingBgUrl variables,
increment bgLoadToken and clear img.onload/img.onerror/removeAttribute("src")
when clearing, revoke pendingBgUrl if present, and when creating newUrl set
pendingBgUrl = newUrl and capture the current token in the onload/onerror
handlers so they ignore stale tokens before assigning currentBgUrl, adding
"bg-visible" or revoking previousUrl; also ensure any errored or cancelled
newUrl is revoked and pendingBgUrl cleared to avoid leaks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a4862cad-2f28-4978-8c18-e341b90dec3a
📒 Files selected for processing (6)
CHANGELOG.mdindex.htmlmanifest(firefox).jsonmanifest.jsonscripts/wallpaper.jsstyle.css
| const img = document.getElementById("bg-img"); | ||
| const previousUrl = currentBgUrl; | ||
| const newUrl = URL.createObjectURL(blob); | ||
| currentBgUrl = newUrl; | ||
| document.body.style.setProperty("--bg-image", `url(${newUrl})`); | ||
|
|
||
| toggleBackgroundType(true); | ||
| if (previousUrl) { | ||
| URL.revokeObjectURL(previousUrl); | ||
| } | ||
| localStorage.setItem("hasWallpaper", "true"); | ||
|
|
||
| img.classList.remove("bg-visible"); // reset opacity for the fade-in | ||
|
|
||
| img.onload = () => { | ||
| requestAnimationFrame(() => { | ||
| requestAnimationFrame(() => { | ||
| currentBgUrl = newUrl; | ||
| img.classList.add("bg-visible"); // fade in only the image | ||
| if (previousUrl) URL.revokeObjectURL(previousUrl); | ||
| }); | ||
| }); | ||
| }; | ||
| img.src = newUrl; | ||
| } |
There was a problem hiding this comment.
Prevent stale onload callbacks from restoring cleared wallpapers and leaking object URLs.
Line 33’s async onload path is not cancellable. A fast re-apply/clear sequence can let an older load callback re-show the image after clear, and intermediate object URLs can remain unreleased.
💡 Proposed fix (token-based cancellation + pending URL cleanup)
let currentBgUrl = null;
+let pendingBgUrl = null;
+let bgLoadToken = 0;
function setBackground(blob) {
const img = document.getElementById("bg-img");
const previousUrl = currentBgUrl;
const newUrl = URL.createObjectURL(blob);
+ const loadToken = ++bgLoadToken;
+
+ // Revoke any not-yet-committed URL from a previous in-flight load.
+ if (pendingBgUrl) {
+ URL.revokeObjectURL(pendingBgUrl);
+ pendingBgUrl = null;
+ }
toggleBackgroundType(true);
localStorage.setItem("hasWallpaper", "true");
img.classList.remove("bg-visible"); // reset opacity for the fade-in
img.onload = () => {
+ if (loadToken !== bgLoadToken) {
+ URL.revokeObjectURL(newUrl);
+ return;
+ }
requestAnimationFrame(() => {
requestAnimationFrame(() => {
currentBgUrl = newUrl;
+ pendingBgUrl = null;
img.classList.add("bg-visible"); // fade in only the image
if (previousUrl) URL.revokeObjectURL(previousUrl);
});
});
};
+
+ img.onerror = () => {
+ if (loadToken !== bgLoadToken) return;
+ URL.revokeObjectURL(newUrl);
+ pendingBgUrl = null;
+ localStorage.removeItem("hasWallpaper");
+ toggleBackgroundType(false);
+ };
+
+ pendingBgUrl = newUrl;
img.src = newUrl;
}And when clearing, cancel in-flight loads before hiding:
const img = document.getElementById("bg-img");
bgLoadToken++;
img.onload = null;
img.onerror = null;
img.removeAttribute("src");
if (pendingBgUrl) {
URL.revokeObjectURL(pendingBgUrl);
pendingBgUrl = null;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const img = document.getElementById("bg-img"); | |
| const previousUrl = currentBgUrl; | |
| const newUrl = URL.createObjectURL(blob); | |
| currentBgUrl = newUrl; | |
| document.body.style.setProperty("--bg-image", `url(${newUrl})`); | |
| toggleBackgroundType(true); | |
| if (previousUrl) { | |
| URL.revokeObjectURL(previousUrl); | |
| } | |
| localStorage.setItem("hasWallpaper", "true"); | |
| img.classList.remove("bg-visible"); // reset opacity for the fade-in | |
| img.onload = () => { | |
| requestAnimationFrame(() => { | |
| requestAnimationFrame(() => { | |
| currentBgUrl = newUrl; | |
| img.classList.add("bg-visible"); // fade in only the image | |
| if (previousUrl) URL.revokeObjectURL(previousUrl); | |
| }); | |
| }); | |
| }; | |
| img.src = newUrl; | |
| } | |
| let currentBgUrl = null; | |
| let pendingBgUrl = null; | |
| let bgLoadToken = 0; | |
| function setBackground(blob) { | |
| const img = document.getElementById("bg-img"); | |
| const previousUrl = currentBgUrl; | |
| const newUrl = URL.createObjectURL(blob); | |
| const loadToken = ++bgLoadToken; | |
| // Revoke any not-yet-committed URL from a previous in-flight load. | |
| if (pendingBgUrl) { | |
| URL.revokeObjectURL(pendingBgUrl); | |
| pendingBgUrl = null; | |
| } | |
| toggleBackgroundType(true); | |
| localStorage.setItem("hasWallpaper", "true"); | |
| img.classList.remove("bg-visible"); // reset opacity for the fade-in | |
| img.onload = () => { | |
| if (loadToken !== bgLoadToken) { | |
| URL.revokeObjectURL(newUrl); | |
| return; | |
| } | |
| requestAnimationFrame(() => { | |
| requestAnimationFrame(() => { | |
| currentBgUrl = newUrl; | |
| pendingBgUrl = null; | |
| img.classList.add("bg-visible"); // fade in only the image | |
| if (previousUrl) URL.revokeObjectURL(previousUrl); | |
| }); | |
| }); | |
| }; | |
| img.onerror = () => { | |
| if (loadToken !== bgLoadToken) return; | |
| URL.revokeObjectURL(newUrl); | |
| pendingBgUrl = null; | |
| localStorage.removeItem("hasWallpaper"); | |
| toggleBackgroundType(false); | |
| }; | |
| pendingBgUrl = newUrl; | |
| img.src = newUrl; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/wallpaper.js` around lines 24 - 43, The onload callback can fire
after a clear and revive an old wallpaper and leak object URLs; implement a
token-based cancellation and pending URL tracking: add a numeric bgLoadToken and
pendingBgUrl variables, increment bgLoadToken and clear
img.onload/img.onerror/removeAttribute("src") when clearing, revoke pendingBgUrl
if present, and when creating newUrl set pendingBgUrl = newUrl and capture the
current token in the onload/onerror handlers so they ignore stale tokens before
assigning currentBgUrl, adding "bg-visible" or revoking previousUrl; also ensure
any errored or cancelled newUrl is revoked and pendingBgUrl cleared to avoid
leaks.
Replace CSS background-image with a fixed
element for wallpapers. Adds the DOM element in index.html and styles it for full-viewport coverage and an opacity-based fade. Update wallpaper.js to set the image via URL.createObjectURL, handle load-based fade-in, revoke previous object URLs, and persist state with localStorage.hasWallpaper. Also remove the persisted flag on errors or when clearing the image and adjust toggle logic accordingly.
Summary
This PR refactors the wallpaper implementation from a CSS
background-imageapproach to a dedicated fixed-position<img id="bg-img">element, enabling smooth fade-in animations on page load and resolving widget transparency rendering delays.Changes
HTML (
index.html)<img id="bg-img">) in the loading screen area, positioned after the existing loading screen elementJavaScript (
scripts/wallpaper.js)setBackground(blob)to:bg-imgelementrequestAnimationFramecalls that apply thebg-visibleclass after image load--bg-imageCSS variable assignment from thebodyelementcheckAndUpdateImage()to removelocalStorage.hasWallpaperwhen stored data is invalid or when loading failslocalStorage.hasWallpaperbg-visibleclass frombg-imgto hide the imagecurrentBgUrlCSS (
style.css)background-imagestyling with fixed attachment and cover sizing#bg-imgstyling with:bg-visibleclass using opacity transitionspointer-events: noneto prevent interactionheight: 100%andmargin: 0Documentation (
CHANGELOG.md)