This commit is contained in:
2026-10-08 08:42:44 +07:00
parent 069f031af9
commit 2efb6ac5ca
24 changed files with 628 additions and 2614 deletions
+64 -32
View File
@@ -1,12 +1,10 @@
use std::rc::Rc;
use anyhow::{Error, anyhow};
use common::config_dir;
use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task, Window};
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use smallvec::{SmallVec, smallvec};
use theme::{Theme, ThemeFamily, ThemeMode};
use theme::{AccentSelection, Appearance, SurfacePreference, Theme, ThemeSelection};
pub fn init(cx: &mut App) {
AppSettings::set_global(cx.new(AppSettings::new), cx)
@@ -53,7 +51,10 @@ macro_rules! setting_getters {
}
setting_accessors! {
pub theme_mode: ThemeMode,
pub appearance: Appearance,
pub accent_selection: AccentSelection,
pub surface_preference: SurfacePreference,
pub theme_selection: ThemeSelection,
pub hide_avatar: bool,
pub screening: bool,
pub nip4e: bool,
@@ -119,11 +120,26 @@ impl RoomConfig {
/// Settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Settings {
/// Theme
pub theme: Option<String>,
/// The per-appearance theme variant selection
#[serde(default)]
pub theme_selection: ThemeSelection,
/// Theme mode
pub theme_mode: ThemeMode,
/// The active appearance; persisted under the legacy `theme_mode` key so
/// old settings files ("Light"/"Dark") keep loading
#[serde(
default,
rename = "theme_mode",
deserialize_with = "deserialize_appearance"
)]
pub appearance: Appearance,
/// The accent color override applied on top of the selected theme
#[serde(default)]
pub accent_selection: AccentSelection,
/// The preferred surface treatment
#[serde(default)]
pub surface_preference: SurfacePreference,
/// Hide user avatars
pub hide_avatar: bool,
@@ -152,8 +168,10 @@ pub struct Settings {
impl Default for Settings {
fn default() -> Self {
Self {
theme: None,
theme_mode: ThemeMode::default(),
theme_selection: ThemeSelection::default(),
appearance: Appearance::default(),
accent_selection: AccentSelection::default(),
surface_preference: SurfacePreference::default(),
hide_avatar: false,
screening: true,
nip4e: false,
@@ -165,6 +183,21 @@ impl Default for Settings {
}
}
/// Accept the legacy "Light"/"Dark" capitalization alongside "light"/"dark".
fn deserialize_appearance<'de, D>(deserializer: D) -> Result<Appearance, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
match value.to_lowercase().as_str() {
"light" => Ok(Appearance::Light),
"dark" => Ok(Appearance::Dark),
_ => Err(serde::de::Error::custom(format!(
"unknown appearance: {value}"
))),
}
}
struct GlobalAppSettings(Entity<AppSettings>);
impl Global for GlobalAppSettings {}
@@ -264,44 +297,43 @@ impl AppSettings {
}
}
/// Set theme
pub fn set_theme<T>(&mut self, theme: T, window: &mut Window, cx: &mut Context<Self>)
where
T: Into<String>,
{
// Update settings
/// Set the theme variant for the current appearance
pub fn set_theme_variant(&mut self, id: String, window: &mut Window, cx: &mut Context<Self>) {
self.inner.update(cx, |this, cx| {
this.theme = Some(theme.into());
let mut selection = this.theme_selection.clone();
selection.set_variant(this.appearance, id);
this.theme_selection = selection;
cx.notify();
});
// Apply the new theme
self.apply_theme(Some(window), cx);
}
/// Reset theme
/// Reset the theme selection to the defaults
pub fn reset_theme(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.inner.update(cx, |this, cx| {
this.theme = None;
this.theme_selection = ThemeSelection::default();
cx.notify();
});
self.apply_theme(Some(window), cx);
}
/// Apply theme
pub fn apply_theme(&mut self, mut window: Option<&mut Window>, cx: &mut Context<Self>) {
if let Some(name) = self.inner.read(cx).theme.as_ref() {
let mode = self.inner.read(cx).theme_mode;
pub fn apply_theme(&mut self, window: Option<&mut Window>, cx: &mut Context<Self>) {
let (selection, accent, surface, appearance) = {
let settings = self.inner.read(cx);
(
settings.theme_selection.clone(),
settings.accent_selection,
settings.surface_preference,
settings.appearance,
)
};
if let Ok(new_theme) = ThemeFamily::from_assets(name) {
Theme::apply_theme(Rc::new(new_theme), window.as_deref_mut(), cx);
Theme::change(mode, window, cx);
} else {
log::info!("Failed to load theme: {name}");
}
} else {
Theme::apply_theme(Rc::new(ThemeFamily::default()), window, cx);
}
Theme::set_selection(selection, cx);
Theme::set_accent_selection(accent, cx);
Theme::set_surface_preference(surface, cx);
Theme::change(appearance, window, cx);
}
/// Check if decoupling encryption key is enabled