import curses 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""" 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 # Date editing mode if self.selected_item == 2: # Date field selected if not hasattr(self, 'date_edit_pos'): self.date_edit_pos = 2 # Default to day (2) if key == 32: # SPACE if alarm['date'] is None: alarm['date'] = datetime.now().date() else: alarm['date'] = None elif alarm['date'] is not None: if key in [ord('h'), curses.KEY_LEFT]: self.date_edit_pos = (self.date_edit_pos - 1) % 3 elif key in [ord('l'), curses.KEY_RIGHT]: self.date_edit_pos = (self.date_edit_pos + 1) % 3 elif key in [ord('j'), curses.KEY_DOWN, ord('k'), curses.KEY_UP]: is_up = key in [ord('k'), curses.KEY_UP] delta = 1 if is_up else -1 try: 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)) return # Navigation and editing if not alarm['editing_name']: if key in [ord('h'), curses.KEY_LEFT]: self.selected_item = (self.selected_item - 1) % 6 self.date_edit_pos = 2 # Reset to day when moving away elif key in [ord('l'), curses.KEY_RIGHT]: self.selected_item = (self.selected_item + 1) % 6 self.date_edit_pos = 2 # Reset to day when moving away # Up/Down for editing values if key in [ord('k'), curses.KEY_UP, ord('j'), curses.KEY_DOWN]: is_up = key in [ord('k'), curses.KEY_UP] if self.selected_item == 0: # Hour alarm['hour'] = (alarm['hour'] + (1 if is_up else -1)) % 24 elif self.selected_item == 1: # Minute alarm['minute'] = (alarm['minute'] + (1 if is_up else -1)) % 60 elif self.selected_item == 3: # Weekdays # Move selection through weekdays if 'current_weekday' not in alarm: alarm['current_weekday'] = 0 alarm['current_weekday'] = (alarm['current_weekday'] + (1 if is_up else -1)) % 7 # Space key for toggling/editing if key == 32: # SPACE if self.selected_item == 4: # Name if not alarm['editing_name']: alarm['editing_name'] = True alarm['temp_name'] = alarm['name'] alarm['name'] = '' elif self.selected_item == 5: # Enabled alarm['enabled'] = not alarm['enabled'] elif self.selected_item == 3: # Weekdays # Toggle current weekday current_day = alarm.get('current_weekday', 0) 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 if 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) 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")