blob: bd0428e36ffb9f6ad146f78857cbe3b7a69ee24e [file] [log] [blame]
aviau6aeb4852016-08-18 16:01:09 -04001/*
2 * Copyright (C) 2016 Savoir-faire Linux Inc.
3 * Author: Alexandre Viau <alexandre.viau@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
21// GTK+ related
22#include <gtk/gtk.h>
23#include <glib/gi18n.h>
24
25// LRC
26#include <codecmodel.h>
27#include <account.h>
28#include <accountmodel.h>
29#include <profilemodel.h>
30#include <profile.h>
31#include <personmodel.h>
32#include <globalinstances.h>
33
34// Ring Client
35#include "avatarmanipulation.h"
36#include "accountmigrationview.h"
37#include "utils/models.h"
38#include "native/pixbufmanipulator.h"
39#include "video/video_widget.h"
40
41/* size of avatar */
42static constexpr int AVATAR_WIDTH = 100; /* px */
43static constexpr int AVATAR_HEIGHT = 100; /* px */
44
45struct _AccountMigrationView
46{
47 GtkBox parent;
48};
49
50struct _AccountMigrationViewClass
51{
52 GtkBoxClass parent_class;
53};
54
55typedef struct _AccountMigrationViewPrivate AccountMigrationViewPrivate;
56
57struct _AccountMigrationViewPrivate
58{
59 Account *account;
60 GtkWidget *stack_account_migration;
61 QMetaObject::Connection state_changed;
62 guint timeout_tag;
63
64 /* generating_account_view */
65 GtkWidget *migrating_account_view;
66
67 /* error_view */
68 GtkWidget *error_view;
69 GtkWidget *button_error_view_ok;
70
71 /* main_view */
72 GtkWidget *main_view;
73 GtkWidget *label_account_alias;
74 GtkWidget *label_account_id;
75 GtkWidget *image_avatar;
76 GtkWidget *label_password_error;
77 GtkWidget *entry_password;
78 GtkWidget *entry_password_confirm;
79 GtkWidget *button_migrate_account;
80};
81
82G_DEFINE_TYPE_WITH_PRIVATE(AccountMigrationView, account_migration_view, GTK_TYPE_BOX);
83
84#define ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ACCOUNT_MIGRATION_VIEW_TYPE, AccountMigrationViewPrivate))
85
86/* signals */
87enum {
88 ACCOUNT_MIGRATION_COMPLETED,
89 ACCOUNT_MIGRATION_FAILED,
90 LAST_SIGNAL
91};
92
93static guint account_migration_view_signals[LAST_SIGNAL] = { 0 };
94
95static void
96account_migration_view_dispose(GObject *object)
97{
98 G_OBJECT_CLASS(account_migration_view_parent_class)->dispose(object);
99}
100
101static void
102account_migration_view_init(AccountMigrationView *view)
103{
104 gtk_widget_init_template(GTK_WIDGET(view));
105}
106
107static void
108account_migration_view_class_init(AccountMigrationViewClass *klass)
109{
110 G_OBJECT_CLASS(klass)->dispose = account_migration_view_dispose;
111
112 gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS (klass),
113 "/cx/ring/RingGnome/accountmigrationview.ui");
114
115 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, stack_account_migration);
116
117 /* error_view */
118 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, error_view);
119 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, button_error_view_ok);
120
121 /* migrating_account_view */
122 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, migrating_account_view);
123
124 /* main_view */
125 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, main_view);
126 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, label_account_alias);
127 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, label_account_id);
128 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, image_avatar);
129 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, label_password_error);
130 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, entry_password);
131 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, entry_password_confirm);
132 gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), AccountMigrationView, button_migrate_account);
133
134 /* add signals */
135 account_migration_view_signals[ACCOUNT_MIGRATION_COMPLETED] = g_signal_new("account-migration-completed",
136 G_TYPE_FROM_CLASS(klass),
137 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
138 0,
139 nullptr,
140 nullptr,
141 g_cclosure_marshal_VOID__VOID,
142 G_TYPE_NONE, 0);
143
144 account_migration_view_signals[ACCOUNT_MIGRATION_FAILED] = g_signal_new("account-migration-failed",
145 G_TYPE_FROM_CLASS(klass),
146 (GSignalFlags) (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION),
147 0,
148 nullptr,
149 nullptr,
150 g_cclosure_marshal_VOID__VOID,
151 G_TYPE_NONE, 0);
152}
153
154static gboolean
155migration_timeout(AccountMigrationView *view)
156{
157 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
158 QObject::disconnect(priv->state_changed);
159 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_migration), priv->error_view);
160 return G_SOURCE_REMOVE;
161}
162
163static void
164button_error_view_ok_clicked(G_GNUC_UNUSED GtkButton* button, AccountMigrationView *view)
165{
166 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
167 g_signal_emit(G_OBJECT(view), account_migration_view_signals[ACCOUNT_MIGRATION_FAILED], 0);
168}
169
170static void
171migrate_account_clicked(G_GNUC_UNUSED GtkButton* button, AccountMigrationView *view)
172{
173 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
174 gtk_widget_hide(priv->label_password_error);
175
176 /* Check for correct password */
177 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
178 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
179
180 if (g_strcmp0(password, password_confirm) != 0)
181 {
182 gtk_widget_show(priv->label_password_error);
183 return;
184 }
185 else
186 {
187 gtk_stack_set_visible_child(GTK_STACK(priv->stack_account_migration), priv->migrating_account_view);
188
189 priv->account->setArchivePassword(password);
190 priv->account->performAction(Account::EditAction::SAVE);
191
192 // Timeout in 30 seconds
193 priv->timeout_tag = g_timeout_add_full(G_PRIORITY_DEFAULT, 30000, (GSourceFunc)migration_timeout, view, NULL);
194
195 priv->state_changed = QObject::connect(
196 priv->account,
197 &Account::stateChanged,
198 [=] (Account::RegistrationState state) {
199 switch(state)
200 {
201 case Account::RegistrationState::READY:
202 case Account::RegistrationState::TRYING:
203 case Account::RegistrationState::UNREGISTERED:
204 {
205 // Make sure that the account is ready to be displayed.
206 priv->account << Account::EditAction::RELOAD;
207
208 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
209 QObject::disconnect(priv->state_changed); // only want to emit once
210 g_source_remove(priv->timeout_tag); // We didn't timeout
211 g_signal_emit(G_OBJECT(view), account_migration_view_signals[ACCOUNT_MIGRATION_COMPLETED], 0);
212 break;
213 }
214 case Account::RegistrationState::ERROR:
215 case Account::RegistrationState::INITIALIZING:
216 case Account::RegistrationState::COUNT__:
217 {
218 // Keep waiting...
219 break;
220 }
221 }
222 }
223 );
224
225 }
226}
227
228static void
229password_entry_changed(G_GNUC_UNUSED GtkEntry* entry, AccountMigrationView *view)
230{
231 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
232
233 const gchar *password = gtk_entry_get_text(GTK_ENTRY(priv->entry_password));
234 const gchar *password_confirm = gtk_entry_get_text(GTK_ENTRY(priv->entry_password_confirm));
235
236 if (strlen(password) > 0 && strlen(password_confirm) > 0)
237 {
238 gtk_widget_set_sensitive(priv->button_migrate_account, TRUE);
239 }
240 else
241 {
242 gtk_widget_set_sensitive(priv->button_migrate_account, FALSE);
243 }
244}
245
246static void
247build_migration_view(AccountMigrationView *view)
248{
249 g_return_if_fail(IS_ACCOUNT_MIGRATION_VIEW(view));
250 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
251
252 g_signal_connect(priv->button_migrate_account, "clicked", G_CALLBACK(migrate_account_clicked), view);
253 g_signal_connect(priv->button_error_view_ok, "clicked", G_CALLBACK(button_error_view_ok_clicked), view);
254 g_signal_connect(priv->entry_password, "changed", G_CALLBACK(password_entry_changed), view);
255 g_signal_connect(priv->entry_password_confirm, "changed", G_CALLBACK(password_entry_changed), view);
256
257 gtk_label_set_text(GTK_LABEL(priv->label_account_alias), priv->account->alias().toUtf8().constData());
258 gtk_label_set_text(GTK_LABEL(priv->label_account_id), priv->account->id().constData());
259
260 /* set the avatar picture */
261 auto photo = GlobalInstances::pixmapManipulator().contactPhoto(
262 ProfileModel::instance().selectedProfile()->person(),
263 QSize(AVATAR_WIDTH, AVATAR_HEIGHT),
264 false);
265 std::shared_ptr<GdkPixbuf> pixbuf_photo = photo.value<std::shared_ptr<GdkPixbuf>>();
266
267 if (photo.isValid()) {
268 gtk_image_set_from_pixbuf (GTK_IMAGE(priv->image_avatar), pixbuf_photo.get());
269 } else {
270 g_warning("invalid pixbuf");
271 }
272}
273
274GtkWidget *
275account_migration_view_new(Account* account)
276{
277 gpointer view = g_object_new(ACCOUNT_MIGRATION_VIEW_TYPE, NULL);
278 AccountMigrationViewPrivate *priv = ACCOUNT_MIGRATION_VIEW_GET_PRIVATE(view);
279 priv->account = account;
280 build_migration_view(ACCOUNT_MIGRATION_VIEW(view));
281 return (GtkWidget *)view;
282}