-
Notifications
You must be signed in to change notification settings - Fork 132
Add themes #908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add themes #908
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ use crate::app::Message; | |
| use crate::i18n::{UnitSystem, unit_system}; | ||
| use crate::services::upower::PeripheralDeviceKind; | ||
| use crate::utils::celsius_to_fahrenheit; | ||
| use crate::utils::themes::PrebuiltTheme; | ||
| use hex_color::HexColor; | ||
| use iced::futures::StreamExt; | ||
| use iced::{Color, Subscription, futures::SinkExt, stream::channel, theme::palette}; | ||
|
|
@@ -1033,11 +1034,9 @@ impl Default for MenuAppearance { | |
| } | ||
| } | ||
|
|
||
| #[derive(Deserialize, Clone, Debug)] | ||
| #[serde(default)] | ||
| #[derive(Clone, Debug)] | ||
| pub struct Appearance { | ||
| pub font_name: Option<String>, | ||
| #[serde(deserialize_with = "scale_factor_deserializer")] | ||
| pub scale_factor: f64, | ||
| pub bar: BarAppearance, | ||
| pub menu: MenuAppearance, | ||
|
|
@@ -1049,11 +1048,85 @@ pub struct Appearance { | |
| pub text_color: AppearanceColor, | ||
| pub workspace_colors: Vec<AppearanceColor>, | ||
| pub special_workspace_colors: Option<Vec<AppearanceColor>>, | ||
| /// Blur the wallpaper behind ashell's translucent surfaces via | ||
| /// `ext-background-effect-v1`. No-op where the protocol is unsupported. | ||
|
Comment on lines
-1052
to
-1053
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ?? |
||
| pub blur: BlurMode, | ||
| pub theme: Option<String>, | ||
| } | ||
|
|
||
| // 2. Define a Shadow Struct that replicates your fields as raw Serde values | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ai tool comment |
||
| #[derive(Deserialize)] | ||
| struct AppearanceShadow { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why AppearanceShadow? |
||
| font_name: Option<String>, | ||
| scale_factor: Option<serde_json::Value>, // Intercepted for your custom helper | ||
| bar: Option<BarAppearance>, | ||
| menu: Option<MenuAppearance>, | ||
| background_color: Option<BackgroundAppearanceColor>, | ||
| primary_color: Option<AppearanceColor>, | ||
| success_color: Option<AppearanceColor>, | ||
| warning_color: Option<AppearanceColor>, | ||
| danger_color: Option<AppearanceColor>, | ||
| text_color: Option<AppearanceColor>, | ||
| workspace_colors: Option<Vec<AppearanceColor>>, | ||
| special_workspace_colors: Option<Vec<AppearanceColor>>, | ||
| blur: Option<BlurMode>, | ||
| theme: Option<String>, | ||
| } | ||
| impl<'de> Deserialize<'de> for Appearance { | ||
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
| where | ||
| D: Deserializer<'de>, | ||
| { | ||
| let shadow = AppearanceShadow::deserialize(deserializer)?; | ||
| let mut app = Appearance::default(); | ||
| if let Some(ref theme_name) = shadow.theme { | ||
| app.theme = Some(theme_name.clone()); | ||
| if let Some(theme) = PrebuiltTheme::parse(theme_name) { | ||
| theme.apply(&mut app); | ||
| } | ||
| } | ||
| if let Some(font) = shadow.font_name { | ||
| app.font_name = Some(font); | ||
| } | ||
| if let Some(bar_cfg) = shadow.bar { | ||
| app.bar = bar_cfg; | ||
| } | ||
| if let Some(menu_cfg) = shadow.menu { | ||
| app.menu = menu_cfg; | ||
| } | ||
| if let Some(bg_color) = shadow.background_color { | ||
| app.background_color = bg_color; | ||
| } | ||
| if let Some(primary) = shadow.primary_color { | ||
| app.primary_color = primary; | ||
| } | ||
| if let Some(success) = shadow.success_color { | ||
| app.success_color = success; | ||
| } | ||
| if let Some(warning) = shadow.warning_color { | ||
| app.warning_color = warning; | ||
| } | ||
| if let Some(danger) = shadow.danger_color { | ||
| app.danger_color = danger; | ||
| } | ||
| if let Some(text) = shadow.text_color { | ||
| app.text_color = text; | ||
| } | ||
| if let Some(workspaces) = shadow.workspace_colors { | ||
| app.workspace_colors = workspaces; | ||
| } | ||
| if let Some(special) = shadow.special_workspace_colors { | ||
| app.special_workspace_colors = Some(special); | ||
| } | ||
| if let Some(blur_cfg) = shadow.blur { | ||
| app.blur = blur_cfg; | ||
| } | ||
| if let Some(raw_scale) = shadow.scale_factor { | ||
| app.scale_factor = | ||
| scale_factor_deserializer(raw_scale).map_err(serde::de::Error::custom)?; | ||
| } | ||
|
|
||
| Ok(app) | ||
| } | ||
| } | ||
| /// When to ask the compositor for background blur. | ||
| #[derive(Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq)] | ||
| #[serde(rename_all = "lowercase")] | ||
|
|
@@ -1152,6 +1225,7 @@ impl Default for Appearance { | |
| ], | ||
| special_workspace_colors: None, | ||
| blur: BlurMode::default(), | ||
| theme: None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| use hex_color::HexColor; | ||
| use iced::{Color, Theme}; | ||
|
|
||
| use crate::config::{Appearance, AppearanceColor}; | ||
|
|
||
| pub struct PrebuiltTheme { | ||
| pub theme: Theme, | ||
| } | ||
| impl PrebuiltTheme { | ||
| pub fn parse(theme_name: &String) -> Option<Self> { | ||
| let theme = match theme_name | ||
| .to_lowercase() | ||
| .replace(|c| [' ', '-', '_'].contains(&c), "") | ||
| .as_str() | ||
| { | ||
| "light" => Some(Theme::Light), | ||
| "dark" => Some(Theme::Dark), | ||
| "dracula" => Some(Theme::Dracula), | ||
| "nord" => Some(Theme::Nord), | ||
| "solarizedlight" => Some(Theme::SolarizedLight), | ||
| "solarizeddark" => Some(Theme::SolarizedDark), | ||
| "gruvboxlight" => Some(Theme::GruvboxLight), | ||
| "gruvboxdark" => Some(Theme::GruvboxDark), | ||
| "catppuccinlatte" => Some(Theme::CatppuccinLatte), | ||
| "catppuccinfrappe" => Some(Theme::CatppuccinFrappe), | ||
| "catppuccinmacchiato" => Some(Theme::CatppuccinMacchiato), | ||
| "catppuccinmocha" | "catppuccin" => Some(Theme::CatppuccinMocha), | ||
| "tokyonight" => Some(Theme::TokyoNight), | ||
| "tokyonightstorm" => Some(Theme::TokyoNightStorm), | ||
| "tokyonightlight" => Some(Theme::TokyoNightLight), | ||
| "kanagawawave" => Some(Theme::KanagawaWave), | ||
| "kanagawadragon" => Some(Theme::KanagawaDragon), | ||
| "kanagawalotus" => Some(Theme::KanagawaLotus), | ||
| "moonfly" => Some(Theme::Moonfly), | ||
| "nightfly" => Some(Theme::Nightfly), | ||
| "oxocarbon" => Some(Theme::Oxocarbon), | ||
| "ferra" => Some(Theme::Ferra), | ||
| //Can add more using the custom theme in iced | ||
| _ => None, | ||
| }; | ||
| if let Some(t) = theme { | ||
| return Some(PrebuiltTheme { theme: t }); | ||
| } | ||
| return None; | ||
| } | ||
| pub fn apply(&self, app: &mut Appearance) { | ||
| let extended = self.theme.extended_palette(); | ||
| let background = extended.background; | ||
| app.background_color = crate::config::BackgroundAppearanceColor::Complete { | ||
| base: color_to_hex_color(background.base.color), | ||
| weakest: Some(color_to_hex_color(background.weakest.color)), | ||
| weaker: Some(color_to_hex_color(background.weaker.color)), | ||
| weak: Some(color_to_hex_color(background.weak.color)), | ||
| neutral: Some(color_to_hex_color(background.neutral.color)), | ||
| strong: Some(color_to_hex_color(background.strong.color)), | ||
| stronger: Some(color_to_hex_color(background.stronger.color)), | ||
| strongest: Some(color_to_hex_color(background.strongest.color)), | ||
| text: Some(color_to_hex_color(background.base.text)), | ||
| }; | ||
| let primary = extended.primary; | ||
| app.primary_color = AppearanceColor::Complete { | ||
| base: color_to_hex_color(primary.base.color), | ||
| strong: Some(color_to_hex_color(primary.strong.color)), | ||
| weak: Some(color_to_hex_color(primary.weak.color)), | ||
| text: Some(color_to_hex_color(primary.base.color)), | ||
| }; | ||
| let success = extended.success; | ||
| app.success_color = AppearanceColor::Complete { | ||
| base: color_to_hex_color(success.base.color), | ||
| strong: Some(color_to_hex_color(success.strong.color)), | ||
| weak: Some(color_to_hex_color(success.weak.color)), | ||
| text: Some(color_to_hex_color(success.base.color)), | ||
| }; | ||
| let warning = extended.warning; | ||
| app.warning_color = AppearanceColor::Complete { | ||
| base: color_to_hex_color(warning.base.color), | ||
| strong: Some(color_to_hex_color(warning.strong.color)), | ||
| weak: Some(color_to_hex_color(warning.weak.color)), | ||
| text: Some(color_to_hex_color(warning.base.color)), | ||
| }; | ||
| let danger = extended.danger; | ||
| app.danger_color = AppearanceColor::Complete { | ||
| base: color_to_hex_color(danger.base.color), | ||
| strong: Some(color_to_hex_color(danger.strong.color)), | ||
| weak: Some(color_to_hex_color(danger.weak.color)), | ||
| text: Some(color_to_hex_color(danger.base.color)), | ||
| }; | ||
| app.text_color = AppearanceColor::Complete { | ||
| base: color_to_hex_color(primary.base.color), | ||
| strong: Some(color_to_hex_color(primary.strong.color)), | ||
| weak: Some(color_to_hex_color(primary.weak.color)), | ||
| text: None, | ||
| }; | ||
| app.workspace_colors = vec![ | ||
| AppearanceColor::Simple(color_to_hex_color(primary.base.color)), | ||
| AppearanceColor::Simple(color_to_hex_color(success.base.color)), | ||
| AppearanceColor::Simple(color_to_hex_color(warning.base.color)), | ||
| ]; | ||
| } | ||
| } | ||
| pub fn color_to_hex_color(color: Color) -> HexColor { | ||
| let r = (color.r.clamp(0.0, 1.0) * 255.0).round() as u8; | ||
| let g = (color.g.clamp(0.0, 1.0) * 255.0).round() as u8; | ||
| let b = (color.b.clamp(0.0, 1.0) * 255.0).round() as u8; | ||
| let a = (color.a.clamp(0.0, 1.0) * 255.0).round() as u8; | ||
| HexColor { r, g, b, a } | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to avoid this conversion? |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
??