use super::presets::{CommandPreset, run_preset_commands};
use super::wizard::run_scan_convert_preview_wizard;
use super::*;
use std::process::Command;
impl CreatorApp {
pub(crate) fn show_feedback(&mut self, title: &str, res: Result<()>) {
match res {
Ok(()) => {
MessageDialog::new()
.set_title(title)
.set_description("Success")
.set_buttons(MessageButtons::Ok)
.show();
self.toasts
.push((format!("{} succeeded", title), Instant::now()));
}
Err(e) => {
MessageDialog::new()
.set_title(title)
.set_description(&e.to_string())
.set_buttons(MessageButtons::Ok)
.show();
self.toasts
.push((format!("{} failed: {}", title, e), Instant::now()));
}
}
}
pub(crate) fn handle_init(&mut self) {
let manifest = Path::new(&self.manifest_path);
let res = init::run(manifest);
self.show_feedback("Init", res);
}
pub(crate) fn handle_scan(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
let res = scan::run(&root, Path::new(&self.manifest_path));
self.show_feedback("Scan", res);
}
}
pub(crate) fn handle_check(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
let fix = matches!(
MessageDialog::new()
.set_title("Apply fixes?")
.set_buttons(MessageButtons::YesNo)
.show(),
MessageDialogResult::Yes
);
let res = check::run(&root, Path::new(&self.manifest_path), fix);
self.show_feedback("Check", res);
}
}
pub(crate) fn handle_vendor(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
if let Some(out) = FileDialog::new().pick_folder() {
let res = vendor::run(&root, Path::new(&self.manifest_path), &out, &[], &[]);
self.show_feedback("Vendor", res);
}
}
}
pub(crate) fn handle_convert(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
let force = matches!(
MessageDialog::new()
.set_title("Force rebuild?")
.set_buttons(MessageButtons::YesNo)
.show(),
MessageDialogResult::Yes
);
let res = convert::run(&root, Path::new(&self.manifest_path), force);
self.show_feedback("Convert", res);
}
}
pub(crate) fn handle_preview(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
let res = preview::run(&root, Path::new(&self.manifest_path));
self.show_feedback("Preview", res);
}
}
pub(crate) fn handle_add_target(&mut self) {
if let Some(vendor_dir) = FileDialog::new().pick_folder() {
if let Some(name) = vendor_dir.file_name().and_then(|n| n.to_str()) {
let res = add_target::run(Path::new(&self.manifest_path), name, &vendor_dir);
self.show_feedback("AddTarget", res);
}
}
}
pub(crate) fn handle_sync(&mut self) {
if let Some(out) = FileDialog::new().pick_folder() {
let dry_run = matches!(
MessageDialog::new()
.set_title("Dry run?")
.set_buttons(MessageButtons::YesNo)
.show(),
MessageDialogResult::Yes
);
let res = sync::run(Path::new(&self.manifest_path), &out, dry_run);
self.show_feedback("Sync", res);
}
}
pub(crate) fn handle_scaffold(&mut self) {
if let Some(path) = FileDialog::new().pick_folder() {
let res = scaffold::run(&path, Path::new(&self.manifest_path));
self.show_feedback("Scaffold", res);
}
}
pub(crate) fn handle_apng(&mut self) {
if let Some(frames) = FileDialog::new().pick_folder() {
if let Some(out) = FileDialog::new()
.add_filter("apng", &["png"])
.set_file_name("animation.png")
.save_file()
{
let res = apng::run(&frames, &out, 100, 0);
self.show_feedback("Apng", res);
}
}
}
pub(crate) fn handle_schema(&mut self) {
let res = schema::run();
self.show_feedback("Schema", res);
}
pub(crate) fn handle_fonts_pack(&mut self) {
self.fonts_pack_open = true;
}
pub(crate) fn handle_lottie_import(&mut self) {
if let Some(json) = FileDialog::new().add_filter("json", &["json"]).pick_file() {
if let Some(out) = FileDialog::new().pick_folder() {
let res = lottie::import(&json, &out, None);
self.show_feedback("Lottie Import", res);
}
}
}
pub(crate) fn handle_lottie_cli(&mut self) {
if let Some(bin) = FileDialog::new().pick_file() {
if let Some(json) = FileDialog::new().add_filter("json", &["json"]).pick_file() {
if let Some(out) = FileDialog::new().pick_folder() {
let res = lottie::import_cli(&bin, &json, &out, None);
self.show_feedback("Lottie CLI", res);
}
}
}
}
pub(crate) fn handle_add_asset(&mut self) {
if let Some(files) = FileDialog::new().pick_files() {
let manifest_dir = Path::new(&self.manifest_path)
.parent()
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("."));
let raw_dir = manifest_dir.join("assets/raw");
if let Err(e) = fs::create_dir_all(&raw_dir) {
self.toasts.push((
format!("Failed to create assets/raw: {}", e),
Instant::now(),
));
return;
}
let mut copied = false;
for file in files {
if let Some(name) = file.file_name() {
let dest = raw_dir.join(name);
match fs::copy(&file, &dest) {
Ok(_) => {
self.toasts.push((
format!("Imported {}", name.to_string_lossy()),
Instant::now(),
));
copied = true;
}
Err(e) => self
.toasts
.push((format!("Copy failed: {}", e), Instant::now())),
}
}
}
if copied {
if let Err(e) = scan::run(&raw_dir, Path::new(&self.manifest_path)) {
self.toasts
.push((format!("Scan failed: {}", e), Instant::now()));
} else if let Ok(file) = File::open(&self.manifest_path) {
if let Ok(manifest) = from_reader(file) {
let path = self.manifest_path.clone();
let mut new_app = Self::new(manifest, path);
new_app.toasts = self.toasts.clone();
new_app.new_group = self.new_group.clone();
*self = new_app;
}
}
}
}
}
pub(crate) fn handle_svg(&mut self) {
self.svg_open = true;
}
pub(crate) fn handle_simulator(&mut self) {
self.sim_open = true;
}
pub(crate) fn handle_run_preset(&mut self) {
if let Some(file) = FileDialog::new()
.add_filter("preset", &["json"])
.pick_file()
{
match fs::read_to_string(&file)
.ok()
.and_then(|t| serde_json::from_str::<CommandPreset>(&t).ok())
{
Some(preset) => {
run_preset_commands(&preset.commands, |c| self.handle_action(c));
self.show_feedback("Run Preset", Ok(()));
}
None => {
self.show_feedback("Run Preset", Err(anyhow::anyhow!("invalid preset file")));
}
}
}
}
pub(crate) fn handle_save_preset(&mut self) {
if let Some(path) = FileDialog::new().set_file_name("preset.json").save_file() {
let preset = CommandPreset {
commands: vec![
"Scan".to_string(),
"Convert".to_string(),
"Preview".to_string(),
],
};
let res = File::create(&path)
.map_err(anyhow::Error::from)
.and_then(|f| serde_json::to_writer(f, &preset).map_err(anyhow::Error::from));
self.show_feedback("Save Preset", res);
}
}
pub(crate) fn handle_scan_convert_preview(&mut self) {
if let Some(root) = FileDialog::new().pick_folder() {
let manifest = Path::new(&self.manifest_path);
let res = run_scan_convert_preview_wizard(
|| scan::run(&root, manifest),
|| convert::run(&root, manifest, false),
|| preview::run(&root, manifest),
|step| {
self.toasts
.push((format!("Wizard step: {:?}", step), Instant::now()));
},
);
self.show_feedback("Scan→Convert→Preview", res);
}
}
pub(crate) fn launch_simulator(&mut self) {
let (width, height) = match self.sim_screen() {
Ok(screen) => screen,
Err(e) => {
self.toasts
.push((format!("Simulator config error: {}", e), Instant::now()));
return;
}
};
let exe = match std::env::current_exe() {
Ok(path) => path,
Err(e) => {
self.toasts
.push((format!("Simulator launch failed: {}", e), Instant::now()));
return;
}
};
let mut cmd = Command::new(exe);
cmd.arg("sim")
.arg("--screen")
.arg(format!("{}x{}", width, height));
if self.sim_use_wgpu {
cmd.arg("--wgpu");
}
if self.sim_show_qrcode {
cmd.arg("--qrcode");
}
if self.sim_show_png {
cmd.arg("--png");
}
if self.sim_show_gif {
cmd.arg("--gif");
}
if self.sim_show_jpeg {
cmd.arg("--jpeg");
}
match cmd.spawn() {
Ok(_) => {
self.toasts
.push(("Simulator launched".into(), Instant::now()));
}
Err(e) => {
self.toasts
.push((format!("Simulator launch failed: {}", e), Instant::now()));
}
}
}
}
impl CreatorApp {
pub(crate) fn handle_action(&mut self, label: &str) {
match label {
"Init" => self.handle_init(),
"Scan" => self.handle_scan(),
"Check" => self.handle_check(),
"Vendor" => self.handle_vendor(),
"Convert" => self.handle_convert(),
"Preview" => self.handle_preview(),
"Add Asset" => self.handle_add_asset(),
"AddTarget" => self.handle_add_target(),
"Sync" => self.handle_sync(),
"Scaffold" => self.handle_scaffold(),
"Fonts Pack" => self.handle_fonts_pack(),
"Svg" => self.handle_svg(),
"Apng" => self.handle_apng(),
"Schema" => self.handle_schema(),
"Lottie Import" => self.handle_lottie_import(),
"Lottie CLI" => self.handle_lottie_cli(),
"Run Preset" => self.handle_run_preset(),
"Save Preset" => self.handle_save_preset(),
"Scan Convert Preview" => self.handle_scan_convert_preview(),
"Simulator" => self.handle_simulator(),
"Qt Ingest" => self.handle_qt_ingest(),
"Qt Check" => self.handle_qt_check(),
"Qt Schema" => self.handle_qt_schema(),
"Qt Emit" => self.handle_qt_emit(),
"Qt Emit Scjson" => self.handle_qt_emit_scjson(),
"Qt Emit Externals" => self.handle_qt_emit_externals(),
"Qt Emit Tokens" => self.handle_qt_emit_tokens(),
"Qt List Assets" => self.handle_qt_list_assets(),
"Qt List Qmldir" => self.handle_qt_list_qmldir(),
"Qt List Qrc" => self.handle_qt_list_qrc(),
_ => {}
}
}
}
impl CreatorApp {
fn pick_qml_input(&self) -> Option<PathBuf> {
if let Some(p) = FileDialog::new().add_filter("QML", &["qml"]).pick_file() {
return Some(p);
}
FileDialog::new().pick_folder()
}
pub(crate) fn handle_qt_ingest(&mut self) {
if let Some(input) = self.pick_qml_input()
&& let Some(out) = FileDialog::new().pick_folder()
{
let res = qt::ingest(&input, &out);
self.show_feedback("Qt Ingest", res);
}
}
pub(crate) fn handle_qt_check(&mut self) {
if let Some(input) = FileDialog::new().add_filter("QML", &["qml"]).pick_file() {
let res = qt::check(&input);
self.show_feedback("Qt Check", res);
}
}
pub(crate) fn handle_qt_schema(&mut self) {
let out = FileDialog::new().add_filter("JSON", &["json"]).save_file();
let res = qt::schema(out.as_deref());
self.show_feedback("Qt Schema", res);
}
pub(crate) fn handle_qt_emit(&mut self) {
if let Some(input) = self.pick_qml_input()
&& let Some(out) = FileDialog::new().pick_folder()
{
let res = qt::emit(&input, &out, qt::EmitTarget::Rlvgl);
self.show_feedback("Qt Emit", res);
}
}
pub(crate) fn handle_qt_emit_scjson(&mut self) {
if let Some(input) = self.pick_qml_input() {
let out = FileDialog::new().pick_folder();
let res = qt::emit_scjson(&input, out.as_deref());
self.show_feedback("Qt Emit Scjson", res);
}
}
pub(crate) fn handle_qt_emit_externals(&mut self) {
if let Some(input) = self.pick_qml_input() {
let out = FileDialog::new().pick_folder();
let res = qt::emit_externals(&input, out.as_deref());
self.show_feedback("Qt Emit Externals", res);
}
}
pub(crate) fn handle_qt_emit_tokens(&mut self) {
if let Some(input) = self.pick_qml_input() {
let out = FileDialog::new().pick_folder();
let res = qt::emit_tokens(&input, out.as_deref());
self.show_feedback("Qt Emit Tokens", res);
}
}
pub(crate) fn handle_qt_list_assets(&mut self) {
if let Some(input) = self.pick_qml_input() {
let out = FileDialog::new().pick_folder();
let res = qt::list_assets(&input, out.as_deref());
self.show_feedback("Qt List Assets", res);
}
}
pub(crate) fn handle_qt_list_qmldir(&mut self) {
if let Some(input) = FileDialog::new().pick_folder() {
let out = FileDialog::new().pick_folder();
let res = qt::list_qmldir(&input, out.as_deref());
self.show_feedback("Qt List Qmldir", res);
}
}
pub(crate) fn handle_qt_list_qrc(&mut self) {
let input = FileDialog::new()
.add_filter("QRC", &["qrc"])
.pick_file()
.or_else(|| FileDialog::new().pick_folder());
if let Some(input) = input {
let out = FileDialog::new().pick_folder();
let res = qt::list_qrc(&input, out.as_deref());
self.show_feedback("Qt List Qrc", res);
}
}
}