213 lines
9.0 KiB
Python
Raw Normal View History

2025-01-23 23:12:52 +02:00
import curses
from datetime import datetime, date, timedelta
import time
from threading import Thread
import sys
import os
from pathlib import Path
from alert_clients.alarm_api_client.alarm_api_client import AlarmApiClient
#from alarm_api_client.alarm_api_client import AlarmApiClient
from ncurses_ui import NcursesUI
from alert_logic import AlarmLogic
from ncurses_threads import NcursesThreads
from alarm_logger import AlarmLogger
class AlarmClock:
def __init__(self, stdscr):
# Initialize logging first
self.logger = AlarmLogger()
try:
self.stdscr = stdscr
self.api_client = AlarmApiClient("http://localhost:8000")
self.alarm_logic = AlarmLogic(self.api_client)
self.ncurses_ui = NcursesUI(stdscr)
self.ncurses_threads = NcursesThreads(self.alarm_logic)
self.alarms = []
self.running = True
self.selected_menu = 0
self.new_alarm_hour = 0
self.new_alarm_minute = 0
self.new_alarm_selected = 0
self.new_alarm_date = None
self.new_alarm_weekdays = []
self.weekday_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
self.current_alarm = None
self.current_alarm_process = False
self.snooze_minutes = 5
self.snooze_until = None
# Initialize curses
self.stdscr.keypad(1)
self.stdscr.timeout(100)
self.logger.log_system_error("Alarm Clock Initialized Successfully")
except Exception as e:
self.logger.log_system_error(f"Initialization Error: {str(e)}", exc_info=True)
raise
def show_error(self, message):
self.logger.log_system_error(message)
self.ncurses_ui.show_error(message)
def handle_add_alarm_input(self, key):
try:
if key == 27: # Escape
self.selected_menu = 0
self.logger.log_system_error("Add Alarm menu cancelled")
return
if key == 10: # Enter
try:
alarm_details = {
"hour": self.new_alarm_hour,
"minute": self.new_alarm_minute,
"date": self.new_alarm_date,
"weekdays": self.new_alarm_weekdays if self.new_alarm_weekdays else None
}
self.alarm_logic.create_alarm(
self.new_alarm_hour,
self.new_alarm_minute,
self.new_alarm_date,
self.new_alarm_weekdays if self.new_alarm_weekdays else None
)
self.logger.log_alarm_created(alarm_details)
self.alarms = self.api_client.get_alarms()
self.selected_menu = 0
except Exception as e:
self.show_error(f"Failed to create alarm: {str(e)}")
return
if key == curses.KEY_LEFT:
self.new_alarm_selected = (self.new_alarm_selected - 1) % 4
self.logger.log_system_error(f"Selected field changed to {self.new_alarm_selected}")
elif key == curses.KEY_RIGHT:
self.new_alarm_selected = (self.new_alarm_selected + 1) % 4
self.logger.log_system_error(f"Selected field changed to {self.new_alarm_selected}")
elif key == 32: # Space
if self.new_alarm_selected == 2: # Date
self.new_alarm_date = None
self.logger.log_system_error(f"Selected field changed to DATE")
elif self.new_alarm_selected == 3: # Weekdays
current_day = len(self.new_alarm_weekdays)
if current_day < 7:
if current_day in self.new_alarm_weekdays:
self.new_alarm_weekdays.remove(current_day)
else:
self.new_alarm_weekdays.append(current_day)
self.new_alarm_weekdays.sort()
elif key == curses.KEY_UP:
if self.new_alarm_selected == 0:
self.new_alarm_hour = (self.new_alarm_hour + 1) % 24
elif self.new_alarm_selected == 1:
self.new_alarm_minute = (self.new_alarm_minute + 1) % 60
elif self.new_alarm_selected == 2:
if not self.new_alarm_date:
self.new_alarm_date = date.today()
else:
self.new_alarm_date += timedelta(days=1)
elif key == curses.KEY_DOWN:
if self.new_alarm_selected == 0:
self.new_alarm_hour = (self.new_alarm_hour - 1) % 24
elif self.new_alarm_selected == 1:
self.new_alarm_minute = (self.new_alarm_minute - 1) % 60
elif self.new_alarm_selected == 2 and self.new_alarm_date:
self.new_alarm_date -= timedelta(days=1)
except Exception as e:
self.logger.log_system_error(f"Error in add alarm input: {str(e)}", exc_info=True)
def delete_selected_alarm(self):
try:
if self.alarms:
alarm = self.alarms[-1] # Get the last alarm
if self.api_client.delete_alarm(alarm["id"]):
self.logger.log_system_error(f"Deleted Alarm ID: {alarm['id']}")
self.alarm_logic.refresh_alarms()
else:
self.show_error("Failed to delete alarm")
except Exception as e:
self.logger.log_system_error(f"Delete alarm error: {str(e)}", exc_info=True)
self.show_error(f"Delete error: {str(e)}")
def handle_list_alarms_input(self, key):
try:
if key == 27: # Escape
self.selected_menu = 0
self.logger.log_system_error("List Alarms menu cancelled")
elif key == ord('d'):
self.logger.log_system_error("Attempting to delete last alarm")
self.delete_selected_alarm()
except Exception as e:
self.logger.log_system_error(f"Error in list alarms input: {str(e)}", exc_info=True)
def draw_main_clock(self):
self.ncurses_ui.draw_main_clock()
def draw_add_alarm(self):
self.ncurses_ui.draw_add_alarm()
def draw_list_alarms(self):
self.ncurses_ui.draw_list_alarms()
def run(self):
try:
# Start alarm checking thread
self.ncurses_threads.start_threads()
self.logger.log_system_error("Alarm checking threads started")
while self.running:
try:
# Clear and redraw the screen
self.stdscr.erase()
if self.selected_menu == 0:
self.draw_main_clock()
elif self.selected_menu == 1:
self.draw_add_alarm()
elif self.selected_menu == 2:
self.draw_list_alarms()
self.stdscr.refresh()
# Handle input with timeout
key = self.stdscr.getch()
if key != -1: # Key was pressed
if self.selected_menu == 0:
if key == ord('q'):
self.logger.log_system_error("Application quit requested")
self.alarm_logic.stop_alarm()
break
elif key == ord('a'):
self.selected_menu = 1
self.logger.log_system_error("Switched to Add Alarm menu")
elif key == ord('l'):
self.selected_menu = 2
self.logger.log_system_error("Switched to List Alarms menu")
elif key == ord('s'):
self.logger.log_system_error("Alarm stopped")
self.alarm_logic.stop_alarm()
elif key == ord('z'):
self.logger.log_alarm_snoozed(
"current_alarm",
self.snooze_minutes
)
self.alarm_logic.snooze_alarm()
elif self.selected_menu == 1:
self.handle_add_alarm_input(key)
elif self.selected_menu == 2:
self.handle_list_alarms_input(key)
except curses.error as e:
self.logger.log_system_error(f"Curses error: {str(e)}", exc_info=True)
self.running = False
raise Exception(f"Curses error: {str(e)}")
except Exception as e:
self.logger.log_system_error(f"Unhandled error in main run loop: {str(e)}", exc_info=True)
raise