diff options
| author | Polesznyák Márk László <116908301+pml68@users.noreply.github.com> | 2025-01-11 23:13:07 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-11 23:13:07 +0100 |
| commit | 103699beeb8bdce38bc5803cbe038e74cbc20e40 (patch) | |
| tree | b79e13b3decc778cc7c66af7187c647ae0a21a52 /src/types/project.rs | |
| parent | Merge pull request #4 from pml68/feat/playground (diff) | |
| parent | refactor: remove iced_drop & workspace (diff) | |
| download | iced-builder-103699beeb8bdce38bc5803cbe038e74cbc20e40.tar.gz | |
Merge pull request #5 from pml68/feat/config
Config done
Diffstat (limited to 'src/types/project.rs')
| -rw-r--r-- | src/types/project.rs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/types/project.rs b/src/types/project.rs new file mode 100644 index 0000000..27c576b --- /dev/null +++ b/src/types/project.rs @@ -0,0 +1,165 @@ +use std::path::{Path, PathBuf}; + +extern crate fxhash; +use fxhash::FxHashMap; +use iced::Theme; +use rust_format::{Edition, Formatter, RustFmt}; +use serde::{Deserialize, Serialize}; + +use super::rendered_element::RenderedElement; +use crate::config::Config; +use crate::theme::{theme_from_str, theme_index, theme_to_string}; +use crate::Error; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Project { + pub title: Option<String>, + pub theme: Option<String>, + pub element_tree: Option<RenderedElement>, + #[serde(skip)] + theme_cache: FxHashMap<String, String>, +} + +impl Default for Project { + fn default() -> Self { + Self::new() + } +} + +impl Project { + pub fn new() -> Self { + Self { + title: None, + theme: None, + element_tree: None, + theme_cache: FxHashMap::default(), + } + } + + pub fn get_theme(&self, config: &Config) -> Theme { + match &self.theme { + Some(theme) => theme_from_str(Some(config), theme), + None => Theme::default(), + } + } + + fn theme_code(&mut self, theme: &Theme) -> String { + let theme_name = theme.to_string(); + if theme_index(&theme_name, Theme::ALL).is_none() { + (*self + .theme_cache + .entry(theme_name) + .or_insert(theme_to_string(theme))) + .to_string() + } else { + theme_name.replace(" ", "") + } + } + + pub async fn from_path( + path: PathBuf, + config: Config, + ) -> Result<(PathBuf, Self), Error> { + let contents = tokio::fs::read_to_string(&path).await?; + let mut project: Self = serde_json::from_str(&contents)?; + + let _ = project.theme_code(&project.get_theme(&config)); + + Ok((path, project)) + } + + pub async fn from_file(config: Config) -> Result<(PathBuf, Self), Error> { + let picked_file = rfd::AsyncFileDialog::new() + .set_title("Open a JSON file...") + .add_filter("*.json, *.JSON", &["json", "JSON"]) + .pick_file() + .await + .ok_or(Error::DialogClosed)?; + + let path = picked_file.path().to_owned(); + + Self::from_path(path, config).await + } + + pub async fn write_to_file( + self, + path: Option<PathBuf>, + ) -> Result<PathBuf, Error> { + let path = if let Some(p) = path { + p + } else { + rfd::AsyncFileDialog::new() + .set_title("Save to JSON file...") + .add_filter("*.json, *.JSON", &["json", "JSON"]) + .save_file() + .await + .as_ref() + .map(rfd::FileHandle::path) + .map(Path::to_owned) + .ok_or(Error::DialogClosed)? + }; + + let contents = serde_json::to_string(&self)?; + tokio::fs::write(&path, contents).await?; + + Ok(path) + } + + pub fn app_code(&mut self, config: &Config) -> Result<String, Error> { + match self.element_tree { + Some(ref element_tree) => { + let (imports, view) = element_tree.codegen(); + let theme = self.get_theme(config); + let theme_code = self.theme_code(&theme); + let mut theme_imports = ""; + if theme_index(&theme.to_string(), Theme::ALL).is_none() { + if theme_code.contains("Extended") { + theme_imports = "use iced::{{color,theme::{{Palette,palette::{{Extended,Background,Primary,Secondary,Success,Danger,Pair}}}}}};\n"; + } else { + theme_imports = "use iced::{{color,theme::Palette}};\n"; + } + } + + let app_code = format!( + r#"// Automatically generated by iced Builder + use iced::{{widget::{{{imports}}},Element}}; + {theme_imports} + + fn main() -> iced::Result {{ + iced::application("{}", State::update, State::view).theme(State::theme).run() + }} + + #[derive(Default)] + struct State; + + #[derive(Debug, Clone)] + enum Message {{}} + + impl State {{ + fn update(&mut self, _message: Message) {{}} + + fn theme(&self) -> iced::Theme {{ + iced::Theme::{} + }} + + fn view(&self) -> Element<Message> {{ + {view}.into() + }} + }}"#, + match self.title { + Some(ref t) => t, + None => "New app", + }, + theme_code + ); + let config = rust_format::Config::new_str() + .edition(Edition::Rust2021) + .option("trailing_comma", "Never") + .option("imports_granularity", "Crate"); + let rustfmt = RustFmt::from_config(config); + Ok(rustfmt.format_str(app_code)?) + } + None => Err("No element tree present".into()), + } + } +} |
