Merge lp:~artmello/indicator-datetime/indicator-datetime-notfication_settings into lp:indicator-datetime

Proposed by Arthur Mello
Status: Merged
Approved by: Charles Kerr
Approved revision: 464
Merged at revision: 457
Proposed branch: lp:~artmello/indicator-datetime/indicator-datetime-notfication_settings
Merge into: lp:indicator-datetime
Diff against target: 809 lines (+296/-164)
11 files modified
debian/control (+2/-2)
include/datetime/settings-live.h (+12/-4)
include/datetime/settings-shared.h (+9/-2)
include/datetime/settings.h (+6/-1)
include/notifications/notifications.h (+6/-0)
src/notifications.cpp (+24/-1)
src/settings-live.cpp (+109/-49)
src/snap.cpp (+46/-20)
tests/test-notification.cpp (+22/-14)
tests/test-settings.cpp (+48/-71)
tests/test-sound.cpp (+12/-0)
To merge this branch: bzr merge lp:~artmello/indicator-datetime/indicator-datetime-notfication_settings
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
PS Jenkins bot continuous-integration Pending
Review via email: mp+298162@code.launchpad.net

Commit message

Update indicator-datetime to work with the new notification settings

Description of the change

Update indicator-datetime to work with the new notification settings

To post a comment you must log in.
Revision history for this message
Charles Kerr (charlesk) wrote :

Haven't tested, but code LGTM. A couple of optional minor suggestions inline.

The biggest takeaway that I'm getting from this patch is the gsettings-propertiescpp bridge code is too brittle. That's not new to this patch and isn't your problem; it's just become worse over time as we add more settings and I'll clean it up in a followup patch.

review: Approve
Revision history for this message
Charles Kerr (charlesk) wrote :

I don't understand the point of r456/r457 and would prefer they be backed out altogether. Surely the gsettings schema should be a hard requirement for us?

review: Needs Information
458. By Arthur Mello

Undo revisions 456/457

459. By Arthur Mello

Fix notifications so it respects if it should or not show bubbles or add to notification list

Revision history for this message
Arthur Mello (artmello) wrote :

> I don't understand the point of r456/r457 and would prefer they be backed out
> altogether. Surely the gsettings schema should be a hard requirement for us?

r458 reverted both r456 and r457 and unittests run fine on device (krillin, rc-proposed r369). This was added to silo 54 and, unfortunately, its build fails under all archs for Vivid, Xenial and Yakkety. Log file [0] for armhf/vivid (but the same error happens on all of them) shows that test-settings is failing with an exception related with missing 'com.canonical.indicator.datetime' gsetting schema. When we instantiate LiveSettings on that test, it will try to open the settings using that schema and that is causing the crash. Idea with r456/r457 was to lookup for the schema and skip settings test if it was missing. Any suggestions on how can we fix this build?

[0] https://launchpadlibrarian.net/268720228/buildlog_ubuntu-vivid-armhf.indicator-datetime_15.10+15.04.20160630-0ubuntu1_BUILDING.txt.gz

Revision history for this message
Arthur Mello (artmello) wrote :

Also r459 fix the control for displaying notification bubbles and adding notifications to messaging menu. Let me know what you think about it

Revision history for this message
Charles Kerr (charlesk) wrote :

> exception related with missing 'com.canonical.indicator.datetime' gsetting schema... any suggestions on how can we fix this build?

That's strange, tests/CMakeLists.txt already has rules in it to ensure the tests can find the schema, and this has been passing up until now.

Off the top of my head I don't know what's going wrong here. I'll see if I can reproduce in a vivid chroot that doesn't have indicator-datetime installed.

A couple of questions about schema lookups are inline below

review: Needs Information
Revision history for this message
Arthur Mello (artmello) wrote :

> That's strange, tests/CMakeLists.txt already has rules in it to ensure the
> tests can find the schema, and this has been passing up until now.
>
> Off the top of my head I don't know what's going wrong here. I'll see if I can
> reproduce in a vivid chroot that doesn't have indicator-datetime installed.

Yes, we were trying to find out what could be causing this after the changes on this MR but didnt find it yet.

> A couple of questions about schema lookups are inline below

I answered those

Revision history for this message
Arthur Mello (artmello) :
Revision history for this message
Charles Kerr (charlesk) wrote :

100% reproducible for me in a vivid chroot. One interesting clue, test-utils loads the same com.canonical.indicator.datetime schema, and /that/ test is passing. They use two different code paths to get there though. I feel like there's something simple here that we're both missing, so I'll stare at the screen a little more. :)

Thanks for explaining the plan with the relocatable schema, that part LGTM.

Revision history for this message
Charles Kerr (charlesk) wrote :

Okay, got a fix for it at http://paste.ubuntu.com/18201522/

The issue is that creating 'source' before calling SetUp() causes glib's schema search path to be created before GLibFixture::SetUp() sets the GSETTINGS_SEARCH_DIR environment variable to prepend our sandbox to the schema search path.

So, that's progress. After that fix I get a new & improved failure:
"Settings schema 'com.ubuntu.notifications.settings' is not installed"

Which I think is more straightforward, I think for /that/ I think we just need to add gsettings-ubuntu-touch-schemes (>= your-version-number) to debian/control

460. By Arthur Mello

Do not fail gracefully if gsettings schema is not installed

461. By Arthur Mello

Remove gsettings source call during unit tests
Set minimal version for gsettings-ubuntu-touch-schemas package

462. By Arthur Mello

Only wake device if bubbles notifications are enabled

463. By Arthur Mello

If in silent mode should only vibrate if the settings say so

464. By Arthur Mello

Should not use sounds notifications for calendar in silent mode

Revision history for this message
Charles Kerr (charlesk) wrote :

LGTM. Thanks Art :-)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2016-05-14 02:07:10 +0000
+++ debian/control 2016-07-04 23:46:11 +0000
@@ -15,7 +15,7 @@
15 liburl-dispatcher1-dev,15 liburl-dispatcher1-dev,
16 libproperties-cpp-dev,16 libproperties-cpp-dev,
17# for com.ubuntu.notifications.hub schema to pick up blacklist of apps that can't show notifications17# for com.ubuntu.notifications.hub schema to pick up blacklist of apps that can't show notifications
18 gsettings-ubuntu-schemas,18 gsettings-ubuntu-schemas (>= 0.0.7),
19# for the test harness:19# for the test harness:
20 libgtest-dev,20 libgtest-dev,
21 libdbustest1-dev,21 libdbustest1-dev,
@@ -47,7 +47,7 @@
47Architecture: any47Architecture: any
48Depends: ${shlibs:Depends}, 48Depends: ${shlibs:Depends},
49 ${misc:Depends},49 ${misc:Depends},
50 gsettings-ubuntu-schemas,50 gsettings-ubuntu-schemas (>= 0.0.7),
51 systemd | systemd-shim,51 systemd | systemd-shim,
52Recommends: indicator-applet | indicator-renderer,52Recommends: indicator-applet | indicator-renderer,
53 evolution-data-server,53 evolution-data-server,
5454
=== modified file 'include/datetime/settings-live.h'
--- include/datetime/settings-live.h 2016-02-02 00:07:18 +0000
+++ include/datetime/settings-live.h 2016-07-04 23:46:11 +0000
@@ -39,9 +39,11 @@
3939
40private:40private:
41 static void on_changed_ccid(GSettings*, gchar*, gpointer);41 static void on_changed_ccid(GSettings*, gchar*, gpointer);
42 static void on_changed_cunh(GSettings*, gchar*, gpointer);42 static void on_changed_cal_notification(GSettings*, gchar*, gpointer);
43 static void on_changed_general_notification(GSettings*, gchar*, gpointer);
43 void update_key_ccid(const std::string& key);44 void update_key_ccid(const std::string& key);
44 void update_key_cunh(const std::string& key);45 void update_key_cal_notification(const std::string& key);
46 void update_key_general_notification(const std::string& key);
4547
46 void update_custom_time_format();48 void update_custom_time_format();
47 void update_locations();49 void update_locations();
@@ -63,10 +65,16 @@
63 void update_alarm_duration();65 void update_alarm_duration();
64 void update_alarm_haptic();66 void update_alarm_haptic();
65 void update_snooze_duration();67 void update_snooze_duration();
66 void update_muted_apps();68 void update_cal_notification_enabled();
69 void update_cal_notification_sounds();
70 void update_cal_notification_vibrations();
71 void update_cal_notification_bubbles();
72 void update_cal_notification_list();
73 void update_vibrate_silent_mode();
6774
68 GSettings* m_settings;75 GSettings* m_settings;
69 GSettings* m_settings_cunh;76 GSettings* m_settings_cal_notification;
77 GSettings* m_settings_general_notification;
7078
71 // we've got a raw pointer here, so disable copying79 // we've got a raw pointer here, so disable copying
72 LiveSettings(const LiveSettings&) =delete;80 LiveSettings(const LiveSettings&) =delete;
7381
=== modified file 'include/datetime/settings-shared.h'
--- include/datetime/settings-shared.h 2016-02-02 00:07:18 +0000
+++ include/datetime/settings-shared.h 2016-07-04 23:46:11 +0000
@@ -52,7 +52,14 @@
52#define SETTINGS_ALARM_HAPTIC_S "alarm-haptic-feedback"52#define SETTINGS_ALARM_HAPTIC_S "alarm-haptic-feedback"
53#define SETTINGS_SNOOZE_DURATION_S "snooze-duration-minutes"53#define SETTINGS_SNOOZE_DURATION_S "snooze-duration-minutes"
5454
55#define SETTINGS_CUNH_SCHEMA_ID "com.ubuntu.notifications.hub"55#define SETTINGS_NOTIFY_APPS_SCHEMA_ID "com.ubuntu.notifications.settings.applications"
56#define SETTINGS_CUNH_BLACKLIST_S "blacklist"56#define SETTINGS_VIBRATE_SILENT_KEY "vibrate-silent-mode"
57#define SETTINGS_NOTIFY_SCHEMA_ID "com.ubuntu.notifications.settings"
58#define SETTINGS_NOTIFY_CALENDAR_PATH "/com/ubuntu/NotificationSettings/com.ubuntu.calendar/calendar/"
59#define SETTINGS_NOTIFY_ENABLED_KEY "enable-notifications"
60#define SETTINGS_NOTIFY_SOUNDS_KEY "use-sounds-notifications"
61#define SETTINGS_NOTIFY_VIBRATIONS_KEY "use-vibrations-notifications"
62#define SETTINGS_NOTIFY_BUBBLES_KEY "use-bubbles-notifications"
63#define SETTINGS_NOTIFY_LIST_KEY "use-list-notifications"
5764
58#endif // INDICATOR_DATETIME_SETTINGS_SHARED65#endif // INDICATOR_DATETIME_SETTINGS_SHARED
5966
=== modified file 'include/datetime/settings.h'
--- include/datetime/settings.h 2016-02-02 00:05:45 +0000
+++ include/datetime/settings.h 2016-07-04 23:46:11 +0000
@@ -62,7 +62,12 @@
62 core::Property<unsigned int> alarm_volume;62 core::Property<unsigned int> alarm_volume;
63 core::Property<unsigned int> alarm_duration;63 core::Property<unsigned int> alarm_duration;
64 core::Property<unsigned int> snooze_duration;64 core::Property<unsigned int> snooze_duration;
65 core::Property<std::set<std::pair<std::string,std::string>>> muted_apps;65 core::Property<bool> cal_notification_enabled;
66 core::Property<bool> cal_notification_sounds;
67 core::Property<bool> cal_notification_vibrations;
68 core::Property<bool> cal_notification_bubbles;
69 core::Property<bool> cal_notification_list;
70 core::Property<bool> vibrate_silent_mode;
66};71};
6772
68} // namespace datetime73} // namespace datetime
6974
=== modified file 'include/notifications/notifications.h'
--- include/notifications/notifications.h 2016-05-14 02:07:10 +0000
+++ include/notifications/notifications.h 2016-07-04 23:46:11 +0000
@@ -77,6 +77,12 @@
77 /** Sets the time-out callback. This will be called exactly once. */77 /** Sets the time-out callback. This will be called exactly once. */
78 void set_timeout_callback (std::function<void()>);78 void set_timeout_callback (std::function<void()>);
7979
80 /** Sets if a notification bubble should be displayed. */
81 void set_show_notification_bubble (bool show);
82
83 /** Sets if notification should be posted to messaging menu after it is closed. */
84 void set_post_to_messaging_menu (bool post);
85
8086
81private:87private:
82 friend class Engine;88 friend class Engine;
8389
=== modified file 'src/notifications.cpp'
--- src/notifications.cpp 2016-05-14 02:07:10 +0000
+++ src/notifications.cpp 2016-07-04 23:46:11 +0000
@@ -61,6 +61,8 @@
61 std::vector<std::pair<std::string,std::string>> m_actions;61 std::vector<std::pair<std::string,std::string>> m_actions;
62 std::function<void(const std::string&)> m_closed_callback;62 std::function<void(const std::string&)> m_closed_callback;
63 std::function<void()> m_timeout_callback;63 std::function<void()> m_timeout_callback;
64 bool m_show_notification_bubble;
65 bool m_post_to_messaging_menu;
64};66};
6567
66Builder::Builder():68Builder::Builder():
@@ -126,6 +128,18 @@
126 impl->m_start_time = time;128 impl->m_start_time = time;
127}129}
128130
131void
132Builder::set_show_notification_bubble (bool show)
133{
134 impl->m_show_notification_bubble = show;
135}
136
137void
138Builder::set_post_to_messaging_menu (bool post)
139{
140 impl->m_post_to_messaging_menu = post;
141}
142
129/***143/***
130****144****
131***/145***/
@@ -262,7 +276,12 @@
262 m_notifications[key] = { nn, info };276 m_notifications[key] = { nn, info };
263 g_signal_connect (nn.get(), "closed",277 g_signal_connect (nn.get(), "closed",
264 G_CALLBACK(on_notification_closed), this);278 G_CALLBACK(on_notification_closed), this);
265 279
280 if (!info.m_show_notification_bubble) {
281 post(info);
282 return ret;
283 }
284
266 GError * error = nullptr;285 GError * error = nullptr;
267 if (notify_notification_show(nn.get(), &error))286 if (notify_notification_show(nn.get(), &error))
268 {287 {
@@ -282,6 +301,10 @@
282301
283 std::string post(const Builder::Impl& data)302 std::string post(const Builder::Impl& data)
284 {303 {
304 if (!data.m_post_to_messaging_menu) {
305 return "";
306 }
307
285 if (!m_messaging_app) {308 if (!m_messaging_app) {
286 return std::string();309 return std::string();
287 }310 }
288311
=== modified file 'src/settings-live.cpp'
--- src/settings-live.cpp 2016-02-03 20:25:19 +0000
+++ src/settings-live.cpp 2016-07-04 23:46:11 +0000
@@ -29,16 +29,20 @@
2929
30LiveSettings::~LiveSettings()30LiveSettings::~LiveSettings()
31{31{
32 g_clear_object(&m_settings_cunh);32 g_clear_object(&m_settings_general_notification);
33 g_clear_object(&m_settings_cal_notification);
33 g_clear_object(&m_settings);34 g_clear_object(&m_settings);
34}35}
3536
36LiveSettings::LiveSettings():37LiveSettings::LiveSettings():
37 m_settings(g_settings_new(SETTINGS_INTERFACE)),38 m_settings(g_settings_new(SETTINGS_INTERFACE)),
38 m_settings_cunh(g_settings_new(SETTINGS_CUNH_SCHEMA_ID))39 m_settings_cal_notification(g_settings_new_with_path(SETTINGS_NOTIFY_SCHEMA_ID, SETTINGS_NOTIFY_CALENDAR_PATH)),
40 m_settings_general_notification(g_settings_new(SETTINGS_NOTIFY_APPS_SCHEMA_ID))
39{41{
40 g_signal_connect (m_settings, "changed", G_CALLBACK(on_changed_ccid), this);42
41 g_signal_connect (m_settings_cunh, "changed", G_CALLBACK(on_changed_cunh), this);43 g_signal_connect (m_settings, "changed", G_CALLBACK(on_changed_ccid), this);
44 g_signal_connect (m_settings_cal_notification, "changed", G_CALLBACK(on_changed_cal_notification), this);
45 g_signal_connect (m_settings_general_notification, "changed", G_CALLBACK(on_changed_general_notification), this);
4246
43 // init the Properties from the GSettings backend47 // init the Properties from the GSettings backend
44 update_custom_time_format();48 update_custom_time_format();
@@ -61,7 +65,12 @@
61 update_alarm_duration();65 update_alarm_duration();
62 update_alarm_haptic();66 update_alarm_haptic();
63 update_snooze_duration();67 update_snooze_duration();
64 update_muted_apps();68 update_cal_notification_enabled();
69 update_cal_notification_sounds();
70 update_cal_notification_vibrations();
71 update_cal_notification_bubbles();
72 update_cal_notification_list();
73 update_vibrate_silent_mode();
6574
66 // now listen for clients to change the properties s.t. we can sync update GSettings75 // now listen for clients to change the properties s.t. we can sync update GSettings
6776
@@ -69,17 +78,6 @@
69 g_settings_set_string(m_settings, SETTINGS_CUSTOM_TIME_FORMAT_S, value.c_str());78 g_settings_set_string(m_settings, SETTINGS_CUSTOM_TIME_FORMAT_S, value.c_str());
70 });79 });
7180
72 muted_apps.changed().connect([this](const std::set<std::pair<std::string,std::string>>& value){
73 GVariantBuilder builder;
74 g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ss)"));
75 for(const auto& app : value){
76 const std::string& pkgname {app.first};
77 const std::string& appname {app.second};
78 g_variant_builder_add(&builder, "(ss)", pkgname.c_str(), appname.c_str());
79 }
80 g_settings_set_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S, g_variant_builder_end(&builder));
81 });
82
83 locations.changed().connect([this](const std::vector<std::string>& value){81 locations.changed().connect([this](const std::vector<std::string>& value){
84 const int n = value.size();82 const int n = value.size();
85 gchar** strv = g_new0(gchar*, n+1);83 gchar** strv = g_new0(gchar*, n+1);
@@ -160,6 +158,30 @@
160 snooze_duration.changed().connect([this](unsigned int value){158 snooze_duration.changed().connect([this](unsigned int value){
161 g_settings_set_uint(m_settings, SETTINGS_SNOOZE_DURATION_S, value);159 g_settings_set_uint(m_settings, SETTINGS_SNOOZE_DURATION_S, value);
162 });160 });
161
162 cal_notification_enabled.changed().connect([this](bool value){
163 g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY, value);
164 });
165
166 cal_notification_sounds.changed().connect([this](bool value){
167 g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY, value);
168 });
169
170 cal_notification_vibrations.changed().connect([this](bool value){
171 g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY, value);
172 });
173
174 cal_notification_bubbles.changed().connect([this](bool value){
175 g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY, value);
176 });
177
178 cal_notification_list.changed().connect([this](bool value){
179 g_settings_set_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY, value);
180 });
181
182 vibrate_silent_mode.changed().connect([this](bool value){
183 g_settings_set_boolean(m_settings_general_notification, SETTINGS_VIBRATE_SILENT_KEY, value);
184 });
163}185}
164186
165/***187/***
@@ -183,24 +205,6 @@
183 locations.set(l);205 locations.set(l);
184}206}
185207
186void LiveSettings::update_muted_apps()
187{
188 std::set<std::pair<std::string,std::string>> apps;
189
190 auto blacklist = g_settings_get_value(m_settings_cunh, SETTINGS_CUNH_BLACKLIST_S);
191 GVariantIter* iter {nullptr};
192 g_variant_get (blacklist, "a(ss)", &iter);
193 gchar* pkgname;
194 gchar* appname;
195 while (g_variant_iter_loop (iter, "(ss)", &pkgname, &appname)) {
196 apps.insert(std::make_pair(pkgname,appname));
197 }
198 g_variant_iter_free (iter);
199 g_clear_pointer(&blacklist, g_variant_unref);
200
201 muted_apps.set(apps);
202}
203
204void LiveSettings::update_show_calendar()208void LiveSettings::update_show_calendar()
205{209{
206 const auto val = g_settings_get_boolean(m_settings, SETTINGS_SHOW_CALENDAR_S);210 const auto val = g_settings_get_boolean(m_settings, SETTINGS_SHOW_CALENDAR_S);
@@ -304,21 +308,77 @@
304 snooze_duration.set(g_settings_get_uint(m_settings, SETTINGS_SNOOZE_DURATION_S));308 snooze_duration.set(g_settings_get_uint(m_settings, SETTINGS_SNOOZE_DURATION_S));
305}309}
306310
307/***311void LiveSettings::update_cal_notification_enabled()
308****312{
309***/313 cal_notification_enabled.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_ENABLED_KEY));
310314}
311void LiveSettings::on_changed_cunh(GSettings* /*settings*/,315
312 gchar* key,316void LiveSettings::update_cal_notification_sounds()
313 gpointer gself)317{
314{318 cal_notification_sounds.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_SOUNDS_KEY));
315 static_cast<LiveSettings*>(gself)->update_key_cunh(key);319}
316}320
317321void LiveSettings::update_cal_notification_vibrations()
318void LiveSettings::update_key_cunh(const std::string& key)322{
319{323 cal_notification_vibrations.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_VIBRATIONS_KEY));
320 if (key == SETTINGS_CUNH_BLACKLIST_S)324}
321 update_muted_apps();325
326void LiveSettings::update_cal_notification_bubbles()
327{
328 cal_notification_bubbles.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_BUBBLES_KEY));
329}
330
331void LiveSettings::update_cal_notification_list()
332{
333 cal_notification_list.set(g_settings_get_boolean(m_settings_cal_notification, SETTINGS_NOTIFY_LIST_KEY));
334}
335
336void LiveSettings::update_vibrate_silent_mode()
337{
338 vibrate_silent_mode.set(g_settings_get_boolean(m_settings_general_notification, SETTINGS_VIBRATE_SILENT_KEY));
339}
340
341/***
342****
343***/
344
345void LiveSettings::on_changed_cal_notification(GSettings* /*settings*/,
346 gchar* key,
347 gpointer gself)
348{
349 static_cast<LiveSettings*>(gself)->update_key_cal_notification(key);
350}
351
352
353void LiveSettings::update_key_cal_notification(const std::string& key)
354{
355 if (key == SETTINGS_NOTIFY_ENABLED_KEY)
356 update_cal_notification_enabled();
357 else if (key == SETTINGS_NOTIFY_SOUNDS_KEY)
358 update_cal_notification_sounds();
359 else if (key == SETTINGS_NOTIFY_VIBRATIONS_KEY)
360 update_cal_notification_vibrations();
361 else if (key == SETTINGS_NOTIFY_BUBBLES_KEY)
362 update_cal_notification_bubbles();
363 else if (key == SETTINGS_NOTIFY_LIST_KEY)
364 update_cal_notification_list();
365}
366
367/***
368****
369***/
370
371void LiveSettings::on_changed_general_notification(GSettings* /*settings*/,
372 gchar* key,
373 gpointer gself)
374{
375 static_cast<LiveSettings*>(gself)->update_key_general_notification(key);
376}
377
378void LiveSettings::update_key_general_notification(const std::string& key)
379{
380 if (key == SETTINGS_VIBRATE_SILENT_KEY)
381 update_vibrate_silent_mode();
322}382}
323383
324/***384/***
325385
=== modified file 'src/snap.cpp'
--- src/snap.cpp 2016-05-14 17:18:45 +0000
+++ src/snap.cpp 2016-07-04 23:46:11 +0000
@@ -84,9 +84,9 @@
84 const Alarm& alarm,84 const Alarm& alarm,
85 response_func on_response)85 response_func on_response)
86 {86 {
87 // If calendar notifications are muted, don't show them87 // If calendar notifications are disabled, don't show them
88 if (!appointment.is_ubuntu_alarm() && calendar_events_are_muted()) {88 if (!appointment.is_ubuntu_alarm() && !calendar_notifications_are_enabled()) {
89 g_debug("Skipping muted calendar event '%s' notification", appointment.summary.c_str());89 g_debug("Skipping disabled calendar event '%s' notification", appointment.summary.c_str());
90 return;90 return;
91 }91 }
9292
@@ -97,13 +97,14 @@
97 const bool interactive = appointment.is_ubuntu_alarm() && m_engine->supports_actions();97 const bool interactive = appointment.is_ubuntu_alarm() && m_engine->supports_actions();
9898
99 // force the system to stay awake99 // force the system to stay awake
100 auto awake = std::make_shared<uin::Awake>(m_engine->app_name());100 std::shared_ptr<uin::Awake> awake;
101 if (appointment.is_ubuntu_alarm() || calendar_bubbles_enabled() || calendar_list_enabled()) {
102 awake = std::make_shared<uin::Awake>(m_engine->app_name());
103 }
101104
102 // calendar events are muted in silent mode; alarm clocks never are105 // calendar events are muted in silent mode; alarm clocks never are
103 std::shared_ptr<uin::Sound> sound;106 std::shared_ptr<uin::Sound> sound;
104 // FIXME: only play sounds for alarms for now, we should itegrate it with107 if (appointment.is_ubuntu_alarm() || (calendar_sounds_enabled() && !silent_mode())) {
105 // system settings to decide if we should play sounds for calendar notification or not
106 if (appointment.is_ubuntu_alarm()) {
107 // create the sound.108 // create the sound.
108 const auto role = appointment.is_ubuntu_alarm() ? "alarm" : "alert";109 const auto role = appointment.is_ubuntu_alarm() ? "alarm" : "alert";
109 const auto uri = get_alarm_uri(appointment, alarm, m_settings);110 const auto uri = get_alarm_uri(appointment, alarm, m_settings);
@@ -114,10 +115,13 @@
114115
115 // create the haptic feedback...116 // create the haptic feedback...
116 std::shared_ptr<uin::Haptic> haptic;117 std::shared_ptr<uin::Haptic> haptic;
117 if (should_vibrate()) {118 if (should_vibrate() && (appointment.is_ubuntu_alarm() || calendar_vibrations_enabled())) {
118 const auto haptic_mode = m_settings->alarm_haptic.get();119 // when in silent mode should only vibrate if user defined so
119 if (haptic_mode == "pulse")120 if (!silent_mode() || vibrate_in_silent_mode_enabled()) {
120 haptic = std::make_shared<uin::Haptic>(uin::Haptic::MODE_PULSE, appointment.is_ubuntu_alarm());121 const auto haptic_mode = m_settings->alarm_haptic.get();
122 if (haptic_mode == "pulse")
123 haptic = std::make_shared<uin::Haptic>(uin::Haptic::MODE_PULSE, appointment.is_ubuntu_alarm());
124 }
121 }125 }
122126
123 // show a notification...127 // show a notification...
@@ -180,6 +184,9 @@
180 });184 });
181 }185 }
182186
187 b.set_show_notification_bubble(appointment.is_ubuntu_alarm() || calendar_bubbles_enabled());
188 b.set_post_to_messaging_menu(appointment.is_ubuntu_alarm() || calendar_list_enabled());
189
183 const auto key = m_engine->show(b);190 const auto key = m_engine->show(b);
184 if (key)191 if (key)
185 m_notifications.insert (key);192 m_notifications.insert (key);
@@ -187,15 +194,34 @@
187194
188private:195private:
189196
190 bool calendar_events_are_muted() const197 bool calendar_notifications_are_enabled() const
191 {198 {
192 for(const auto& app : m_settings->muted_apps.get()) {199 return m_settings->cal_notification_enabled.get();
193 if (app.first == "com.ubuntu.calendar") {200 }
194 return true;201
195 }202 bool calendar_sounds_enabled() const
196 }203 {
197204 return m_settings->cal_notification_sounds.get();
198 return false;205 }
206
207 bool calendar_vibrations_enabled() const
208 {
209 return m_settings->cal_notification_vibrations.get();
210 }
211
212 bool calendar_bubbles_enabled() const
213 {
214 return m_settings->cal_notification_bubbles.get();
215 }
216
217 bool calendar_list_enabled() const
218 {
219 return m_settings->cal_notification_list.get();
220 }
221
222 bool vibrate_in_silent_mode_enabled() const
223 {
224 return m_settings->vibrate_silent_mode.get();
199 }225 }
200226
201 static void on_sound_proxy_ready(GObject* /*source_object*/, GAsyncResult* res, gpointer gself)227 static void on_sound_proxy_ready(GObject* /*source_object*/, GAsyncResult* res, gpointer gself)
202228
=== modified file 'tests/test-notification.cpp'
--- tests/test-notification.cpp 2016-05-16 20:57:51 +0000
+++ tests/test-notification.cpp 2016-07-04 23:46:11 +0000
@@ -87,18 +87,16 @@
87 { false, true, false }87 { false, true, false }
88 };88 };
8989
90 // combinatorial factor #4: system settings' notifications app blacklist90 // combinatorial factor #4: system settings' notifications disabled
91 const std::set<std::pair<std::string,std::string>> blacklist_calendar { std::make_pair(std::string{"com.ubuntu.calendar"}, std::string{"calendar-app"}) };
92 const std::set<std::pair<std::string,std::string>> blacklist_empty;
93 struct {91 struct {
94 std::set<std::pair<std::string,std::string>> muted_apps; // apps that should not trigger notifications92 bool cal_notification_enabled; // calendar app can trigger notifications
95 std::set<Appointment::Type> expected_notify_called; // do we expect the notification to show?93 std::set<Appointment::Type> expected_notify_called; // do we expect the notification to show?
96 std::set<Appointment::Type> expected_vibrate_called; // do we expect the phone to vibrate?94 std::set<Appointment::Type> expected_vibrate_called; // do we expect the phone to vibrate?
97 } test_muted_apps[] = {95 } test_cal_disabled[] = {
98 { blacklist_empty, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT },96 { true, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT },
99 std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } },97 std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM, Appointment::Type::EVENT } },
100 { blacklist_calendar, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM },98 { false, std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM },
101 std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM } }99 std::set<Appointment::Type>{ Appointment::Type::UBUNTU_ALARM } }
102 };100 };
103101
104 for (const auto& test_appt : test_appts)102 for (const auto& test_appt : test_appts)
@@ -107,20 +105,24 @@
107 {105 {
108 for (const auto& test_vibes : test_other_vibrations)106 for (const auto& test_vibes : test_other_vibrations)
109 {107 {
110 for (const auto& test_muted : test_muted_apps)108 for (const auto& test_disabled : test_cal_disabled)
111 {109 {
112 const bool expected_notify_called = test_appt.expected_notify_called110 const bool expected_notify_called = test_appt.expected_notify_called
113 && test_vibes.expected_notify_called111 && test_vibes.expected_notify_called
114 && (test_muted.expected_notify_called.count(test_appt.appt.type) > 0)112 && (test_disabled.expected_notify_called.count(test_appt.appt.type) > 0)
115 && test_haptic.expected_notify_called;113 && test_haptic.expected_notify_called;
116114
117 const bool expected_vibrate_called = test_appt.expected_vibrate_called115 const bool expected_vibrate_called = test_appt.expected_vibrate_called
118 && test_vibes.expected_vibrate_called116 && test_vibes.expected_vibrate_called
119 && (test_muted.expected_vibrate_called.count(test_appt.appt.type) > 0)117 && (test_disabled.expected_vibrate_called.count(test_appt.appt.type) > 0)
120 && test_haptic.expected_vibrate_called;118 && test_haptic.expected_vibrate_called;
121119
122 // set test case properties: blacklist120 // set test case properties: cal_notification_enabled
123 settings->muted_apps.set(test_muted.muted_apps);121 settings->cal_notification_enabled.set(test_disabled.cal_notification_enabled);
122 settings->cal_notification_sounds.set(test_disabled.cal_notification_enabled);
123 settings->cal_notification_vibrations.set(test_disabled.cal_notification_enabled);
124 settings->cal_notification_bubbles.set(test_disabled.cal_notification_enabled);
125 settings->cal_notification_list.set(test_disabled.cal_notification_enabled);
124126
125 // set test case properties: haptic mode127 // set test case properties: haptic mode
126 settings->alarm_haptic.set(test_haptic.haptic_mode);128 settings->alarm_haptic.set(test_haptic.haptic_mode);
@@ -228,6 +230,12 @@
228 };230 };
229231
230232
233 settings->cal_notification_enabled.set(true);
234 settings->cal_notification_sounds.set(true);
235 settings->cal_notification_vibrations.set(true);
236 settings->cal_notification_bubbles.set(true);
237 settings->cal_notification_list.set(true);
238
231 // walk through the tests239 // walk through the tests
232 for (const auto& test : tests)240 for (const auto& test : tests)
233 {241 {
234242
=== modified file 'tests/test-settings.cpp'
--- tests/test-settings.cpp 2016-02-02 00:08:13 +0000
+++ tests/test-settings.cpp 2016-07-04 23:46:11 +0000
@@ -37,15 +37,15 @@
3737
38 std::shared_ptr<LiveSettings> m_live;38 std::shared_ptr<LiveSettings> m_live;
39 std::shared_ptr<Settings> m_settings;39 std::shared_ptr<Settings> m_settings;
40 GSettings * m_gsettings;40 GSettings * m_gsettings {};
41 GSettings * m_gsettings_cunh;41 GSettings * m_gsettings_cal_notification {};
4242
43 void SetUp() override43 void SetUp() override
44 {44 {
45 super::SetUp();45 super::SetUp();
4646
47 m_gsettings = g_settings_new(SETTINGS_INTERFACE);47 m_gsettings = g_settings_new(SETTINGS_INTERFACE);
48 m_gsettings_cunh = g_settings_new(SETTINGS_CUNH_SCHEMA_ID);48 m_gsettings_cal_notification = g_settings_new_with_path(SETTINGS_NOTIFY_SCHEMA_ID, SETTINGS_NOTIFY_CALENDAR_PATH);
4949
50 m_live.reset(new LiveSettings);50 m_live.reset(new LiveSettings);
51 m_settings = std::dynamic_pointer_cast<Settings>(m_live);51 m_settings = std::dynamic_pointer_cast<Settings>(m_live);
@@ -53,7 +53,7 @@
5353
54 void TearDown() override54 void TearDown() override
55 {55 {
56 g_clear_object(&m_gsettings_cunh);56 g_clear_object(&m_gsettings_cal_notification);
57 g_clear_object(&m_gsettings);57 g_clear_object(&m_gsettings);
58 m_settings.reset();58 m_settings.reset();
59 m_live.reset();59 m_live.reset();
@@ -61,62 +61,62 @@
61 super::TearDown();61 super::TearDown();
62 }62 }
6363
64 void TestBoolProperty(core::Property<bool>& property, const gchar* key)64 void TestBoolProperty(GSettings* gsettings, core::Property<bool>& property, const gchar* key)
65 {65 {
66 EXPECT_EQ(g_settings_get_boolean(m_gsettings, key), property.get());66 EXPECT_EQ(g_settings_get_boolean(gsettings, key), property.get());
67 g_settings_set_boolean(m_gsettings, key, false);67 g_settings_set_boolean(gsettings, key, false);
68 EXPECT_FALSE(property.get());68 EXPECT_FALSE(property.get());
69 g_settings_set_boolean(m_gsettings, key, true);69 g_settings_set_boolean(gsettings, key, true);
70 EXPECT_TRUE(property.get());70 EXPECT_TRUE(property.get());
7171
72 property.set(false);72 property.set(false);
73 EXPECT_FALSE(g_settings_get_boolean(m_gsettings, key));73 EXPECT_FALSE(g_settings_get_boolean(gsettings, key));
74 property.set(true);74 property.set(true);
75 EXPECT_TRUE(g_settings_get_boolean(m_gsettings, key));75 EXPECT_TRUE(g_settings_get_boolean(gsettings, key));
76 }76 }
7777
78 void TestStringProperty(core::Property<std::string>& property, const gchar* key)78 void TestStringProperty(GSettings* gsettings, core::Property<std::string>& property, const gchar* key)
79 {79 {
80 gchar* tmp;80 gchar* tmp;
81 std::string str;81 std::string str;
8282
83 tmp = g_settings_get_string(m_gsettings, key);83 tmp = g_settings_get_string(gsettings, key);
84 EXPECT_EQ(tmp, property.get());84 EXPECT_EQ(tmp, property.get());
85 g_clear_pointer(&tmp, g_free);85 g_clear_pointer(&tmp, g_free);
8686
87 str = "a";87 str = "a";
88 g_settings_set_string(m_gsettings, key, str.c_str());88 g_settings_set_string(gsettings, key, str.c_str());
89 EXPECT_EQ(str, property.get());89 EXPECT_EQ(str, property.get());
9090
91 str = "b";91 str = "b";
92 g_settings_set_string(m_gsettings, key, str.c_str());92 g_settings_set_string(gsettings, key, str.c_str());
93 EXPECT_EQ(str, property.get());93 EXPECT_EQ(str, property.get());
9494
95 str = "a";95 str = "a";
96 property.set(str);96 property.set(str);
97 tmp = g_settings_get_string(m_gsettings, key);97 tmp = g_settings_get_string(gsettings, key);
98 EXPECT_EQ(str, tmp);98 EXPECT_EQ(str, tmp);
99 g_clear_pointer(&tmp, g_free);99 g_clear_pointer(&tmp, g_free);
100100
101 str = "b";101 str = "b";
102 property.set(str);102 property.set(str);
103 tmp = g_settings_get_string(m_gsettings, key);103 tmp = g_settings_get_string(gsettings, key);
104 EXPECT_EQ(str, tmp);104 EXPECT_EQ(str, tmp);
105 g_clear_pointer(&tmp, g_free);105 g_clear_pointer(&tmp, g_free);
106 }106 }
107107
108 void TestUIntProperty(core::Property<unsigned int>& property, const gchar* key)108 void TestUIntProperty(GSettings* gsettings, core::Property<unsigned int>& property, const gchar* key)
109 {109 {
110 EXPECT_EQ(g_settings_get_uint(m_gsettings, key), property.get());110 EXPECT_EQ(g_settings_get_uint(gsettings, key), property.get());
111111
112 unsigned int expected_values[] = { 1, 2, 3 };112 unsigned int expected_values[] = { 1, 2, 3 };
113113
114 // modify GSettings and confirm that the new value is propagated114 // modify GSettings and confirm that the new value is propagated
115 for(const auto& expected_value : expected_values)115 for(const auto& expected_value : expected_values)
116 {116 {
117 g_settings_set_uint(m_gsettings, key, expected_value);117 g_settings_set_uint(gsettings, key, expected_value);
118 EXPECT_EQ(expected_value, property.get());118 EXPECT_EQ(expected_value, property.get());
119 EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key));119 EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key));
120 }120 }
121121
122 // modify the property and confirm that the new value is propagated122 // modify the property and confirm that the new value is propagated
@@ -124,7 +124,7 @@
124 {124 {
125 property.set(expected_value);125 property.set(expected_value);
126 EXPECT_EQ(expected_value, property.get());126 EXPECT_EQ(expected_value, property.get());
127 EXPECT_EQ(expected_value, g_settings_get_uint(m_gsettings, key));127 EXPECT_EQ(expected_value, g_settings_get_uint(gsettings, key));
128 }128 }
129 }129 }
130};130};
@@ -140,32 +140,32 @@
140140
141TEST_F(SettingsFixture, BoolProperties)141TEST_F(SettingsFixture, BoolProperties)
142{142{
143 TestBoolProperty(m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S);143 TestBoolProperty(m_gsettings, m_settings->show_seconds, SETTINGS_SHOW_SECONDS_S);
144 TestBoolProperty(m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S);144 TestBoolProperty(m_gsettings, m_settings->show_calendar, SETTINGS_SHOW_CALENDAR_S);
145 TestBoolProperty(m_settings->show_clock, SETTINGS_SHOW_CLOCK_S);145 TestBoolProperty(m_gsettings, m_settings->show_clock, SETTINGS_SHOW_CLOCK_S);
146 TestBoolProperty(m_settings->show_date, SETTINGS_SHOW_DATE_S);146 TestBoolProperty(m_gsettings, m_settings->show_date, SETTINGS_SHOW_DATE_S);
147 TestBoolProperty(m_settings->show_day, SETTINGS_SHOW_DAY_S);147 TestBoolProperty(m_gsettings, m_settings->show_day, SETTINGS_SHOW_DAY_S);
148 TestBoolProperty(m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S);148 TestBoolProperty(m_gsettings, m_settings->show_detected_location, SETTINGS_SHOW_DETECTED_S);
149 TestBoolProperty(m_settings->show_events, SETTINGS_SHOW_EVENTS_S);149 TestBoolProperty(m_gsettings, m_settings->show_events, SETTINGS_SHOW_EVENTS_S);
150 TestBoolProperty(m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S);150 TestBoolProperty(m_gsettings, m_settings->show_locations, SETTINGS_SHOW_LOCATIONS_S);
151 TestBoolProperty(m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S);151 TestBoolProperty(m_gsettings, m_settings->show_week_numbers, SETTINGS_SHOW_WEEK_NUMBERS_S);
152 TestBoolProperty(m_settings->show_year, SETTINGS_SHOW_YEAR_S);152 TestBoolProperty(m_gsettings, m_settings->show_year, SETTINGS_SHOW_YEAR_S);
153}153}
154154
155TEST_F(SettingsFixture, UIntProperties)155TEST_F(SettingsFixture, UIntProperties)
156{156{
157 TestUIntProperty(m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S);157 TestUIntProperty(m_gsettings, m_settings->alarm_duration, SETTINGS_ALARM_DURATION_S);
158 TestUIntProperty(m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S);158 TestUIntProperty(m_gsettings, m_settings->alarm_volume, SETTINGS_ALARM_VOLUME_S);
159 TestUIntProperty(m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S);159 TestUIntProperty(m_gsettings, m_settings->snooze_duration, SETTINGS_SNOOZE_DURATION_S);
160}160}
161161
162TEST_F(SettingsFixture, StringProperties)162TEST_F(SettingsFixture, StringProperties)
163{163{
164 TestStringProperty(m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S);164 TestStringProperty(m_gsettings, m_settings->custom_time_format, SETTINGS_CUSTOM_TIME_FORMAT_S);
165 TestStringProperty(m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S);165 TestStringProperty(m_gsettings, m_settings->timezone_name, SETTINGS_TIMEZONE_NAME_S);
166 TestStringProperty(m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S);166 TestStringProperty(m_gsettings, m_settings->alarm_sound, SETTINGS_ALARM_SOUND_S);
167 TestStringProperty(m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S);167 TestStringProperty(m_gsettings, m_settings->calendar_sound, SETTINGS_CALENDAR_SOUND_S);
168 TestStringProperty(m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S);168 TestStringProperty(m_gsettings, m_settings->alarm_haptic, SETTINGS_ALARM_HAPTIC_S);
169}169}
170170
171TEST_F(SettingsFixture, TimeFormatMode)171TEST_F(SettingsFixture, TimeFormatMode)
@@ -229,36 +229,13 @@
229229
230TEST_F(SettingsFixture, MutedApps)230TEST_F(SettingsFixture, MutedApps)
231{231{
232 const auto key = SETTINGS_CUNH_BLACKLIST_S;232 if (!m_gsettings_cal_notification) {
233233 return;
234 struct {234 }
235 std::string pkgname;235
236 std::string appname;236 TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_enabled, SETTINGS_NOTIFY_ENABLED_KEY);
237 } apps[] = {237 TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_sounds, SETTINGS_NOTIFY_SOUNDS_KEY);
238 { "", "ubuntu-system-settings" },238 TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_vibrations, SETTINGS_NOTIFY_VIBRATIONS_KEY);
239 { "com.ubuntu.calendar", "calendar" },239 TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_bubbles, SETTINGS_NOTIFY_BUBBLES_KEY);
240 { "com.ubuntu.developer.webapps.webapp-facebook", "webapp-facebook" },240 TestBoolProperty(m_gsettings_cal_notification, m_settings->cal_notification_list, SETTINGS_NOTIFY_LIST_KEY);
241 { "com.ubuntu.reminders", "reminders" }
242 };
243 std::set<std::pair<std::string,std::string>> apps_set;
244 for (const auto& app : apps)
245 apps_set.insert(std::make_pair(app.pkgname, app.appname));
246
247 // test that changing Settings is reflected in the schema
248 m_settings->muted_apps.set(apps_set);
249 auto v = g_settings_get_value(m_gsettings_cunh, key);
250 auto str = g_variant_print(v, true);
251 EXPECT_STREQ("[('', 'ubuntu-system-settings'), ('com.ubuntu.calendar', 'calendar'), ('com.ubuntu.developer.webapps.webapp-facebook', 'webapp-facebook'), ('com.ubuntu.reminders', 'reminders')]", str);
252 g_clear_pointer(&str, g_free);
253
254 // test that clearing the schema clears the settings
255 g_settings_reset(m_gsettings_cunh, key);
256 EXPECT_EQ(0, m_settings->muted_apps.get().size());
257
258 // test thst setting the schema updates the settings
259 g_settings_set_value(m_gsettings_cunh, key, v);
260 EXPECT_EQ(apps_set, m_settings->muted_apps.get());
261
262 // cleanup
263 g_clear_pointer(&v, g_variant_unref);
264}241}
265242
=== modified file 'tests/test-sound.cpp'
--- tests/test-sound.cpp 2016-05-14 17:20:00 +0000
+++ tests/test-sound.cpp 2016-07-04 23:46:11 +0000
@@ -59,6 +59,12 @@
59 auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();59 auto sb = std::make_shared<unity::indicator::notifications::DefaultSoundBuilder>();
60 auto snap = create_snap(ne, sb, settings);60 auto snap = create_snap(ne, sb, settings);
6161
62 settings->cal_notification_enabled.set(true);
63 settings->cal_notification_sounds.set(true);
64 settings->cal_notification_vibrations.set(true);
65 settings->cal_notification_bubbles.set(true);
66 settings->cal_notification_list.set(true);
67
62 make_interactive();68 make_interactive();
6369
64 // call the Snap Decision70 // call the Snap Decision
@@ -150,6 +156,12 @@
150 auto sb = std::make_shared<TestSoundBuilder>();156 auto sb = std::make_shared<TestSoundBuilder>();
151 auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);};157 auto func = [this](const Appointment&, const Alarm&, const Snap::Response&){g_idle_add(quit_idle, loop);};
152158
159 settings->cal_notification_enabled.set(true);
160 settings->cal_notification_sounds.set(true);
161 settings->cal_notification_vibrations.set(true);
162 settings->cal_notification_bubbles.set(true);
163 settings->cal_notification_list.set(true);
164
153 const struct {165 const struct {
154 Appointment appointment;166 Appointment appointment;
155 std::string expected_role;167 std::string expected_role;

Subscribers

People subscribed via source and target branches