welcomeview.cpp 13.4 KB
Newer Older
1
/*
2
 *  Copyright (C) 2015-2019 Savoir-faire Linux Inc.
3
 *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
4 5
 *  Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>
 *  Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */

22
#include "welcomeview.h"
23
#include "utils/drawing.h"
24 25 26 27

#include <gtk/gtk.h>
#include <glib/gi18n.h>

28 29
#include <api/newaccountmodel.h>

30 31 32 33
// Qt
#include <QObject>
#include <QItemSelectionModel>

34
struct _WelcomeView
35
{
36
    GtkScrolledWindow parent;
37 38
};

39
struct _WelcomeViewClass
40
{
41
    GtkScrolledWindowClass parent_class;
42 43
};

44
typedef struct _WelcomeViewPrivate WelcomeViewPrivate;
45

46
struct _WelcomeViewPrivate
47
{
48
    GtkWidget *box_overlay;
49
    GtkWidget *label_explanation;
50 51
    GtkWidget *hbox_idlayout;
    GtkWidget *label_ringid;
52
    GtkWidget *button_qrcode;
53
    GtkWidget *revealer_qrcode;
54

55 56
    bool useDarkTheme {false};

57
    AccountInfoPointer const *accountInfo_;
58 59
    QMetaObject::Connection nameRegistrationEnded_;

60 61
};

62
G_DEFINE_TYPE_WITH_PRIVATE(WelcomeView, welcome_view, GTK_TYPE_SCROLLED_WINDOW);
63

64
#define WELCOME_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), WELCOME_VIEW_TYPE, WelcomeViewPrivate))
65

66 67
static gboolean   draw_qr_event(GtkWidget*,cairo_t*,WelcomeView*);
static void       switch_qrcode(WelcomeView* self);
aviau's avatar
aviau committed
68

69
void
70 71
welcome_update_view(WelcomeView* self) {
    auto priv = WELCOME_VIEW_GET_PRIVATE(self);
72

73
    // Only draw a basic view for SIP accounts
74
    if (not *priv->accountInfo_ || (*priv->accountInfo_)->profileInfo.type == lrc::api::profile::Type::SIP) {
75
        gtk_widget_hide(priv->button_qrcode);
76
        gtk_widget_hide(priv->hbox_idlayout);
77 78
        gtk_widget_hide(priv->label_ringid);
        gtk_widget_hide(priv->label_explanation);
79
        gtk_widget_hide(priv->revealer_qrcode);
80
        gtk_widget_set_opacity(priv->box_overlay, 1.0);
81 82 83 84
        gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer_qrcode), FALSE);
        return;
    }

85 86
    auto color = priv->useDarkTheme? "white" : "black";

87
    // Get registeredName, else the ID
88
    gchar *id = nullptr;
89
    if(! (*priv->accountInfo_)->registeredName.empty()){
90 91
        gtk_label_set_text(
            GTK_LABEL(priv->label_explanation),
92
            _("This is your Jami username.\nCopy and share it with your friends!")
93
        );
94
        id = g_markup_printf_escaped("<span fgcolor=\"%s\">%s</span>", color,
95
                                          (*priv->accountInfo_)->registeredName.c_str());
96
    }
97
    else if (!(*priv->accountInfo_)->profileInfo.uri.empty()) {
98 99
        gtk_label_set_text(
            GTK_LABEL(priv->label_explanation),
100
            _("This is your ID.\nCopy and share it with your friends!")
101
        );
102
        id = g_markup_printf_escaped("<span fgcolor=\"%s\">%s</span>", color,
103
                                          (*priv->accountInfo_)->profileInfo.uri.c_str());
104 105
    } else {
        gtk_label_set_text(GTK_LABEL(priv->label_explanation), NULL);
106
        id = g_strdup("");
107 108
    }

109
    gtk_label_set_markup(GTK_LABEL(priv->label_ringid), id);
110 111

    gtk_widget_show(priv->label_explanation);
112
    gtk_widget_show(priv->hbox_idlayout);
113 114 115
    gtk_widget_show(priv->label_ringid);
    gtk_widget_show(priv->button_qrcode);
    gtk_widget_show(priv->revealer_qrcode);
116

117
    g_free(id);
118

119 120 121 122 123 124 125 126 127 128 129 130

    GError *error = NULL;
    GdkPixbuf *image_qr = gdk_pixbuf_new_from_resource_at_scale(priv->useDarkTheme? "/net/jami/JamiGnome/qrcode-white" : "/net/jami/JamiGnome/qrcode",
                                                                  -1, 16, TRUE, &error);
    if (!image_qr) {
        g_warning("Could not load icon: %s", error->message);
        g_clear_error(&error);
    } else {
        auto image = gtk_image_new_from_pixbuf(image_qr);
        gtk_button_set_image(GTK_BUTTON(priv->button_qrcode), image);
    }

131 132 133 134 135 136 137 138
    priv->nameRegistrationEnded_ = QObject::connect(
        (*priv->accountInfo_)->accountModel,
        &lrc::api::NewAccountModel::nameRegistrationEnded,
        [=] (const std::string& accountId, lrc::api::account::RegisterNameStatus status, const std::string& name) {
            if (not *priv->accountInfo_) return;
            if (accountId == (*priv->accountInfo_)->id
                && status == lrc::api::account::RegisterNameStatus::SUCCESS)
                {
139
                    gchar *markup = g_markup_printf_escaped("<span fgcolor=\"%s\">%s</span>", color,
140 141 142 143 144
                        name.c_str());
                    gtk_label_set_markup(GTK_LABEL(priv->label_ringid), markup);
                    g_free(markup);
                }
        });
145 146
}

147
void
148
welcome_set_theme(WelcomeView* self, bool useDarkTheme)
149
{
150 151
    g_return_if_fail(IS_WELCOME_VIEW(self));
    auto* priv = WELCOME_VIEW_GET_PRIVATE(self);
152 153 154 155
    priv->useDarkTheme = useDarkTheme;
}


156
static void
157
welcome_view_init(WelcomeView *self)
158
{
159 160
    g_return_if_fail(IS_WELCOME_VIEW(self));
    auto* priv = WELCOME_VIEW_GET_PRIVATE(self);
161

162 163
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(self), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    auto box_main = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
    gtk_container_add(GTK_CONTAINER(self), box_main);
    gtk_box_set_baseline_position(GTK_BOX(box_main), GTK_BASELINE_POSITION_CENTER);
    gtk_widget_set_vexpand(GTK_WIDGET(box_main), TRUE);
    gtk_widget_set_hexpand(GTK_WIDGET(box_main), FALSE);
    gtk_widget_set_valign(GTK_WIDGET(box_main), GTK_ALIGN_CENTER);
    gtk_widget_set_halign(GTK_WIDGET(box_main), GTK_ALIGN_CENTER);
    gtk_widget_set_visible(GTK_WIDGET(box_main), TRUE);

    /* overlay to show hide the qr code over the stuff in it */
    auto overlay_qrcode = gtk_overlay_new();
    gtk_box_pack_start(GTK_BOX(box_main), overlay_qrcode, FALSE, TRUE, 0);

    /* box which will be in the overaly so that we can display the QR code over the stuff in this box */
    priv->box_overlay = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
    gtk_container_add(GTK_CONTAINER(overlay_qrcode), priv->box_overlay);
180 181 182

    /* get logo */
    GError *error = NULL;
183
    GdkPixbuf* logo = gdk_pixbuf_new_from_resource_at_scale("/net/jami/JamiGnome/jami-logo-blue",
184 185 186 187 188 189
                                                            350, -1, TRUE, &error);
    if (logo == NULL) {
        g_debug("Could not load logo: %s", error->message);
        g_clear_error(&error);
    } else {
        auto image_ring_logo = gtk_image_new_from_pixbuf(logo);
190
        gtk_box_pack_start(GTK_BOX(priv->box_overlay), image_ring_logo, FALSE, TRUE, 0);
aviau's avatar
aviau committed
191
        gtk_widget_set_visible(GTK_WIDGET(image_ring_logo), TRUE);
192 193 194
    }

    /* welcome text */
195
    auto label_welcome_text = gtk_label_new(_("Jami is free software for universal communication which respects the freedoms and privacy of its users."));
196
    gtk_label_set_justify(GTK_LABEL(label_welcome_text), GTK_JUSTIFY_CENTER);
197 198 199 200 201
    PangoAttrList *attrs_welcome_text = pango_attr_list_new();
    PangoAttribute *font_desc_welcome_text = pango_attr_font_desc_new(pango_font_description_from_string("12"));
    pango_attr_list_insert(attrs_welcome_text, font_desc_welcome_text);
    gtk_label_set_attributes(GTK_LABEL(label_welcome_text), attrs_welcome_text);
    pango_attr_list_unref(attrs_welcome_text);
202 203 204 205
    gtk_label_set_line_wrap(GTK_LABEL(label_welcome_text), TRUE);
    /* the max width chars is to limit how much the text expands */
    gtk_label_set_max_width_chars(GTK_LABEL(label_welcome_text), 50);
    gtk_label_set_selectable(GTK_LABEL(label_welcome_text), TRUE);
206
    gtk_box_pack_start(GTK_BOX(priv->box_overlay), label_welcome_text, FALSE, TRUE, 0);
aviau's avatar
aviau committed
207
    gtk_widget_set_visible(GTK_WIDGET(label_welcome_text), TRUE);
208

209
    /* ID explanation */
210
    priv->label_explanation = gtk_label_new(NULL);
211
    auto context = gtk_widget_get_style_context(priv->label_explanation);
212
    gtk_style_context_add_class(context, GTK_STYLE_CLASS_DIM_LABEL);
213 214 215 216
    gtk_label_set_justify(GTK_LABEL(priv->label_explanation), GTK_JUSTIFY_CENTER);
    gtk_label_set_selectable(GTK_LABEL(priv->label_explanation), TRUE);
    gtk_widget_set_margin_top(priv->label_explanation, 20);
    gtk_widget_set_no_show_all(priv->label_explanation, TRUE);
217
    gtk_box_pack_start(GTK_BOX(priv->box_overlay), priv->label_explanation, FALSE, TRUE, 0);
218

219 220 221 222 223 224 225 226 227 228
    priv->hbox_idlayout = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 15);
    gtk_container_add(GTK_CONTAINER(self), priv->hbox_idlayout);
    gtk_box_set_baseline_position(GTK_BOX(priv->hbox_idlayout), GTK_BASELINE_POSITION_CENTER);
    gtk_widget_set_vexpand(GTK_WIDGET(priv->hbox_idlayout), FALSE);
    gtk_widget_set_hexpand(GTK_WIDGET(priv->hbox_idlayout), FALSE);
    gtk_widget_set_valign(GTK_WIDGET(priv->hbox_idlayout), GTK_ALIGN_CENTER);
    gtk_widget_set_halign(GTK_WIDGET(priv->hbox_idlayout), GTK_ALIGN_CENTER);
    gtk_widget_set_visible(GTK_WIDGET(priv->hbox_idlayout), TRUE);

    /* ID label */
229 230
    priv->label_ringid = gtk_label_new(NULL);
    gtk_label_set_selectable(GTK_LABEL(priv->label_ringid), TRUE);
231 232 233 234 235
    PangoAttrList *attrs_ringid = pango_attr_list_new();
    PangoAttribute *font_desc_ringid = pango_attr_font_desc_new(pango_font_description_from_string("monospace 12"));
    pango_attr_list_insert(attrs_ringid, font_desc_ringid);
    gtk_label_set_attributes(GTK_LABEL(priv->label_ringid), attrs_ringid);
    pango_attr_list_unref(attrs_ringid);
236
    gtk_widget_set_no_show_all(priv->label_ringid, TRUE);
237
    gtk_box_pack_start(GTK_BOX(priv->hbox_idlayout), priv->label_ringid, FALSE, TRUE, 0);
238

aviau's avatar
aviau committed
239
    /* QR drawing area */
240
    auto drawingarea_qrcode = gtk_drawing_area_new();
aviau's avatar
aviau committed
241
    auto qrsize = 200;
242
    gtk_widget_set_size_request(drawingarea_qrcode, qrsize, qrsize);
243
    g_signal_connect(drawingarea_qrcode, "draw", G_CALLBACK(draw_qr_event), self);
244 245 246 247 248 249 250 251 252 253 254
    gtk_widget_set_visible(drawingarea_qrcode, TRUE);

    /* revealer which will show the qr code */
    priv->revealer_qrcode = gtk_revealer_new();
    gtk_container_add(GTK_CONTAINER(priv->revealer_qrcode), drawingarea_qrcode);
    gtk_revealer_set_transition_type(GTK_REVEALER(priv->revealer_qrcode), GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); //GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    gtk_widget_set_halign(priv->revealer_qrcode, GTK_ALIGN_CENTER);
    gtk_widget_set_valign(priv->revealer_qrcode, GTK_ALIGN_CENTER);
    gtk_overlay_add_overlay(GTK_OVERLAY(overlay_qrcode), priv->revealer_qrcode);
    gtk_widget_set_no_show_all(priv->revealer_qrcode, TRUE);
    gtk_widget_set_visible(priv->revealer_qrcode, FALSE);
aviau's avatar
aviau committed
255 256

    /* QR code button */
257
    priv->button_qrcode = gtk_button_new();
258
    GdkPixbuf *image_qr = gdk_pixbuf_new_from_resource_at_scale(priv->useDarkTheme? "/net/jami/JamiGnome/qrcode-white" : "/net/jami/JamiGnome/qrcode",
259 260 261 262 263 264 265 266
                                                                  -1, 16, TRUE, &error);
    if (!image_qr) {
        g_warning("Could not load icon: %s", error->message);
        g_clear_error(&error);
    } else {
        auto image = gtk_image_new_from_pixbuf(image_qr);
        gtk_button_set_image(GTK_BUTTON(priv->button_qrcode), image);
    }
267 268
    gtk_widget_set_hexpand(priv->button_qrcode, FALSE);
    gtk_widget_set_size_request(priv->button_qrcode,10,10);
269
    g_signal_connect_swapped(priv->button_qrcode, "clicked", G_CALLBACK(switch_qrcode), self);
270
    gtk_widget_set_no_show_all(priv->button_qrcode, TRUE);
271 272 273 274
    gtk_box_pack_start(GTK_BOX(priv->hbox_idlayout), priv->button_qrcode, TRUE, TRUE, 0);

    gtk_box_pack_start(GTK_BOX(box_main), priv->hbox_idlayout, FALSE, TRUE, 0);
    gtk_label_set_ellipsize(GTK_LABEL(priv->label_ringid), PANGO_ELLIPSIZE_END);
275 276

    gtk_widget_show_all(GTK_WIDGET(self));
277 278 279
}

static void
280
welcome_view_dispose(GObject *object)
281
{
282
    auto* priv = WELCOME_VIEW_GET_PRIVATE(object);
283
    QObject::disconnect(priv->nameRegistrationEnded_);
284
    G_OBJECT_CLASS(welcome_view_parent_class)->dispose(object);
285 286 287
}

static void
288
welcome_view_finalize(GObject *object)
289
{
290
    G_OBJECT_CLASS(welcome_view_parent_class)->finalize(object);
291 292 293
}

static void
294
welcome_view_class_init(WelcomeViewClass *klass)
295
{
296 297
    G_OBJECT_CLASS(klass)->finalize = welcome_view_finalize;
    G_OBJECT_CLASS(klass)->dispose = welcome_view_dispose;
298 299 300
}

GtkWidget *
301
welcome_view_new(AccountInfoPointer const & accountInfo)
302
{
303 304
    gpointer self = g_object_new(WELCOME_VIEW_TYPE, NULL);
    auto priv = WELCOME_VIEW_GET_PRIVATE(self);
305
    priv->accountInfo_ = &accountInfo;
306
    welcome_update_view(WELCOME_VIEW(self));
307 308 309

    return (GtkWidget *)self;
}
aviau's avatar
aviau committed
310

311

aviau's avatar
aviau committed
312
static gboolean
313
draw_qr_event(G_GNUC_UNUSED GtkWidget* diese,
aviau's avatar
aviau committed
314
            cairo_t*   cr,
315
            WelcomeView* self)
aviau's avatar
aviau committed
316
{
317
    auto priv = WELCOME_VIEW_GET_PRIVATE(self);
318 319
    g_return_val_if_fail(priv, false);
    return draw_qrcode(cr, (*priv->accountInfo_)->profileInfo.uri.c_str(), 200);
aviau's avatar
aviau committed
320 321 322
}

static void
323
switch_qrcode(WelcomeView* self)
aviau's avatar
aviau committed
324
{
325
    auto priv = WELCOME_VIEW_GET_PRIVATE(self);
326 327 328 329

    auto to_reveal = !gtk_revealer_get_reveal_child(GTK_REVEALER(priv->revealer_qrcode));
    gtk_revealer_set_reveal_child(GTK_REVEALER(priv->revealer_qrcode), to_reveal);
    gtk_widget_set_opacity(priv->box_overlay, to_reveal ? 0.25 : 1.0);
aviau's avatar
aviau committed
330
}