display presence status
- Modify RecentContactsView so that it displays the number of unread
messages as a number
- Modify PixbufManipulator so that it draws presence status if
displayPresence parameter is set to true. It dispays presence status
as a green circle in the corner of the avatar.
[SS: moved drawing call to PixbufManipulator from RecentContactsView]
[SS: fixed unread count being hardcoded to 10]
Tuleap: #1379
Change-Id: I1fda061d26f231e9d0bb82f044eac91ecdb74db8
Signed-off-by: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
diff --git a/src/native/pixbufmanipulator.cpp b/src/native/pixbufmanipulator.cpp
index 1e534bf..3790d58 100644
--- a/src/native/pixbufmanipulator.cpp
+++ b/src/native/pixbufmanipulator.cpp
@@ -36,7 +36,7 @@
}
std::shared_ptr<GdkPixbuf>
-PixbufManipulator::scaleAndFrame(const GdkPixbuf *photo, const QSize& size)
+PixbufManipulator::scaleAndFrame(const GdkPixbuf *photo, const QSize& size, bool display_presence, bool is_present)
{
/**
* for now, respect the height requested
@@ -63,14 +63,25 @@
g_object_unref};
/* frame photo */
- return {ring_frame_avatar(scaled_photo.get()), g_object_unref};
+ std::shared_ptr<GdkPixbuf> result {
+ ring_frame_avatar(scaled_photo.get()),
+ g_object_unref
+ };
+
+ /* draw presence */
+ if (display_presence)
+ result.reset(ring_draw_presence(result.get(), is_present), g_object_unref);
+
+ return result;
}
QVariant
PixbufManipulator::callPhoto(Call* c, const QSize& size, bool displayPresence)
{
- if (c->type() == Call::Type::CONFERENCE)
- return QVariant::fromValue(scaleAndFrame(conferenceAvatar_.get(), size));
+ if (c->type() == Call::Type::CONFERENCE) {
+ /* conferences are always "online" */
+ return QVariant::fromValue(scaleAndFrame(conferenceAvatar_.get(), size, displayPresence, TRUE));
+ }
return callPhoto(c->peerContactMethod(), size, displayPresence);
}
@@ -80,15 +91,13 @@
if (n->contact()) {
return contactPhoto(n->contact(), size, displayPresence);
} else {
- return QVariant::fromValue(scaleAndFrame(fallbackAvatar_.get(), size));
+ return QVariant::fromValue(scaleAndFrame(fallbackAvatar_.get(), size, displayPresence, n->isPresent()));
}
}
QVariant
PixbufManipulator::contactPhoto(Person* c, const QSize& size, bool displayPresence)
{
- Q_UNUSED(displayPresence);
-
/**
* try to get the photo
* otherwise use the fallback avatar
@@ -101,7 +110,7 @@
else
photo = fallbackAvatar_;
- return QVariant::fromValue(scaleAndFrame(photo.get(), size));
+ return QVariant::fromValue(scaleAndFrame(photo.get(), size, displayPresence, c->isPresent()));
}
QVariant PixbufManipulator::personPhoto(const QByteArray& data, const QString& type)
diff --git a/src/native/pixbufmanipulator.h b/src/native/pixbufmanipulator.h
index 3122678..ddeb4e1 100644
--- a/src/native/pixbufmanipulator.h
+++ b/src/native/pixbufmanipulator.h
@@ -55,7 +55,7 @@
QVariant decorationRole(const Account* p) override;
private:
- std::shared_ptr<GdkPixbuf> scaleAndFrame(const GdkPixbuf *photo, const QSize& size);
+ std::shared_ptr<GdkPixbuf> scaleAndFrame(const GdkPixbuf *photo, const QSize& size, bool display_presence = false, bool is_present = false);
std::shared_ptr<GdkPixbuf> fallbackAvatar_;
std::shared_ptr<GdkPixbuf> conferenceAvatar_;
};
diff --git a/src/recentcontactsview.cpp b/src/recentcontactsview.cpp
index 2d14c77..f903fba 100644
--- a/src/recentcontactsview.cpp
+++ b/src/recentcontactsview.cpp
@@ -102,22 +102,18 @@
if (idx.isValid() && object.isValid()) {
QVariant var_photo;
if (auto person = object.value<Person *>()) {
- var_photo = GlobalInstances::pixmapManipulator().contactPhoto(person, QSize(50, 50), false);
+ var_photo = GlobalInstances::pixmapManipulator().contactPhoto(person, QSize(50, 50), true);
} else if (auto cm = object.value<ContactMethod *>()) {
/* get photo, note that this should in all cases be the fallback avatar, since there
* shouldn't be a person associated with this contact method */
- var_photo = GlobalInstances::pixmapManipulator().callPhoto(cm, QSize(50, 50), false);
+ var_photo = GlobalInstances::pixmapManipulator().callPhoto(cm, QSize(50, 50), true);
} else if (auto call = object.value<Call *>()) {
if (call->type() == Call::Type::CONFERENCE) {
- var_photo = GlobalInstances::pixmapManipulator().callPhoto(call, QSize(50, 50), false);
+ var_photo = GlobalInstances::pixmapManipulator().callPhoto(call, QSize(50, 50), true);
}
}
if (var_photo.isValid()) {
- std::shared_ptr<GdkPixbuf> photo = var_photo.value<std::shared_ptr<GdkPixbuf>>();
-
- auto unread = idx.data(static_cast<int>(Ring::Role::UnreadTextMessageCount));
-
- image.reset(ring_draw_unread_messages(photo.get(), unread.toInt()), g_object_unref);
+ image = var_photo.value<std::shared_ptr<GdkPixbuf>>();
} else {
// set the width of the cell rendered to the with of the photo
// so that the other renderers are shifted to the right
@@ -279,6 +275,13 @@
{
text = g_markup_escape_text(duration.value<QString>().toUtf8().constData(), -1);
}
+ else
+ {
+ auto unread = idx.data(static_cast<int>(Ring::Role::UnreadTextMessageCount)).toInt();
+ if (unread > 0){
+ text = g_markup_printf_escaped("<span color=\"red\" font_weight=\"bold\">%d</span>", unread);
+ }
+ }
}
break;
case Ring::ObjectType::Call:
@@ -623,7 +626,7 @@
self,
NULL);
- /* call duration */
+ /* call duration or unread messages */
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
gtk_cell_area_box_pack_end(GTK_CELL_AREA_BOX(area), renderer, FALSE, FALSE, FALSE);
diff --git a/src/utils/drawing.cpp b/src/utils/drawing.cpp
index eec274a..20d33c8 100644
--- a/src/utils/drawing.cpp
+++ b/src/utils/drawing.cpp
@@ -26,6 +26,8 @@
static constexpr int MSG_COUNT_FONT_SIZE = 12;
static constexpr GdkRGBA MSG_COUNT_FONT_COLOUR = {1.0, 1.0, 1.0, 1.0}; // white
static constexpr GdkRGBA MSG_COUNT_BACKGROUND = {0.984, 0.282, 0.278, 0.9}; // red 251, 72, 71, 0.9
+static constexpr GdkRGBA PRESENCE_PRESENT_BACKGROUND = {0.4375, 0.0234375, 0.84765625, 0.9}; // green 112, 217, 6, 0.9
+static constexpr GdkRGBA PRESENCE_ABSENT_BACKGROUND = {0.984, 0.282, 0.278, 0.9}; // red 251, 72, 71, 0.9
GdkPixbuf *
ring_draw_fallback_avatar(int size) {
@@ -170,6 +172,55 @@
}
/**
+ * Draws the presence icon in the top right corner of the given image.
+ */
+GdkPixbuf *
+ring_draw_presence(const GdkPixbuf *avatar, bool present) {
+ if (!present) {
+ // simply return a copy of the original pixbuf
+ return gdk_pixbuf_copy(avatar);
+ }
+
+ int w = gdk_pixbuf_get_width(avatar);
+ int h = gdk_pixbuf_get_height(avatar);
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
+ cairo_t *cr = cairo_create(surface);
+ cairo_surface_destroy(surface);
+
+ /* draw original image */
+ gdk_cairo_set_source_pixbuf(cr, avatar, 0, 0);
+ cairo_paint(cr);
+
+ /* draw rounded rectangle, with 3 pixel border
+ * ie: 6 pixels higher, 6 pixels wider */
+ int border_width = 5;
+ double rec_x = w - border_width * 2.5;
+ double rec_y = h - border_width * 2.5;
+ double rec_w = border_width * 2;
+ double rec_h = border_width * 2;
+ double corner_radius = rec_h/2.5;
+ create_rounded_rectangle_path(cr, corner_radius, rec_x, rec_y, rec_w, rec_h);
+
+ // For now we don't draw the absent background.
+ auto background = present ? PRESENCE_PRESENT_BACKGROUND : PRESENCE_ABSENT_BACKGROUND;
+ cairo_set_source_rgba(
+ cr,
+ background.red,
+ background.blue,
+ background.green,
+ background.alpha
+ );
+ cairo_fill(cr);
+
+ GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, w, h);
+
+ /* free resources */
+ cairo_destroy(cr);
+
+ return pixbuf;
+}
+
+/**
* Draws the unread message count in the bottom right corner of the given image.
* In the case that the count is less than or equal to 0, nothing is drawn.
*/
diff --git a/src/utils/drawing.h b/src/utils/drawing.h
index ee96cc3..cbae46f 100644
--- a/src/utils/drawing.h
+++ b/src/utils/drawing.h
@@ -30,4 +30,6 @@
GdkPixbuf *ring_draw_unread_messages(const GdkPixbuf *avatar, int unread_count);
+GdkPixbuf *ring_draw_presence(const GdkPixbuf *avatar, bool present);
+
#endif /* _DRAWING */