# Persisted Reader Settings (theme, font size, ...)

`theme`, `fontSize`, `fontSet` and `favorites` are persisted settings. Use them as the template for any new user-configurable setting. This file covers the reader side. Where the value is stored and how changes reach other tabs is up to each host's adapter (see [host-adapter.md](host-adapter.md)).

1. **Storage goes through the adapter.** Write with `g.hostAdapter.saveSetting(key, value)` and read with `await g.hostAdapter.getSetting(key)`. Never touch `localStorage` or `chrome.*` from reader code. Each setting uses its own top-level key.
2. **Split the apply function in two:**
   - An **absolute setter** (e.g. `setTheme(value, shouldSave = false)` in [helpers.js](../helpers.js), `setFontSet(id, shouldSave)` in [Fonts.js](../Fonts.js), `g.pdm.setFontSize(value)` in [PopupDocumentManager.js](../PopupDocumentManager.js)). It only applies the value to the DOM and state. Startup restore and incoming broadcasts call it, and it must never save on those paths.
   - The **user-facing action** (a shortcut in [KeyboardManager.js](../KeyboardManager.js), a UI control, ...) calls the setter and is the only place that also calls `saveSetting`. Because only the user-initiated path writes to storage, broadcasting is loop-safe by construction.
3. **Startup restore:** in [readerStartUp.js](../readerStartUp.js), add a `useSaved<Setting>()` async function (like `useSavedTheme` / `useSavedFontSize`) and await it from `applyAllSavedSettings()`. The host calls that after `loadUIAndIcons()` and before the document loads. If the setter touches DOM elements that don't exist yet (e.g. `CurrentDocumentMainDiv`, created inside `loadDocument()`), only set the raw state property and let the later apply-on-load code pick it up. `useSavedFontSize` sets `g.pdm.fontSize` this way.
4. **Gate it if a host can't support it:** if the setting only makes sense on some hosts, add a boolean field to the adapter (like `allowFontResizing`) and document it in [host-adapter.md](host-adapter.md).
5. **Live sync across tabs** is the host's job. The host listens for its own change notifications and calls the absolute setter with saving disabled, after comparing with the current in-memory value to skip redundant work. In the extension this is `bridge.js` (`chrome.storage.onChanged`) plus the `THEME_CHANGED` / `FONT_SIZE_CHANGED` / `FONT_SET_CHANGED` / `FAVORITES_CHANGED` handlers in its `HostAdapter.initReader()`.
