feat(app): adaptive image quality on slow connections + data-saver toggle#1724
feat(app): adaptive image quality on slow connections + data-saver toggle#1724MrDirkelz wants to merge 2 commits into
Conversation
…ggle
Serve lighter images when bandwidth is constrained, decided by three
signals (OR): a measured-slow connection, a new user Data Saver toggle,
and the OS/browser Data Saver flag.
- useNetworkSpeed: probe-based speed estimate (times a download of a
small same-origin asset) instead of navigator.connection.downlink,
which is Chromium-only. Same code path on every browser; refreshes on
startup, regained connectivity, tab focus, and toggling Data Saver off;
throttled and skipped when offline or already saving data.
- LImageProvider: in reduced-data mode, trim the srcset ladder to <=600px
(keeping the smallest) and advertise reduced `sizes`. Recomputes live.
- LToggle: native <button role="switch"> toggle (no HeadlessUI), themed
for the app; used for the Settings Data Saver control.
- SettingsPage: connection speed now reads the live composable value; adds
the Data Saver card, i18n'd via new settings.data_saver.* keys.
- globalConfig: add persisted userDataSaverEnabled; drop the unused
Chromium-only getConnectionSpeed.
- api: seed settings.data_saver.{title,description} in lang-eng / lang-fra.
Adds app/public/network-probe.bin (100 KB incompressible) as the probe
target. New unit tests for the composable, LToggle, and the image trim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The data-saver image reduction from b505823 didn't actually shrink images on mobile. Two reasons: sizesReducedMap equals the mobile slot width for every thumbnail (only the hero halved), and `sizes` is DPR-blind, so a 144px thumbnail on a DPR-3 phone fetched the same ~432px (600w) variant in both normal and reduced mode. Replace the srcset-ladder capping (capFiles/REDUCED_MAX_WIDTH) with a DPR cap on the reduced `sizes`: divide the reduced slot width by the device pixel ratio (down to REDUCED_DPR_CAP=1) so a retina device fetches a ~1x image instead of 2-3x. The full srcset ladder is kept intact — only `sizes` shrinks — so quality recovers automatically when the connection improves. No-op on 1x displays. A `width` attribute would not help here: with w-descriptor srcsets the browser selects purely from `sizes` x DPR. Tests: drop the three trim tests; add DPR-cap tests (mock devicePixelRatio=3) asserting the reduced/declarative `sizes` is 48px and the full ladder is retained. Existing tests pass unchanged (jsdom DPR=1, where the scale is a no-op). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ivanslabbert
left a comment
There was a problem hiding this comment.
Add note in settings when detecting that the browser is in low-data mode, stating why the setting is disabled (as the browser setting takes preference). Note to be in end-user understandable language with i18n support
There was a problem hiding this comment.
rename to useNetworkSpeedEstimator (or something shorter that better describes the composable)
| * Settings page surfaces the live number so the constants below can be tuned against real readings. | ||
| */ | ||
|
|
||
| const isTestEnv = import.meta.env.MODE === "test"; |
There was a problem hiding this comment.
We should preferably not have testing switches in the production code. This causes our tests to run in a different environment than in production. See if you can mock rather?
There was a problem hiding this comment.
When browser data savings mode is detected, force the toggle to the on position (visual only, do NOT set the app level data saving mode to true), and add a note that browser data saving mode is detected.
When slow network speed is detected (and neither browser or app level data saving mode is enabled), add a note that data saving mode will be applied due to slow network conditions.
Serve lighter images when bandwidth is constrained, decided by three signals (OR): a measured-slow connection, a new user Data Saver toggle, and the OS/browser Data Saver flag.
sizes. Recomputes live.Adds app/public/network-probe.bin (100 KB incompressible) as the probe target. New unit tests for the composable, LToggle, and the image trim.|