gradience_lib/
shell.rs

1use crate::preset::{AccentsColor, ApplyBuilder, Mode, Preset};
2use crate::utils::{get_gnome_shell_version, run_command, ShellVersion};
3use grass::from_path;
4use walkdir::WalkDir;
5
6pub struct Shell {
7    pub version: ShellVersion,
8    pub source_dir: String,
9    pub preset: Preset,
10}
11
12pub enum ThemeName {
13    Default,
14    Custom { name: String },
15}
16
17impl Shell {
18    pub fn new(source_dir: String, preset: Preset) -> Shell {
19        let version = get_gnome_shell_version();
20        Shell {
21            version,
22            source_dir,
23            preset,
24        }
25    }
26
27    fn apply_gtk(&self, mode: Mode, accent: AccentsColor, theme_dir: String) {
28        if !std::path::Path::new(&format!("{}/gtk-4.0", theme_dir)).exists() {
29            std::fs::create_dir_all(&format!("{}/gtk-4.0", theme_dir)).unwrap();
30        }
31        if !std::path::Path::new(&format!("{}/gtk-3.0", theme_dir)).exists() {
32            std::fs::create_dir_all(&format!("{}/gtk-3.0", theme_dir)).unwrap();
33        }
34
35        ApplyBuilder::new(self.preset.clone())
36            .accent(accent)
37            .mode(mode)
38            .gtk3_path(format!("{}/gtk-3.0/gtk.css", theme_dir).as_str())
39            .gtk4_path(format!("{}/gtk-4.0/gtk.css", theme_dir).as_str())
40            .apply();
41    }
42
43    pub fn apply(
44        &self,
45        target_dir: String,
46        themes_dir: String,
47        mode: Mode,
48        accent: AccentsColor,
49        theme_name: ThemeName,
50    ) -> Result<(), std::io::Error> {
51        let version = match self.version {
52            ShellVersion::G46 => "46",
53            ShellVersion::Unsupported => {
54                return Err(std::io::Error::new(
55                    std::io::ErrorKind::Other,
56                    "Unsupported shell version",
57                ))
58            }
59        };
60
61        let source_path = format!("{}/{}", self.source_dir, version);
62        let target_path = match theme_name {
63            ThemeName::Default => format!(
64                "{}/{}-{:?}-{:?}",
65                target_dir, self.preset.name, mode, accent
66            ),
67            ThemeName::Custom { ref name } => name.to_string(),
68        };
69        let theme_dir = match theme_name {
70            ThemeName::Default => format!(
71                "{}/{}-{:?}-{:?}",
72                themes_dir, self.preset.name, mode, accent
73            ),
74            ThemeName::Custom { ref name } => name.to_string(),
75        };
76
77        if !std::path::Path::new(&target_path).exists() {
78            std::fs::create_dir_all(&target_path).unwrap();
79        }
80
81        if !std::path::Path::new(&theme_dir).exists() {
82            std::fs::create_dir_all(&theme_dir).unwrap();
83        }
84
85        std::fs::create_dir_all(&format!("{}/gnome-shell", theme_dir)).unwrap();
86
87        let output = run_command(&format!("cp -r {}/* {}", source_path, target_path));
88
89        if !output.status.success() {
90            return Err(std::io::Error::new(
91                std::io::ErrorKind::Other,
92                "Failed to copy files",
93            ));
94        }
95
96        for entry in WalkDir::new(&target_path) {
97            let entry = entry?;
98            if entry.path().extension().unwrap_or_default() == "template" {
99                let template = std::fs::read_to_string(entry.path())?;
100                let rendered = self.preset.render_template(template, mode, accent);
101                std::fs::write(entry.path().with_extension("scss"), rendered)?;
102                std::fs::remove_file(entry.path().with_extension("template"))?;
103            }
104        }
105
106        let css = from_path(
107            &format!("{}/gnome-shell.scss", target_path),
108            &grass::Options::default(),
109        )
110        .unwrap();
111        std::fs::write(format!("{}/gnome-shell/gnome-shell.css", theme_dir), css)?;
112        self.apply_gtk(mode, accent, theme_dir);
113
114        return Ok(());
115    }
116}