aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp5
-rw-r--r--src/notifications.cpp127
-rw-r--r--src/snap.cpp12
3 files changed, 136 insertions, 8 deletions
diff --git a/src/main.cpp b/src/main.cpp
index bb77c0e..f9a934a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -156,7 +156,10 @@ main(int /*argc*/, char** /*argv*/)
auto on_snooze = [snooze_planner](const Appointment& appointment, const Alarm& alarm) {
snooze_planner->add(appointment, alarm);
};
- auto on_ok = [](const Appointment&, const Alarm&){};
+ auto on_ok = [actions](const Appointment& app, const Alarm&){
+ //TODO: add support for desktop
+ actions->phone_open_appointment(app, app.begin);
+ };
auto on_alarm_reached = [&engine, &snap, &on_snooze, &on_ok](const Appointment& appointment, const Alarm& alarm) {
(*snap)(appointment, alarm, on_snooze, on_ok);
engine->disable_ubuntu_alarm(appointment);
diff --git a/src/notifications.cpp b/src/notifications.cpp
index 051653d..2d22087 100644
--- a/src/notifications.cpp
+++ b/src/notifications.cpp
@@ -21,10 +21,18 @@
#include <libnotify/notify.h>
+#include <messaging-menu/messaging-menu-app.h>
+#include <messaging-menu/messaging-menu-message.h>
+
+
+#include <uuid/uuid.h>
+
#include <map>
#include <set>
#include <string>
#include <vector>
+#include <memory>
+
namespace ayatana {
namespace indicator {
@@ -45,9 +53,11 @@ public:
std::string m_body;
std::string m_icon_name;
std::chrono::seconds m_duration;
+ gint64 m_start_time;
std::set<std::string> m_string_hints;
std::vector<std::pair<std::string,std::string>> m_actions;
std::function<void(const std::string&)> m_closed_callback;
+ std::function<void()> m_missed_click_callback;
};
Builder::Builder():
@@ -101,6 +111,18 @@ Builder::set_closed_callback (std::function<void (const std::string&)> cb)
impl->m_closed_callback.swap (cb);
}
+void
+Builder::set_missed_click_callback (std::function<void()> cb)
+{
+ impl->m_missed_click_callback.swap (cb);
+}
+
+void
+Builder::set_start_time (uint64_t time)
+{
+ impl->m_start_time = time;
+}
+
/***
****
***/
@@ -110,23 +132,39 @@ class Engine::Impl
struct notification_data
{
std::shared_ptr<NotifyNotification> nn;
- std::function<void(const std::string&)> closed_callback;
+ Builder::Impl data;
+ };
+
+ struct messaging_menu_data
+ {
+ std::shared_ptr<MessagingMenuMessage> mm;
+ std::function<void()> callback;
};
public:
Impl(const std::string& app_name):
+ m_messaging_app(messaging_menu_app_new(DATETIME_INDICATOR_DESKTOP_FILE), g_object_unref),
m_app_name(app_name)
{
if (!notify_init(app_name.c_str()))
g_critical("Unable to initialize libnotify!");
+
+ // messaging menu
+ GIcon *icon = g_themed_icon_new("calendar-app");
+
+ messaging_menu_app_register(m_messaging_app.get());
+ messaging_menu_app_append_source(m_messaging_app.get(), m_app_name.c_str(), icon, "Calendar");
+ g_object_unref(icon);
}
~Impl()
{
close_all ();
+ remove_all ();
notify_uninit ();
+ messaging_menu_app_unregister (m_messaging_app.get());
}
const std::string& app_name() const
@@ -217,7 +255,7 @@ public:
notification_key_quark(),
GINT_TO_POINTER(key));
- m_notifications[key] = { nn, info.m_closed_callback };
+ m_notifications[key] = { nn, info };
g_signal_connect (nn.get(), "closed",
G_CALLBACK(on_notification_closed), this);
@@ -238,6 +276,59 @@ public:
return ret;
}
+ std::string post(const Builder::Impl& data)
+ {
+ uuid_t message_uuid;
+ uuid_generate(message_uuid);
+
+ char message_id[37];
+ uuid_unparse(message_uuid, message_id);
+
+ GIcon *icon = g_themed_icon_new(data.m_icon_name.c_str());
+ std::shared_ptr<MessagingMenuMessage> msg (messaging_menu_message_new(message_id,
+ icon,
+ data.m_title.c_str(),
+ nullptr,
+ data.m_body.c_str(),
+ data.m_start_time * 1000000), // secs -> microsecs
+ g_object_ref);
+ g_object_unref(icon);
+ if (msg)
+ {
+ m_messaging_messages[std::string(message_id)] = { msg, data.m_missed_click_callback };
+ g_signal_connect(msg.get(), "activate",
+ G_CALLBACK(on_message_activated), this);
+ messaging_menu_app_append_message(m_messaging_app.get(), msg.get(), m_app_name.c_str(), false);
+ return message_id;
+ } else {
+ g_warning("Fail to create messaging menu message");
+ }
+ return "";
+ }
+
+ void remove (const std::string &key)
+ {
+ auto it = m_messaging_messages.find(key);
+ if (it != m_messaging_messages.end())
+ {
+ // tell the server to remove message
+ messaging_menu_app_remove_message(m_messaging_app.get(), it->second.mm.get());
+ m_messaging_messages.erase(it);
+ }
+ }
+
+ void remove_all ()
+ {
+ // call remove() on all our keys
+
+ std::set<std::string> keys;
+ for (const auto& it : m_messaging_messages)
+ keys.insert (it.first);
+
+ for (const std::string &key : keys)
+ remove (key);
+ }
+
private:
const std::set<std::string>& server_caps() const
@@ -279,6 +370,22 @@ private:
static_cast<Impl*>(gself)->remove_closed_notification(GPOINTER_TO_INT(gkey));
}
+ static void on_message_activated (MessagingMenuMessage *,
+ const char *actionId,
+ GVariant *,
+ gpointer gself)
+ {
+ auto self = static_cast<Impl*>(gself);
+ auto it = self->m_messaging_messages.find(actionId);
+ g_return_if_fail (it != self->m_messaging_messages.end());
+ const auto& ndata = it->second;
+
+ if (ndata.callback)
+ ndata.callback();
+
+ self->m_messaging_messages.erase(it);
+ }
+
void remove_closed_notification (int key)
{
auto it = m_notifications.find(key);
@@ -286,16 +393,20 @@ private:
const auto& ndata = it->second;
auto nn = ndata.nn.get();
- if (ndata.closed_callback)
+
+ if (ndata.data.m_closed_callback)
{
std::string action;
-
const GQuark q = notification_action_quark();
const gpointer p = g_object_get_qdata(G_OBJECT(nn), q);
if (p != nullptr)
action = static_cast<const char*>(p);
- ndata.closed_callback (action);
+ ndata.data.m_closed_callback (action);
+ // empty action means that the notification got timeout
+ // post a message on messaging menu
+ if (action.empty())
+ post(ndata.data);
}
m_notifications.erase(it);
@@ -305,6 +416,10 @@ private:
****
***/
+ // messaging menu
+ std::shared_ptr<MessagingMenuApp> m_messaging_app;
+ std::map<std::string, messaging_menu_data> m_messaging_messages;
+
const std::string m_app_name;
// key-to-data
@@ -315,6 +430,8 @@ private:
mutable std::set<std::string> m_lazy_caps;
static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"};
+ static constexpr char const * DATETIME_INDICATOR_DESKTOP_FILE {"indicator-datetime.desktop"};
+ static constexpr char const * DATETIME_INDICATOR_SOURCE_ID {"indicator-datetime"};
};
/***
diff --git a/src/snap.cpp b/src/snap.cpp
index 259592e..5c530be 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -122,8 +122,9 @@ public:
const auto minutes = std::chrono::minutes(m_settings->alarm_duration.get());
ain::Builder b;
b.set_body (appointment.summary);
- b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "reminder");
+ b.set_icon_name (appointment.is_ubuntu_alarm() ? "alarm-clock" : "appointment");
b.add_hint (ain::Builder::HINT_NONSHAPED_ICON);
+ b.set_start_time (appointment.begin.to_unix());
const char * timefmt;
if (is_locale_12h()) {
@@ -152,6 +153,9 @@ public:
b.add_hint (ain::Builder::HINT_AFFIRMATIVE_HINT);
b.add_action ("ok", _("OK"));
b.add_action ("snooze", _("Snooze"));
+ } else {
+ b.add_hint (ain::Builder::HINT_INTERACTIVE);
+ b.add_action ("ok", _("OK"));
}
// add 'sound', 'haptic', and 'awake' objects to the capture so
@@ -161,10 +165,14 @@ public:
(const std::string& action){
if (action == "snooze")
snooze(appointment, alarm);
- else
+ else if (action == "ok")
ok(appointment, alarm);
});
+ b.set_missed_click_callback([appointment, alarm, ok](){
+ ok(appointment, alarm);
+ });
+
const auto key = m_engine->show(b);
if (key)
m_notifications.insert (key);