diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2016-03-18 10:17:55 -0500 |
---|---|---|
committer | Robert Tari <robert@tari.in> | 2021-07-05 00:44:01 +0200 |
commit | e47d49aca4da2d97c06acccc967abdf5698b044d (patch) | |
tree | d3edead4a7396f959706242fed978f6bc0a9c238 /src/menu.cpp | |
parent | 179bbad3a5c1c12abb36dc1c3702cb50b6be8f2e (diff) | |
download | ayatana-indicator-datetime-e47d49aca4da2d97c06acccc967abdf5698b044d.tar.gz ayatana-indicator-datetime-e47d49aca4da2d97c06acccc967abdf5698b044d.tar.bz2 ayatana-indicator-datetime-e47d49aca4da2d97c06acccc967abdf5698b044d.zip |
get event selection up-to-date with the spec, including showing in-progress events. add unit tests to cover event priority and display order.
Diffstat (limited to 'src/menu.cpp')
-rw-r--r-- | src/menu.cpp | 111 |
1 files changed, 93 insertions, 18 deletions
diff --git a/src/menu.cpp b/src/menu.cpp index d19ad73..0cd3f9b 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -22,6 +22,8 @@ #include <datetime/state.h> #include <glib/gi18n.h> #include <gio/gio.h> +#include <algorithm> +#include <iterator> #include <vector> extern "C" @@ -58,11 +60,90 @@ GMenuModel* Menu::menu_model() return G_MENU_MODEL(m_menu); } +/** + * To avoid a giant menu on the PC, and to avoid pushing lower menu items + * off-screen on the phone, the menu should show the + * next five calendar events, if any. + * + * The list might include multiple occurrences of the same event (bug 1515821). + */ +std::vector<Appointment> +Menu::get_display_appointments(const std::vector<Appointment>& appointments_in, + const DateTime& now, + unsigned int max_items) +{ + std::vector<Appointment> appointments; + std::copy_if(appointments_in.begin(), + appointments_in.end(), + std::back_inserter(appointments), + [now](const Appointment& a){return a.end >= now;}); + + if (appointments.size() > max_items) + { + const auto next_minute = now.add_full(0,0,0,0,1,-now.seconds()); + const auto start_of_day = now.start_of_day(); + const auto end_of_day = now.end_of_day(); + + /* + * If there are more than five, the events shown should be, in order of priority: + * 1. any events that start or end (bug 1329048) after the current minute today; + * 2. any full-day events that span all of today (bug 1302004); + * 3. any events that start or end tomorrow; + * 4. any events that start or end the day after tomorrow; and so on. + */ + auto compare = [next_minute, start_of_day, end_of_day]( + const Appointment& a, + const Appointment& b) + { + const bool a_later_today = (a.begin >= next_minute) || (a.end <= end_of_day); + const bool b_later_today = (b.begin >= next_minute) || (b.end <= end_of_day); + if (a_later_today != b_later_today) + return a_later_today; + + const bool a_full_day_today = (a.begin <= start_of_day) && (end_of_day <= a.end); + const bool b_full_day_today = (b.begin <= start_of_day) && (end_of_day <= b.end); + if (a_full_day_today != b_full_day_today) + return a_full_day_today; + + const bool a_after_today = (a.begin > end_of_day) || (a.end > end_of_day); + const bool b_after_today = (a.begin > end_of_day) || (a.end > end_of_day); + if (a_after_today != b_after_today) + return a_after_today; + if (a.begin != b.begin) + return a.begin < b.begin; + if (b.end != b.end) + return a.end < b.end; + + return false; + }; + std::sort(appointments.begin(), appointments.end(), compare); + appointments.resize(max_items); + } + + /* + * However, the display order should be the reverse: full-day events + * first (since they start first), part-day events afterward in + * chronological order. If multiple events have exactly the same start+end + * time, they should be sorted alphabetically. + */ + auto compare = [](const Appointment& a, const Appointment& b) + { + if (a.begin != b.begin) + return a.begin < b.begin; + + if (a.end != b.end) + return a.end < b.end; + + return a.summary < b.summary; + }; + std::sort(appointments.begin(), appointments.end(), compare); + return appointments; +} + /**** ***** ****/ - #define ALARM_ICON_NAME "alarm-clock" #define CALENDAR_ICON_NAME "calendar" @@ -150,25 +231,19 @@ protected: void update_upcoming() { - // The usual case is on desktop (and /only/ case on phone) - // is that we're looking at the current date and want to see - // "the next five calendar events, if any." - // - // However on the Desktop when the user clicks onto a different - // calendar date, show the next five calendar events starting - // from the beginning of that clicked day. - DateTime begin; + // The usual case is to show events germane to the current time. + // However when the user clicks onto a different calendar date, + // we pick events starting from the beginning of that clicked day. const auto now = m_state->clock->localtime(); const auto calendar_day = m_state->calendar_month->month().get(); - if ((profile() == Desktop) && !DateTime::is_same_day(now, calendar_day)) - begin = calendar_day.start_of_day(); - else - begin = now.start_of_minute(); - - std::vector<Appointment> upcoming; - for(const auto& a : m_state->calendar_upcoming->appointments().get()) - if (begin <= a.begin) - upcoming.push_back(a); + const auto begin = DateTime::is_same_day(now, calendar_day) + ? now.start_of_minute() + : calendar_day.start_of_day(); + + auto upcoming = get_display_appointments( + m_state->calendar_upcoming->appointments().get(), + begin + ); if (m_upcoming != upcoming) { |