From 2bb9e9d4e8f10bf5f9487c213eca6e0caf43e266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sun, 3 May 2015 14:35:29 +0200 Subject: view: sort contacts by most recent event --- libempathy-gtk/empathy-roster-contact.c | 121 ++++++++++++++++++++++++++++++++ libempathy-gtk/empathy-roster-contact.h | 5 ++ libempathy-gtk/empathy-roster-view.c | 22 +++++- src/empathy-roster-window.c | 42 ++++------- 4 files changed, 161 insertions(+), 29 deletions(-) diff --git a/libempathy-gtk/empathy-roster-contact.c b/libempathy-gtk/empathy-roster-contact.c index df57a87fb..d98ca13fc 100644 --- a/libempathy-gtk/empathy-roster-contact.c +++ b/libempathy-gtk/empathy-roster-contact.c @@ -18,6 +18,7 @@ enum PROP_GROUP, PROP_ONLINE, PROP_ALIAS, + PROP_MOST_RECENT_EVENT, N_PROPS }; @@ -33,12 +34,17 @@ static guint signals[LAST_SIGNAL]; struct _EmpathyRosterContactPriv { FolksIndividual *individual; + EmpathyContact *contact; gchar *group; + TplLogManager *log_manager; + TplEvent *most_recent_event; + GtkWidget *avatar; GtkWidget *first_line_alig; GtkWidget *alias; GtkWidget *presence_msg; + GtkWidget *most_recent_msg; GtkWidget *presence_icon; GtkWidget *phone_icon; @@ -77,6 +83,9 @@ empathy_roster_contact_get_property (GObject *object, case PROP_ALIAS: g_value_set_string (value, get_alias (self)); break; + case PROP_MOST_RECENT_EVENT: + g_value_set_object (value, self->priv->most_recent_event); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -107,6 +116,24 @@ empathy_roster_contact_set_property (GObject *object, } } +gint64 +empathy_roster_contact_get_most_recent_timestamp (EmpathyRosterContact *contact) +{ + if (contact->priv->most_recent_event) { + return tpl_event_get_timestamp (contact->priv->most_recent_event); + } + return 0; +} + +static const gchar* +get_most_recent_message (EmpathyRosterContact *contact) +{ + if (contact->priv->most_recent_event) { + return tpl_text_event_get_message (TPL_TEXT_EVENT(contact->priv->most_recent_event)); + } + return NULL; +} + static void avatar_loaded_cb (GObject *source, GAsyncResult *result, @@ -138,6 +165,29 @@ out: tp_weak_ref_destroy (wr); } +static void +update_most_recent_msg (EmpathyRosterContact *self) +{ + const gchar* msg = get_most_recent_message (self); + + if (tp_str_empty (msg)) + { + gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig), + 0, 0.5, 1, 1); + gtk_widget_hide (self->priv->most_recent_msg); + } + else + { + gchar *tmp = g_strdup (msg); + if (strchr(tmp, '\n')) strchr(tmp, '\n')[0] = 0; + gtk_label_set_text (GTK_LABEL (self->priv->most_recent_msg), tmp); + gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig), + 0, 0.75, 1, 1); + gtk_misc_set_alignment (GTK_MISC (self->priv->most_recent_msg), 0, 0.25); + g_free (tmp); + } +} + static void update_avatar (EmpathyRosterContact *self) { @@ -291,10 +341,36 @@ presence_status_changed_cb (FolksIndividual *individual, update_online (self); } +static void +get_filtered_events (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + EmpathyRosterContact *contact = EMPATHY_ROSTER_CONTACT (user_data); + GError *error; + GList *events; + + error = NULL; + if (!tpl_log_manager_get_filtered_events_finish (contact->priv->log_manager, res, &events, &error)) + { + g_warning ("Unable to get events: %s", error->message); + g_error_free (error); + goto out; + } + + if (events) { + contact->priv->most_recent_event = TPL_EVENT (events->data); + g_object_notify (G_OBJECT (contact), "most-recent-event"); + update_most_recent_msg (contact); + } + + out: + return; +} + static void empathy_roster_contact_constructed (GObject *object) { EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + TplEntity *tpl_entity; void (*chain_up) (GObject *) = ((GObjectClass *) empathy_roster_contact_parent_class)->constructed; @@ -303,6 +379,26 @@ empathy_roster_contact_constructed (GObject *object) g_assert (FOLKS_IS_INDIVIDUAL (self->priv->individual)); + self->priv->contact = empathy_contact_dup_best_for_action ( + self->priv->individual, + EMPATHY_ACTION_CHAT); + + self->priv->log_manager = tpl_log_manager_dup_singleton (); + + tpl_entity = tpl_entity_new_from_tp_contact ( + empathy_contact_get_tp_contact (self->priv->contact), + TPL_ENTITY_CONTACT); + tpl_log_manager_get_filtered_events_async( + self->priv->log_manager, + empathy_contact_get_account (self->priv->contact), + tpl_entity, + TPL_EVENT_MASK_TEXT, + 1, + NULL, + NULL, + get_filtered_events, + object); + tp_g_signal_connect_object (self->priv->individual, "notify::avatar", G_CALLBACK (avatar_changed_cb), self, 0); tp_g_signal_connect_object (self->priv->individual, "notify::alias", @@ -343,6 +439,7 @@ empathy_roster_contact_finalize (GObject *object) g_free (self->priv->group); g_free (self->priv->event_icon); + g_object_unref (self->priv->log_manager); if (chain_up != NULL) chain_up (object); @@ -385,6 +482,12 @@ empathy_roster_contact_class_init ( G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (oclass, PROP_ALIAS, spec); + spec = g_param_spec_object ("most-recent-event", "Most recent event", + "Most recent event", + TPL_TYPE_EVENT, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_MOST_RECENT_EVENT, spec); + g_type_class_add_private (klass, sizeof (EmpathyRosterContactPriv)); } @@ -445,12 +548,24 @@ empathy_roster_contact_init (EmpathyRosterContact *self) self->priv->presence_msg = gtk_label_new (NULL); gtk_label_set_ellipsize (GTK_LABEL (self->priv->presence_msg), PANGO_ELLIPSIZE_END); + /* gtk_box_pack_start (GTK_BOX (box), self->priv->presence_msg, TRUE, TRUE, 0); gtk_widget_show (self->priv->presence_msg); + */ context = gtk_widget_get_style_context (self->priv->presence_msg); gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL); + /* Most recent message */ + self->priv->most_recent_msg = gtk_label_new (NULL); + gtk_label_set_ellipsize (GTK_LABEL (self->priv->most_recent_msg), + PANGO_ELLIPSIZE_END); + gtk_box_pack_start (GTK_BOX (box), self->priv->most_recent_msg, TRUE, TRUE, 0); + gtk_widget_show (self->priv->most_recent_msg); + + context = gtk_widget_get_style_context (self->priv->most_recent_msg); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL); + /* Presence icon */ self->priv->presence_icon = gtk_image_new (); @@ -481,6 +596,12 @@ empathy_roster_contact_get_individual (EmpathyRosterContact *self) return self->priv->individual; } +EmpathyContact * +empathy_roster_contact_get_contact (EmpathyRosterContact *self) +{ + return self->priv->contact; +} + gboolean empathy_roster_contact_is_online (EmpathyRosterContact *self) { diff --git a/libempathy-gtk/empathy-roster-contact.h b/libempathy-gtk/empathy-roster-contact.h index 6e05959f7..1dc463a79 100644 --- a/libempathy-gtk/empathy-roster-contact.h +++ b/libempathy-gtk/empathy-roster-contact.h @@ -3,6 +3,7 @@ #include #include +#include "empathy-contact.h" G_BEGIN_DECLS @@ -52,6 +53,8 @@ GtkWidget * empathy_roster_contact_new (FolksIndividual *individual, FolksIndividual * empathy_roster_contact_get_individual (EmpathyRosterContact *self); +EmpathyContact * empathy_roster_contact_get_contact (EmpathyRosterContact *self); + const gchar * empathy_roster_contact_get_group (EmpathyRosterContact *self); gboolean empathy_roster_contact_is_online (EmpathyRosterContact *self); @@ -62,6 +65,8 @@ void empathy_roster_contact_set_event_icon (EmpathyRosterContact *self, GdkPixbuf * empathy_roster_contact_get_avatar_pixbuf ( EmpathyRosterContact *self); +gint64 empathy_roster_contact_get_most_recent_timestamp (EmpathyRosterContact *contact); + G_END_DECLS #endif /* #ifndef __EMPATHY_ROSTER_CONTACT_H__*/ diff --git a/libempathy-gtk/empathy-roster-view.c b/libempathy-gtk/empathy-roster-view.c index 0dab3ba66..e463bd9f0 100644 --- a/libempathy-gtk/empathy-roster-view.c +++ b/libempathy-gtk/empathy-roster-view.c @@ -189,6 +189,10 @@ add_roster_contact (EmpathyRosterView *self, g_signal_connect (contact, "notify::alias", G_CALLBACK (roster_contact_changed_cb), self); + /* Need to resort if most recent event changed */ + g_signal_connect (contact, "notify::most-recent-event", + G_CALLBACK (roster_contact_changed_cb), self); + gtk_widget_show (contact); gtk_container_add (GTK_CONTAINER (self), contact); @@ -625,6 +629,20 @@ contact_in_top (EmpathyRosterView *self, return FALSE; } +static gint +compare_roster_contacts_by_conversation_time (EmpathyRosterContact *a, + EmpathyRosterContact *b) +{ + gint64 ts_a, ts_b; + + ts_a = empathy_roster_contact_get_most_recent_timestamp (a); + ts_b = empathy_roster_contact_get_most_recent_timestamp (b); + + if (ts_a == ts_b) return 0; + if (ts_a > ts_b) return -1; + return 1; +} + static gint compare_roster_contacts_by_alias (EmpathyRosterContact *a, EmpathyRosterContact *b) @@ -654,7 +672,7 @@ compare_roster_contacts_no_group (EmpathyRosterView *self, if (top_a == top_b) /* Both contacts are in the top of the roster (or not). Sort them * alphabetically */ - return compare_roster_contacts_by_alias (a, b); + return compare_roster_contacts_by_conversation_time (a, b); else if (top_a) return -1; else @@ -691,7 +709,7 @@ compare_roster_contacts_with_groups (EmpathyRosterView *self, if (!tp_strdiff (group_a, group_b)) /* Same group, compare the contacts */ - return compare_roster_contacts_by_alias (a, b); + return compare_roster_contacts_by_conversation_time (a, b); /* Sort by group */ return compare_group_names (group_a, group_b); diff --git a/src/empathy-roster-window.c b/src/empathy-roster-window.c index e874fb533..080aeb0a4 100644 --- a/src/empathy-roster-window.c +++ b/src/empathy-roster-window.c @@ -208,7 +208,7 @@ roster_window_auth_display (EmpathyRosterWindow *self, gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_QUESTION); gtk_widget_set_no_show_all (info_bar, TRUE); - gtk_box_pack_start (GTK_BOX (self->priv->auth_vbox), info_bar, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (self->priv->auth_vbox), info_bar); gtk_widget_show (info_bar); icon_name = tp_account_get_icon_name (account); @@ -228,8 +228,8 @@ roster_window_auth_display (EmpathyRosterWindow *self, g_free (str); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); - gtk_box_pack_start (GTK_BOX (content_area), image, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (content_area), label, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (content_area), image); + gtk_container_add (GTK_CONTAINER (content_area), label); image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON); add_button = gtk_button_new (); @@ -248,7 +248,7 @@ roster_window_auth_display (EmpathyRosterWindow *self, gtk_widget_show (action_grid); action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar)); - gtk_box_pack_start (GTK_BOX (action_area), action_grid, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (action_area), action_grid); gtk_grid_attach (GTK_GRID (action_grid), add_button, 0, 0, 1, 1); gtk_grid_attach (GTK_GRID (action_grid), close_button, 1, 0, 1, 1); @@ -608,7 +608,7 @@ roster_window_error_create_info_bar (EmpathyRosterWindow *self, gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), message_type); gtk_widget_set_no_show_all (info_bar, TRUE); - gtk_box_pack_start (GTK_BOX (self->priv->errors_vbox), info_bar, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (self->priv->errors_vbox), info_bar); gtk_widget_show (info_bar); icon_name = tp_account_get_icon_name (account); @@ -623,8 +623,8 @@ roster_window_error_create_info_bar (EmpathyRosterWindow *self, gtk_widget_show (label); content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); - gtk_box_pack_start (GTK_BOX (content_area), image, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (content_area), label, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (content_area), image); + gtk_container_add (GTK_CONTAINER (content_area), label); action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar)); gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), @@ -879,7 +879,7 @@ roster_window_setup_balance (EmpathyRosterWindow *self, /* protocol icon */ image = gtk_image_new (); - gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (hbox), image); g_object_bind_property (account, "icon-name", image, "icon-name", G_BINDING_SYNC_CREATE); @@ -887,14 +887,14 @@ roster_window_setup_balance (EmpathyRosterWindow *self, label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (hbox), label); g_object_bind_property (account, "display-name", label, "label", G_BINDING_SYNC_CREATE); /* balance label */ label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (hbox), label); /* top up button */ uri = tp_connection_get_balance_uri (conn); @@ -909,7 +909,7 @@ roster_window_setup_balance (EmpathyRosterWindow *self, GTK_ICON_SIZE_SMALL_TOOLBAR)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_set_tooltip_text (button, _("Top up account")); - gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (hbox), button); g_signal_connect_data (button, "clicked", G_CALLBACK (empathy_url_show), @@ -917,7 +917,7 @@ roster_window_setup_balance (EmpathyRosterWindow *self, 0); } - gtk_box_pack_start (GTK_BOX (self->priv->balance_vbox), hbox, FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (self->priv->balance_vbox), hbox); gtk_widget_show_all (hbox); g_object_set_data (G_OBJECT (account), "balance-money-label", label); @@ -2305,14 +2305,6 @@ roster_window_most_available_presence_changed_cb (TpAccountManager *manager, set_notebook_page (self); } -static void -show_offline_changed_cb (GSettings *settings, - const gchar *key, - EmpathyRosterWindow *self) -{ - set_notebook_page (self); -} - static void empathy_roster_window_init (EmpathyRosterWindow *self) { @@ -2429,9 +2421,7 @@ empathy_roster_window_init (EmpathyRosterWindow *self) /* Set up presence chooser */ self->priv->presence_chooser = empathy_presence_chooser_new (); gtk_widget_show (self->priv->presence_chooser); - gtk_box_pack_start (GTK_BOX (self->priv->presence_toolbar), - self->priv->presence_chooser, - TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (self->priv->presence_toolbar), self->priv->presence_chooser); /* Set up the throbber */ self->priv->throbber = gtk_spinner_new (); @@ -2440,9 +2430,7 @@ empathy_roster_window_init (EmpathyRosterWindow *self) g_signal_connect (self->priv->throbber, "button-press-event", G_CALLBACK (roster_window_throbber_button_press_event_cb), self); - gtk_box_pack_start (GTK_BOX (self->priv->presence_toolbar), - self->priv->throbber, - FALSE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (self->priv->presence_toolbar), self->priv->throbber); self->priv->individual_manager = empathy_individual_manager_dup_singleton (); @@ -2506,7 +2494,7 @@ empathy_roster_window_init (EmpathyRosterWindow *self) self->priv->chat_window = GTK_WIDGET (empathy_chat_window_new ()); gtk_widget_show (GTK_WIDGET (self->priv->chat_window) ); - gtk_box_pack_start (GTK_BOX (chat_vbox), self->priv->chat_window, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (chat_vbox), self->priv->chat_window); /* Enable event handling */ self->priv->call_observer = empathy_call_observer_dup_singleton (); -- cgit v1.2.1