feat(tahuantinsuyu): editor inline para cartas libres (F2)

Las cartas libres ahora se pueden editar en su totalidad (fecha,
hora, lugar, lat/lon/alt, TZ, label) desde el menú contextual.
La edición es **in-memory** — la carta se queda como libre tras
el cambio; para persistirla hay que usar "Guardar como…".

Tree:
- Nuevo `Modal::EditFreeChart { source_id, form, error }`
  paralelo al `Modal::EditChart` existente. Reusa la misma
  `ChartForm` (11 TextInputs: name + place + date + time + TZ
  + lat/lon/alt) y la misma función `render_chart_form` para
  pintarlo. El title cambia a "Editar carta libre".
- `open_edit_free_chart_modal(source_id, w, cx)`: lee el entry
  de `self.free_charts` (que ahora trae `birth_data` además
  de id+label), pre-puebla el form, y abre el modal.
- Submit: `build_chart_from_form` parsea + valida; al éxito
  emite nuevo evento `TreeEvent::FreeChartEditConfirmed
  { source_id, birth_data, label }`. Al error, conserva el
  modal con la pill destructiva.
- City picker funciona como antes — el branch de
  `apply_city_preset` se extendió para que reconozca
  `Modal::EditFreeChart` además de Create/Edit.

Modelo:
- `FreeChartEntry` ahora incluye `birth_data: StoredBirthData`
  además de id+label. El shell se lo pasa al setter; el tree
  lo usa para pre-poblar el form sin tener que pedirlo al
  shell.

Shell:
- `push_free_charts_to_tree` clona `birth_data` en cada entry.
- Handler `FreeChartEditConfirmed`: actualiza
  `free_charts[id]` con los nuevos datos + label, re-publica
  al tree, y si la carta editada era la activa, re-renderea
  el wheel.

Menú contextual de "Cartas libres" / `<carta libre>` ahora:
- Editar datos…
- Guardar como…
- Borrar  (no se ofrece sobre sky-now)

10 tests verdes (sin afectar lo testeado).

Próximo y último: F4 — botón "Guardar como…" en cada módulo
overlay (RS, prog, sa, gr) que captura la carta derivada con
un sufijo automático en el contacto original.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-18 21:51:51 +00:00
parent a83b0396ce
commit dd836522ab
2 changed files with 145 additions and 3 deletions
+28
View File
@@ -249,6 +249,7 @@ impl Shell {
entries.push(FreeChartEntry {
id: FreeChartId::sky_now(),
label: c.label.clone(),
birth_data: c.birth_data.clone(),
});
}
let mut others: Vec<(&FreeChartId, &Chart)> = self
@@ -261,6 +262,7 @@ impl Shell {
entries.push(FreeChartEntry {
id: id.clone(),
label: c.label.clone(),
birth_data: c.birth_data.clone(),
});
}
self.tree
@@ -502,6 +504,32 @@ impl Shell {
);
return;
}
TreeEvent::FreeChartEditConfirmed {
source_id,
birth_data,
label,
} => {
if let Some(chart) = self.free_charts.get_mut(source_id) {
chart.birth_data = birth_data.clone();
chart.label = label.clone();
}
self.push_free_charts_to_tree(cx);
// Si la carta editada era la activa, re-render.
if let Some(current) = self.current_chart.as_mut() {
// Heurística: comparamos por label (ya cambiado al
// que pidió el usuario). Si el label de la activa
// coincide, era esta carta.
if current.label == label.clone()
|| current.birth_data.subject_name.as_deref() == Some("Cielo")
{
if let Some(updated) = self.free_charts.get(source_id) {
*current = updated.clone();
self.render_current(cx);
}
}
}
return;
}
TreeEvent::DeleteFreeChartRequested(id) => {
if id.is_sky_now() {
return; // no se borra el Cielo