203 lines
8.8 KiB
Python
203 lines
8.8 KiB
Python
![]() |
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")
|