diff options
Diffstat (limited to 'liszt/contact-view.c')
-rw-r--r-- | liszt/contact-view.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/liszt/contact-view.c b/liszt/contact-view.c new file mode 100644 index 000000000..41ef7978e --- /dev/null +++ b/liszt/contact-view.c @@ -0,0 +1,499 @@ +#include <folks/folks.h> +#include <folks/folks-telepathy.h> + +#include "contact-view.h" + +#include <libempathy/empathy-dispatcher.h> +#include <libempathy/empathy-call-factory.h> + +G_DEFINE_TYPE (LolContactView, lol_contact_view, CLUTTER_TYPE_BOX) + +/* signals */ +enum { + SELECTED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +/* properties */ +enum +{ + PROP_INDIVIDUAL = 1, +}; + +struct _LolContactViewPrivate +{ + FolksIndividual *individual; + + ClutterActor *presence_texture; + ClutterActor *name_text; + ClutterActor *avatar_texture; + ClutterActor *actions; + + gboolean selected; +}; + +static void +lol_contact_view_init (LolContactView *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, LOL_TYPE_CONTACT_VIEW, + LolContactViewPrivate); +} + +static const gchar * +lol_contact_view_get_presence_string (FolksPresenceType presence) +{ + switch (presence) + { + case FOLKS_PRESENCE_TYPE_AVAILABLE: + return "Available"; + break; + case FOLKS_PRESENCE_TYPE_AWAY: + case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY: + return "Away"; + break; + case FOLKS_PRESENCE_TYPE_HIDDEN: + case FOLKS_PRESENCE_TYPE_BUSY: + return "Busy"; + break; + case FOLKS_PRESENCE_TYPE_UNKNOWN: + case FOLKS_PRESENCE_TYPE_UNSET: + case FOLKS_PRESENCE_TYPE_OFFLINE: + case FOLKS_PRESENCE_TYPE_ERROR: + default: + return ""; + } +} + +static void +lol_contact_view_set_markup (LolContactView *self, + const gchar *text, + FolksPresenceType presence) +{ + LolContactViewPrivate *priv = self->priv; + gchar *markup; + + markup = g_strdup_printf ("%s\n<span size=\"x-small\">%s</span>", + text, lol_contact_view_get_presence_string (presence)); + clutter_text_set_markup (CLUTTER_TEXT (priv->name_text), markup); + g_free (markup); +} + +static void +lol_contact_view_set_avatar (LolContactView *self, + GFile *file) +{ + LolContactViewPrivate *priv = self->priv; + gchar *tmp; + + if (file == NULL) + return; + + tmp = g_file_get_path (file); + + clutter_texture_set_from_file ( + CLUTTER_TEXTURE (priv->avatar_texture), + tmp, NULL); + + g_free (tmp); +} + +static void +lol_contact_view_set_presence (LolContactView *self, + FolksPresenceType presence) +{ + LolContactViewPrivate *priv = self->priv; + const gchar *icon_name = NULL; + + switch (presence) + { + case FOLKS_PRESENCE_TYPE_AVAILABLE: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-available.png"; + break; + case FOLKS_PRESENCE_TYPE_AWAY: + case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-away.png"; + break; + case FOLKS_PRESENCE_TYPE_HIDDEN: + case FOLKS_PRESENCE_TYPE_BUSY: + icon_name = "/usr/share/empathy/icons/hicolor/32x32/status/user-busy.png"; + break; + case FOLKS_PRESENCE_TYPE_UNKNOWN: + case FOLKS_PRESENCE_TYPE_UNSET: + case FOLKS_PRESENCE_TYPE_OFFLINE: + case FOLKS_PRESENCE_TYPE_ERROR: + break; + } + + if (icon_name == NULL) + return; + + clutter_texture_set_from_file ( + CLUTTER_TEXTURE (priv->presence_texture), + icon_name, NULL); +} + +static void +lol_contact_view_update_individual (LolContactView *self) +{ + + FolksIndividual *individual = self->priv->individual; + FolksPresenceType presence_type; + + presence_type = folks_presence_get_presence_type (FOLKS_PRESENCE (individual)); + + lol_contact_view_set_markup (self, + folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)), + presence_type); + + lol_contact_view_set_presence (self, presence_type); + + lol_contact_view_set_avatar (self, + folks_avatar_get_avatar (FOLKS_AVATAR (individual))); + + /* online */ + if (presence_type > FOLKS_PRESENCE_TYPE_OFFLINE + && presence_type < FOLKS_PRESENCE_TYPE_UNKNOWN) + { + clutter_actor_show (CLUTTER_ACTOR (self)); + } + else + { + clutter_actor_hide (CLUTTER_ACTOR (self)); + } +} + +static void +individual_notify_cb (FolksIndividual *individual, + GParamSpec *pspec, + LolContactView *self) +{ + lol_contact_view_update_individual (self); +} + +static void +lol_contact_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + LolContactView *self = (LolContactView *) object; + LolContactViewPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_INDIVIDUAL: + { + if (priv->individual == NULL) + { + priv->individual = g_value_dup_object (value); + lol_contact_view_update_individual (self); + g_signal_connect (priv->individual, "notify", + G_CALLBACK (individual_notify_cb), self); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +lol_contact_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + LolContactView *self = (LolContactView *) object; + LolContactViewPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_INDIVIDUAL: + g_value_set_object (value, priv->individual); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static TpContact * +get_contact_and_account (LolContactView *self, + TpAccount **account) +{ + LolContactViewPrivate *priv = self->priv; + GList *personas, *l; + FolksPersona *persona; + FolksPersonaStore *store; + TpContact *contact; + + personas = folks_individual_get_personas (priv->individual); + + for (l = personas; l != NULL; l = l->next) + { + if (!TPF_IS_PERSONA (l->data)) + continue; + + persona = l->data; + break; + } + + if (persona == NULL) + return NULL; + + store = folks_persona_get_store (persona); + contact = tpf_persona_get_contact (TPF_PERSONA (persona)); + + if (account != NULL) + *account = tpf_persona_store_get_account (TPF_PERSONA_STORE (store)); + + return contact; +} + +static void +chat_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + empathy_dispatcher_chat_with_contact_id ( + account, + tp_contact_get_identifier (contact), + TP_USER_ACTION_TIME_CURRENT_TIME); +} + +static void +audio_call_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + EmpathyContact *e_contact; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + e_contact = empathy_contact_dup_from_tp_contact (contact); + + empathy_call_factory_new_call_with_streams (e_contact, + TRUE, FALSE, TP_USER_ACTION_TIME_CURRENT_TIME, + NULL); + + g_object_unref (e_contact); +} + +static void +video_call_clicked_cb (MxButton *button, + LolContactView *self) +{ + TpContact *contact; + TpAccount *account; + EmpathyContact *e_contact; + + contact = get_contact_and_account (self, &account); + + if (contact == NULL) + return; + + e_contact = empathy_contact_dup_from_tp_contact (contact); + + empathy_call_factory_new_call_with_streams (e_contact, + TRUE, TRUE, TP_USER_ACTION_TIME_CURRENT_TIME, + NULL); + + g_object_unref (e_contact); +} + +static void +lol_contact_view_constructed (GObject *obj) +{ + LolContactView *self = LOL_CONTACT_VIEW (obj); + LolContactViewPrivate *priv = self->priv; + ClutterBoxLayout *layout; + + ClutterActor *box, *button; + + void (*chain_up) (GObject *) = + ((GObjectClass *) lol_contact_view_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (obj); + + layout = CLUTTER_BOX_LAYOUT (clutter_box_get_layout_manager (CLUTTER_BOX (self))); + clutter_box_layout_set_spacing (layout, 10); + clutter_box_layout_set_vertical (layout, TRUE); + + box = clutter_box_new (clutter_box_layout_new ()); + clutter_actor_set_height (box, 48.0); + + priv->presence_texture = clutter_texture_new (); + clutter_actor_set_height (priv->presence_texture, 32.0); + clutter_actor_set_width (priv->presence_texture, 32.0); + clutter_box_pack (CLUTTER_BOX (box), priv->presence_texture, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_actor_show (priv->presence_texture); + + priv->name_text = clutter_text_new (); + clutter_box_pack (CLUTTER_BOX (box), priv->name_text, + "x-align", CLUTTER_BOX_ALIGNMENT_START, + "y-align", CLUTTER_BOX_ALIGNMENT_CENTER, + "x-fill", TRUE, + "y-fill", FALSE, + "expand", TRUE, + NULL); + clutter_actor_show (priv->name_text); + + priv->avatar_texture = clutter_texture_new (); + clutter_actor_set_height (priv->avatar_texture, 32.0); + clutter_actor_set_width (priv->avatar_texture, 32.0); + clutter_box_pack (CLUTTER_BOX (box), priv->avatar_texture, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_actor_show (priv->avatar_texture); + + /* add the first hbox to the vbox */ + clutter_box_pack (CLUTTER_BOX (obj), box, + "expand", TRUE, + "x-fill", TRUE, + "y-fill", TRUE, + NULL); + + /* now onto the second box */ + layout = CLUTTER_BOX_LAYOUT (clutter_box_layout_new ()); + priv->actions = clutter_box_new (CLUTTER_LAYOUT_MANAGER (layout)); + clutter_actor_set_height (priv->actions, 32.0); + + button = mx_button_new_with_label ("Chat"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (chat_clicked_cb), self); + + button = mx_button_new_with_label ("Audio Call"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (audio_call_clicked_cb), self); + + button = mx_button_new_with_label ("Video Call"); + clutter_box_pack (CLUTTER_BOX (priv->actions), button, + "expand", FALSE, + "x-fill", FALSE, + "y-fill", FALSE, + NULL); + clutter_box_layout_set_alignment (layout, button, + CLUTTER_BOX_ALIGNMENT_START, CLUTTER_BOX_ALIGNMENT_START); + + g_signal_connect (button, "clicked", G_CALLBACK (video_call_clicked_cb), self); + + clutter_box_pack (CLUTTER_BOX (obj), priv->actions, + "expand", TRUE, + "x-fill", TRUE, + "y-fill", TRUE, + NULL); + clutter_actor_hide (priv->actions); + + clutter_actor_hide (CLUTTER_ACTOR (self)); +} + +static void +lol_contact_view_dispose (GObject *obj) +{ + LolContactView *self = LOL_CONTACT_VIEW (obj); + + if (self->priv->individual != NULL) + { + g_object_unref (self->priv->individual); + self->priv->individual = NULL; + } + + if (G_OBJECT_CLASS (lol_contact_view_parent_class)->finalize != NULL) + G_OBJECT_CLASS (lol_contact_view_parent_class)->finalize (obj); +} + +static void +lol_contact_view_class_init (LolContactViewClass *cls) +{ + GObjectClass *object_class = G_OBJECT_CLASS (cls); + + object_class->set_property = lol_contact_view_set_property; + object_class->get_property = lol_contact_view_get_property; + object_class->constructed = lol_contact_view_constructed; + object_class->dispose = lol_contact_view_dispose; + + g_object_class_install_property (object_class, + PROP_INDIVIDUAL, + g_param_spec_object ("individual", "Individual", "FolksIndividual", + FOLKS_TYPE_INDIVIDUAL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + signals[SELECTED] = g_signal_new ("selected", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + g_type_class_add_private (cls, sizeof (LolContactViewPrivate)); +} + +LolContactView * +lol_contact_view_new (void) +{ + return g_object_new (LOL_TYPE_CONTACT_VIEW, + "layout-manager", clutter_box_layout_new (), + "reactive", TRUE, + NULL); +} + +void +lol_contact_view_toggle_selected (LolContactView *self) +{ + LolContactViewPrivate *priv = self->priv; + ClutterColor blue = { 83, 136, 224, 255 }; + ClutterColor white = { 255, 255, 255, 255 }; + ClutterColor black = { 0, 0, 0, 255 }; + + priv->selected = !priv->selected; + + if (priv->selected) + { + clutter_box_set_color (CLUTTER_BOX (self), &blue); + clutter_actor_show (priv->actions); + clutter_text_set_color (CLUTTER_TEXT (priv->name_text), &white); + } + else + { + clutter_box_set_color (CLUTTER_BOX (self), &white); + clutter_actor_hide (priv->actions); + clutter_text_set_color (CLUTTER_TEXT (priv->name_text), &black); + } + + g_signal_emit (self, signals[SELECTED], 0, priv->selected); +} |