Commit b413b300 authored by Nicolas Jager's avatar Nicolas Jager Committed by Stepan Salenikovich

profile: avatar selection during account wizard

- sets name and photo to profile.
- adds avatar selection dialog.
- allows to take a photo as avatar.
- allows to choose a picture from disk as avatar.
- alter photo/picture to 100x100px.
- allows to save avatar on the computer.
- handles some case if no webcam can be set by lrc.

Tuleap: #655
Change-Id: Ib88b66596e83c3e3bf1e38d272ccffbca402a2bc
parent f9681389
......@@ -293,6 +293,8 @@ SET( SRC_FILES
src/recentcontactsview.cpp
src/chatview.h
src/chatview.cpp
src/avatarmanipulation.h
src/avatarmanipulation.cpp
)
# compile glib resource files to c code
......
This diff is collapsed.
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Nicolas Jager <nicolas.jager@savoirfairelinux.com>
*
* 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.
*/
#ifndef _AVATARMANIPULATION_H
#define _AVATARMANIPULATION_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define AVATAR_MANIPULATION_TYPE (avatar_manipulation_get_type ())
#define AVATAR_MANIPULATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), AVATAR_MANIPULATION_TYPE, AvatarManipulation))
#define AVATAR_MANIPULATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), AVATAR_MANIPULATION_TYPE, AvatarManipulation))
#define IS_AVATAR_MANIPULATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), AVATAR_MANIPULATION_TYPE))
#define IS_AVATAR_MANIPULATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), AVATAR_MANIPULATION_TYPE))
typedef struct _AvatarManipulation AvatarManipulation;
typedef struct _AvatarManipulationClass AvatarManipulationClass;
/**
* AvatarManipulationState:
* @AVATAR_MANIPULATION_STATE_CURRENT: The initial state. The widget will display the current
* or the default avatar, with the possible actions being to delete (and select a new one) or to
* save to disk the current avatar.
* @AVATAR_MANIPULATION_STATE_NEW: The state in which the user is selecting a new avatar. If
* a video device is available, it will will be turned on. The possible actions being to take a
* snapshot or to select an existing image from a file.
* @AVATAR_MANIPULATION_STATE_EDIT: The state after selecting a new image when the user must
* select the square area they wish to use for the avatar. The possible actions being to confirm
* the selection or to discard it.
*/
typedef enum
{
AVATAR_MANIPULATION_STATE_CURRENT,
AVATAR_MANIPULATION_STATE_NEW,
AVATAR_MANIPULATION_STATE_EDIT
} AvatarManipulationState;
GType avatar_manipulation_get_type (void) G_GNUC_CONST;
GtkWidget *avatar_manipulation_new (void);
GtkWidget *avatar_manipulation_new_from_wizard(void); /* should be used from the account creation wizard */
G_END_DECLS
#endif /* _AVATARMANIPULATION_H */
......@@ -50,6 +50,11 @@
#include "utils/files.h"
#include "revision.h"
#include "utils/accounts.h"
/*lrc*/
#include "profilemodel.h"
#include "profile.h"
#include "peerprofilecollection.h"
#include "localprofilecollection.h"
struct _RingClientClass
{
......@@ -318,6 +323,8 @@ ring_client_startup(GApplication *app)
/* add backends */
CategorizedHistoryModel::instance().addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
PersonModel::instance().addCollection<PeerProfileCollection>(LoadOptions::FORCE_ENABLED);
ProfileModel::instance().addCollection<LocalProfileCollection>(LoadOptions::FORCE_ENABLED);
/* fallback backend for vcards */
PersonModel::instance().addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED);
......
......@@ -56,6 +56,13 @@
#include <recentmodel.h>
#include "chatview.h"
/*TODO : sorting headers */
/* client */
#include "avatarmanipulation.h"
/* lrc */
#include <profilemodel.h>
#include <profile.h>
static constexpr const char* CALL_VIEW_NAME = "calls";
static constexpr const char* CREATE_ACCOUNT_VIEW_NAME = "wizard";
static constexpr const char* GENERAL_SETTINGS_VIEW_NAME = "general";
......@@ -118,6 +125,7 @@ struct _RingMainWindowPrivate
GtkWidget *label_generating_account;
GtkWidget *spinner_generating_account;
GtkWidget *button_account_creation_next;
GtkWidget *box_avatarselection;
QMetaObject::Connection hash_updated;
......@@ -500,10 +508,21 @@ create_ring_account(RingMainWindow *win)
/* create account and set UPnP enabled, as its not by default in the daemon */
const gchar *alias = gtk_entry_get_text(GTK_ENTRY(priv->entry_alias));
Account *account = nullptr;
if (alias && strlen(alias) > 0)
account = AccountModel::instance().add(alias, Account::Protocol::RING);
else
account = AccountModel::instance().add(C_("The default username / account alias, if none is set by the user", "Unknown"), Account::Protocol::RING);
/* get profile (if so) */
auto profile = ProfileModel::instance().selectedProfile();
if (profile) {
if (alias && strlen(alias) > 0) {
account = AccountModel::instance().add(alias, Account::Protocol::RING);
profile->person()->setFormattedName(alias);
} else {
auto unknown_alias = C_("The default username / account alias, if none is set by the user", "Unknown");
account = AccountModel::instance().add(unknown_alias, Account::Protocol::RING);
profile->person()->setFormattedName(unknown_alias);
}
}
account->setDisplayName(alias); // set the display name to the same as the alias
account->setUpnpEnabled(TRUE);
......@@ -525,6 +544,7 @@ create_ring_account(RingMainWindow *win)
);
account->performAction(Account::EditAction::SAVE);
profile->save();
return G_SOURCE_REMOVE;
}
......@@ -607,6 +627,9 @@ show_account_creation(RingMainWindow *win)
else
gtk_entry_set_text(GTK_ENTRY(priv->entry_alias), user_name);
/* avatar manipulation widget */
gtk_box_pack_start(GTK_BOX(priv->box_avatarselection), avatar_manipulation_new_from_wizard(), true, true, 0);
/* connect signals */
g_signal_connect(priv->entry_alias, "changed", G_CALLBACK(alias_entry_changed), win);
g_signal_connect(priv->button_account_creation_next, "clicked", G_CALLBACK(account_creation_next_clicked), win);
......@@ -1089,6 +1112,7 @@ ring_main_window_class_init(RingMainWindowClass *klass)
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, label_generating_account);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, spinner_generating_account);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, button_account_creation_next);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), RingMainWindow, box_avatarselection);
}
GtkWidget *
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.19.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkImage" id="image_add_symbolic">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">list-add-symbolic</property>
</object>
<object class="GtkImage" id="image_camera_photo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">camera-photo-symbolic</property>
</object>
<object class="GtkImage" id="image_save_symbolic">
<property name="can_focus">False</property>
<property name="icon_name">document-save-symbolic</property>
</object>
<object class="GtkImage" id="image_select_symbolic">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">object-select-symbolic</property>
</object>
<object class="GtkImage" id="image_trash_symbolic">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
<template class="AvatarManipulation" parent="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="box_views_and_controls">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkStack" id="stack_views">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image_avatar">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="name">page_avatar</property>
</packing>
</child>
<child>
<object class="GtkBox" id="vbox_selector">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="valign">center</property>
<property name="halign">center</property>
</object>
<packing>
<property name="name">page_edit_view</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_controls">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<style>
<class name="linked"/>
<class name="horizontal"/>
</style>
<child>
<object class="GtkButton" id="button_take_photo">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="image">image_camera_photo</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_trash_avatar">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="image">image_trash_symbolic</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_set_avatar">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="image">image_select_symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_choose_picture">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="image">image_add_symbolic</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_export_avatar">
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image_save_symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</template>
</interface>
......@@ -275,55 +275,92 @@
<!-- account creation wizard -->
<object class="GtkBox" id="account_creation">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<property name="spacing">20</property>
<property name="border_width">10</property>
<property name="orientation">vertical</property>
<property name="spacing">15</property>
<child>
<object class="GtkBox" id="hbox_account_creation_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<child>
<object class="GtkLabel" id="label_welcome">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Welcome to </property>
<attributes>
<attribute name="scale" value="2"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="image_ring_logo">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="vbox_account_creation_entry">
<property name="visible">True</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<property name="spacing">20</property>
<property name="homogeneous">True</property>
<property name="spacing">10</property>
<child>
<object class="GtkLabel" id="label_enter_alias">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Choose your username:</property>
<property name="label" translatable="yes">Choose an avatar and your username:</property>
</object>
<packing> <!-- nicoo, check if packing is needed -->
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_avatarselection">
<property name="visible">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry_alias">
<property name="width_request">400</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="xalign">0.5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_default_name">
......
......@@ -16,5 +16,6 @@
<file preprocess="xml-stripblanks">editcontactview.ui</file>
<file preprocess="xml-stripblanks">choosecontactview.ui</file>
<file preprocess="xml-stripblanks">chatview.ui</file>
<file preprocess="xml-stripblanks">avatarmanipulation.ui</file>
</gresource>
</gresources>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment