import curses from datetime import datetime, date, timedelta class InputHandling: def _handle_active_alarms_input(self, key): """Handle input for active alarms view""" if not self.active_alarms: # No active alarms, return to clock view self.current_view = 'CLOCK' return # Get the first (or only) active alarm alarm_id = list(self.active_alarms.keys())[0] if key == ord('s'): # Snooze # Send snooze command to control queue self.control_queue.put({ 'type': 'snooze', 'alarm_id': alarm_id }) # Remove from active alarms del self.active_alarms[alarm_id] # Optional: show a snooze confirmation self._show_error("Alarm Snoozed") elif key == ord('d'): # Dismiss # Send dismiss command to control queue self.control_queue.put({ 'type': 'dismiss', 'alarm_id': alarm_id }) # Remove from active alarms del self.active_alarms[alarm_id] # Return to clock view self.current_view = 'CLOCK' def _handle_clock_input(self, key): """Handle input on the clock view""" if key == ord('a'): self.current_view = 'ADD_ALARM' elif key == ord('s'): self.current_view = 'LIST_ALARMS' self.alarm_list = self.storage.get_saved_alerts() def _handle_add_alarm_input(self, key): """Handle input for alarm creation""" if not hasattr(self, 'alarm_draft'): self.alarm_draft = { 'hour': datetime.now().hour, 'minute': datetime.now().minute, 'name': 'New Alarm', 'enabled': True, 'date': None, 'weekdays': [], 'current_weekday': 0, # Add this to track currently selected weekday 'editing_name': False, 'temp_name': '' } alarm = self.alarm_draft # Escape key handling if key == 27: # ESC if alarm['editing_name']: # Cancel name editing alarm['name'] = alarm['temp_name'] alarm['editing_name'] = False else: # Return to clock view self.current_view = 'CLOCK' return # Enter key handling if key == 10: # ENTER if alarm['editing_name']: # Finish name editing alarm['editing_name'] = False self.selected_item = 0 else: # Save alarm try: alarm_data = { "name": alarm['name'], "time": f"{alarm['hour']:02d}:{alarm['minute']:02d}:00", "enabled": alarm['enabled'], "repeat_rule": { "type": "weekly" if alarm['weekdays'] else "once", "days_of_week": [self.weekday_names[day].lower() for day in alarm['weekdays']], "at": alarm['date'].strftime("%Y-%m-%d") if alarm['date'] and not alarm['weekdays'] else None } } self.storage.save_new_alert(alarm_data) self.current_view = 'CLOCK' except Exception as e: self._show_error(str(e)) return # Move selection using Left (h) and Right (l) if not alarm['editing_name']: if key in [ord('h'), curses.KEY_LEFT]: self.selected_item = (self.selected_item - 1) % 6 elif key in [ord('l'), curses.KEY_RIGHT]: self.selected_item = (self.selected_item + 1) % 6 # Handle numeric values (Hour, Minute, Date) if key in [ord('k'), curses.KEY_UP, ord('j'), curses.KEY_DOWN]: is_up = key in [ord('k'), curses.KEY_UP] delta = 1 if is_up else -1 if self.selected_item == 0: # Hour alarm['hour'] = (alarm['hour'] + delta) % 24 elif self.selected_item == 1: # Minute alarm['minute'] = (alarm['minute'] + delta) % 60 elif self.selected_item == 2: # Date if not alarm['date']: alarm['date'] = datetime.now().date() else: try: if not hasattr(self, 'date_edit_pos'): self.date_edit_pos = 2 # Default to editing the day current_date = alarm['date'] if self.date_edit_pos == 0: # Year alarm['date'] = current_date.replace(year=max(current_date.year + delta, datetime.now().year)) elif self.date_edit_pos == 1: # Month new_month = max(1, min(12, current_date.month + delta)) max_day = (datetime(current_date.year, new_month, 1) + timedelta(days=31)).replace(day=1) - timedelta(days=1) alarm['date'] = current_date.replace(month=new_month, day=min(current_date.day, max_day.day)) elif self.date_edit_pos == 2: # Day max_day = (datetime(current_date.year, current_date.month, 1) + timedelta(days=31)).replace(day=1) - timedelta(days=1) alarm['date'] = current_date.replace(day=max(1, min(max_day.day, current_date.day + delta))) except ValueError as e: self._show_error(str(e)) # Weekday Selection elif self.selected_item == 3: # When weekdays are selected if key in [ord('h'), curses.KEY_LEFT]: # Move selection left alarm['current_weekday'] = (alarm['current_weekday'] - 1) % 7 elif key in [ord('l'), curses.KEY_RIGHT]: # Move selection right alarm['current_weekday'] = (alarm['current_weekday'] + 1) % 7 elif key == 32: # SPACE to toggle selection current_day = alarm['current_weekday'] if current_day in alarm['weekdays']: alarm['weekdays'].remove(current_day) else: alarm['weekdays'].append(current_day) alarm['weekdays'].sort() # Clear date if weekdays are selected if alarm['weekdays']: alarm['date'] = None # Name Editing elif self.selected_item == 4: if key == 32: # SPACE to start editing if not alarm['editing_name']: alarm['editing_name'] = True alarm['temp_name'] = alarm['name'] alarm['name'] = '' elif alarm['editing_name']: if key == curses.KEY_BACKSPACE or key == 127: alarm['name'] = alarm['name'][:-1] elif 32 <= key <= 126: # Printable ASCII alarm['name'] += chr(key) # Enabled/Disabled Toggle elif self.selected_item == 5 and key == 32: alarm['enabled'] = not alarm['enabled'] def _handle_list_alarms_input(self, key): """Handle input for alarm list view""" total_items = len(self.alarm_list) + 1 # +1 for "Add new alarm" option if key == 27: # ESC self.current_view = 'CLOCK' elif key in [ord('j'), curses.KEY_DOWN]: self.selected_item = (self.selected_item + 1) % total_items elif key in [ord('k'), curses.KEY_UP]: self.selected_item = (self.selected_item - 1) % total_items elif key == ord('d'): # Only delete if a real alarm is selected (not the "Add new" option) if self.selected_item < len(self.alarm_list) and self.alarm_list: try: alarm_to_delete = self.alarm_list[self.selected_item] self.storage.remove_saved_alert(alarm_to_delete['id']) self.alarm_list = self.storage.get_saved_alerts() # Adjust selected item if needed if self.selected_item >= len(self.alarm_list): self.selected_item = len(self.alarm_list) except Exception as e: self._show_error(f"Failed to delete alarm: {e}") elif key in [ord('a'), 10]: # 'a' or Enter if self.selected_item == len(self.alarm_list): # "Add new alarm" option selected self.current_view = 'ADD_ALARM' else: # TODO: Implement alarm editing self._show_error("Alarm editing not implemented yet")