Keep the theme on the account, not in the browser
- users.theme and users.theme_mode, added by migrate(); GET /api/me returns them and PATCH /api/me saves them, refusing anything but a plain name and light/dark/auto, since index() writes them into the page's <html> tag. - The page arrives with data-theme and data-choice already on <html> (and data-mode unless Auto), so it is drawn in the account's theme from the start. - A theme a browser kept in localStorage goes up to the account once, the first time an account with none loads the page. - Saves go one at a time, each with the choice as it stands: sent all at once, a quick run through the list could land out of order and keep a theme passed on the way. The browser test caught it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
25
src/db.rs
25
src/db.rs
@@ -81,7 +81,10 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
is_admin INTEGER NOT NULL DEFAULT 0,
|
||||
-- For whoever maintains the server. NULL where it is not known.
|
||||
created INTEGER,
|
||||
last_login INTEGER
|
||||
last_login INTEGER,
|
||||
-- The theme chosen in Settings, and light, dark or auto. NULL until one is chosen.
|
||||
theme TEXT,
|
||||
theme_mode TEXT
|
||||
);
|
||||
|
||||
-- What one person wants from a feed. The feed, its items and its files are shared; this
|
||||
@@ -176,6 +179,9 @@ fn migrate(conn: &Connection) -> Result<()> {
|
||||
("feeds", "error_since", "INTEGER"),
|
||||
("feeds", "category", "TEXT"),
|
||||
("entry_state", "duration", "INTEGER"),
|
||||
// Kept per account so a theme follows you to another browser; it was in localStorage.
|
||||
("users", "theme", "TEXT"),
|
||||
("users", "theme_mode", "TEXT"),
|
||||
];
|
||||
let retired: &[(&str, &str)] = &[
|
||||
// Read state from before accounts, long since moved to entry_state. Two bugs came from
|
||||
@@ -1180,6 +1186,23 @@ impl Db {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The theme this person chose, and light, dark or auto; None for either until they choose.
|
||||
pub fn theme(&self, user_id: i64) -> Result<(Option<String>, Option<String>)> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
Ok(conn.query_row("SELECT theme, theme_mode FROM users WHERE id = ?1", [user_id], |r| {
|
||||
Ok((r.get(0)?, r.get(1)?))
|
||||
})?)
|
||||
}
|
||||
|
||||
pub fn set_theme(&self, user_id: i64, theme: &str, mode: &str) -> Result<()> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute(
|
||||
"UPDATE users SET theme = ?2, theme_mode = ?3 WHERE id = ?1",
|
||||
params![user_id, theme, mode],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The user behind a session cookie, if it is still live. Idle sessions expire after
|
||||
/// `max_idle_secs`; touching `seen` is what keeps a session in daily use alive.
|
||||
pub fn session_user(&self, token: &str, max_idle_secs: i64) -> Result<Option<User>> {
|
||||
|
||||
Reference in New Issue
Block a user