164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
import datetime
|
|
import shelve
|
|
import os
|
|
import time
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
|
|
DB_FILE = 'alarm_data.db'
|
|
|
|
def get_db_path():
|
|
"""Obtiene la ruta completa para el archivo shelve."""
|
|
return os.path.join(os.path.dirname(os.path.abspath(__file__)), DB_FILE)
|
|
|
|
def load_alarms():
|
|
"""Carga las alarmas con un sistema de reintentos por si el archivo está ocupado."""
|
|
alarms = []
|
|
|
|
for _ in range(5):
|
|
try:
|
|
with shelve.open(get_db_path()) as db:
|
|
if 'alarms' in db:
|
|
alarms = list(db['alarms'])
|
|
break
|
|
except OSError as e:
|
|
time.sleep(0.1)
|
|
except Exception as e:
|
|
print(f"Error al cargar alarmas: {e}")
|
|
break
|
|
return alarms
|
|
|
|
def save_alarms(alarms):
|
|
"""Guarda las alarmas con el mismo sistema de paciencia (reintentos)."""
|
|
for _ in range(5):
|
|
try:
|
|
with shelve.open(get_db_path(), writeback=True) as db:
|
|
db['alarms'] = alarms
|
|
break
|
|
except OSError:
|
|
time.sleep(0.1)
|
|
except Exception as e:
|
|
print(f"Error al guardar alarmas: {e}")
|
|
break
|
|
|
|
def add_alarm(hour, minute, message):
|
|
"""Añade una nueva alarma y la guarda."""
|
|
alarms = load_alarms()
|
|
new_id = max([a['id'] for a in alarms] + [0]) + 1
|
|
|
|
new_alarm = {
|
|
'id': new_id,
|
|
'hour': int(hour),
|
|
'minute': int(minute),
|
|
'message': message,
|
|
'active': True
|
|
}
|
|
alarms.append(new_alarm)
|
|
save_alarms(alarms)
|
|
return alarms
|
|
|
|
def delete_alarm(alarm_id):
|
|
"""Elimina una alarma por su ID."""
|
|
alarms = load_alarms()
|
|
alarms = [alarm for alarm in alarms if alarm['id'] != alarm_id]
|
|
save_alarms(alarms)
|
|
return alarms
|
|
|
|
def toggle_alarm(alarm_id, active_state):
|
|
"""Cambia el estado activo de una alarma."""
|
|
alarms = load_alarms()
|
|
for alarm in alarms:
|
|
if alarm['id'] == alarm_id:
|
|
alarm['active'] = active_state
|
|
break
|
|
save_alarms(alarms)
|
|
return alarms
|
|
|
|
def postpone_alarm(alarm_id):
|
|
"""
|
|
Posiciona la alarma un minuto más tarde y la marca como activa.
|
|
IMPORTANTE: Esto sobrescribe la hora original de la alarma.
|
|
"""
|
|
alarms = load_alarms()
|
|
for alarm in alarms:
|
|
if alarm['id'] == alarm_id:
|
|
current_time = datetime.datetime(1, 1, 1, alarm['hour'], alarm['minute'])
|
|
new_time = current_time + datetime.timedelta(minutes=1)
|
|
|
|
alarm['hour'] = new_time.hour
|
|
alarm['minute'] = new_time.minute
|
|
alarm['active'] = True
|
|
break
|
|
save_alarms(alarms)
|
|
return alarms
|
|
|
|
def check_alarms(root, alarm_list_ref, notify_callback):
|
|
"""
|
|
Función principal de verificación de alarmas.
|
|
Utiliza una función de callback para mostrar el POP-UP.
|
|
"""
|
|
now = datetime.datetime.now()
|
|
current_hour = now.hour
|
|
current_minute = now.minute
|
|
|
|
alarms = load_alarms()
|
|
|
|
for alarm in alarms:
|
|
if alarm['active'] and alarm['hour'] == current_hour and alarm['minute'] == current_minute:
|
|
|
|
notify_callback(alarm)
|
|
|
|
alarm['active'] = False
|
|
|
|
save_alarms(alarms)
|
|
|
|
alarm_list_ref.update_list(alarms)
|
|
break
|
|
|
|
root.after(1000, check_alarms, root, alarm_list_ref, notify_callback)
|
|
|
|
|
|
|
|
class CustomAlarmDialog(tk.Toplevel):
|
|
"""Ventana de diálogo personalizada para la alarma con botones renombrados."""
|
|
def __init__(self, master, alarm_data):
|
|
super().__init__(master)
|
|
self.transient(master)
|
|
self.title("🔔 ¡ALARMA ACTIVA!")
|
|
self.result = None
|
|
|
|
self.grab_set()
|
|
self.focus_set()
|
|
|
|
self.geometry("300x150")
|
|
self.resizable(False, False)
|
|
|
|
message_text = f"ALARMA SONANDO!\n\nMensaje: {alarm_data['message']}"
|
|
|
|
tk.Label(self, text="⚠️", font=("Arial", 20)).pack(pady=5)
|
|
tk.Label(self, text=message_text, font=("Arial", 10, "bold")).pack(pady=5)
|
|
|
|
button_frame = tk.Frame(self)
|
|
button_frame.pack(pady=10)
|
|
|
|
tk.Button(button_frame, text="POSPONER (1 min)", command=lambda: self.on_action('posponer'),
|
|
bg='blue', fg='white').pack(side=tk.LEFT, padx=10)
|
|
|
|
tk.Button(button_frame, text="DETENER", command=lambda: self.on_action('detener'),
|
|
bg='red', fg='white').pack(side=tk.LEFT, padx=10)
|
|
|
|
self.protocol("WM_DELETE_WINDOW", lambda: self.on_action('detener'))
|
|
|
|
self.master.update_idletasks()
|
|
width = self.winfo_width()
|
|
height = self.winfo_height()
|
|
x = (self.master.winfo_width() // 2) - (width // 2)
|
|
y = (self.master.winfo_height() // 2) - (height // 2)
|
|
self.geometry('+%d+%d' % (self.master.winfo_x() + x, self.master.winfo_y() + y))
|
|
|
|
self.master.wait_window(self)
|
|
|
|
def on_action(self, action):
|
|
self.result = action
|
|
self.grab_release()
|
|
self.destroy() |