Inicio Apuntes FPApuntes DAWEstira las piernas. Aplicación de escritorio para recordar las pausas

Estira las piernas. Aplicación de escritorio para recordar las pausas

Publicado por
about estira las piernas

Una vez más aquí. Después de cambiar de hosting esta web, aquí va la primera publicación. Este va a ser un artículo sobre una pequeña aplicación que me parece que necesito tener instalada en mis equipos para recordarme que cada 40 o 50 minutos debo levantarme un rato. Esto es algo que nos pasa a todos los que pasamos muchas horas delante de las pantallas … y no hacerlo acaba pasando factura. Sé que existen miles de aplicaciones de este estilo, pero para probar algunas cosas de este equipo desde el que escribo pues me hice la mía … que bauticé como «Estira las piernas«.

En las siguientes líneas vamos a explicar paso a paso cómo se ha desarrollado «Estira las piernas», que es una aplicación de escritorio open source escrita en Python con tkinter para Ubuntu. Como decía el único objetivo de esta aplicación es recordar al usuario que debe levantarse, estirar las piernas y descansar la vista durante un rato. A continuación repasaremos su objetivo, su arquitectura modular y las decisiones de diseño más relevantes del código fuente.

Por qué necesitas una app como «Estira las piernas» si trabajas frente al ordenador

estira las piernas logo

Cualquiera que trabaje frente a un ordenador conoce la escena: llevas tres o cuatro horas concentrado, la espalda protesta, los ojos pican y ni siquiera recuerdas la última vez que te levantaste de la silla pues tu culo hace dos horas que ya no lo notas. La Organización Mundial de la Salud y numerosos estudios de salud laboral repiten el mismo consejo: levántate cada 45‑60 minutos, camina unos pasos y estira el cuerpo. Sin embargo, en la práctica nadie lo cumple porque la concentración devora la noción del tiempo. El sedentarismo prolongado se asocia con dolor de espalda, problemas circulatorios, fatiga visual y riesgo cardiovascular a largo plazo.

Estira las piernas nació exactamente de este tipo de casos, de los que tras el paso de los años, y tras ignorar estos consejos, comienzo a notar el error que he cometido. Por eso, el objetivo de esta aplicación es sencillo: crear una aplicación de escritorio ligera y nativa para Ubuntu que recordase al usuario que es hora de moverse. Sin navegador abierto, sin dependencias pesadas, sin cuentas ni suscripciones. Solo Python, tkinter y las herramientas que ya vienen con cualquier instalación de Ubuntu.

Para qué sirve Estira las piernas: objetivo y funcionalidades principales

El programa persigue tres metas concretas:

1. Recordar periódicamente al usuario que debe levantarse, mediante una notificación de escritorio nativa y un sonido configurable. El intervalo por defecto es de 45 minutos, pero se puede ajustar entre 5 y 240 minutos según las necesidades de cada persona.

2. Ofrecer un modo Pomodoro integrado, con ciclos de trabajo y descanso configurables. Al terminar un ciclo de trabajo se abre una ventana a pantalla completa que obliga al usuario a descansar durante el tiempo configurado, reforzando el hábito de forma visual e inequívoca … vamos que se hace más difícil pasar del aviso. Esta técnica de gestión del tiempo, conocida como técnica Pomodoro, divide la jornada en bloques de concentración seguidos de pausas breves.

3. Registrar estadísticas de pausas activas para que el usuario vea cuántas pausas ha realizado hoy, su racha de días consecutivos y el tiempo activo desde la primera pausa. Tener datos visibles creo que puede motivar a mantener la constancia.

Todo esto vive en la bandeja del sistema de GNOME, con un par de atajos de teclado globales para no interrumpir el flujo de trabajo al interactuar con la app. La aplicación es completamente gratuita, open source y no requiere conexión a internet.

Cómo está estructurado el código fuente en Python: arquitectura modular

Una de las decisiones que tomé al poco tiempo de empezar a escribir el código, durante el desarrollo, fue la de modularizar el código en lugar de mantener todo en un único archivo monolítico. La versión actual está organizada en una carpeta ‘src/’ con diez módulos Python. Cada uno con una responsabilidad clara y bien definida.

Tengo que aclarar que aquí no voy a colocar el código del programa, ya que entre una cosa y otra se quedaría un artículo kilométrico, y tampoco es plan. El código completo de la aplicación se va a encontrar en el repositorio de GitHub que voy a colocar al final del artículo.

El punto de entrada del programa es el archivo ‘estira_las_piernas.py’, que apenas supera las 30 líneas: crea la ventana raíz de tkinter, instancia la clase principal y gestiona señales del sistema (SIGINT y SIGTERM) para un cierre limpio.

Constantes y configuración global (`constantes.py`)

En este módulo se definen todas las constantes globales del proyecto: intervalos de tiempo por defecto, rutas de los archivos de configuración y estadísticas, el diccionario de sonidos del sistema y los atajos de teclado predeterminados. También contiene las importaciones opcionales de GObject Introspection (‘AppIndicator3’, ‘Gtk’, ‘GLib’, ‘Keybinder’). Estas bibliotecas se importan dentro de un bloque `try/except` porque no todos los sistemas Ubuntu las tienen instaladas. Se inicializan a `None` con tipo `Any` antes del intento de importación para que los analizadores estáticos como Pylance no generen advertencias de «posiblemente desvinculado».

Este patrón de importación defensiva permite que la aplicación funcione en modo degradado: sin ‘AppIndicator3’ no aparece el icono en la bandeja, sin `Keybinder` no hay atajos globales, pero el temporizador de pausas activas sigue funcionando perfectamente.

Persistencia de datos con JSON (`config.py` y `estadisticas.py`)

La configuración del usuario (intervalo, sonido seleccionado, atajos personalizados, estado del modo Pomodoro) se van a guardar en ‘~/.config/estira-las-piernas/config.json‘. El módulo ‘config.py’ contiene dos funciones: `cargar()` y `guardar()`. Usa ‘pathlib.Path’ para construir las rutas de forma segura y ‘json’ para serializar.

Las estadísticas (estadisticas.py) siguen el mismo patrón pero con la lógica a mayores. La clase Estadisticas registra cada pausa con marca de tiempo, calcula la racha de días consecutivos recorriendo las fechas en orden inverso y mide el tiempo activo restando la hora de la primera pausa del día a la hora actual.

Sonidos y notificaciones de escritorio en Linux (`sonido.py` y `notificaciones.py`)

El módulo de sonido implementa un sistema de fallback encadenado que garantiza compatibilidad con distintas configuraciones de Ubuntu. Primero intenta reproducir el archivo de audio con paplay (PulseAudio), después con aplay (ALSA, solo para archivos WAV), luego con canberra-gtk-play y, si ningún reproductor está disponible, emite un pitido de terminal. Cada reproductor se busca en el PATH del sistema con shutil.which() antes de intentar ejecutarlo. Esto hace que la app funcione en prácticamente cualquier distribución de Linux basada en Ubuntu sin que el usuario tenga que instalar paquetes a mayores.

El módulo de notificaciones de escritorio sigue una filosofía similar al anterior. Si el comando notify-send está disponible, se usa para mostrar una notificación nativa del escritorio GNOME. Si no, se recurre a un messagebox de tkinter como último recurso.

Atajos de teclado globales en GNOME con Keybinder3 (`atajos.py`)

Este módulo encapsula las llamadas a Keybinder en tres funciones: inicializar(), vincular() y desvincular(). Todas comprueban primero que la biblioteca esté disponible antes de hacer nada. Los atajos predeterminados son ‘Ctrl+Alt+P’ para iniciar/detener el temporizador y ‘Ctrl+Alt+S’ para mostrar/ocultar la ventana. El usuario puede cambiarlos desde la pestaña de Atajos en la interfaz, y los nuevos valores persisten gracias al archivo de configuración.

Cómo integrar un icono en la bandeja del sistema de Ubuntu (`bandeja.py`)

La clase BandejaSistema crea un AppIndicator3.Indicator con un menú contextual GTK que ofrece tres acciones: mostrar/ocultar la ventana, iniciar/detener el temporizador y salir de la aplicación. El bucle de eventos de GTK (GLib.MainLoop) se ejecuta en un hilo independiente para no bloquear el mainloop de tkinter, que es el bucle principal de la interfaz gráfica.

Un detalle importante es que la referencia al bucle GTK se almacena en self._bucle y se reutiliza en el método detener(). Esto corrige un bug anterior donde se creaba una nueva instancia de GLib.MainLoop() al intentar detenerlo, lo que dejaba el hilo corriendo indefinidamente en segundo plano, y terminaba siendo un problema para el usuario y la ejecución del programa.

Interfaz gráfica moderna con tkinter y TTK (`estilo.py`)

Interfaz de la aplicación para tomar descansos

La función configurar_estilo() aplica el tema clam de TTK personalizado con una paleta de colores un poco diferente a la básica de tkinter. Esta incluye un fondo grisáceo suave, tarjetas blancas, tipografía legible, texto oscuro y botones con acento azul. Aquí se define estilos específicos para títulos, subtítulos, etiquetas de estado y un estilo Accent.TButton con estados visuales para hover y pressed. El resultado es un aspecto visual limpio y sin necesidad de frameworks CSS externos ni Electron.

Ventana fullscreen de descanso con cuenta atrás (`ventana_descanso.py`)

Pantalla de descanso

Este módulo implementa la ventana de descanso a pantalla completa que aparece cuando termina un ciclo de trabajo en modo Pomodoro. Es una de las funcionalidades más visibles de la aplicación y está diseñada para que el usuario realmente se tome la pausa en lugar de ignorar la simple notificación.

La clase VentanaDescanso crea un tk.Toplevel con los atributos -fullscreen y -topmost, un fondo oscuro, y un diseño centrado que incluye un emoji motivador, el mensaje «¡Hora de descansar!», una cuenta atrás grande en azul y una indicación para saltar el descanso con la tecla Escape.

La cuenta atrás se actualiza cada segundo usando el método ventana.after() de tkinter. Cuando llega a cero, la ventana se destruye automáticamente y ejecuta un callback que notifica a la aplicación principal para que retome el ciclo de trabajo. El protocolo WM_DELETE_WINDOW está bloqueado para evitar que el usuario cierre la ventana con Alt+F4, obligándolo a completar el descanso o conscientemente pulsar Escape si realmente necesita volver al trabajo.

Clase principal: la lógica del temporizador y la interfaz con pestañas (aplicacion.py)

Con casi 700 líneas, esta es la clase más grande del proyecto. AplicacionRecordatorioEstiramiento construye la interfaz con seis pestañas (Temporizador, Pomodoro, Sonido, Estadísticas, Atajos y Acerca de), gestiona el ciclo de vida del temporizador y coordina todos los módulos auxiliares.

El temporizador utiliza el método ventana_raiz.after() de tkinter para programar callbacks de forma asíncrona sin bloquear la interfaz gráfica. Cuando el usuario pulsa «Iniciar», el método ‘_programar_siguiente()’ calcula el intervalo de la fase actual (trabajo o descanso en modo Pomodoro, o el intervalo fijo en modo normal), programa el callback ‘_al_recordatorio()’ y arranca la actualización visual de la cuenta atrás cada segundo.

El método ‘_al_recordatorio()‘ es el corazón de la lógica de la aplicación: registra la pausa en las estadísticas, decide si debe alternar de fase en modo Pomodoro y desencadena la notificación, el sonido y en el caso del fin de un ciclo de trabajo, la apertura de la ventana de descanso fullscreen. Cuando la ventana de descanso se cierra, el callback ‘_al_finalizar_descanso()‘ retoma el control, cambia a fase de trabajo y reprograma automáticamente el siguiente ciclo.

Decisiones de diseño más importantes del proyecto

  • Cero dependencias de pip. Todo el proyecto funciona con la biblioteca estándar de Python más las bibliotecas opcionales de GObject Introspection que ya están disponibles en los repositorios de Ubuntu. No es necesario crear un entorno virtual ni ejecutar `pip install`.
  • Degradación elegante. Si falta ‘AppIndicator3’, la app funciona sin bandeja. Si falta ‘Keybinder’, funciona sin atajos globales. En caso de faltar ‘paplay‘, intenta otro reproductor de audio. La aplicación siempre funciona en algún nivel, adaptándose al entorno del usuario.
  • Manejo de señales del sistema. Se capturan ‘SIGINT’ y ‘SIGTERM’ para guardar la configuración y cerrar limpiamente, mostrando un mensaje amigable en lugar de un traceback de Python.
  • Código modular y mantenible. Cada módulo tiene una única responsabilidad y podría testearse de forma aislada. La clase principal coordina pero delega los detalles de bajo nivel a los módulos especializados.

Tecnologías utilizadas

TecnologíaUso del proyecto
Python3Lenguaje principal
tkinter/TTKInterfaz gráfica de escritorio
AppIndicator3Icono de la bandeja del sistema GNOME
GLib.MainLoopBucle de eventos GTK en hilo secundario
Keybinder3Atajo de teclado globales
Notify-sendNotificaciones nativas del escritorio
Papaly / aplayReproducción de sonidos de aviso
JSONPersistencia de configuración y estadísticas

Conclusión: una app de escritorio útil sin Electron ni frameworks pesados

Estira las piernas es una pequeña aplicación que me puede resultar útil, y que creo que viene a demostrar que no hace falta Electron ni un framework JavaScript pesado para crear una aplicación de escritorio útil en Linux. Con Python, tkinter y las APIs nativas de GNOME se consigue una herramienta ligera, funcional y visualmente agradable que cumple un único propósito: recordarte que tu cuerpo necesita moverse antes de que se te quede pegado el culo a la silla.

El código se intentó diseñar para ser legible, mantenible y resistente a entornos con dependencias parciales, priorizando siempre que la experiencia del usuario sea fluida independientemente de lo que tenga instalado en su sistema.

El proyecto es open source y está disponible en GitHub. Ahí se encuentra la documentación del archivo README.md donde se puede ver cómo ejecutar o instalar el programa en un sistema Ubuntu.

Si trabajas muchas horas frente al ordenador y usas Ubuntu, pruébalo: tu espalda te lo agradecerá.

También te puede interesar ...

Deja un comentario

* Al utilizar este formulario, aceptas que este sitio web almacene y maneje tus datos.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Adblock Detectado!!

Ayúdanos deshabilitando la extensión AdBlocker de tu navegador para visitar esta web.
Si no sabes hacerlo en Chrome, consulta el siguiente enlace. Si utilizas Firefox, puedes consultar este otro enlace.
Esto mejorará tu experiencia en este sitio web.