1
0
forked from blue/squawk

changing avatar in local vcard, no uploading yet

This commit is contained in:
Blue 2019-10-23 17:49:56 +03:00
parent 2a37f36b83
commit 652381b067
9 changed files with 221 additions and 63 deletions

View File

@ -29,17 +29,14 @@ Models::Roster::Roster(QObject* parent):
groups(), groups(),
contacts() contacts()
{ {
connect(accountsModel, connect(accountsModel, &Accounts::dataChanged, this, &Roster::onAccountDataChanged);
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)), connect(root, &Item::childChanged, this, &Roster::onChildChanged);
this, connect(root, &Item::childIsAboutToBeInserted, this, &Roster::onChildIsAboutToBeInserted);
SLOT(onAccountDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); connect(root, &Item::childInserted, this, &Roster::onChildInserted);
connect(root, SIGNAL(childChanged(Models::Item*, int, int)), this, SLOT(onChildChanged(Models::Item*, int, int))); connect(root, &Item::childIsAboutToBeRemoved, this, &Roster::onChildIsAboutToBeRemoved);
connect(root, SIGNAL(childIsAboutToBeInserted(Item*, int, int)), this, SLOT(onChildIsAboutToBeInserted(Item*, int, int))); connect(root, &Item::childRemoved, this, &Roster::onChildRemoved);
connect(root, SIGNAL(childInserted()), this, SLOT(onChildInserted())); connect(root, &Item::childIsAboutToBeMoved, this, &Roster::onChildIsAboutToBeMoved);
connect(root, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)), this, SLOT(onChildIsAboutToBeRemoved(Item*, int, int))); connect(root, &Item::childMoved, this, &Roster::onChildMoved);
connect(root, SIGNAL(childRemoved()), this, SLOT(onChildRemoved()));
connect(root, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)), this, SLOT(onChildIsAboutToBeMoved(Item*, int, int, Item*, int)));
connect(root, SIGNAL(childMoved()), this, SLOT(onChildMoved()));
} }
Models::Roster::~Roster() Models::Roster::~Roster()
@ -69,6 +66,7 @@ QVariant Models::Roster::data (const QModelIndex& index, int role) const
case Qt::DisplayRole: case Qt::DisplayRole:
{ {
if (index.column() != 0) { if (index.column() != 0) {
result = "";
break; break;
} }
switch (item->type) { switch (item->type) {

View File

@ -56,6 +56,8 @@ Squawk::Squawk(QWidget *parent) :
connect(rosterModel.accountsModel, SIGNAL(sizeChanged(unsigned int)), this, SLOT(onAccountsSizeChanged(unsigned int))); connect(rosterModel.accountsModel, SIGNAL(sizeChanged(unsigned int)), this, SLOT(onAccountsSizeChanged(unsigned int)));
//m_ui->mainToolBar->addWidget(m_ui->comboBox); //m_ui->mainToolBar->addWidget(m_ui->comboBox);
setWindowTitle(tr("Contact list"));
} }
Squawk::~Squawk() { Squawk::~Squawk() {
@ -768,10 +770,16 @@ void Squawk::onActivateVCard(const QString& account, const QString& jid, bool ed
card = itr->second; card = itr->second;
} else { } else {
card = new VCard(jid, edition); card = new VCard(jid, edition);
if (edition) {
card->setWindowTitle(tr("%1 account card").arg(account));
} else {
card->setWindowTitle(tr("%1 contact card").arg(jid));
}
card->setAttribute(Qt::WA_DeleteOnClose); card->setAttribute(Qt::WA_DeleteOnClose);
vCards.insert(std::make_pair(jid, card)); vCards.insert(std::make_pair(jid, card));
connect(card, &VCard::destroyed, this, &Squawk::onVCardClosed); connect(card, &VCard::destroyed, this, &Squawk::onVCardClosed);
connect(card, &VCard::saveVCard, std::bind( &Squawk::onVCardSave, this, std::placeholders::_1, account));
} }
card->show(); card->show();
@ -780,3 +788,11 @@ void Squawk::onActivateVCard(const QString& account, const QString& jid, bool ed
emit requestVCard(account, jid); emit requestVCard(account, jid);
} }
void Squawk::onVCardSave(const Shared::VCard& card, const QString& account)
{
VCard* widget = static_cast<VCard*>(sender());
emit uploadVCard(account, card);
widget->deleteLater();
}

View File

@ -73,6 +73,7 @@ signals:
void fileLocalPathRequest(const QString& messageId, const QString& url); void fileLocalPathRequest(const QString& messageId, const QString& url);
void downloadFileRequest(const QString& messageId, const QString& url); void downloadFileRequest(const QString& messageId, const QString& url);
void requestVCard(const QString& account, const QString& jid); void requestVCard(const QString& account, const QString& jid);
void uploadVCard(const QString& account, const Shared::VCard& card);
public slots: public slots:
void newAccount(const QMap<QString, QVariant>& account); void newAccount(const QMap<QString, QVariant>& account);
@ -126,6 +127,7 @@ private slots:
void onAccountsClosed(QObject* parent = 0); void onAccountsClosed(QObject* parent = 0);
void onConversationClosed(QObject* parent = 0); void onConversationClosed(QObject* parent = 0);
void onVCardClosed(); void onVCardClosed();
void onVCardSave(const Shared::VCard& card, const QString& account);
void onActivateVCard(const QString& account, const QString& jid, bool edition = false); void onActivateVCard(const QString& account, const QString& jid, bool edition = false);
void onComboboxActivated(int index); void onComboboxActivated(int index);
void onRosterItemDoubleClicked(const QModelIndex& item); void onRosterItemDoubleClicked(const QModelIndex& item);

View File

@ -29,16 +29,6 @@ Image::Image(const QString& path, quint16 p_minWidth, QWidget* parent):
recalculateAspectRatio(); recalculateAspectRatio();
} }
Image::Image(const QString& path, quint16 width, quint16 height, quint16 p_minWidth, QWidget* parent):
QLabel(parent),
pixmap(QIcon(path).pixmap(QSize(width, height))),
aspectRatio(0),
minWidth(p_minWidth)
{
setScaledContents(true);
recalculateAspectRatio();
}
Image::~Image() Image::~Image()
{ {
@ -83,9 +73,3 @@ void Image::setPath(const QString& path)
pixmap = QPixmap(path); pixmap = QPixmap(path);
recalculateAspectRatio(); recalculateAspectRatio();
} }
void Image::setPath(const QString& path, quint16 width, quint16 height)
{
pixmap = QPixmap(QIcon(path).pixmap(QSize(width, height)));
recalculateAspectRatio();
}

View File

@ -21,7 +21,6 @@
#include <QLabel> #include <QLabel>
#include <QPixmap> #include <QPixmap>
#include <QIcon>
/** /**
* @todo write docs * @todo write docs
@ -30,7 +29,6 @@ class Image : public QLabel
{ {
public: public:
Image(const QString& path, quint16 minWidth = 50, QWidget* parent = nullptr); Image(const QString& path, quint16 minWidth = 50, QWidget* parent = nullptr);
Image(const QString& path, quint16 width, quint16 height, quint16 minWidth = 50, QWidget* parent = nullptr);
~Image(); ~Image();
@ -38,7 +36,6 @@ public:
int widthForHeight(int height) const; int widthForHeight(int height) const;
bool hasHeightForWidth() const override; bool hasHeightForWidth() const override;
void setPath(const QString& path); void setPath(const QString& path);
void setPath(const QString& path, quint16 width, quint16 height);
void setMinWidth(quint16 minWidth); void setMinWidth(quint16 minWidth);
private: private:

View File

@ -257,11 +257,11 @@ void Conversation::showEvent(QShowEvent* event)
void Conversation::onAttach() void Conversation::onAttach()
{ {
QFileDialog* d = new QFileDialog(this, "Chose a file to send"); QFileDialog* d = new QFileDialog(this, tr("Chose a file to send"));
d->setFileMode(QFileDialog::ExistingFile); d->setFileMode(QFileDialog::ExistingFile);
connect(d, SIGNAL(accepted()), this, SLOT(onFileSelected())); connect(d, &QFileDialog::accepted, this, &Conversation::onFileSelected);
connect(d, SIGNAL(rejected()), d, SLOT(deleteLater())); connect(d, &QFileDialog::rejected, d, &QFileDialog::deleteLater);
d->show(); d->show();
} }

View File

@ -19,22 +19,37 @@
#include "vcard.h" #include "vcard.h"
#include "ui_vcard.h" #include "ui_vcard.h"
#include <QDebug>
const std::set<QString> VCard::supportedTypes = {"image/jpeg", "image/png"};
VCard::VCard(const QString& jid, bool edit, QWidget* parent): VCard::VCard(const QString& jid, bool edit, QWidget* parent):
QWidget(parent), QWidget(parent),
m_ui(new Ui::VCard()), m_ui(new Ui::VCard()),
avatar(QApplication::palette().window().color().lightnessF() > 0.5 ? ":/images/fallback/dark/big/user.svg" : ":/images/fallback/light/big/user.svg", 256, 256, 256) avatarButtonMargins(),
avatarMenu(nullptr),
editable(edit),
currentAvatarType(Shared::Avatar::empty),
currentAvatarPath("")
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->jabberID->setText(jid); m_ui->jabberID->setText(jid);
m_ui->jabberID->setReadOnly(true); m_ui->jabberID->setReadOnly(true);
QGridLayout* general = static_cast<QGridLayout*>(m_ui->General->layout());
general->addWidget(&avatar, 2, 2, 1, 1); QAction* setAvatar = m_ui->actionSetAvatar;
avatar.setFrameShape(QFrame::StyledPanel); QAction* clearAvatar = m_ui->actionClearAvatar;
avatar.setFrameShadow(QFrame::Sunken);
avatar.setMargin(6); connect(setAvatar, &QAction::triggered, this, &VCard::onSetAvatar);
connect(clearAvatar, &QAction::triggered, this, &VCard::onClearAvatar);
setAvatar->setEnabled(true);
clearAvatar->setEnabled(false);
if (edit) { if (edit) {
avatarMenu = new QMenu();
m_ui->avatarButton->setMenu(avatarMenu);
avatarMenu->addAction(setAvatar);
avatarMenu->addAction(clearAvatar);
} else { } else {
m_ui->buttonBox->hide(); m_ui->buttonBox->hide();
m_ui->firstName->setReadOnly(true); m_ui->firstName->setReadOnly(true);
@ -53,13 +68,17 @@ VCard::VCard(const QString& jid, bool edit, QWidget* parent):
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &VCard::onButtonBoxAccepted); connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &VCard::onButtonBoxAccepted);
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, m_ui->buttonBox, &QDialogButtonBox::deleteLater); connect(m_ui->buttonBox, &QDialogButtonBox::rejected, m_ui->buttonBox, &QDialogButtonBox::deleteLater);
int height = m_ui->personalForm->minimumSize().height(); avatarButtonMargins = m_ui->avatarButton->size();
avatar.setMaximumSize(avatar.widthForHeight(height), height);
avatar.setMinimumSize(avatar.widthForHeight(height), height); int height = m_ui->personalForm->minimumSize().height() - avatarButtonMargins.height();
m_ui->avatarButton->setIconSize(QSize(height, height));
} }
VCard::~VCard() VCard::~VCard()
{ {
if (editable) {
avatarMenu->deleteLater();
}
} }
void VCard::setVCard(const QString& jid, const Shared::VCard& card) void VCard::setVCard(const QString& jid, const Shared::VCard& card)
@ -80,20 +99,10 @@ void VCard::setVCard(const Shared::VCard& card)
//m_ui->organizationTitle->setText(card.get()); //m_ui->organizationTitle->setText(card.get());
//m_ui->organizationRole->setText(card.get()); //m_ui->organizationRole->setText(card.get());
m_ui->description->setText(card.getDescription()); m_ui->description->setText(card.getDescription());
currentAvatarType = card.getAvatarType();
currentAvatarPath = card.getAvatarPath();
switch (card.getAvatarType()) { updateAvatar();
case Shared::Avatar::empty:
avatar.setPath(QApplication::palette().window().color().lightnessF() > 0.5 ? ":/images/fallback/dark/big/user.svg" : ":/images/fallback/light/big/user.svg", 256, 256);
break;
case Shared::Avatar::autocreated:
case Shared::Avatar::valid:
avatar.setPath(card.getAvatarPath());
break;
}
int height = m_ui->personalForm->minimumSize().height();
avatar.setMaximumSize(avatar.widthForHeight(height), height);
avatar.setMinimumSize(avatar.widthForHeight(height), height);
} }
QString VCard::getJid() const QString VCard::getJid() const
@ -110,6 +119,86 @@ void VCard::onButtonBoxAccepted()
card.setNickName(m_ui->nickName->text()); card.setNickName(m_ui->nickName->text());
card.setBirthday(m_ui->birthday->date()); card.setBirthday(m_ui->birthday->date());
card.setDescription(m_ui->description->toPlainText()); card.setDescription(m_ui->description->toPlainText());
card.setAvatarPath(currentAvatarPath);
card.setAvatarType(currentAvatarType);
emit saveVCard(card); emit saveVCard(card);
} }
void VCard::onClearAvatar()
{
currentAvatarType = Shared::Avatar::empty;
currentAvatarPath = "";
updateAvatar();
}
void VCard::onSetAvatar()
{
QFileDialog* d = new QFileDialog(this, tr("Chose your new avatar"));
d->setFileMode(QFileDialog::ExistingFile);
d->setNameFilter(tr("Images (*.png *.jpg *.jpeg)"));
connect(d, &QFileDialog::accepted, this, &VCard::onAvatarSelected);
connect(d, &QFileDialog::rejected, d, &QFileDialog::deleteLater);
d->show();
}
void VCard::updateAvatar()
{
int height = m_ui->personalForm->minimumSize().height() - avatarButtonMargins.height();
switch (currentAvatarType) {
case Shared::Avatar::empty:
m_ui->avatarButton->setIcon(Shared::icon("user", true));
m_ui->avatarButton->setIconSize(QSize(height, height));
m_ui->actionClearAvatar->setEnabled(false);
break;
case Shared::Avatar::autocreated:
case Shared::Avatar::valid:
QPixmap pixmap(currentAvatarPath);
qreal h = pixmap.height();
qreal w = pixmap.width();
qreal aspectRatio = w / h;
m_ui->avatarButton->setIconSize(QSize(height * aspectRatio, height));
m_ui->avatarButton->setIcon(QIcon(currentAvatarPath));
m_ui->actionClearAvatar->setEnabled(true);
break;
}
}
void VCard::onAvatarSelected()
{
QFileDialog* d = static_cast<QFileDialog*>(sender());
QMimeDatabase db;
QString path = d->selectedFiles().front();
QMimeType type = db.mimeTypeForFile(path);
d->deleteLater();
if (supportedTypes.find(type.name()) == supportedTypes.end()) {
qDebug() << "Selected for avatar file is not supported, skipping";
} else {
QImage src(path);
QImage dst;
if (src.width() > 160 || src.height() > 160) {
dst = src.scaled(160, 160, Qt::KeepAspectRatio);
}
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + m_ui->jabberID->text() + ".temp." + type.preferredSuffix();
QFile oldTemp(path);
if (oldTemp.exists()) {
if (!oldTemp.remove()) {
qDebug() << "Error removing old temp avatar" << path;
return;
}
}
bool success = dst.save(path);
if (success) {
currentAvatarPath = path;
currentAvatarType = Shared::Avatar::valid;
updateAvatar();
} else {
qDebug() << "couldn't save avatar" << path << ", skipping";
}
}
}

View File

@ -21,9 +21,16 @@
#include <QWidget> #include <QWidget>
#include <QScopedPointer> #include <QScopedPointer>
#include <QPixmap>
#include <QMenu>
#include <QFileDialog>
#include <QMimeDatabase>
#include <QImage>
#include <QStandardPaths>
#include <set>
#include "../../global.h" #include "../../global.h"
#include "../utils/image.h"
namespace Ui namespace Ui
{ {
@ -49,10 +56,22 @@ signals:
private slots: private slots:
void onButtonBoxAccepted(); void onButtonBoxAccepted();
void onClearAvatar();
void onSetAvatar();
void onAvatarSelected();
private: private:
QScopedPointer<Ui::VCard> m_ui; QScopedPointer<Ui::VCard> m_ui;
Image avatar; QSize avatarButtonMargins;
QMenu* avatarMenu;
bool editable;
Shared::Avatar currentAvatarType;
QString currentAvatarPath;
static const std::set<QString> supportedTypes;
private:
void updateAvatar();
}; };
#endif // VCARD_H #endif // VCARD_H

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>560</width> <width>537</width>
<height>534</height> <height>539</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
@ -411,6 +411,43 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2">
<widget class="QToolButton" name="avatarButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="user"/>
</property>
<property name="iconSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="arrowType">
<enum>Qt::NoArrow</enum>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="Contact"> <widget class="QWidget" name="Contact">
@ -459,8 +496,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>548</width> <width>525</width>
<height>410</height> <height>415</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="1,4,1"> <layout class="QGridLayout" name="gridLayout_3" columnstretch="1,4,1">
@ -625,7 +662,7 @@
<item row="9" column="1"> <item row="9" column="1">
<layout class="QVBoxLayout" name="addressesLayout"> <layout class="QVBoxLayout" name="addressesLayout">
<item> <item>
<widget class="QLabel" name="EmptyAddressesPlaceholder"> <widget class="QLabel" name="emptyAddressesPlaceholder">
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;User has no contact e-mail addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;User has no contact e-mail addresses&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
@ -717,6 +754,22 @@
</widget> </widget>
</item> </item>
</layout> </layout>
<action name="actionSetAvatar">
<property name="icon">
<iconset theme="photo"/>
</property>
<property name="text">
<string>Set avatar</string>
</property>
</action>
<action name="actionClearAvatar">
<property name="icon">
<iconset theme="edit-clear-all"/>
</property>
<property name="text">
<string>Clear avatar</string>
</property>
</action>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>firstName</tabstop> <tabstop>firstName</tabstop>