El escritorio aprende a medir el trabajo efectivo, y lo dice en la bandeja

Sensor nuevo (src/tracker.rs): cada 5 s mira que app esta al frente y si
hubo entrada; con 3 minutos sin entrada deja de contar (ocio profundo, que
cubre tambien pantalla bloqueada y suspension). Acumula bloques {app,
titulo, segundos, segundos activos} y los sube cada 5 min a /api/tracker con
el token del equipo; sin red la cola persiste en disco y reintenta, y un 401
(token revocado desde Ajustes) descarta el token y vacia la cola.

Lo que NO hace, a proposito: no registra que teclas se pulsan —solo compara
una huella de posicion del raton y cuantas teclas hay presionadas—, no toma
pantallazos y no lista procesos de fondo. El estado vive VISIBLE en el menu
de la bandeja, con pausa de un toque.

Ojo al tocar el menu: set_text de Tauri despacha al hilo principal y bloquea
esperandolo, asi que llamarlo desde setup() —que corre en ese mismo hilo
antes de que el bucle de eventos atienda— colgaria la app al abrir. Por eso
los items nacen ya con su texto y todo repintado posterior sale de un hilo
secundario.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Este commit está contenido en:
Munka
2026-08-13 15:48:54 -05:00
padre 3798970f74
commit cac69dd7be
Se han modificado 3 ficheros con 382 adiciones y 2 borrados

Ver fichero

@@ -32,6 +32,8 @@
// `core:default` también para el origen remoto (capabilities/default.json). Así no hace falta
// declarar comandos propios en el ACL para páginas remotas.
mod tracker;
use std::sync::Mutex;
use serde::{Deserialize, Serialize};
@@ -1394,10 +1396,13 @@ pub fn run() {
}
});
// Icono en la bandeja del sistema con menú Abrir / Salir.
// Icono en la bandeja: Abrir / estado del rastreador + pausa / Salir.
let abrir = MenuItem::with_id(app, "abrir", "Abrir Labstream", true, None::<&str>)?;
let salir = MenuItem::with_id(app, "salir", "Salir", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&abrir, &salir])?;
let (trk_estado, trk_toggle) = tracker::armar_menu(app.handle())?;
let sep1 = PredefinedMenuItem::separator(app)?;
let sep2 = PredefinedMenuItem::separator(app)?;
let menu = Menu::with_items(app, &[&abrir, &sep1, &trk_estado, &trk_toggle, &sep2, &salir])?;
TrayIconBuilder::with_id("main-tray")
.icon(app.default_window_icon().unwrap().clone())
@@ -1410,6 +1415,7 @@ pub fn run() {
save_persisted(app);
app.exit(0);
}
id if tracker::menu_event(app, id) => {}
_ => {}
})
.on_tray_icon_event(|tray, event| {
@@ -1425,6 +1431,9 @@ pub fn run() {
})
.build(app)?;
// El sensor del rastreador: listener de vinculación + hilo de medición.
tracker::iniciar(app.handle());
Ok(())
})
.on_window_event(|window, event| {