blob: ccddf71554138a7386b289ba7c3b86418cbe4212 [file] [log] [blame]
Stepan Salenikovich2cde7612015-09-25 10:44:01 -04001/*
Guillaume Roguez2a6150d2017-07-19 18:24:47 -04002 * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
Stepan Salenikovich2cde7612015-09-25 10:44:01 -04003 * Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "ringwelcomeview.h"
21
22#include <gtk/gtk.h>
23#include <glib/gi18n.h>
24#include "utils/accounts.h"
25#include <account.h>
26#include <accountmodel.h>
aviaudd355ba2016-04-08 14:23:09 -040027#include <qrencode.h>
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040028
Nicolas Jager15a8b902017-03-21 07:53:06 -040029// Qt
30#include <QObject>
31#include <QItemSelectionModel>
32
Nicolas Jagerf71f8d82017-04-17 10:22:06 -040033// LRC
34#include <availableaccountmodel.h>
35
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040036struct _RingWelcomeView
37{
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050038 GtkScrolledWindow parent;
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040039};
40
41struct _RingWelcomeViewClass
42{
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050043 GtkScrolledWindowClass parent_class;
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040044};
45
46typedef struct _RingWelcomeViewPrivate RingWelcomeViewPrivate;
47
48struct _RingWelcomeViewPrivate
49{
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -040050 GtkWidget *box_overlay;
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040051 GtkWidget *label_ringid;
52 GtkWidget *label_explanation;
53 GtkWidget *button_qrcode;
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -040054 GtkWidget *revealer_qrcode;
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040055
aviaudf1f97b2016-10-24 12:34:14 -040056 QMetaObject::Connection account_model_data_changed;
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040057};
58
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -050059G_DEFINE_TYPE_WITH_PRIVATE(RingWelcomeView, ring_welcome_view, GTK_TYPE_SCROLLED_WINDOW);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040060
61#define RING_WELCOME_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), RING_WELCOME_VIEW_TYPE, RingWelcomeViewPrivate))
62
aviaudd355ba2016-04-08 14:23:09 -040063static gboolean draw_qrcode(GtkWidget*,cairo_t*,gpointer);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -040064static void switch_qrcode(RingWelcomeView* self);
aviaudd355ba2016-04-08 14:23:09 -040065
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040066static void
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040067update_view(RingWelcomeView *self) {
68 auto priv = RING_WELCOME_VIEW_GET_PRIVATE(self);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040069
Nicolas Jager15a8b902017-03-21 07:53:06 -040070 if (auto account = get_active_ring_account()) {
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040071 gchar *ring_id = nullptr;
aviauf74c7b52016-12-01 13:57:00 -050072 if(!account->registeredName().isEmpty()){
73 gtk_label_set_text(
74 GTK_LABEL(priv->label_explanation),
75 _("This is your Ring username.\nCopy and share it with your friends!")
76 );
77 ring_id = g_markup_printf_escaped("<span fgcolor=\"black\">ring:%s</span>",
78 account->registeredName().toUtf8().constData());
79 }
80 else if (!account->username().isEmpty()) {
81 gtk_label_set_text(
82 GTK_LABEL(priv->label_explanation),
83 C_("Do not translate \"RingID\"", "This is your RingID.\nCopy and share it with your friends!")
84 );
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040085 ring_id = g_markup_printf_escaped("<span fgcolor=\"black\">%s</span>",
86 account->username().toUtf8().constData());
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040087 } else {
aviauf74c7b52016-12-01 13:57:00 -050088 gtk_label_set_text(GTK_LABEL(priv->label_explanation), NULL);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040089 ring_id = g_markup_printf_escaped("<span fgcolor=\"gray\">%s</span>",
90 _("fetching RingID..."));
Stepan Salenikovich2cde7612015-09-25 10:44:01 -040091 }
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040092 gtk_label_set_markup(GTK_LABEL(priv->label_ringid), ring_id);
Nicolas Jager15a8b902017-03-21 07:53:06 -040093 gtk_widget_show(priv->label_explanation);
94 gtk_widget_show(priv->label_ringid);
95 gtk_widget_show(priv->button_qrcode);
96 gtk_widget_show(priv->revealer_qrcode);
97
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040098 g_free(ring_id);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -040099
Nicolas Jager15a8b902017-03-21 07:53:06 -0400100 } else { // any other protocols
101 gtk_widget_hide(priv->label_explanation);
102 gtk_widget_hide(priv->label_ringid);
103 gtk_widget_hide(priv->button_qrcode);
104 gtk_widget_hide(priv->revealer_qrcode);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400105 gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer_qrcode), FALSE);
106 gtk_widget_set_opacity(priv->box_overlay, 1.0);
107 }
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400108}
109
110static void
111ring_welcome_view_init(RingWelcomeView *self)
112{
113 RingWelcomeViewPrivate *priv = RING_WELCOME_VIEW_GET_PRIVATE(self);
114
Stepan Salenikovichab0f5be2016-02-05 15:16:35 -0500115 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(self), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
116
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400117 auto box_main = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
118 gtk_container_add(GTK_CONTAINER(self), box_main);
119 gtk_box_set_baseline_position(GTK_BOX(box_main), GTK_BASELINE_POSITION_CENTER);
120 gtk_widget_set_vexpand(GTK_WIDGET(box_main), TRUE);
121 gtk_widget_set_hexpand(GTK_WIDGET(box_main), FALSE);
122 gtk_widget_set_valign(GTK_WIDGET(box_main), GTK_ALIGN_CENTER);
123 gtk_widget_set_halign(GTK_WIDGET(box_main), GTK_ALIGN_CENTER);
124 gtk_widget_set_visible(GTK_WIDGET(box_main), TRUE);
125
126 /* overlay to show hide the qr code over the stuff in it */
127 auto overlay_qrcode = gtk_overlay_new();
128 gtk_box_pack_start(GTK_BOX(box_main), overlay_qrcode, FALSE, TRUE, 0);
129
130 /* box which will be in the overaly so that we can display the QR code over the stuff in this box */
131 priv->box_overlay = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
132 gtk_container_add(GTK_CONTAINER(overlay_qrcode), priv->box_overlay);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400133
134 /* get logo */
135 GError *error = NULL;
136 GdkPixbuf* logo = gdk_pixbuf_new_from_resource_at_scale("/cx/ring/RingGnome/ring-logo-blue",
137 350, -1, TRUE, &error);
138 if (logo == NULL) {
139 g_debug("Could not load logo: %s", error->message);
140 g_clear_error(&error);
141 } else {
142 auto image_ring_logo = gtk_image_new_from_pixbuf(logo);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400143 gtk_box_pack_start(GTK_BOX(priv->box_overlay), image_ring_logo, FALSE, TRUE, 0);
aviaudd355ba2016-04-08 14:23:09 -0400144 gtk_widget_set_visible(GTK_WIDGET(image_ring_logo), TRUE);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400145 }
146
147 /* welcome text */
Stepan Salenikovichd4d19d62016-11-03 11:12:22 -0400148 auto label_welcome_text = gtk_label_new(_("Ring is free software for universal communication which respects the freedoms and privacy of its users."));
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400149 gtk_label_set_justify(GTK_LABEL(label_welcome_text), GTK_JUSTIFY_CENTER);
Houmin68293822017-05-16 12:13:55 +0800150 PangoAttrList *attrs_welcome_text = pango_attr_list_new();
151 PangoAttribute *font_desc_welcome_text = pango_attr_font_desc_new(pango_font_description_from_string("12"));
152 pango_attr_list_insert(attrs_welcome_text, font_desc_welcome_text);
153 gtk_label_set_attributes(GTK_LABEL(label_welcome_text), attrs_welcome_text);
154 pango_attr_list_unref(attrs_welcome_text);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400155 gtk_label_set_line_wrap(GTK_LABEL(label_welcome_text), TRUE);
156 /* the max width chars is to limit how much the text expands */
157 gtk_label_set_max_width_chars(GTK_LABEL(label_welcome_text), 50);
158 gtk_label_set_selectable(GTK_LABEL(label_welcome_text), TRUE);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400159 gtk_box_pack_start(GTK_BOX(priv->box_overlay), label_welcome_text, FALSE, TRUE, 0);
aviaudd355ba2016-04-08 14:23:09 -0400160 gtk_widget_set_visible(GTK_WIDGET(label_welcome_text), TRUE);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400161
162 /* RingID explanation */
aviauf74c7b52016-12-01 13:57:00 -0500163 priv->label_explanation = gtk_label_new(NULL);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400164 auto context = gtk_widget_get_style_context(priv->label_explanation);
Stepan Salenikovichcebc5922015-10-22 15:43:09 -0400165 gtk_style_context_add_class(context, GTK_STYLE_CLASS_DIM_LABEL);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400166 gtk_label_set_justify(GTK_LABEL(priv->label_explanation), GTK_JUSTIFY_CENTER);
167 gtk_label_set_selectable(GTK_LABEL(priv->label_explanation), TRUE);
168 gtk_widget_set_margin_top(priv->label_explanation, 20);
169 gtk_widget_set_no_show_all(priv->label_explanation, TRUE);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400170 gtk_box_pack_start(GTK_BOX(priv->box_overlay), priv->label_explanation, FALSE, TRUE, 0);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400171
172 /* RingID label */
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400173 priv->label_ringid = gtk_label_new(NULL);
174 gtk_label_set_selectable(GTK_LABEL(priv->label_ringid), TRUE);
Houmin68293822017-05-16 12:13:55 +0800175 PangoAttrList *attrs_ringid = pango_attr_list_new();
176 PangoAttribute *font_desc_ringid = pango_attr_font_desc_new(pango_font_description_from_string("monospace 12"));
177 pango_attr_list_insert(attrs_ringid, font_desc_ringid);
178 gtk_label_set_attributes(GTK_LABEL(priv->label_ringid), attrs_ringid);
179 pango_attr_list_unref(attrs_ringid);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400180 gtk_widget_set_no_show_all(priv->label_ringid, TRUE);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400181 gtk_box_pack_start(GTK_BOX(box_main), priv->label_ringid, FALSE, TRUE, 0);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400182 gtk_label_set_ellipsize(GTK_LABEL(priv->label_ringid), PANGO_ELLIPSIZE_END);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400183
aviaudd355ba2016-04-08 14:23:09 -0400184 /* QR drawing area */
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400185 auto drawingarea_qrcode = gtk_drawing_area_new();
aviaudd355ba2016-04-08 14:23:09 -0400186 auto qrsize = 200;
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400187 gtk_widget_set_size_request(drawingarea_qrcode, qrsize, qrsize);
188 g_signal_connect(drawingarea_qrcode, "draw", G_CALLBACK(draw_qrcode), NULL);
189 gtk_widget_set_visible(drawingarea_qrcode, TRUE);
190
191 /* revealer which will show the qr code */
192 priv->revealer_qrcode = gtk_revealer_new();
193 gtk_container_add(GTK_CONTAINER(priv->revealer_qrcode), drawingarea_qrcode);
194 gtk_revealer_set_transition_type(GTK_REVEALER(priv->revealer_qrcode), GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); //GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
195 gtk_widget_set_halign(priv->revealer_qrcode, GTK_ALIGN_CENTER);
196 gtk_widget_set_valign(priv->revealer_qrcode, GTK_ALIGN_CENTER);
197 gtk_overlay_add_overlay(GTK_OVERLAY(overlay_qrcode), priv->revealer_qrcode);
198 gtk_widget_set_no_show_all(priv->revealer_qrcode, TRUE);
199 gtk_widget_set_visible(priv->revealer_qrcode, FALSE);
aviaudd355ba2016-04-08 14:23:09 -0400200
201 /* QR code button */
aviauf74c7b52016-12-01 13:57:00 -0500202 priv->button_qrcode = gtk_button_new_with_label(C_("Do not translate \"Ring ID\"", "Ring ID QR code"));
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400203 gtk_widget_set_hexpand(priv->button_qrcode, FALSE);
204 gtk_widget_set_size_request(priv->button_qrcode,10,10);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400205 g_signal_connect_swapped(priv->button_qrcode, "clicked", G_CALLBACK(switch_qrcode), self);
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400206 gtk_widget_set_no_show_all(priv->button_qrcode, TRUE);
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400207 gtk_box_pack_start(GTK_BOX(box_main), priv->button_qrcode, TRUE, TRUE, 0);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400208
Stepan Salenikovich11d88d82017-04-26 13:53:11 -0400209 update_view(self);
aviaudf1f97b2016-10-24 12:34:14 -0400210 priv->account_model_data_changed = QObject::connect(
Nicolas Jagere23e4942017-04-18 13:48:22 -0400211 AvailableAccountModel::instance().selectionModel(),
212 &QItemSelectionModel::currentChanged,
213 [self] ()
Nicolas Jagerf71f8d82017-04-17 10:22:06 -0400214 {
215 update_view(self);
216 });
Nicolas Jager15a8b902017-03-21 07:53:06 -0400217
Stepan Salenikovich64d446c2016-09-15 10:56:55 -0400218 gtk_widget_show_all(GTK_WIDGET(self));
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400219}
220
221static void
222ring_welcome_view_dispose(GObject *object)
223{
224 RingWelcomeView *self = RING_WELCOME_VIEW(object);
225 RingWelcomeViewPrivate *priv = RING_WELCOME_VIEW_GET_PRIVATE(self);
226
aviaudf1f97b2016-10-24 12:34:14 -0400227 QObject::disconnect(priv->account_model_data_changed);
Stepan Salenikovich2cde7612015-09-25 10:44:01 -0400228
229 G_OBJECT_CLASS(ring_welcome_view_parent_class)->dispose(object);
230}
231
232static void
233ring_welcome_view_finalize(GObject *object)
234{
235 G_OBJECT_CLASS(ring_welcome_view_parent_class)->finalize(object);
236}
237
238static void
239ring_welcome_view_class_init(RingWelcomeViewClass *klass)
240{
241 G_OBJECT_CLASS(klass)->finalize = ring_welcome_view_finalize;
242 G_OBJECT_CLASS(klass)->dispose = ring_welcome_view_dispose;
243}
244
245GtkWidget *
246ring_welcome_view_new()
247{
248 gpointer self = g_object_new(RING_WELCOME_VIEW_TYPE, NULL);
249
250 return (GtkWidget *)self;
251}
aviaudd355ba2016-04-08 14:23:09 -0400252
253static gboolean
Stepan Salenikovich635258c2016-05-17 14:41:20 -0400254draw_qrcode(G_GNUC_UNUSED GtkWidget* diese,
aviaudd355ba2016-04-08 14:23:09 -0400255 cairo_t* cr,
Stepan Salenikovich635258c2016-05-17 14:41:20 -0400256 G_GNUC_UNUSED gpointer data)
aviaudd355ba2016-04-08 14:23:09 -0400257{
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400258 auto account = get_active_ring_account();
259 if (!account)
260 return TRUE;
261
262 auto rcode = QRcode_encodeString(account->username().toStdString().c_str(),
aviaudd355ba2016-04-08 14:23:09 -0400263 0, //Let the version be decided by libqrencode
264 QR_ECLEVEL_L, // Lowest level of error correction
265 QR_MODE_8, // 8-bit data mode
266 1);
267
268 if (!rcode) { // no rcode, no draw
269 g_warning("Failed to generate QR code");
270 return TRUE;
271 }
272
273 auto margin = 5;
274 auto qrsize = 200;
275 int qrwidth = rcode->width + margin * 2;
276
277 /* scaling */
278 auto scale = qrsize/qrwidth;
279 cairo_scale(cr, scale, scale);
280
281 /* fill the background in white */
282 cairo_set_source_rgb(cr, 1, 1, 1);
283 cairo_rectangle(cr, 0, 0, qrwidth, qrwidth);
284 cairo_fill (cr);
285
286 unsigned char *row, *p;
287 p = rcode->data;
288 cairo_set_source_rgb(cr, 0, 0, 0); // back in black
289 for(int y = 0; y < rcode->width; y++) {
290 row = (p + (y * rcode->width));
291 for(int x = 0; x < rcode->width; x++) {
292 if(*(row + x) & 0x1) {
293 cairo_rectangle(cr, margin + x, margin + y, 1, 1);
294 cairo_fill(cr);
295 }
296 }
297
298 }
299
300 QRcode_free(rcode);
301 return TRUE;
302
303}
304
305static void
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400306switch_qrcode(RingWelcomeView* self)
aviaudd355ba2016-04-08 14:23:09 -0400307{
Stepan Salenikovich3e2851a2016-09-15 12:08:13 -0400308 auto priv = RING_WELCOME_VIEW_GET_PRIVATE(self);
309
310 auto to_reveal = !gtk_revealer_get_reveal_child(GTK_REVEALER(priv->revealer_qrcode));
311 gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer_qrcode), to_reveal);
312 gtk_widget_set_opacity(priv->box_overlay, to_reveal ? 0.25 : 1.0);
aviaudd355ba2016-04-08 14:23:09 -0400313}