Skip to content

machingclee/2025-10-13-Iced-gui-experiment

Repository files navigation

Shell Script GUI App

Trial to Iced Framework

demo.mp4
  • This project aims at experimenting GUI framework in Rust ecosystem.

  • Iced depends everything in messages, which means that we can apply traditional command/event for the frontend (which is also a pattern in WPF where each button in the XAML file has a "commmand" props).

  • In frontend we can even arrange main app as Root State, and for each subdomain logic we define new struct as a separated state, as if it is an redux state management tool.

    The app listens to messages to execute different action:

    // app_slice.rs
    
    impl ShellScriptsAppRootState {
        pub fn update(&mut self, message: Message) -> Task<Message> {
            match message {
                Message::DatabaseConnected(db) => {
                    self.db = Some(db.clone());
                    self.folder_state.folder_script_repository =
                        Some(Arc::new(ScriptFolderRepository::new(db.clone())));
                    self.folder_state.shell_script_repository =
                        Some(Arc::new(ShellScriptRepository::new(db.clone())));
                    self.loading = false;
                    println!("Database connected successfully!");
                    Task::perform(async {}, |_| Message::Folder(FolderMessage::LoadFolders))
                }
                // forward message to subdomain
                Message::Folder(folder_msg) => {
                    self.folder_state.update(folder_msg).map(Message::Folder)
                }
                ...
            }
        }
    }
    
    // folder_slice.rs
    
    impl FolderState {
        pub fn update(&mut self, message: FolderMessage) -> Task<FolderMessage> {
            match message {
                FolderMessage::SelectFolder(folder) => {
                    self.selected_folder = Some(folder.clone());
                    Task::perform(async {}, move |_| {
                        FolderMessage::FolderSelected(folder.clone())
                    })
                }
                FolderMessage::FolderSelected(selected_folder) => {
                    if let Some(repo) = &self.shell_script_repository {
                        let repo = repo.clone();
                        let folder_id = selected_folder.id;
                        let folder_name = selected_folder.name.clone();
    
                        Task::perform(
                            async move { repo.get_all_scripts_of_folder(folder_id) },
                            move |scripts| {
                                println!(
                                    "Loaded {} scripts for folder {}",
                                    scripts.len(),
                                    folder_name
                                );
                                FolderMessage::ScriptsLoaded(scripts)
                            },
                        )
                    } else {
                        Task::none()
                    }
                }
                ...
            }
        }
    }

SQLite Integration

This app in DEV mode (cargo build, cargo run etc) has bound with a dev-database.db in the project root directory, which will be generated upon the first loading of the app.

In development I usually turn the auto-creation of the tables off and do the schema-migration as if it is a standard backend application.

We have arranged the project so that we use prisma to compile its schema.prisma file into Rust entity classes, see the build.rs for detail.

Limitation

UI flexibility is very limited. There is no way to create a standard "context-menu" that captures my clicking position $(X,Y)$ and displays the menu with that $(X, Y)$ as my origin.

Future Direction

For standard grids Iced is fine, but I am seeking for the most powerful one, so I would stop at this stage and try other framework such as egui.

About

Manage plenty of shell scripts by one GUI application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published