feat: add bounded agenda view

Add a read-only 42-day occurrence agenda with keyboard navigation, six-week paging, exact return-to-grid focus, search and calendar overlays, and bounded recurrence expansion.

Keep agenda state outside persistence, document month-only mutations, and cover empty windows, filtering, overlays, navigation, rendering, and terminal restoration.
This commit is contained in:
2026-07-18 09:19:01 +01:00
parent 590db2f488
commit 8b6cf2e877
11 changed files with 609 additions and 16 deletions

View File

@@ -51,6 +51,17 @@ struct SearchResultItem {
bool recurring{false};
};
struct AgendaItem {
std::string focus_id;
std::string title;
std::chrono::year_month_day day;
std::optional<std::chrono::minutes> time_of_day;
bool all_day{false};
std::string location;
std::string calendar_id;
bool recurring{false};
};
struct ScreenState {
std::chrono::year_month visible_month{std::chrono::year{1970}, std::chrono::month{1}};
std::chrono::year_month_day selected_day{std::chrono::year{1970}, std::chrono::month{1},
@@ -73,6 +84,11 @@ struct ScreenState {
bool notification_is_error{false};
bool show_calendar_picker{false};
std::size_t calendar_index{0};
bool show_agenda{false};
std::chrono::year_month_day agenda_start_day{
std::chrono::year{1970}, std::chrono::month{1}, std::chrono::day{1}};
std::vector<AgendaItem> agenda_items;
std::size_t agenda_index{0};
};
// Render a complete frame. The result contains no cursor positioning, which
@@ -117,6 +133,7 @@ enum class Action {
undo,
redo,
search,
agenda,
calendars,
quit,
};

View File

@@ -48,6 +48,7 @@ public:
[[nodiscard]] bool calendar_picker_active() const noexcept {
return state_.show_calendar_picker;
}
[[nodiscard]] bool agenda_active() const noexcept { return state_.show_agenda; }
[[nodiscard]] const std::vector<Calendar>& calendars() const noexcept {
return calendars_;
}
@@ -89,6 +90,11 @@ private:
void begin_calendar_picker();
void close_calendar_picker();
void toggle_selected_calendar();
void begin_agenda();
void close_agenda();
void refresh_agenda();
void shift_agenda(int direction);
void choose_agenda_item();
[[nodiscard]] HistorySnapshot capture_history_snapshot() const;
void restore_history_snapshot(HistorySnapshot snapshot);
void push_history(std::vector<HistoryEntry>& history, HistoryEntry entry);