use super::{local_load::load_diagram_detail, shared::non_empty};
use crate::{
EditorModel, LibraryModel, MainWindow,
bridge::{library::source::LibrarySource, render_thread::RenderContext},
gui::{
library::{
diagram_list::sync_range_bounds_to_ui_preserving_filters,
search::refresh_diagram_list_via_source,
},
show_toast,
},
};
use indicatrix_vault::{db::sqlite::Database, model::metadata_update::MetadataUpdate};
use slint::{ComponentHandle, Model, SharedString};
use std::sync::{Arc, Mutex};
pub fn setup_save_metadata_callback(
ui: &MainWindow,
db_mutex: &Arc<Mutex<Database>>,
source: &Arc<Mutex<LibrarySource>>,
render_ctx: &Arc<Mutex<RenderContext>>,
) {
let db_meta = Arc::clone(db_mutex);
let source_meta = Arc::clone(source);
let render_ctx_meta = Arc::clone(render_ctx);
let ui_weak = ui.as_weak();
ui.global::<LibraryModel>().on_save_metadata(
move |title: SharedString,
designer: SharedString,
shape: SharedString,
refractive_index: SharedString,
index_gear: SharedString,
facets_count: SharedString,
symmetry_order: SharedString,
mirror_symmetry: bool,
lw_ratio: SharedString,
hw_ratio: SharedString,
cw_ratio: SharedString,
pw_ratio: SharedString,
volume: SharedString| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
if source_meta
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.is_remote()
{
show_toast(
&ui,
"Switch to the local library to edit a design's metadata.",
"error",
);
return;
}
let entry_id = ui.global::<LibraryModel>().get_selected_entry_id();
if entry_id < 0 {
return;
}
let entry_id = i64::from(entry_id);
let update = MetadataUpdate {
designer_info: non_empty(&designer),
shape: non_empty(&shape),
refractive_index: non_empty(&refractive_index),
index_gear: non_empty(&index_gear),
facets_count: non_empty(&facets_count),
symmetry_order: non_empty(&symmetry_order),
mirror_symmetry: Some(mirror_symmetry),
lw_ratio: non_empty(&lw_ratio),
hw_ratio: non_empty(&hw_ratio),
cw_ratio: non_empty(&cw_ratio),
pw_ratio: non_empty(&pw_ratio),
volume: non_empty(&volume),
};
let result = {
let db = db_meta
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let result = db.rename_and_update_metadata(entry_id, &title, &update);
if result.is_ok() {
invalidate_derived_caches(&db, entry_id);
}
drop(db);
result
};
match result {
Ok(()) => {
show_toast(&ui, "Metadata updated.", "success");
if crate::gui::editor::native_io::mark_design_row_edited(entry_id) {
ui.global::<EditorModel>().set_is_dirty(true);
}
load_diagram_detail(&ui, &db_meta, &render_ctx_meta, entry_id);
sync_range_bounds_to_ui_preserving_filters(&ui, &db_meta);
let search = ui.global::<LibraryModel>().get_search_text();
let shape_idx = ui.global::<LibraryModel>().get_selected_shape_index() as usize;
let shape_filter = ui
.global::<LibraryModel>()
.get_shape_options()
.row_data(shape_idx)
.unwrap_or_default();
let gear_idx = ui.global::<LibraryModel>().get_selected_gear_index() as usize;
let gear_filter = ui
.global::<LibraryModel>()
.get_gear_options()
.row_data(gear_idx)
.unwrap_or_default();
refresh_diagram_list_via_source(
&ui,
&db_meta,
&source_meta,
&search,
&shape_filter,
&gear_filter,
);
}
Err(e) => show_toast(&ui, &format!("Metadata update failed: {e}"), "error"),
}
},
);
}
fn invalidate_derived_caches(db: &Database, entry_id: i64) {
if let Err(e) = db.delete_preview_images(entry_id) {
tracing::warn!("Metadata edit: failed to drop cached previews for #{entry_id}: {e}");
}
if let Err(e) = db.delete_tilt_curves(entry_id) {
tracing::warn!("Metadata edit: failed to drop cached tilt curves for #{entry_id}: {e}");
}
if let Err(e) = db.delete_solid_extents(entry_id) {
tracing::warn!("Metadata edit: failed to drop cached solid extents for #{entry_id}: {e}");
}
}