Initial commit
45
addfriendform.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "addfriendform.h"
|
||||
#include "ui_widget.h"
|
||||
#include <QFont>
|
||||
|
||||
AddFriendForm::AddFriendForm()
|
||||
{
|
||||
main = new QWidget(), head = new QWidget();
|
||||
QFont bold;
|
||||
bold.setBold(true);
|
||||
headLabel.setText("Add Friends");
|
||||
headLabel.setFont(bold);
|
||||
|
||||
toxIdLabel.setText("Tox ID");
|
||||
messageLabel.setText("Message");
|
||||
sendButton.setText("Send friend request");
|
||||
|
||||
main->setLayout(&layout);
|
||||
layout.addWidget(&toxIdLabel);
|
||||
layout.addWidget(&toxId);
|
||||
layout.addWidget(&messageLabel);
|
||||
layout.addWidget(&message);
|
||||
layout.addWidget(&sendButton);
|
||||
|
||||
head->setLayout(&headLayout);
|
||||
headLayout.addWidget(&headLabel);
|
||||
|
||||
connect(&sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||
}
|
||||
|
||||
void AddFriendForm::show(Ui::Widget &ui)
|
||||
{
|
||||
ui.mainContent->layout()->addWidget(main);
|
||||
ui.mainHead->layout()->addWidget(head);
|
||||
main->show();
|
||||
head->show();
|
||||
}
|
||||
|
||||
void AddFriendForm::onSendTriggered()
|
||||
{
|
||||
QString id = toxId.text(), msg = message.toPlainText();
|
||||
if (id.isEmpty())
|
||||
return;
|
||||
|
||||
emit friendRequested(id, msg);
|
||||
}
|
35
addfriendform.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef ADDFRIENDFORM_H
|
||||
#define ADDFRIENDFORM_H
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "ui_widget.h"
|
||||
|
||||
class AddFriendForm : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AddFriendForm();
|
||||
|
||||
void show(Ui::Widget& ui);
|
||||
|
||||
signals:
|
||||
void friendRequested(const QString& friendAddress, const QString& message);
|
||||
|
||||
private slots:
|
||||
void onSendTriggered();
|
||||
|
||||
private:
|
||||
QLabel headLabel, toxIdLabel, messageLabel;
|
||||
QPushButton sendButton;
|
||||
QLineEdit toxId;
|
||||
QTextEdit message;
|
||||
QVBoxLayout layout, headLayout;
|
||||
QWidget *head, *main;
|
||||
};
|
||||
|
||||
#endif // ADDFRIENDFORM_H
|
153
chatform.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
#include "chatform.h"
|
||||
#include "friend.h"
|
||||
#include "friendwidget.h"
|
||||
#include "widget.h"
|
||||
#include <QFont>
|
||||
#include <QTime>
|
||||
#include <QScrollBar>
|
||||
|
||||
ChatForm::ChatForm(Friend* chatFriend)
|
||||
: f(chatFriend), curRow{0}, lockSliderToBottom{true}
|
||||
{
|
||||
main = new QWidget(), head = new QWidget(), chatAreaWidget = new QWidget();
|
||||
name = new QLabel(), avatar = new QLabel(), statusMessage = new QLabel();
|
||||
headLayout = new QHBoxLayout(), mainFootLayout = new QHBoxLayout();
|
||||
headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout();
|
||||
mainChatLayout = new QGridLayout();
|
||||
msgEdit = new ChatTextEdit();
|
||||
sendButton = new QPushButton();
|
||||
chatArea = new QScrollArea();
|
||||
|
||||
QFont bold;
|
||||
bold.setBold(true);
|
||||
name->setText(chatFriend->widget->name.text());
|
||||
name->setFont(bold);
|
||||
statusMessage->setText(chatFriend->widget->statusMessage.text());
|
||||
avatar->setPixmap(*chatFriend->widget->avatar.pixmap());
|
||||
|
||||
chatAreaWidget->setLayout(mainChatLayout);
|
||||
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
chatArea->setWidgetResizable(true);
|
||||
mainChatLayout->setColumnStretch(1,1);
|
||||
mainChatLayout->setSpacing(10);
|
||||
|
||||
sendButton->setIcon(QIcon("img/button icons/sendmessage_2x.png"));
|
||||
sendButton->setFlat(true);
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::Button, QColor(107,194,96)); // Tox Green
|
||||
sendButton->setPalette(pal);
|
||||
sendButton->setAutoFillBackground(true);
|
||||
msgEdit->setFixedHeight(50);
|
||||
sendButton->setFixedSize(50, 50);
|
||||
|
||||
main->setLayout(mainLayout);
|
||||
mainLayout->addWidget(chatArea);
|
||||
mainLayout->addLayout(mainFootLayout);
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
mainFootLayout->addWidget(msgEdit);
|
||||
mainFootLayout->addWidget(sendButton);
|
||||
|
||||
head->setLayout(headLayout);
|
||||
headLayout->addWidget(avatar);
|
||||
headLayout->addLayout(headTextLayout);
|
||||
headLayout->addStretch();
|
||||
|
||||
headTextLayout->addStretch();
|
||||
headTextLayout->addWidget(name);
|
||||
headTextLayout->addWidget(statusMessage);
|
||||
headTextLayout->addStretch();
|
||||
|
||||
chatArea->setWidget(chatAreaWidget);
|
||||
|
||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
|
||||
}
|
||||
|
||||
ChatForm::~ChatForm()
|
||||
{
|
||||
delete main;
|
||||
delete head;
|
||||
}
|
||||
|
||||
void ChatForm::show(Ui::Widget &ui)
|
||||
{
|
||||
ui.mainContent->layout()->addWidget(main);
|
||||
ui.mainHead->layout()->addWidget(head);
|
||||
main->show();
|
||||
head->show();
|
||||
}
|
||||
|
||||
void ChatForm::setName(QString newName)
|
||||
{
|
||||
name->setText(newName);
|
||||
}
|
||||
|
||||
void ChatForm::setStatusMessage(QString newMessage)
|
||||
{
|
||||
statusMessage->setText(newMessage);
|
||||
}
|
||||
|
||||
void ChatForm::onSendTriggered()
|
||||
{
|
||||
QString msg = msgEdit->toPlainText();
|
||||
if (msg.isEmpty())
|
||||
return;
|
||||
QString name = Widget::getInstance()->getUsername();
|
||||
msgEdit->clear();
|
||||
addMessage(name, msg);
|
||||
emit sendMessage(f->friendId, msg);
|
||||
}
|
||||
|
||||
void ChatForm::addFriendMessage(QString message)
|
||||
{
|
||||
QLabel *msgAuthor = new QLabel(name->text());
|
||||
QLabel *msgText = new QLabel(message);
|
||||
QLabel *msgDate = new QLabel(QTime::currentTime().toString("hh:mm"));
|
||||
|
||||
addMessage(msgAuthor, msgText, msgDate);
|
||||
}
|
||||
|
||||
void ChatForm::addMessage(QString author, QString message, QString date)
|
||||
{
|
||||
addMessage(new QLabel(author), new QLabel(message), new QLabel(date));
|
||||
}
|
||||
|
||||
void ChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date)
|
||||
{
|
||||
QScrollBar* scroll = chatArea->verticalScrollBar();
|
||||
lockSliderToBottom = scroll && scroll->value() == scroll->maximum();
|
||||
author->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
||||
date->setAlignment(Qt::AlignTop);
|
||||
if (author->text() == Widget::getInstance()->getUsername())
|
||||
{
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::WindowText, Qt::gray);
|
||||
author->setPalette(pal);
|
||||
message->setPalette(pal);
|
||||
}
|
||||
if (previousName.isEmpty() || previousName != author->text())
|
||||
{
|
||||
if (curRow)
|
||||
{
|
||||
mainChatLayout->setRowStretch(curRow, 0);
|
||||
mainChatLayout->addItem(new QSpacerItem(0,AUTHOR_CHANGE_SPACING),curRow,0,1,3);
|
||||
curRow++;
|
||||
}
|
||||
mainChatLayout->addWidget(author, curRow, 0);
|
||||
}
|
||||
previousName = author->text();
|
||||
mainChatLayout->addWidget(message, curRow, 1);
|
||||
mainChatLayout->addWidget(date, curRow, 3);
|
||||
mainChatLayout->setRowStretch(curRow+1, 1);
|
||||
mainChatLayout->setRowStretch(curRow, 0);
|
||||
curRow++;
|
||||
}
|
||||
|
||||
void ChatForm::onSliderRangeChanged()
|
||||
{
|
||||
QScrollBar* scroll = chatArea->verticalScrollBar();
|
||||
if (lockSliderToBottom)
|
||||
scroll->setValue(scroll->maximum());
|
||||
}
|
57
chatform.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef CHATFORM_H
|
||||
#define CHATFORM_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QScrollArea>
|
||||
#include <QTime>
|
||||
|
||||
#include "chattextedit.h"
|
||||
#include "ui_widget.h"
|
||||
|
||||
// Spacing in px inserted when the author of the last message changes
|
||||
#define AUTHOR_CHANGE_SPACING 5
|
||||
|
||||
class Friend;
|
||||
|
||||
class ChatForm : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChatForm(Friend* chatFriend);
|
||||
~ChatForm();
|
||||
void show(Ui::Widget& ui);
|
||||
void setName(QString newName);
|
||||
void setStatusMessage(QString newMessage);
|
||||
void addFriendMessage(QString message);
|
||||
void addMessage(QString author, QString message, QString date=QTime::currentTime().toString("hh:mm"));
|
||||
void addMessage(QLabel* author, QLabel* message, QLabel* date);
|
||||
|
||||
|
||||
signals:
|
||||
void sendMessage(int, QString);
|
||||
|
||||
private slots:
|
||||
void onSendTriggered();
|
||||
void onSliderRangeChanged();
|
||||
|
||||
private:
|
||||
Friend* f;
|
||||
QHBoxLayout *headLayout, *mainFootLayout;
|
||||
QVBoxLayout *headTextLayout, *mainLayout;
|
||||
QGridLayout *mainChatLayout;
|
||||
QLabel *avatar, *name, *statusMessage;
|
||||
ChatTextEdit *msgEdit;
|
||||
QPushButton *sendButton;
|
||||
QScrollArea *chatArea;
|
||||
QWidget *main, *head, *chatAreaWidget;
|
||||
QString previousName;
|
||||
int curRow;
|
||||
bool lockSliderToBottom;
|
||||
};
|
||||
|
||||
#endif // CHATFORM_H
|
19
chattextedit.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "chattextedit.h"
|
||||
#include <QKeyEvent>
|
||||
|
||||
ChatTextEdit::ChatTextEdit(QWidget *parent) :
|
||||
QTextEdit(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ChatTextEdit::keyPressEvent(QKeyEvent * event)
|
||||
{
|
||||
int key = event->key();
|
||||
if ((key == Qt::Key_Enter || key == Qt::Key_Return)
|
||||
&& !(event->modifiers() && Qt::ShiftModifier))
|
||||
{
|
||||
emit enterPressed();
|
||||
return;
|
||||
}
|
||||
QTextEdit::keyPressEvent(event);
|
||||
}
|
20
chattextedit.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef CHATTEXTEDIT_H
|
||||
#define CHATTEXTEDIT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
|
||||
class ChatTextEdit : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ChatTextEdit(QWidget *parent = 0);
|
||||
virtual void keyPressEvent(QKeyEvent * event) override;
|
||||
|
||||
signals:
|
||||
void enterPressed();
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // CHATTEXTEDIT_H
|
47
copyableelidelabel.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "copyableelidelabel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
#include <QClipboard>
|
||||
|
||||
CopyableElideLabel::CopyableElideLabel(QWidget* parent) :
|
||||
ElideLabel(parent)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, &CopyableElideLabel::customContextMenuRequested, this, &CopyableElideLabel::showContextMenu);
|
||||
|
||||
actionCopy = new QAction(tr("Copy"), this);
|
||||
connect(actionCopy, &QAction::triggered, [this]() {
|
||||
QApplication::clipboard()->setText(text());
|
||||
});
|
||||
}
|
||||
|
||||
void CopyableElideLabel::showContextMenu(const QPoint& pos)
|
||||
{
|
||||
if (text().length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint globalPos = mapToGlobal(pos);
|
||||
|
||||
QMenu contextMenu;
|
||||
contextMenu.addAction(actionCopy);
|
||||
|
||||
contextMenu.exec(globalPos);
|
||||
}
|
35
copyableelidelabel.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef COPYABLEELIDELABEL_HPP
|
||||
#define COPYABLEELIDELABEL_HPP
|
||||
|
||||
#include "elidelabel.h"
|
||||
|
||||
class CopyableElideLabel : public ElideLabel
|
||||
{
|
||||
public:
|
||||
explicit CopyableElideLabel(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
QAction* actionCopy;
|
||||
|
||||
private slots:
|
||||
void showContextMenu(const QPoint& pos);
|
||||
|
||||
};
|
||||
|
||||
#endif // COPYABLEELIDELABEL_HPP
|
568
core.cpp
Normal file
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QtEndian>
|
||||
#include <QThread>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
const QString Core::CONFIG_FILE_NAME = "tox_save";
|
||||
|
||||
Core::Core() :
|
||||
tox(nullptr)
|
||||
{
|
||||
toxTimer = new QTimer(this);
|
||||
toxTimer->setSingleShot(true);
|
||||
saveTimer = new QTimer(this);
|
||||
saveTimer->start(TOX_SAVE_INTERVAL);
|
||||
connect(toxTimer, &QTimer::timeout, this, &Core::process);
|
||||
connect(saveTimer, &QTimer::timeout, this, &Core::saveConfiguration);
|
||||
connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::bootstrapDht);
|
||||
}
|
||||
|
||||
Core::~Core()
|
||||
{
|
||||
if (tox) {
|
||||
saveConfiguration();
|
||||
tox_kill(tox);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::onFriendRequest(Tox*/* tox*/, const uint8_t* cUserId, const uint8_t* cMessage, uint16_t cMessageSize, void* core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->friendRequestReceived(CUserId::toString(cUserId), CString::toString(cMessage, cMessageSize));
|
||||
}
|
||||
|
||||
void Core::onFriendMessage(Tox*/* tox*/, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize));
|
||||
}
|
||||
|
||||
void Core::onFriendNameChange(Tox*/* tox*/, int friendId, uint8_t* cName, uint16_t cNameSize, void* core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->friendUsernameChanged(friendId, CString::toString(cName, cNameSize));
|
||||
}
|
||||
|
||||
void Core::onFriendTypingChange(Tox*/* tox*/, int friendId, uint8_t isTyping, void *core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->friendTypingChanged(friendId, isTyping ? true : false);
|
||||
}
|
||||
|
||||
void Core::onStatusMessageChanged(Tox*/* tox*/, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->friendStatusMessageChanged(friendId, CString::toString(cMessage, cMessageSize));
|
||||
}
|
||||
|
||||
void Core::onUserStatusChanged(Tox*/* tox*/, int friendId, uint8_t userstatus, void* core)
|
||||
{
|
||||
Status status;
|
||||
switch (userstatus) {
|
||||
case TOX_USERSTATUS_NONE:
|
||||
status = Status::Online;
|
||||
break;
|
||||
case TOX_USERSTATUS_AWAY:
|
||||
status = Status::Away;
|
||||
break;
|
||||
case TOX_USERSTATUS_BUSY:
|
||||
status = Status::Busy;
|
||||
break;
|
||||
default:
|
||||
status = Status::Online;
|
||||
break;
|
||||
}
|
||||
emit static_cast<Core*>(core)->friendStatusChanged(friendId, status);
|
||||
}
|
||||
|
||||
void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, void* core)
|
||||
{
|
||||
Status friendStatus = status ? Status::Online : Status::Offline;
|
||||
emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus);
|
||||
if (friendStatus == Status::Offline) {
|
||||
static_cast<Core*>(core)->checkLastOnline(friendId);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::onAction(Tox*/* tox*/, int friendId, uint8_t *cMessage, uint16_t cMessageSize, void *core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize));
|
||||
}
|
||||
|
||||
void Core::onGroupInvite(Tox*, int friendnumber, uint8_t *group_public_key, void *core)
|
||||
{
|
||||
qDebug() << QString("Core: Group invite by %1").arg(friendnumber);
|
||||
emit static_cast<Core*>(core)->groupInviteReceived(friendnumber, group_public_key);
|
||||
}
|
||||
|
||||
void Core::onGroupMessage(Tox*, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->groupMessageReceived(groupnumber, friendgroupnumber, CString::toString(message, length));
|
||||
}
|
||||
|
||||
void Core::onGroupNamelistChange(Tox*, int groupnumber, int peernumber, uint8_t change, void *core)
|
||||
{
|
||||
qDebug() << QString("Core: Group namelist change %1:%2 %3").arg(groupnumber).arg(peernumber).arg(change);
|
||||
emit static_cast<Core*>(core)->groupNamelistChanged(groupnumber, peernumber, change);
|
||||
}
|
||||
|
||||
void Core::acceptFriendRequest(const QString& userId)
|
||||
{
|
||||
int friendId = tox_add_friend_norequest(tox, CUserId(userId).data());
|
||||
if (friendId == -1) {
|
||||
emit failedToAddFriend(userId);
|
||||
} else {
|
||||
emit friendAdded(friendId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::requestFriendship(const QString& friendAddress, const QString& message)
|
||||
{
|
||||
CString cMessage(message);
|
||||
|
||||
int friendId = tox_add_friend(tox, CFriendAddress(friendAddress).data(), cMessage.data(), cMessage.size());
|
||||
const QString userId = friendAddress.mid(0, TOX_CLIENT_ID_SIZE * 2);
|
||||
// TODO: better error handling
|
||||
if (friendId < 0) {
|
||||
emit failedToAddFriend(userId);
|
||||
} else {
|
||||
emit friendAdded(friendId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::sendMessage(int friendId, const QString& message)
|
||||
{
|
||||
CString cMessage(message);
|
||||
|
||||
int messageId = tox_send_message(tox, friendId, cMessage.data(), cMessage.size());
|
||||
emit messageSentResult(friendId, message, messageId);
|
||||
}
|
||||
|
||||
void Core::sendAction(int friendId, const QString &action)
|
||||
{
|
||||
CString cMessage(action);
|
||||
int ret = tox_send_action(tox, friendId, cMessage.data(), cMessage.size());
|
||||
emit actionSentResult(friendId, action, ret);
|
||||
}
|
||||
|
||||
void Core::sendTyping(int friendId, bool typing)
|
||||
{
|
||||
int ret = tox_set_user_is_typing(tox, friendId, typing);
|
||||
if (ret == -1)
|
||||
emit failedToSetTyping(typing);
|
||||
}
|
||||
|
||||
void Core::sendGroupMessage(int groupId, const QString& message)
|
||||
{
|
||||
CString cMessage(message);
|
||||
|
||||
tox_group_message_send(tox, groupId, cMessage.data(), cMessage.size());
|
||||
}
|
||||
|
||||
void Core::removeFriend(int friendId)
|
||||
{
|
||||
if (tox_del_friend(tox, friendId) == -1) {
|
||||
emit failedToRemoveFriend(friendId);
|
||||
} else {
|
||||
emit friendRemoved(friendId);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::removeGroup(int groupId)
|
||||
{
|
||||
tox_del_groupchat(tox, groupId);
|
||||
}
|
||||
|
||||
void Core::setUsername(const QString& username)
|
||||
{
|
||||
CString cUsername(username);
|
||||
|
||||
if (tox_set_name(tox, cUsername.data(), cUsername.size()) == -1) {
|
||||
emit failedToSetUsername(username);
|
||||
} else {
|
||||
emit usernameSet(username);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::setStatusMessage(const QString& message)
|
||||
{
|
||||
CString cMessage(message);
|
||||
|
||||
if (tox_set_status_message(tox, cMessage.data(), cMessage.size()) == -1) {
|
||||
emit failedToSetStatusMessage(message);
|
||||
} else {
|
||||
emit statusMessageSet(message);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::setStatus(Status status)
|
||||
{
|
||||
TOX_USERSTATUS userstatus;
|
||||
switch (status) {
|
||||
case Status::Online:
|
||||
userstatus = TOX_USERSTATUS_NONE;
|
||||
break;
|
||||
case Status::Away:
|
||||
userstatus = TOX_USERSTATUS_AWAY;
|
||||
break;
|
||||
case Status::Busy:
|
||||
userstatus = TOX_USERSTATUS_BUSY;
|
||||
break;
|
||||
default:
|
||||
userstatus = TOX_USERSTATUS_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tox_set_user_status(tox, userstatus) == 0) {
|
||||
emit statusSet(status);
|
||||
} else {
|
||||
emit failedToSetStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::bootstrapDht()
|
||||
{
|
||||
const Settings& s = Settings::getInstance();
|
||||
QList<Settings::DhtServer> dhtServerList = s.getDhtServerList();
|
||||
|
||||
for (const Settings::DhtServer& dhtServer : dhtServerList) {
|
||||
tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), 0, qToBigEndian(dhtServer.port), CUserId(dhtServer.userId).data());
|
||||
}
|
||||
}
|
||||
|
||||
void Core::process()
|
||||
{
|
||||
tox_do(tox);
|
||||
#ifdef DEBUG
|
||||
//we want to see the debug messages immediately
|
||||
fflush(stdout);
|
||||
#endif
|
||||
checkConnection();
|
||||
if (!tox_isconnected(tox))
|
||||
bootstrapDht();
|
||||
toxTimer->start(tox_do_interval(tox));
|
||||
}
|
||||
|
||||
void Core::checkConnection()
|
||||
{
|
||||
static bool isConnected = false;
|
||||
|
||||
if (tox_isconnected(tox) && !isConnected) {
|
||||
emit connected();
|
||||
isConnected = true;
|
||||
} else if (!tox_isconnected(tox) && isConnected) {
|
||||
emit disconnected();
|
||||
isConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::loadConfiguration()
|
||||
{
|
||||
QString path = Settings::getSettingsDirPath() + '/' + CONFIG_FILE_NAME;
|
||||
|
||||
QFile configurationFile(path);
|
||||
|
||||
if (!configurationFile.exists()) {
|
||||
qWarning() << "The Tox configuration file was not found";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configurationFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "File " << path << " cannot be opened";
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 fileSize = configurationFile.size();
|
||||
if (fileSize > 0) {
|
||||
QByteArray data = configurationFile.readAll();
|
||||
tox_load(tox, reinterpret_cast<uint8_t *>(data.data()), data.size());
|
||||
}
|
||||
|
||||
configurationFile.close();
|
||||
|
||||
loadFriends();
|
||||
}
|
||||
|
||||
void Core::saveConfiguration()
|
||||
{
|
||||
QString path = Settings::getSettingsDirPath();
|
||||
|
||||
QDir directory(path);
|
||||
|
||||
if (!directory.exists() && !directory.mkpath(directory.absolutePath())) {
|
||||
qCritical() << "Error while creating directory " << path;
|
||||
return;
|
||||
}
|
||||
|
||||
path += '/' + CONFIG_FILE_NAME;
|
||||
QSaveFile configurationFile(path);
|
||||
if (!configurationFile.open(QIODevice::WriteOnly)) {
|
||||
qCritical() << "File " << path << " cannot be opened";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Core: writing tox_save";
|
||||
uint32_t fileSize = tox_size(tox);
|
||||
if (fileSize > 0 && fileSize <= INT32_MAX) {
|
||||
uint8_t *data = new uint8_t[fileSize];
|
||||
tox_save(tox, data);
|
||||
configurationFile.write(reinterpret_cast<char *>(data), fileSize);
|
||||
configurationFile.commit();
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::loadFriends()
|
||||
{
|
||||
const uint32_t friendCount = tox_count_friendlist(tox);
|
||||
if (friendCount > 0) {
|
||||
// assuming there are not that many friends to fill up the whole stack
|
||||
int32_t *ids = new int32_t[friendCount];
|
||||
tox_get_friendlist(tox, ids, friendCount);
|
||||
uint8_t clientId[TOX_CLIENT_ID_SIZE];
|
||||
for (int32_t i = 0; i < static_cast<int32_t>(friendCount); ++i) {
|
||||
if (tox_get_client_id(tox, ids[i], clientId) == 0) {
|
||||
emit friendAdded(ids[i], CUserId::toString(clientId));
|
||||
|
||||
const int nameSize = tox_get_name_size(tox, ids[i]);
|
||||
if (nameSize > 0) {
|
||||
uint8_t *name = new uint8_t[nameSize];
|
||||
if (tox_get_name(tox, ids[i], name) == nameSize) {
|
||||
emit friendUsernameLoaded(ids[i], CString::toString(name, nameSize));
|
||||
}
|
||||
delete[] name;
|
||||
}
|
||||
|
||||
const int statusMessageSize = tox_get_status_message_size(tox, ids[i]);
|
||||
if (statusMessageSize > 0) {
|
||||
uint8_t *statusMessage = new uint8_t[statusMessageSize];
|
||||
if (tox_get_status_message(tox, ids[i], statusMessage, statusMessageSize) == statusMessageSize) {
|
||||
emit friendStatusMessageLoaded(ids[i], CString::toString(statusMessage, statusMessageSize));
|
||||
}
|
||||
delete[] statusMessage;
|
||||
}
|
||||
|
||||
checkLastOnline(ids[i]);
|
||||
}
|
||||
|
||||
}
|
||||
delete[] ids;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::checkLastOnline(int friendId) {
|
||||
const uint64_t lastOnline = tox_get_last_online(tox, friendId);
|
||||
if (lastOnline > 0) {
|
||||
emit friendLastSeenChanged(friendId, QDateTime::fromTime_t(lastOnline));
|
||||
}
|
||||
}
|
||||
|
||||
void Core::start()
|
||||
{
|
||||
tox = tox_new(0);
|
||||
|
||||
if (tox == nullptr) {
|
||||
qCritical() << "Core failed to start";
|
||||
emit failedToStart();
|
||||
return;
|
||||
}
|
||||
|
||||
loadConfiguration();
|
||||
|
||||
tox_callback_friend_request(tox, onFriendRequest, this);
|
||||
tox_callback_friend_message(tox, onFriendMessage, this);
|
||||
tox_callback_friend_action(tox, onAction, this);
|
||||
tox_callback_name_change(tox, onFriendNameChange, this);
|
||||
tox_callback_typing_change(tox, onFriendTypingChange, this);
|
||||
tox_callback_status_message(tox, onStatusMessageChanged, this);
|
||||
tox_callback_user_status(tox, onUserStatusChanged, this);
|
||||
tox_callback_connection_status(tox, onConnectionStatusChanged, this);
|
||||
tox_callback_group_invite(tox, onGroupInvite, this);
|
||||
tox_callback_group_message(tox, onGroupMessage, this);
|
||||
tox_callback_group_namelist_change(tox, onGroupNamelistChange, this);
|
||||
|
||||
uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(tox, friendAddress);
|
||||
|
||||
emit friendAddressGenerated(CFriendAddress::toString(friendAddress));
|
||||
|
||||
CString cUsername(Settings::getInstance().getUsername());
|
||||
tox_set_name(tox, cUsername.data(), cUsername.size());
|
||||
|
||||
CString cStatusMessage(Settings::getInstance().getStatusMessage());
|
||||
tox_set_status_message(tox, cStatusMessage.data(), cStatusMessage.size());
|
||||
|
||||
bootstrapDht();
|
||||
|
||||
toxTimer->start(tox_do_interval(tox));
|
||||
}
|
||||
|
||||
int Core::getGroupNumberPeers(int groupId) const
|
||||
{
|
||||
return tox_group_number_peers(tox, groupId);
|
||||
}
|
||||
|
||||
QString Core::getGroupPeerName(int groupId, int peerId) const
|
||||
{
|
||||
QString name;
|
||||
uint8_t nameArray[TOX_MAX_NAME_LENGTH];
|
||||
int length = tox_group_peername(tox, groupId, peerId, nameArray);
|
||||
if (length == -1)
|
||||
{
|
||||
qWarning() << "Core::getGroupPeerName: Unknown error";
|
||||
return name;
|
||||
}
|
||||
name = CString::toString(nameArray, length);
|
||||
return name;
|
||||
}
|
||||
|
||||
QList<QString> Core::getGroupPeerNames(int groupId) const
|
||||
{
|
||||
QList<QString> names;
|
||||
int nPeers = getGroupNumberPeers(groupId);
|
||||
if (nPeers == -1)
|
||||
{
|
||||
qWarning() << "Core::getGroupPeerNames: Unable to get number of peers";
|
||||
return names;
|
||||
}
|
||||
uint8_t namesArray[nPeers][TOX_MAX_NAME_LENGTH];
|
||||
uint16_t* lengths = new uint16_t[nPeers];
|
||||
int result = tox_group_get_names(tox, groupId, namesArray, lengths, nPeers);
|
||||
if (result != nPeers)
|
||||
{
|
||||
qWarning() << "Core::getGroupPeerNames: Unexpected result";
|
||||
return names;
|
||||
}
|
||||
for (int i=0; i<nPeers; i++)
|
||||
names.push_back(CString::toString(namesArray[i], lengths[i]));
|
||||
return names;
|
||||
}
|
||||
|
||||
int Core::joinGroupchat(int32_t friendnumber, uint8_t* friend_group_public_key) const
|
||||
{
|
||||
return tox_join_groupchat(tox, friendnumber, friend_group_public_key);
|
||||
}
|
||||
|
||||
// CData
|
||||
|
||||
Core::CData::CData(const QString &data, uint16_t byteSize)
|
||||
{
|
||||
cData = new uint8_t[byteSize];
|
||||
cDataSize = fromString(data, cData);
|
||||
}
|
||||
|
||||
Core::CData::~CData()
|
||||
{
|
||||
delete[] cData;
|
||||
}
|
||||
|
||||
uint8_t* Core::CData::data()
|
||||
{
|
||||
return cData;
|
||||
}
|
||||
|
||||
uint16_t Core::CData::size()
|
||||
{
|
||||
return cDataSize;
|
||||
}
|
||||
|
||||
QString Core::CData::toString(const uint8_t *cData, const uint16_t cDataSize)
|
||||
{
|
||||
return QString(QByteArray(reinterpret_cast<const char*>(cData), cDataSize).toHex()).toUpper();
|
||||
}
|
||||
|
||||
uint16_t Core::CData::fromString(const QString& data, uint8_t* cData)
|
||||
{
|
||||
QByteArray arr = QByteArray::fromHex(data.toLower().toLatin1());
|
||||
memcpy(cData, reinterpret_cast<uint8_t*>(arr.data()), arr.size());
|
||||
return arr.size();
|
||||
}
|
||||
|
||||
|
||||
// CUserId
|
||||
|
||||
Core::CUserId::CUserId(const QString &userId) :
|
||||
CData(userId, SIZE)
|
||||
{
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
QString Core::CUserId::toString(const uint8_t* cUserId)
|
||||
{
|
||||
return CData::toString(cUserId, SIZE);
|
||||
}
|
||||
|
||||
|
||||
// CFriendAddress
|
||||
|
||||
Core::CFriendAddress::CFriendAddress(const QString &friendAddress) :
|
||||
CData(friendAddress, SIZE)
|
||||
{
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
QString Core::CFriendAddress::toString(const uint8_t *cFriendAddress)
|
||||
{
|
||||
return CData::toString(cFriendAddress, SIZE);
|
||||
}
|
||||
|
||||
|
||||
// CString
|
||||
|
||||
Core::CString::CString(const QString& string)
|
||||
{
|
||||
cString = new uint8_t[string.length() * MAX_SIZE_OF_UTF8_ENCODED_CHARACTER]();
|
||||
cStringSize = fromString(string, cString);
|
||||
}
|
||||
|
||||
Core::CString::~CString()
|
||||
{
|
||||
delete[] cString;
|
||||
}
|
||||
|
||||
uint8_t* Core::CString::data()
|
||||
{
|
||||
return cString;
|
||||
}
|
||||
|
||||
uint16_t Core::CString::size()
|
||||
{
|
||||
return cStringSize;
|
||||
}
|
||||
|
||||
QString Core::CString::toString(const uint8_t* cString, uint16_t cStringSize)
|
||||
{
|
||||
return QString::fromUtf8(reinterpret_cast<const char*>(cString), cStringSize);
|
||||
}
|
||||
|
||||
uint16_t Core::CString::fromString(const QString& string, uint8_t* cString)
|
||||
{
|
||||
QByteArray byteArray = QByteArray(string.toUtf8());
|
||||
memcpy(cString, reinterpret_cast<uint8_t*>(byteArray.data()), byteArray.size());
|
||||
return byteArray.size();
|
||||
}
|
||||
|
||||
void Core::quitGroupChat(int groupId) const
|
||||
{
|
||||
tox_del_groupchat(tox, groupId);
|
||||
}
|
216
core.h
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef CORE_HPP
|
||||
#define CORE_HPP
|
||||
|
||||
#include "status.h"
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#define GROUPCHAT_MAX_SIZE 32
|
||||
#define TOX_SAVE_INTERVAL 10*1000
|
||||
|
||||
struct DhtServer
|
||||
{
|
||||
QString name;
|
||||
QString userId;
|
||||
QString address;
|
||||
int port;
|
||||
};
|
||||
|
||||
class Core : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Core();
|
||||
~Core();
|
||||
|
||||
private:
|
||||
static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage, uint16_t cMessageSize, void* core);
|
||||
static void onFriendMessage(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core);
|
||||
static void onFriendNameChange(Tox* tox, int friendId, uint8_t* cName, uint16_t cNameSize, void* core);
|
||||
static void onFriendTypingChange(Tox* tox, int friendId, uint8_t isTyping, void* core);
|
||||
static void onStatusMessageChanged(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core);
|
||||
static void onUserStatusChanged(Tox* tox, int friendId, uint8_t userstatus, void* core);
|
||||
static void onConnectionStatusChanged(Tox* tox, int friendId, uint8_t status, void* core);
|
||||
static void onAction(Tox* tox, int friendId, uint8_t* cMessage, uint16_t cMessageSize, void* core);
|
||||
static void onGroupInvite(Tox *tox, int friendnumber, uint8_t *group_public_key, void *userdata);
|
||||
static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata);
|
||||
static void onGroupNamelistChange(Tox *tox, int groupnumber, int peernumber, uint8_t change, void *userdata);
|
||||
|
||||
void checkConnection();
|
||||
|
||||
void loadConfiguration();
|
||||
void saveConfiguration();
|
||||
void loadFriends();
|
||||
|
||||
void checkLastOnline(int friendId);
|
||||
|
||||
Tox* tox;
|
||||
QTimer *toxTimer, *saveTimer;
|
||||
QList<DhtServer> dhtServerList;
|
||||
int dhtServerId;
|
||||
|
||||
static const QString CONFIG_FILE_NAME;
|
||||
|
||||
class CData
|
||||
{
|
||||
public:
|
||||
uint8_t* data();
|
||||
uint16_t size();
|
||||
|
||||
protected:
|
||||
explicit CData(const QString& data, uint16_t byteSize);
|
||||
virtual ~CData();
|
||||
|
||||
static QString toString(const uint8_t* cData, const uint16_t cDataSize);
|
||||
|
||||
private:
|
||||
uint8_t* cData;
|
||||
uint16_t cDataSize;
|
||||
|
||||
static uint16_t fromString(const QString& userId, uint8_t* cData);
|
||||
};
|
||||
|
||||
class CUserId : public CData
|
||||
{
|
||||
public:
|
||||
explicit CUserId(const QString& userId);
|
||||
|
||||
static QString toString(const uint8_t *cUserId);
|
||||
|
||||
private:
|
||||
static const uint16_t SIZE = TOX_CLIENT_ID_SIZE;
|
||||
|
||||
};
|
||||
|
||||
class CFriendAddress : public CData
|
||||
{
|
||||
public:
|
||||
explicit CFriendAddress(const QString& friendAddress);
|
||||
|
||||
static QString toString(const uint8_t* cFriendAddress);
|
||||
|
||||
private:
|
||||
static const uint16_t SIZE = TOX_FRIEND_ADDRESS_SIZE;
|
||||
|
||||
};
|
||||
|
||||
class CString
|
||||
{
|
||||
public:
|
||||
explicit CString(const QString& string);
|
||||
~CString();
|
||||
|
||||
uint8_t* data();
|
||||
uint16_t size();
|
||||
|
||||
static QString toString(const uint8_t* cMessage, const uint16_t cMessageSize);
|
||||
|
||||
private:
|
||||
const static int MAX_SIZE_OF_UTF8_ENCODED_CHARACTER = 4;
|
||||
|
||||
uint8_t* cString;
|
||||
uint16_t cStringSize;
|
||||
|
||||
static uint16_t fromString(const QString& message, uint8_t* cMessage);
|
||||
};
|
||||
|
||||
public:
|
||||
int getGroupNumberPeers(int groupId) const;
|
||||
QString getGroupPeerName(int groupId, int peerId) const;
|
||||
QList<QString> getGroupPeerNames(int groupId) const;
|
||||
int joinGroupchat(int32_t friendnumber, uint8_t* friend_group_public_key) const;
|
||||
void quitGroupChat(int groupId) const;
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
|
||||
void acceptFriendRequest(const QString& userId);
|
||||
void requestFriendship(const QString& friendAddress, const QString& message);
|
||||
|
||||
void removeFriend(int friendId);
|
||||
void removeGroup(int groupId);
|
||||
|
||||
void sendMessage(int friendId, const QString& message);
|
||||
void sendAction(int friendId, const QString& action);
|
||||
void sendTyping(int friendId, bool typing);
|
||||
void sendGroupMessage(int groupId, const QString& message);
|
||||
|
||||
void setUsername(const QString& username);
|
||||
void setStatusMessage(const QString& message);
|
||||
void setStatus(Status status);
|
||||
|
||||
void process();
|
||||
|
||||
void bootstrapDht();
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
|
||||
void friendRequestReceived(const QString& userId, const QString& message);
|
||||
void friendMessageReceived(int friendId, const QString& message);
|
||||
|
||||
void friendAdded(int friendId, const QString& userId);
|
||||
|
||||
void friendStatusChanged(int friendId, Status status);
|
||||
void friendStatusMessageChanged(int friendId, const QString& message);
|
||||
void friendUsernameChanged(int friendId, const QString& username);
|
||||
void friendTypingChanged(int friendId, bool isTyping);
|
||||
|
||||
void friendStatusMessageLoaded(int friendId, const QString& message);
|
||||
void friendUsernameLoaded(int friendId, const QString& username);
|
||||
|
||||
void friendAddressGenerated(const QString& friendAddress);
|
||||
|
||||
void friendRemoved(int friendId);
|
||||
|
||||
void friendLastSeenChanged(int friendId, const QDateTime& dateTime);
|
||||
|
||||
void groupInviteReceived(int friendnumber, uint8_t *group_public_key);
|
||||
void groupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message);
|
||||
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
|
||||
|
||||
void usernameSet(const QString& username);
|
||||
void statusMessageSet(const QString& message);
|
||||
void statusSet(Status status);
|
||||
|
||||
void messageSentResult(int friendId, const QString& message, int messageId);
|
||||
void actionSentResult(int friendId, const QString& action, int success);
|
||||
|
||||
void failedToAddFriend(const QString& userId);
|
||||
void failedToRemoveFriend(int friendId);
|
||||
void failedToSetUsername(const QString& username);
|
||||
void failedToSetStatusMessage(const QString& message);
|
||||
void failedToSetStatus(Status status);
|
||||
void failedToSetTyping(bool typing);
|
||||
|
||||
void actionReceived(int friendId, const QString& acionMessage);
|
||||
|
||||
void failedToStart();
|
||||
|
||||
};
|
||||
|
||||
#endif // CORE_HPP
|
||||
|
110
editablelabelwidget.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "editablelabelwidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QFontMetrics>
|
||||
#include <QMouseEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ClickableCopyableElideLabel::ClickableCopyableElideLabel(QWidget* parent) :
|
||||
CopyableElideLabel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool ClickableCopyableElideLabel::event(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
emit clicked();
|
||||
}
|
||||
} else if (event->type() == QEvent::Enter) {
|
||||
QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
return CopyableElideLabel::event(event);
|
||||
}
|
||||
|
||||
EditableLabelWidget::EditableLabelWidget(QWidget* parent) :
|
||||
QStackedWidget(parent), isSubmitting(false)
|
||||
{
|
||||
label = new ClickableCopyableElideLabel(this);
|
||||
|
||||
connect(label, &ClickableCopyableElideLabel::clicked, this, &EditableLabelWidget::onLabelClicked);
|
||||
|
||||
lineEdit = new EscLineEdit(this);
|
||||
lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
lineEdit->setMinimumHeight(label->fontMetrics().lineSpacing() + LINE_SPACING_OFFSET);
|
||||
|
||||
connect(lineEdit, &EscLineEdit::editingFinished, this, &EditableLabelWidget::onLabelChangeSubmited);
|
||||
connect(lineEdit, &EscLineEdit::escPressed, this, &EditableLabelWidget::onLabelChangeCancelled);
|
||||
|
||||
addWidget(label);
|
||||
addWidget(lineEdit);
|
||||
|
||||
setCurrentWidget(label);
|
||||
}
|
||||
|
||||
void EditableLabelWidget::setText(const QString& text)
|
||||
{
|
||||
label->setText(text);
|
||||
lineEdit->setText(text);
|
||||
}
|
||||
|
||||
QString EditableLabelWidget::text()
|
||||
{
|
||||
return label->text();
|
||||
}
|
||||
|
||||
void EditableLabelWidget::onLabelChangeSubmited()
|
||||
{
|
||||
if (isSubmitting) {
|
||||
return;
|
||||
}
|
||||
isSubmitting = true;
|
||||
|
||||
QString oldText = label->text();
|
||||
QString newText = lineEdit->text();
|
||||
// `lineEdit->clearFocus()` triggers `onLabelChangeSubmited()`, we use `isSubmitting` as a workaround
|
||||
lineEdit->clearFocus();
|
||||
setCurrentWidget(label);
|
||||
|
||||
if (oldText != newText) {
|
||||
label->setText(newText);
|
||||
emit textChanged(newText, oldText);
|
||||
}
|
||||
|
||||
isSubmitting = false;
|
||||
}
|
||||
|
||||
void EditableLabelWidget::onLabelChangeCancelled()
|
||||
{
|
||||
// order of calls matters, since clearFocus() triggers EditableLabelWidget::onLabelChangeSubmited()
|
||||
lineEdit->setText(label->text());
|
||||
lineEdit->clearFocus();
|
||||
setCurrentWidget(label);
|
||||
}
|
||||
|
||||
void EditableLabelWidget::onLabelClicked()
|
||||
{
|
||||
setCurrentWidget(lineEdit);
|
||||
lineEdit->setFocus();
|
||||
}
|
66
editablelabelwidget.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef EDITABLELABELWIDGET_HPP
|
||||
#define EDITABLELABELWIDGET_HPP
|
||||
|
||||
#include "copyableelidelabel.h"
|
||||
#include "esclineedit.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QStackedWidget>
|
||||
|
||||
class ClickableCopyableElideLabel : public CopyableElideLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClickableCopyableElideLabel(QWidget* parent = 0);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
};
|
||||
|
||||
class EditableLabelWidget : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EditableLabelWidget(QWidget* parent = 0);
|
||||
|
||||
ClickableCopyableElideLabel* label;
|
||||
EscLineEdit* lineEdit;
|
||||
|
||||
void setText(const QString& text);
|
||||
QString text();
|
||||
|
||||
private:
|
||||
static const int LINE_SPACING_OFFSET = 2;
|
||||
bool isSubmitting;
|
||||
|
||||
private slots:
|
||||
void onLabelChangeSubmited();
|
||||
void onLabelChangeCancelled();
|
||||
void onLabelClicked();
|
||||
|
||||
signals:
|
||||
void textChanged(QString newText, QString oldText);
|
||||
|
||||
};
|
||||
|
||||
#endif // EDITABLELABELWIDGET_HPP
|
82
elidelabel.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "elidelabel.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QEvent>
|
||||
|
||||
ElideLabel::ElideLabel(QWidget *parent) :
|
||||
QLabel(parent), _textElide(false), _textElideMode(Qt::ElideNone), _showToolTipOnElide(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ElideLabel::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QFrame::paintEvent(event);
|
||||
QPainter p(this);
|
||||
QFontMetrics metrics(font());
|
||||
if ((metrics.width(text()) > contentsRect().width()) && textElide()) {
|
||||
QString elidedText = fontMetrics().elidedText(text(), textElideMode(), rect().width());
|
||||
p.drawText(rect(), alignment(), elidedText);
|
||||
} else {
|
||||
QLabel::paintEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool ElideLabel::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::ToolTip) {
|
||||
QFontMetrics metrics(font());
|
||||
if ((metrics.width(text()) > contentsRect().width()) && textElide() && showToolTipOnElide()) {
|
||||
setToolTip(text());
|
||||
} else {
|
||||
setToolTip("");
|
||||
}
|
||||
}
|
||||
|
||||
return QLabel::event(event);
|
||||
}
|
||||
|
||||
void ElideLabel::setTextElide(bool set)
|
||||
{
|
||||
_textElide = set;
|
||||
}
|
||||
|
||||
bool ElideLabel::textElide() const
|
||||
{
|
||||
return _textElide;
|
||||
}
|
||||
|
||||
void ElideLabel::setTextElideMode(Qt::TextElideMode mode)
|
||||
{
|
||||
_textElideMode = mode;
|
||||
}
|
||||
|
||||
Qt::TextElideMode ElideLabel::textElideMode() const
|
||||
{
|
||||
return _textElideMode;
|
||||
}
|
||||
|
||||
void ElideLabel::setShowToolTipOnElide(bool show)
|
||||
{
|
||||
_showToolTipOnElide = show;
|
||||
}
|
||||
|
||||
bool ElideLabel::showToolTipOnElide()
|
||||
{
|
||||
return _showToolTipOnElide;
|
||||
}
|
50
elidelabel.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef ELIDELABEL_HPP
|
||||
#define ELIDELABEL_HPP
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
class ElideLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ElideLabel(QWidget *parent = 0);
|
||||
|
||||
void setTextElide(bool set);
|
||||
bool textElide() const;
|
||||
|
||||
void setTextElideMode(Qt::TextElideMode mode);
|
||||
Qt::TextElideMode textElideMode() const;
|
||||
|
||||
void setShowToolTipOnElide(bool show);
|
||||
bool showToolTipOnElide();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
|
||||
bool event(QEvent *e) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool _textElide;
|
||||
Qt::TextElideMode _textElideMode;
|
||||
|
||||
bool _showToolTipOnElide;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // ELIDELABEL_HPP
|
34
esclineedit.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "esclineedit.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
|
||||
EscLineEdit::EscLineEdit(QWidget* parent) :
|
||||
QLineEdit(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void EscLineEdit::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Escape && event->modifiers() == Qt::NoModifier) {
|
||||
emit escPressed();
|
||||
} else {
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
||||
}
|
36
esclineedit.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef ESCLINEEDIT_HPP
|
||||
#define ESCLINEEDIT_HPP
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
class EscLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EscLineEdit(QWidget* parent);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
signals:
|
||||
void escPressed();
|
||||
|
||||
};
|
||||
|
||||
#endif // ESCLINEEDIT_HPP
|
33
friend.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "friend.h"
|
||||
#include "friendlist.h"
|
||||
#include "friendwidget.h"
|
||||
|
||||
Friend::Friend(int FriendId, QString UserId)
|
||||
: friendId(FriendId), userId(UserId)
|
||||
{
|
||||
widget = new FriendWidget(friendId, userId);
|
||||
chatForm = new ChatForm(this);
|
||||
}
|
||||
|
||||
Friend::~Friend()
|
||||
{
|
||||
delete chatForm;
|
||||
delete widget;
|
||||
}
|
||||
|
||||
void Friend::setName(QString name)
|
||||
{
|
||||
widget->name.setText(name);
|
||||
chatForm->setName(name);
|
||||
}
|
||||
|
||||
void Friend::setStatusMessage(QString message)
|
||||
{
|
||||
widget->statusMessage.setText(message);
|
||||
chatForm->setStatusMessage(message);
|
||||
}
|
||||
|
||||
QString Friend::getName()
|
||||
{
|
||||
return widget->name.text();
|
||||
}
|
25
friend.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef FRIEND_H
|
||||
#define FRIEND_H
|
||||
|
||||
#include <QString>
|
||||
#include "chatform.h"
|
||||
|
||||
class FriendWidget;
|
||||
|
||||
struct Friend
|
||||
{
|
||||
public:
|
||||
Friend(int FriendId, QString UserId);
|
||||
~Friend();
|
||||
void setName(QString name);
|
||||
void setStatusMessage(QString message);
|
||||
QString getName();
|
||||
|
||||
public:
|
||||
FriendWidget* widget;
|
||||
int friendId;
|
||||
QString userId;
|
||||
ChatForm* chatForm;
|
||||
};
|
||||
|
||||
#endif // FRIEND_H
|
32
friendlist.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "friend.h"
|
||||
#include "friendlist.h"
|
||||
#include <QMenu>
|
||||
|
||||
QList<Friend*> FriendList::friendList;
|
||||
|
||||
Friend* FriendList::addFriend(int friendId, QString userId)
|
||||
{
|
||||
Friend* newfriend = new Friend(friendId, userId);
|
||||
friendList.append(newfriend);
|
||||
return newfriend;
|
||||
}
|
||||
|
||||
Friend* FriendList::findFriend(int friendId)
|
||||
{
|
||||
for (Friend* f : friendList)
|
||||
if (f->friendId == friendId)
|
||||
return f;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FriendList::removeFriend(int friendId)
|
||||
{
|
||||
for (int i=0; i<friendList.size(); i++)
|
||||
{
|
||||
if (friendList[i]->friendId == friendId)
|
||||
{
|
||||
friendList.removeAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
21
friendlist.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef FRIENDLIST_H
|
||||
#define FRIENDLIST_H
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
class Friend;
|
||||
|
||||
class FriendList
|
||||
{
|
||||
public:
|
||||
FriendList();
|
||||
static Friend* addFriend(int friendId, QString userId);
|
||||
static Friend* findFriend(int friendId);
|
||||
static void removeFriend(int friendId);
|
||||
|
||||
public:
|
||||
static QList<Friend*> friendList;
|
||||
};
|
||||
|
||||
#endif // FRIENDLIST_H
|
61
friendrequestdialog.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "friendrequestdialog.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
FriendRequestDialog::FriendRequestDialog(QWidget *parent, const QString &userId, const QString &message) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle("Friend request");
|
||||
|
||||
QLabel *friendsLabel = new QLabel("Someone wants to make friends with you.", this);
|
||||
QLabel *userIdLabel = new QLabel("User ID:", this);
|
||||
QLineEdit *userIdEdit = new QLineEdit(userId, this);
|
||||
userIdEdit->setCursorPosition(0);
|
||||
userIdEdit->setReadOnly(true);
|
||||
QLabel *messageLabel = new QLabel("Friend request message:", this);
|
||||
QPlainTextEdit *messageEdit = new QPlainTextEdit(message, this);
|
||||
messageEdit->setReadOnly(true);
|
||||
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this);
|
||||
|
||||
buttonBox->addButton("Accept", QDialogButtonBox::AcceptRole);
|
||||
buttonBox->addButton("Reject", QDialogButtonBox::RejectRole);
|
||||
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &FriendRequestDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &FriendRequestDialog::reject);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(friendsLabel);
|
||||
layout->addSpacing(12);
|
||||
layout->addWidget(userIdLabel);
|
||||
layout->addWidget(userIdEdit);
|
||||
layout->addWidget(messageLabel);
|
||||
layout->addWidget(messageEdit);
|
||||
layout->addWidget(buttonBox);
|
||||
|
||||
resize(300, 200);
|
||||
}
|
29
friendrequestdialog.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef FRIENDREQUESTDIALOG_HPP
|
||||
#define FRIENDREQUESTDIALOG_HPP
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class FriendRequestDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FriendRequestDialog(QWidget *parent, const QString &userId, const QString &message);
|
||||
};
|
||||
|
||||
#endif // FRIENDREQUESTDIALOG_HPP
|
62
friendwidget.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "friendwidget.h"
|
||||
#include <QContextMenuEvent>
|
||||
#include <QMenu>
|
||||
|
||||
FriendWidget::FriendWidget(int FriendId, QString id)
|
||||
: friendId(FriendId)
|
||||
{
|
||||
this->setLayout(&layout);
|
||||
this->setFixedWidth(225);
|
||||
this->setFixedHeight(55);
|
||||
layout.setSpacing(0);
|
||||
layout.setMargin(0);
|
||||
textLayout.setSpacing(0);
|
||||
textLayout.setMargin(0);
|
||||
|
||||
avatar.setPixmap(QPixmap("img/contact list icons/contact.png"));
|
||||
name.setText(id);
|
||||
statusPic.setPixmap(QPixmap("img/status/dot_away.png"));
|
||||
QFont small;
|
||||
small.setPixelSize(10);
|
||||
statusMessage.setFont(small);
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::WindowText,Qt::gray);
|
||||
statusMessage.setPalette(pal);
|
||||
|
||||
textLayout.addStretch();
|
||||
textLayout.addWidget(&name);
|
||||
textLayout.addWidget(&statusMessage);
|
||||
textLayout.addStretch();
|
||||
|
||||
layout.addSpacing(20);
|
||||
layout.addWidget(&avatar);
|
||||
layout.addSpacing(5);
|
||||
layout.addLayout(&textLayout);
|
||||
layout.addStretch();
|
||||
layout.addSpacing(5);
|
||||
layout.addWidget(&statusPic);
|
||||
layout.addSpacing(5);
|
||||
}
|
||||
|
||||
void FriendWidget::mouseReleaseEvent (QMouseEvent*)
|
||||
{
|
||||
emit friendWidgetClicked(this);
|
||||
}
|
||||
|
||||
void FriendWidget::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
QPoint pos = event->globalPos();
|
||||
QMenu menu;
|
||||
menu.addAction("Remove friend");
|
||||
|
||||
QAction* selectedItem = menu.exec(pos);
|
||||
if (selectedItem)
|
||||
{
|
||||
if (selectedItem->text() == "Remove friend")
|
||||
{
|
||||
hide();
|
||||
emit removeFriend(friendId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
28
friendwidget.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef FRIENDWIDGET_H
|
||||
#define FRIENDWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
struct FriendWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FriendWidget(int FriendId, QString id);
|
||||
void mouseReleaseEvent (QMouseEvent* event);
|
||||
void contextMenuEvent(QContextMenuEvent * event);
|
||||
|
||||
signals:
|
||||
void friendWidgetClicked(FriendWidget* widget);
|
||||
void removeFriend(int friendId);
|
||||
|
||||
public:
|
||||
int friendId;
|
||||
QLabel avatar, name, statusMessage, statusPic;
|
||||
QHBoxLayout layout;
|
||||
QVBoxLayout textLayout;
|
||||
};
|
||||
|
||||
#endif // FRIENDWIDGET_H
|
98
group.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
#include "group.h"
|
||||
#include "groupwidget.h"
|
||||
#include "groupchatform.h"
|
||||
#include "friendlist.h"
|
||||
#include "friend.h"
|
||||
#include "widget.h"
|
||||
#include "core.h"
|
||||
#include <QDebug>
|
||||
|
||||
Group::Group(int GroupId, QString Name)
|
||||
: groupId(GroupId), nPeers{0}, hasPeerInfo{false}
|
||||
{
|
||||
widget = new GroupWidget(groupId, Name);
|
||||
chatForm = new GroupChatForm(this);
|
||||
connect(&peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo()));
|
||||
peerInfoTimer.setInterval(500);
|
||||
peerInfoTimer.setSingleShot(false);
|
||||
//peerInfoTimer.start();
|
||||
}
|
||||
|
||||
Group::~Group()
|
||||
{
|
||||
delete chatForm;
|
||||
delete widget;
|
||||
}
|
||||
|
||||
void Group::queryPeerInfo()
|
||||
{
|
||||
const Core* core = Widget::getInstance()->getCore();
|
||||
int nPeersResult = core->getGroupNumberPeers(groupId);
|
||||
if (nPeersResult == -1)
|
||||
{
|
||||
qDebug() << "Group::queryPeerInfo: Can't get number of peers";
|
||||
return;
|
||||
}
|
||||
nPeers = nPeersResult;
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
|
||||
if (nPeersResult == 0)
|
||||
return;
|
||||
|
||||
bool namesOk = true;
|
||||
QList<QString> names = core->getGroupPeerNames(groupId);
|
||||
if (names.isEmpty())
|
||||
{
|
||||
qDebug() << "Group::queryPeerInfo: Can't get names of peers";
|
||||
return;
|
||||
}
|
||||
for (int i=0; i<names.size(); i++)
|
||||
{
|
||||
QString name = names[i];
|
||||
if (name.isEmpty())
|
||||
{
|
||||
name = "<Unknown>";
|
||||
namesOk = false;
|
||||
}
|
||||
peers[i] = name;
|
||||
}
|
||||
nPeers = names.size();
|
||||
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
|
||||
if (namesOk)
|
||||
{
|
||||
qDebug() << "Group::queryPeerInfo: Successfully loaded names";
|
||||
hasPeerInfo = true;
|
||||
peerInfoTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Group::addPeer(int peerId, QString name)
|
||||
{
|
||||
if (peers.contains(peerId))
|
||||
qWarning() << "Group::addPeer: peerId already used, overwriting anyway";
|
||||
if (name.isEmpty())
|
||||
peers[peerId] = "<Unknown>";
|
||||
else
|
||||
peers[peerId] = name;
|
||||
nPeers++;
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
}
|
||||
|
||||
void Group::removePeer(int peerId)
|
||||
{
|
||||
peers.remove(peerId);
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
}
|
||||
|
||||
void Group::updatePeer(int peerId, QString name)
|
||||
{
|
||||
peers[peerId] = name;
|
||||
widget->onUserListChanged();
|
||||
chatForm->onUserListChanged();
|
||||
}
|
37
group.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef GROUP_H
|
||||
#define GROUP_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QTimer>
|
||||
|
||||
#define RETRY_PEER_INFO_INTERVAL 500
|
||||
|
||||
class Friend;
|
||||
class GroupWidget;
|
||||
class GroupChatForm;
|
||||
|
||||
class Group : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Group(int GroupId, QString Name);
|
||||
~Group();
|
||||
void addPeer(int peerId, QString name);
|
||||
void removePeer(int peerId);
|
||||
void updatePeer(int peerId, QString newName);
|
||||
|
||||
private slots:
|
||||
void queryPeerInfo();
|
||||
|
||||
public:
|
||||
int groupId;
|
||||
QMap<int,QString> peers;
|
||||
int nPeers;
|
||||
GroupWidget* widget;
|
||||
GroupChatForm* chatForm;
|
||||
bool hasPeerInfo;
|
||||
QTimer peerInfoTimer;
|
||||
};
|
||||
|
||||
#endif // GROUP_H
|
175
groupchatform.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include "groupchatform.h"
|
||||
#include "group.h"
|
||||
#include "groupwidget.h"
|
||||
#include "widget.h"
|
||||
#include "friend.h"
|
||||
#include "friendlist.h"
|
||||
#include <QFont>
|
||||
#include <QTime>
|
||||
#include <QScrollBar>
|
||||
|
||||
GroupChatForm::GroupChatForm(Group* chatGroup)
|
||||
: group(chatGroup), curRow{0}, lockSliderToBottom{true}
|
||||
{
|
||||
main = new QWidget(), head = new QWidget(), chatAreaWidget = new QWidget();
|
||||
headLayout = new QHBoxLayout(), mainFootLayout = new QHBoxLayout();
|
||||
headTextLayout = new QVBoxLayout(), mainLayout = new QVBoxLayout();
|
||||
mainChatLayout = new QGridLayout();
|
||||
avatar = new QLabel(), name = new QLabel(), nusers = new QLabel(), namesList = new QLabel();
|
||||
msgEdit = new ChatTextEdit();
|
||||
sendButton = new QPushButton();
|
||||
chatArea = new QScrollArea();
|
||||
QFont bold;
|
||||
bold.setBold(true);
|
||||
QFont small;
|
||||
small.setPixelSize(10);
|
||||
name->setText(group->widget->name.text());
|
||||
name->setFont(bold);
|
||||
nusers->setFont(small);
|
||||
nusers->setText(QString("%1 users in chat").arg(group->peers.size()));
|
||||
avatar->setPixmap(QPixmap("img/contact list icons/group.png"));
|
||||
QString names;
|
||||
for (QString& s : group->peers)
|
||||
names.append(s+", ");
|
||||
names.chop(2);
|
||||
namesList->setText(names);
|
||||
namesList->setFont(small);
|
||||
|
||||
chatAreaWidget->setLayout(mainChatLayout);
|
||||
chatArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
chatArea->setWidgetResizable(true);
|
||||
mainChatLayout->setColumnStretch(1,1);
|
||||
mainChatLayout->setHorizontalSpacing(10);
|
||||
|
||||
sendButton->setIcon(QIcon("img/button icons/sendmessage_2x.png"));
|
||||
sendButton->setFlat(true);
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::Button, QColor(107,194,96)); // Tox Green
|
||||
sendButton->setPalette(pal);
|
||||
sendButton->setAutoFillBackground(true);
|
||||
msgEdit->setFixedHeight(50);
|
||||
sendButton->setFixedSize(50, 50);
|
||||
|
||||
main->setLayout(mainLayout);
|
||||
mainLayout->addWidget(chatArea);
|
||||
mainLayout->addLayout(mainFootLayout);
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
mainFootLayout->addWidget(msgEdit);
|
||||
mainFootLayout->addWidget(sendButton);
|
||||
|
||||
head->setLayout(headLayout);
|
||||
headLayout->addWidget(avatar);
|
||||
headLayout->addLayout(headTextLayout);
|
||||
headLayout->addStretch();
|
||||
headLayout->setMargin(0);
|
||||
|
||||
headTextLayout->addStretch();
|
||||
headTextLayout->addWidget(name);
|
||||
headTextLayout->addWidget(nusers);
|
||||
headTextLayout->addWidget(namesList);
|
||||
headTextLayout->setMargin(0);
|
||||
headTextLayout->setSpacing(0);
|
||||
headTextLayout->addStretch();
|
||||
|
||||
chatArea->setWidget(chatAreaWidget);
|
||||
|
||||
connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered()));
|
||||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||
connect(chatArea->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
|
||||
}
|
||||
|
||||
GroupChatForm::~GroupChatForm()
|
||||
{
|
||||
delete head;
|
||||
delete main;
|
||||
}
|
||||
|
||||
void GroupChatForm::show(Ui::Widget &ui)
|
||||
{
|
||||
ui.mainContent->layout()->addWidget(main);
|
||||
ui.mainHead->layout()->addWidget(head);
|
||||
main->show();
|
||||
head->show();
|
||||
}
|
||||
|
||||
void GroupChatForm::setName(QString newName)
|
||||
{
|
||||
name->setText(newName);
|
||||
}
|
||||
|
||||
void GroupChatForm::onSendTriggered()
|
||||
{
|
||||
QString msg = msgEdit->toPlainText();
|
||||
if (msg.isEmpty())
|
||||
return;
|
||||
msgEdit->clear();
|
||||
emit sendMessage(group->groupId, msg);
|
||||
}
|
||||
|
||||
void GroupChatForm::addGroupMessage(QString message, int peerId)
|
||||
{
|
||||
QLabel *msgAuthor;
|
||||
if (group->peers.contains(peerId))
|
||||
msgAuthor = new QLabel(group->peers[peerId]);
|
||||
else
|
||||
msgAuthor = new QLabel("<Unknown>");
|
||||
|
||||
QLabel *msgText = new QLabel(message);
|
||||
QLabel *msgDate = new QLabel(QTime::currentTime().toString("hh:mm"));
|
||||
|
||||
addMessage(msgAuthor, msgText, msgDate);
|
||||
}
|
||||
|
||||
void GroupChatForm::addMessage(QString author, QString message, QString date)
|
||||
{
|
||||
addMessage(new QLabel(author), new QLabel(message), new QLabel(date));
|
||||
}
|
||||
|
||||
void GroupChatForm::addMessage(QLabel* author, QLabel* message, QLabel* date)
|
||||
{
|
||||
QScrollBar* scroll = chatArea->verticalScrollBar();
|
||||
lockSliderToBottom = scroll && scroll->value() == scroll->maximum();
|
||||
author->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
date->setAlignment(Qt::AlignTop);
|
||||
if (author->text() == Widget::getInstance()->getUsername())
|
||||
{
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::WindowText, Qt::gray);
|
||||
author->setPalette(pal);
|
||||
message->setPalette(pal);
|
||||
}
|
||||
if (previousName.isEmpty() || previousName != author->text())
|
||||
{
|
||||
if (curRow)
|
||||
{
|
||||
mainChatLayout->setRowStretch(curRow, 0);
|
||||
mainChatLayout->addItem(new QSpacerItem(0,AUTHOR_CHANGE_SPACING),curRow,0,1,3);
|
||||
curRow++;
|
||||
}
|
||||
mainChatLayout->addWidget(author, curRow, 0);
|
||||
}
|
||||
previousName = author->text();
|
||||
mainChatLayout->addWidget(message, curRow, 1);
|
||||
mainChatLayout->addWidget(date, curRow, 3);
|
||||
mainChatLayout->setRowStretch(curRow+1, 1);
|
||||
mainChatLayout->setRowStretch(curRow, 0);
|
||||
curRow++;
|
||||
}
|
||||
|
||||
void GroupChatForm::onSliderRangeChanged()
|
||||
{
|
||||
QScrollBar* scroll = chatArea->verticalScrollBar();
|
||||
if (lockSliderToBottom)
|
||||
scroll->setValue(scroll->maximum());
|
||||
}
|
||||
|
||||
void GroupChatForm::onUserListChanged()
|
||||
{
|
||||
nusers->setText(QString("%1 users in chat").arg(group->nPeers));
|
||||
QString names;
|
||||
for (QString& s : group->peers)
|
||||
names.append(s+", ");
|
||||
names.chop(2);
|
||||
namesList->setText(names);
|
||||
}
|
56
groupchatform.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef GROUPCHATFORM_H
|
||||
#define GROUPCHATFORM_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QScrollArea>
|
||||
#include <QTime>
|
||||
|
||||
#include "chattextedit.h"
|
||||
#include "ui_widget.h"
|
||||
|
||||
// Spacing in px inserted when the author of the last message changes
|
||||
#define AUTHOR_CHANGE_SPACING 5
|
||||
|
||||
class Group;
|
||||
|
||||
class GroupChatForm : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupChatForm(Group* chatGroup);
|
||||
~GroupChatForm();
|
||||
void show(Ui::Widget& ui);
|
||||
void setName(QString newName);
|
||||
void addGroupMessage(QString message, int peerId);
|
||||
void addMessage(QString author, QString message, QString date=QTime::currentTime().toString("hh:mm"));
|
||||
void addMessage(QLabel* author, QLabel* message, QLabel* date);
|
||||
void onUserListChanged();
|
||||
|
||||
signals:
|
||||
void sendMessage(int, QString);
|
||||
|
||||
private slots:
|
||||
void onSendTriggered();
|
||||
void onSliderRangeChanged();
|
||||
|
||||
private:
|
||||
Group* group;
|
||||
QHBoxLayout *headLayout, *mainFootLayout;
|
||||
QVBoxLayout *headTextLayout, *mainLayout;
|
||||
QGridLayout *mainChatLayout;
|
||||
QLabel *avatar, *name, *nusers, *namesList;
|
||||
ChatTextEdit *msgEdit;
|
||||
QPushButton *sendButton;
|
||||
QScrollArea *chatArea;
|
||||
QWidget *main, *head, *chatAreaWidget;
|
||||
QString previousName;
|
||||
int curRow;
|
||||
bool lockSliderToBottom;
|
||||
};
|
||||
|
||||
#endif // GROUPCHATFORM_H
|
31
grouplist.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "grouplist.h"
|
||||
#include "group.h"
|
||||
|
||||
QList<Group*> GroupList::groupList;
|
||||
|
||||
Group* GroupList::addGroup(int groupId, QString name)
|
||||
{
|
||||
Group* newGroup = new Group(groupId, name);
|
||||
groupList.append(newGroup);
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
Group* GroupList::findGroup(int groupId)
|
||||
{
|
||||
for (Group* g : groupList)
|
||||
if (g->groupId == groupId)
|
||||
return g;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GroupList::removeGroup(int groupId)
|
||||
{
|
||||
for (int i=0; i<groupList.size(); i++)
|
||||
{
|
||||
if (groupList[i]->groupId == groupId)
|
||||
{
|
||||
groupList.removeAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
22
grouplist.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef GROUPLIST_H
|
||||
#define GROUPLIST_H
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
|
||||
class Group;
|
||||
|
||||
class GroupList
|
||||
{
|
||||
public:
|
||||
GroupList();
|
||||
static Group* addGroup(int groupId, QString name);
|
||||
static Group* findGroup(int groupId);
|
||||
static void removeGroup(int groupId);
|
||||
|
||||
public:
|
||||
static QList<Group*> groupList;
|
||||
};
|
||||
|
||||
#endif // GROUPLIST_H
|
75
groupwidget.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "groupwidget.h"
|
||||
#include "grouplist.h"
|
||||
#include "group.h"
|
||||
#include <QPalette>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
GroupWidget::GroupWidget(int GroupId, QString Name)
|
||||
: groupId{GroupId}
|
||||
{
|
||||
this->setLayout(&layout);
|
||||
this->setFixedWidth(225);
|
||||
this->setFixedHeight(55);
|
||||
layout.setSpacing(0);
|
||||
layout.setMargin(0);
|
||||
textLayout.setSpacing(0);
|
||||
textLayout.setMargin(0);
|
||||
|
||||
avatar.setPixmap(QPixmap("img/contact list icons/group_2x.png"));
|
||||
name.setText(Name);
|
||||
QFont small;
|
||||
small.setPixelSize(10);
|
||||
nusers.setFont(small);
|
||||
QPalette pal;
|
||||
pal.setColor(QPalette::WindowText,Qt::gray);
|
||||
nusers.setPalette(pal);
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
if (g)
|
||||
nusers.setText(QString("%1 users in chat").arg(g->peers.size()));
|
||||
else
|
||||
nusers.setText("0 users in chat");
|
||||
|
||||
textLayout.addStretch();
|
||||
textLayout.addWidget(&name);
|
||||
textLayout.addWidget(&nusers);
|
||||
textLayout.addStretch();
|
||||
|
||||
layout.addSpacing(20);
|
||||
layout.addWidget(&avatar);
|
||||
layout.addSpacing(5);
|
||||
layout.addLayout(&textLayout);
|
||||
layout.addStretch();
|
||||
}
|
||||
|
||||
void GroupWidget::mouseReleaseEvent (QMouseEvent*)
|
||||
{
|
||||
emit groupWidgetClicked(this);
|
||||
}
|
||||
|
||||
void GroupWidget::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
QPoint pos = event->globalPos();
|
||||
QMenu menu;
|
||||
menu.addAction("Quit group");
|
||||
|
||||
QAction* selectedItem = menu.exec(pos);
|
||||
if (selectedItem)
|
||||
{
|
||||
if (selectedItem->text() == "Quit group")
|
||||
{
|
||||
hide();
|
||||
emit removeGroup(groupId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupWidget::onUserListChanged()
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
if (g)
|
||||
nusers.setText(QString("%1 users in chat").arg(g->nPeers));
|
||||
else
|
||||
nusers.setText("0 users in chat");
|
||||
}
|
29
groupwidget.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef GROUPWIDGET_H
|
||||
#define GROUPWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class GroupWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupWidget(int GroupId, QString Name);
|
||||
void onUserListChanged();
|
||||
void mouseReleaseEvent (QMouseEvent* event);
|
||||
void contextMenuEvent(QContextMenuEvent * event);
|
||||
|
||||
signals:
|
||||
void groupWidgetClicked(GroupWidget* widget);
|
||||
void removeGroup(int groupId);
|
||||
|
||||
public:
|
||||
int groupId;
|
||||
QLabel avatar, name, nusers;
|
||||
QHBoxLayout layout;
|
||||
QVBoxLayout textLayout;
|
||||
};
|
||||
|
||||
#endif // GROUPWIDGET_H
|
BIN
img/button icons/arrow_medgrey.png
Normal file
After Width: | Height: | Size: 172 B |
7
img/button icons/arrow_medgrey.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="7.145px" height="6.187px" viewBox="0 0 7.145 6.187" enable-background="new 0 0 7.145 6.187" xml:space="preserve">
|
||||
<polygon fill="#636365" points="7.145,0 3.572,6.187 0,0 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 549 B |
BIN
img/button icons/arrow_medgrey_2x.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
img/button icons/arrow_white.png
Normal file
After Width: | Height: | Size: 152 B |
7
img/button icons/arrow_white.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="7.145px" height="6.187px" viewBox="0 0 7.145 6.187" enable-background="new 0 0 7.145 6.187" xml:space="preserve">
|
||||
<polygon fill="#FFFFFF" points="7.145,0 3.572,6.187 0,0 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 549 B |
BIN
img/button icons/arrow_white_2x.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
img/button icons/attach.png
Normal file
After Width: | Height: | Size: 274 B |
38
img/button icons/attach.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="13.736px" height="13.708px" viewBox="0 0 13.736 13.708" enable-background="new 0 0 13.736 13.708" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M13.629,2.874c-0.062-0.255-0.149-0.494-0.256-0.716c-0.188-0.388-0.438-0.719-0.718-0.992
|
||||
c-0.21-0.206-0.438-0.382-0.672-0.527c-0.353-0.221-0.72-0.377-1.078-0.481c-0.179-0.053-0.355-0.091-0.528-0.118
|
||||
C10.204,0.014,10.036,0,9.872,0C9.446,0,9.068,0.061,8.744,0.156C8.501,0.228,8.29,0.317,8.107,0.413
|
||||
C7.835,0.558,7.632,0.713,7.49,0.84C7.396,0.926,7.33,0.996,7.291,1.043L1.279,6.974L1.278,6.977
|
||||
C1.12,7.134,0.962,7.315,0.812,7.523C0.587,7.834,0.383,8.206,0.235,8.636C0.089,9.066,0,9.556,0,10.099
|
||||
c0.001,0.216,0.028,0.432,0.079,0.645c0.088,0.371,0.246,0.734,0.461,1.075c0.161,0.256,0.354,0.5,0.578,0.724
|
||||
c0.336,0.336,0.743,0.626,1.211,0.834c0.233,0.104,0.482,0.187,0.743,0.244c0.262,0.057,0.536,0.088,0.82,0.088
|
||||
c0.27,0,0.529-0.042,0.774-0.108c0.214-0.06,0.418-0.138,0.609-0.229c0.338-0.16,0.642-0.357,0.914-0.562
|
||||
c0.406-0.306,0.738-0.629,0.976-0.878c0.235-0.25,0.374-0.426,0.384-0.439L6.44,10.622l0,0l0.51,0.399l-0.51-0.4l0.453,0.356
|
||||
l-0.452-0.356H6.44l0,0v0.001l0,0c-0.002,0.004-0.093,0.116-0.246,0.282c-0.116,0.126-0.269,0.281-0.447,0.441
|
||||
c-0.133,0.121-0.28,0.245-0.437,0.358c-0.233,0.175-0.485,0.328-0.73,0.433c-0.123,0.054-0.243,0.094-0.359,0.121
|
||||
c-0.115,0.027-0.225,0.04-0.328,0.04c-0.185,0-0.36-0.021-0.527-0.058c-0.293-0.063-0.561-0.182-0.803-0.336
|
||||
c-0.181-0.115-0.346-0.253-0.49-0.403c-0.217-0.227-0.387-0.481-0.499-0.73c-0.056-0.125-0.098-0.246-0.124-0.36
|
||||
S1.41,10.19,1.41,10.099c0-0.26,0.028-0.493,0.075-0.705C1.557,9.077,1.671,8.806,1.81,8.571c0.138-0.234,0.302-0.433,0.466-0.597
|
||||
l6.065-5.986l0.023-0.03c0.009-0.01,0.042-0.048,0.104-0.1c0.096-0.08,0.252-0.191,0.48-0.282C9.063,1.53,9.195,1.489,9.348,1.459
|
||||
s0.326-0.048,0.524-0.048c0.1,0,0.219,0.01,0.348,0.032c0.226,0.038,0.48,0.116,0.727,0.232c0.186,0.089,0.366,0.198,0.53,0.329
|
||||
c0.124,0.097,0.238,0.207,0.34,0.327c0.152,0.182,0.277,0.388,0.366,0.629c0.09,0.241,0.143,0.518,0.144,0.848
|
||||
c0,0.151-0.02,0.297-0.053,0.436c-0.053,0.21-0.139,0.407-0.248,0.59s-0.241,0.348-0.376,0.486l-0.001,0.002L8.609,8.496
|
||||
C8.604,8.5,8.586,8.519,8.553,8.542C8.501,8.579,8.418,8.63,8.306,8.671C8.194,8.712,8.052,8.744,7.869,8.744
|
||||
c-0.051,0-0.098-0.006-0.141-0.016c-0.075-0.017-0.14-0.047-0.202-0.09c-0.046-0.03-0.089-0.071-0.13-0.118
|
||||
C7.336,8.449,7.284,8.359,7.248,8.257C7.213,8.155,7.192,8.043,7.192,7.926c0-0.111,0.021-0.216,0.055-0.314
|
||||
c0.024-0.075,0.058-0.145,0.094-0.207C7.396,7.31,7.455,7.231,7.498,7.183C7.52,7.156,7.537,7.14,7.546,7.13
|
||||
C7.55,7.127,7.553,7.125,7.554,7.123l0.008-0.008l2.355-2.326L8.925,3.786L6.593,6.09c-0.025,0.024-0.072,0.07-0.13,0.134
|
||||
c-0.115,0.128-0.278,0.334-0.42,0.618C5.973,6.983,5.907,7.146,5.86,7.328C5.813,7.51,5.781,7.711,5.781,7.926
|
||||
c0.001,0.281,0.05,0.557,0.143,0.814c0.069,0.193,0.164,0.376,0.282,0.545c0.09,0.126,0.193,0.243,0.31,0.349
|
||||
c0.176,0.158,0.38,0.289,0.609,0.381c0.229,0.091,0.482,0.141,0.744,0.141c0.273,0,0.521-0.04,0.735-0.1
|
||||
c0.161-0.045,0.304-0.103,0.427-0.162C9.217,9.803,9.359,9.704,9.46,9.623c0.09-0.07,0.146-0.128,0.174-0.156l3.03-3.166
|
||||
c0.268-0.277,0.53-0.623,0.732-1.041c0.101-0.209,0.186-0.436,0.245-0.679c0.061-0.242,0.095-0.503,0.095-0.772
|
||||
C13.736,3.479,13.699,3.167,13.629,2.874z M8.362,1.96L8.362,1.96L8.362,1.96L8.362,1.96z"/>
|
||||
<polygon fill="#FFFFFF" points="12.666,6.299 12.664,6.301 12.664,6.301 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
BIN
img/button icons/attach_2x.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
img/button icons/call.png
Normal file
After Width: | Height: | Size: 307 B |
10
img/button icons/call.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="21.222px" height="19.66px" viewBox="0 0 21.222 19.66" enable-background="new 0 0 21.222 19.66" xml:space="preserve">
|
||||
<path fill="#FFFFFF" d="M16.656,0.009c0,0-0.501-0.112-0.723,0.473l-1.782,4.204c0,0-0.334,0.611,0.167,1.196l1.28,1.67
|
||||
c0,0,0.473,0.446,0.111,0.975c-0.362,0.528-2.255,4.036-7.154,6.235c0,0-0.611,0.417-1.056-0.195
|
||||
c-0.446-0.612-1.811-2.839-2.674-2.365l-4.509,2.115c0,0-0.39,0.027-0.306,0.835C0.095,15.958-0.017,19.66,5.3,19.66
|
||||
c6.348,0,15.922-9.061,15.922-14.809c0,0,0-4.843-2.979-4.843H16.656z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 890 B |
BIN
img/button icons/call_2x.png
Normal file
After Width: | Height: | Size: 510 B |
7
img/button icons/check.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="12.608px" height="10.029px" viewBox="0 0 12.608 10.029" enable-background="new 0 0 12.608 10.029" xml:space="preserve">
|
||||
<polygon fill="#FFFFFF" points="4.24,6.707 1.661,4.127 0,5.789 4.24,10.029 4.241,10.029 5.902,8.369 12.608,1.662 10.946,0 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 621 B |
BIN
img/button icons/emoticon.png
Normal file
After Width: | Height: | Size: 220 B |
10
img/button icons/emoticon.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="10.664px" height="11.333px" viewBox="0 0 10.664 11.333" enable-background="new 0 0 10.664 11.333" xml:space="preserve">
|
||||
<path fill="#FFFFFF" d="M5.332,11.333C2.387,11.332,0.002,8.947,0,6.001h1.582C1.582,7.041,2,7.972,2.68,8.654
|
||||
c0.682,0.68,1.613,1.098,2.652,1.098s1.973-0.418,2.654-1.098c0.68-0.682,1.098-1.613,1.098-2.652h1.58
|
||||
C10.664,8.947,8.277,11.332,5.332,11.333z M3.75,1.5c0,0.826-0.672,1.5-1.5,1.5s-1.5-0.674-1.5-1.5c0-0.83,0.672-1.5,1.5-1.5
|
||||
S3.75,0.669,3.75,1.5z M9.75,1.5c0,0.826-0.672,1.5-1.5,1.5s-1.5-0.674-1.5-1.5c0-0.83,0.672-1.5,1.5-1.5S9.75,0.669,9.75,1.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 953 B |
BIN
img/button icons/emoticon_2x.png
Normal file
After Width: | Height: | Size: 323 B |
BIN
img/button icons/no.png
Normal file
After Width: | Height: | Size: 178 B |
8
img/button icons/no.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="10.086px" height="10.087px" viewBox="0 0 10.086 10.087" enable-background="new 0 0 10.086 10.087" xml:space="preserve">
|
||||
<polygon fill="#FFFFFF" points="10.086,1.692 8.395,0 5.043,3.351 1.693,0.001 0,1.693 3.35,5.043 0,8.394 1.693,10.086
|
||||
5.043,6.736 8.395,10.087 10.086,8.394 6.734,5.043 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 668 B |
BIN
img/button icons/no_2x.png
Normal file
After Width: | Height: | Size: 265 B |
BIN
img/button icons/pause.png
Normal file
After Width: | Height: | Size: 142 B |
10
img/button icons/pause.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="8.4px" height="9.4px" viewBox="0 0 8.4 9.4" enable-background="new 0 0 8.4 9.4" xml:space="preserve">
|
||||
<g>
|
||||
<rect y="0.002" fill="#FFFFFF" width="2.395" height="9.398"/>
|
||||
<rect x="6.007" fill="#FFFFFF" width="2.395" height="9.4"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 610 B |
BIN
img/button icons/pause_2x.png
Normal file
After Width: | Height: | Size: 129 B |
BIN
img/button icons/sendmessage.png
Normal file
After Width: | Height: | Size: 327 B |
10
img/button icons/sendmessage.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="19.509px" height="23.089px" viewBox="0 0 19.509 23.089" enable-background="new 0 0 19.509 23.089" xml:space="preserve">
|
||||
<path fill="#FFFFFF" d="M3.663,2.025C2.146,3.105,0.95,4.664,0.417,6.458c-0.68,2.182-0.537,4.631,0.494,6.682
|
||||
c1.055,2.143,3.014,3.775,5.248,4.58c1.865,0.723,3.939,0.826,5.881,0.365c-0.232,1.795-1.008,3.461-1.922,5.004
|
||||
c2.865-1.863,5.223-4.416,7.145-7.227c1.414-2.119,2.354-4.643,2.236-7.219c-0.104-2.264-1.211-4.419-2.852-5.96
|
||||
c-1.777-1.665-4.189-2.613-6.619-2.677C7.757-0.078,5.485,0.677,3.663,2.025z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 902 B |
BIN
img/button icons/sendmessage_2x.png
Normal file
After Width: | Height: | Size: 533 B |
BIN
img/button icons/video.png
Normal file
After Width: | Height: | Size: 248 B |
10
img/button icons/video.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="22.625px" height="14.396px" viewBox="0 0 22.625 14.396" enable-background="new 0 0 22.625 14.396" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M8.845,2c0-1.1,0.9-2,2-2h9.78c1.1,0,2,0.9,2,2v10.396c0,1.1-0.9,2-2,2h-9.78c-1.1,0-2-0.9-2-2V2z"/>
|
||||
<polygon fill="#FFFFFF" points="0,12.916 7.509,8.581 7.509,5.814 0,1.48 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 705 B |
BIN
img/button icons/video_2x.png
Normal file
After Width: | Height: | Size: 382 B |
BIN
img/button icons/yes.png
Normal file
After Width: | Height: | Size: 183 B |
BIN
img/button icons/yes_2x.png
Normal file
After Width: | Height: | Size: 267 B |
BIN
img/contact list icons/add.png
Normal file
After Width: | Height: | Size: 164 B |
8
img/contact list icons/add.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="15.884px" height="15.883px" viewBox="0 0 15.884 15.883" enable-background="new 0 0 15.884 15.883" xml:space="preserve">
|
||||
<polygon fill="#FFFFFF" points="9.563,6.319 9.563,0 6.321,0 6.321,6.321 0,6.321 0,9.563 6.321,9.563 6.321,15.883 9.563,15.883
|
||||
9.563,9.563 15.884,9.563 15.884,6.319 "/>
|
||||
</svg>
|
After Width: | Height: | Size: 665 B |
BIN
img/contact list icons/add_2x.png
Normal file
After Width: | Height: | Size: 192 B |
BIN
img/contact list icons/contact.png
Normal file
After Width: | Height: | Size: 790 B |
BIN
img/contact list icons/group.png
Normal file
After Width: | Height: | Size: 314 B |
20
img/contact list icons/group.svg
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="15.402px" height="15.918px" viewBox="0 0 15.402 15.918" enable-background="new 0 0 15.402 15.918" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M9.429,11.411c4.71,1.681,3.195,4.507,3.195,4.507H2.666c0,0-0.773-3.161,3.465-4.507
|
||||
C6.131,11.411,7.813,12.823,9.429,11.411z"/>
|
||||
<path fill="#FFFFFF" d="M4.92,6.682c0,0,0.27,3.938,2.793,3.938s2.826-3.668,2.826-3.668s0.101-3.194-2.826-3.194
|
||||
S4.92,6.682,4.92,6.682z"/>
|
||||
<path fill="#FFFFFF" d="M3.359,7.276c-0.005-0.092-0.016-0.52,0.093-1.082c-0.521-0.1-0.841-0.336-0.841-0.336
|
||||
c-3.15,1.045-2.569,3.23-2.569,3.23h3.651C3.428,8.178,3.368,7.413,3.361,7.313L3.359,7.276z"/>
|
||||
<path fill="#FFFFFF" d="M12.1,7.522v0.041l-0.004,0.04c-0.035,0.427-0.127,0.944-0.29,1.485h3.554c0,0,0.583-2.186-2.567-3.23
|
||||
c0,0-0.319,0.234-0.835,0.335C12.111,6.877,12.104,7.414,12.1,7.522z"/>
|
||||
<path fill="#FFFFFF" d="M5.904,2.525C5.923,2.403,5.93,2.328,5.93,2.328S6.002,0,3.88,0S1.855,2.131,1.855,2.131
|
||||
s0.18,2.606,1.781,2.85c0.176-0.513,0.461-1.063,0.922-1.545C4.859,3.121,5.297,2.774,5.904,2.525z"/>
|
||||
<path fill="#FFFFFF" d="M11.758,4.99c1.664-0.17,1.869-2.662,1.869-2.662S13.699,0,11.576,0C9.455,0,9.553,2.131,9.553,2.131
|
||||
s0.013,0.183,0.061,0.454c0.519,0.238,0.905,0.548,1.18,0.832C11.262,3.901,11.564,4.459,11.758,4.99z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
BIN
img/contact list icons/group_2x.png
Normal file
After Width: | Height: | Size: 512 B |
BIN
img/contact list icons/settings.png
Normal file
After Width: | Height: | Size: 291 B |
19
img/contact list icons/settings.svg
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="15.615px" height="15.616px" viewBox="0 0 15.615 15.616" enable-background="new 0 0 15.615 15.616" xml:space="preserve">
|
||||
<path fill="#FFFFFF" d="M15.615,7.034c0-0.197-0.163-0.358-0.358-0.358h-0.66c-0.199,0-0.407-0.154-0.462-0.345l-0.896-2.092
|
||||
c-0.095-0.171-0.064-0.425,0.075-0.567l0.446-0.445c0.14-0.14,0.14-0.367,0-0.507l-1.073-1.074c-0.139-0.14-0.367-0.14-0.51,0
|
||||
L11.694,2.13c-0.142,0.142-0.399,0.18-0.574,0.09L9.3,1.49c-0.19-0.053-0.348-0.259-0.348-0.458V0.357C8.952,0.162,8.791,0,8.596,0
|
||||
h-1.52C6.879,0,6.717,0.162,6.717,0.357v0.675c0,0.199-0.156,0.406-0.344,0.465L4.263,2.4c-0.17,0.099-0.422,0.066-0.563-0.072
|
||||
L3.225,1.854c-0.138-0.139-0.367-0.139-0.506,0L1.645,2.929c-0.141,0.14-0.141,0.367,0,0.507l0.515,0.519
|
||||
c0.143,0.14,0.181,0.396,0.089,0.57L1.531,6.33C1.478,6.521,1.272,6.676,1.073,6.676H0.357C0.16,6.676,0,6.837,0,7.034v1.519
|
||||
c0,0.198,0.16,0.36,0.357,0.36h0.716c0.199,0,0.407,0.154,0.464,0.344l0.882,2.076c0.101,0.171,0.065,0.425-0.072,0.564L1.853,12.39
|
||||
c-0.139,0.14-0.139,0.367,0,0.507l1.076,1.074c0.14,0.14,0.368,0.14,0.505,0l0.528-0.525c0.141-0.14,0.394-0.177,0.57-0.083
|
||||
l1.841,0.734c0.188,0.055,0.344,0.262,0.344,0.458v0.702c0,0.198,0.162,0.359,0.359,0.359h1.52c0.195,0,0.356-0.161,0.356-0.359
|
||||
v-0.702c0-0.196,0.156-0.403,0.348-0.461l2.059-0.874c0.172-0.097,0.422-0.063,0.564,0.075l0.465,0.468
|
||||
c0.139,0.139,0.368,0.139,0.507,0l1.076-1.076c0.139-0.139,0.139-0.368,0-0.506l-0.497-0.495c-0.137-0.14-0.176-0.396-0.082-0.57
|
||||
l0.746-1.857c0.052-0.19,0.26-0.345,0.459-0.347h0.66c0.195,0,0.358-0.161,0.358-0.358V7.034z M7.808,10.36
|
||||
c-1.411,0-2.552-1.143-2.552-2.553s1.141-2.552,2.552-2.552c1.409,0,2.554,1.142,2.554,2.552S9.217,10.36,7.808,10.36z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
BIN
img/contact list icons/settings_2x.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
img/contact list icons/transfer.png
Normal file
After Width: | Height: | Size: 288 B |
18
img/contact list icons/transfer.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="15.604px" height="15.604px" viewBox="0 0 15.604 15.604" enable-background="new 0 0 15.604 15.604" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M6.303,15.588c-0.104-0.018-0.24-0.057-0.317-0.15s-0.149-0.301-0.119-0.604L6.482,8.78
|
||||
c0.023-0.23,0.115-0.492,0.297-0.461c0.133,0.023,0.34,0.164,0.552,0.375l1.4,1.4l4.144-4.145c0.076-0.076,0.191-0.105,0.321-0.084
|
||||
c0.131,0.023,0.263,0.096,0.37,0.203l1.828,1.828c0.223,0.223,0.277,0.533,0.117,0.691l-4.143,4.143l1.4,1.4
|
||||
c0.293,0.293,0.387,0.508,0.377,0.602s-0.138,0.215-0.463,0.248l-6.055,0.615C6.513,15.608,6.402,15.606,6.303,15.588L6.303,15.588
|
||||
z"/>
|
||||
<path fill="#FFFFFF" d="M9.303,0.015c0.102,0.018,0.24,0.057,0.316,0.15C9.696,0.259,9.77,0.467,9.738,0.77L9.122,6.825
|
||||
C9.1,7.055,9.006,7.315,8.825,7.284C8.691,7.26,8.484,7.122,8.273,6.911l-1.4-1.4L2.729,9.655C2.652,9.731,2.539,9.76,2.408,9.737
|
||||
C2.277,9.715,2.146,9.645,2.037,9.536L0.209,7.708c-0.223-0.223-0.275-0.533-0.117-0.693l4.143-4.143l-1.4-1.4
|
||||
c-0.292-0.291-0.385-0.505-0.375-0.6c0.01-0.094,0.137-0.215,0.462-0.247l6.056-0.617C9.092-0.005,9.201-0.002,9.303,0.015
|
||||
L9.303,0.015z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
img/contact list icons/transfer_2x.png
Normal file
After Width: | Height: | Size: 433 B |
BIN
img/icon.ico
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
img/icon.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
img/status/dot_away.png
Normal file
After Width: | Height: | Size: 407 B |
36
img/status/dot_away.svg
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="10.057px" height="10.055px" viewBox="0 0 10.057 10.055" enable-background="new 0 0 10.057 10.055" xml:space="preserve">
|
||||
<path fill="#C94F4F" d="M5.029,0C2.252,0,0,2.25,0,5.027s2.252,5.027,5.029,5.027c2.775,0,5.027-2.25,5.027-5.027S7.805,0,5.029,0z
|
||||
M5.029,8.641c-1.996,0-3.613-1.617-3.613-3.613c0-1.033,0.434-1.967,1.131-2.625C2.549,2.4,2.553,2.396,2.555,2.395
|
||||
c0.033-0.031,0.066-0.061,0.098-0.09c0.008-0.004,0.014-0.01,0.02-0.016C2.705,2.262,2.736,2.234,2.77,2.207
|
||||
c0.006-0.004,0.014-0.01,0.02-0.014C2.93,2.082,3.08,1.98,3.238,1.891C3.25,1.883,3.264,1.875,3.277,1.867
|
||||
C3.307,1.85,3.336,1.834,3.367,1.82c0.018-0.012,0.037-0.02,0.055-0.029C3.449,1.777,3.479,1.762,3.508,1.75
|
||||
C3.529,1.74,3.549,1.73,3.57,1.721c0.027-0.012,0.057-0.023,0.084-0.035c0.023-0.01,0.047-0.02,0.07-0.027
|
||||
c0.027-0.012,0.055-0.021,0.08-0.031c0.029-0.01,0.057-0.02,0.086-0.029c0.035-0.012,0.07-0.023,0.105-0.033
|
||||
c0.039-0.012,0.078-0.023,0.115-0.033c0.023-0.006,0.047-0.01,0.068-0.016C4.213,1.508,4.244,1.5,4.275,1.494
|
||||
c0.023-0.006,0.049-0.012,0.072-0.016c0.031-0.006,0.064-0.012,0.096-0.016c0.023-0.004,0.049-0.01,0.072-0.012
|
||||
c0.033-0.004,0.066-0.01,0.1-0.014c0.023-0.002,0.047-0.004,0.068-0.006c0.037-0.006,0.076-0.008,0.113-0.01
|
||||
C4.816,1.42,4.836,1.42,4.855,1.418c0.057-0.002,0.113-0.004,0.17-0.004c0,0,0.002,0,0.004,0l0,0l0,0
|
||||
c0.059,0,0.115,0.002,0.174,0.004C5.221,1.42,5.238,1.42,5.256,1.422c0.041,0.002,0.08,0.004,0.121,0.01
|
||||
c0.02,0.002,0.039,0.004,0.061,0.006c0.037,0.004,0.074,0.01,0.109,0.014c0.021,0.002,0.043,0.008,0.063,0.01
|
||||
c0.037,0.006,0.074,0.014,0.109,0.02c0.02,0.004,0.039,0.008,0.059,0.012C5.818,1.5,5.857,1.51,5.896,1.52
|
||||
c0.016,0.004,0.029,0.008,0.045,0.01c0.055,0.016,0.107,0.029,0.162,0.047c0,0,0,0.002,0.002,0.002
|
||||
C6.158,1.594,6.209,1.611,6.26,1.629c0.016,0.008,0.031,0.014,0.047,0.018C6.344,1.66,6.379,1.676,6.414,1.689
|
||||
c0.018,0.008,0.037,0.016,0.055,0.023c0.033,0.016,0.064,0.029,0.096,0.045c0.02,0.008,0.039,0.016,0.059,0.027
|
||||
c0.029,0.014,0.061,0.029,0.092,0.047C6.732,1.84,6.75,1.85,6.77,1.859c0.031,0.018,0.063,0.037,0.096,0.057
|
||||
C6.881,1.924,6.895,1.934,6.91,1.941C6.957,1.971,7,1.998,7.045,2.027c0.014,0.01,0.027,0.02,0.039,0.029
|
||||
C7.115,2.078,7.146,2.1,7.176,2.123c0.02,0.014,0.039,0.027,0.057,0.043c0.023,0.018,0.047,0.035,0.07,0.053
|
||||
c0.021,0.018,0.041,0.035,0.061,0.053s0.041,0.033,0.063,0.051c0.02,0.02,0.039,0.037,0.061,0.057
|
||||
c0.018,0.018,0.037,0.035,0.055,0.053c0.021,0.02,0.041,0.039,0.061,0.061C7.619,2.51,7.635,2.527,7.652,2.543
|
||||
c0.02,0.023,0.041,0.043,0.061,0.066c0.004,0.004,0.006,0.006,0.01,0.01c0.053,0.059,0.102,0.119,0.152,0.184
|
||||
c0.01,0.014,0.021,0.027,0.033,0.041c0.02,0.027,0.039,0.055,0.059,0.082C7.979,2.941,7.99,2.957,8,2.973
|
||||
C8.02,3,8.039,3.029,8.057,3.057c0.01,0.016,0.021,0.031,0.031,0.049c0.018,0.027,0.037,0.057,0.055,0.088
|
||||
C8.15,3.207,8.158,3.223,8.166,3.236c0.02,0.033,0.037,0.064,0.055,0.098c0.006,0.01,0.01,0.02,0.016,0.029
|
||||
C8.297,3.48,8.352,3.602,8.4,3.727c0.004,0.008,0.006,0.018,0.01,0.025c0.014,0.037,0.027,0.074,0.039,0.111
|
||||
c0.006,0.014,0.01,0.029,0.016,0.043c0.01,0.035,0.021,0.072,0.031,0.107c0.006,0.016,0.01,0.031,0.014,0.047
|
||||
c0.01,0.037,0.02,0.072,0.029,0.109c0.002,0.004,0.002,0.01,0.004,0.016l0,0c0.064,0.27,0.1,0.551,0.1,0.842
|
||||
C8.643,7.023,7.023,8.641,5.029,8.641z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
BIN
img/status/dot_away_2x.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
img/status/dot_away_notification.png
Normal file
After Width: | Height: | Size: 472 B |
40
img/status/dot_away_notification.svg
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="16.814px" height="16.816px" viewBox="0 0 16.814 16.816" enable-background="new 0 0 16.814 16.816" xml:space="preserve">
|
||||
<path fill="#C94F4F" d="M8.408,3.381c-2.777,0-5.029,2.25-5.029,5.027s2.252,5.027,5.029,5.027c2.775,0,5.027-2.25,5.027-5.027
|
||||
S11.184,3.381,8.408,3.381z M8.408,12.021c-1.996,0-3.613-1.617-3.613-3.613c0-1.033,0.434-1.967,1.131-2.625
|
||||
c0.002-0.002,0.006-0.006,0.008-0.008C5.967,5.744,6,5.715,6.031,5.686c0.008-0.004,0.014-0.01,0.02-0.016
|
||||
c0.033-0.027,0.064-0.055,0.098-0.082c0.006-0.004,0.014-0.01,0.02-0.014c0.141-0.111,0.291-0.213,0.449-0.303
|
||||
c0.012-0.008,0.025-0.016,0.039-0.023c0.029-0.018,0.059-0.033,0.09-0.047c0.018-0.012,0.037-0.02,0.055-0.029
|
||||
c0.027-0.014,0.057-0.029,0.086-0.041c0.021-0.01,0.041-0.02,0.063-0.029C6.977,5.09,7.006,5.078,7.033,5.066
|
||||
c0.023-0.01,0.047-0.02,0.07-0.027c0.027-0.012,0.055-0.021,0.08-0.031c0.029-0.01,0.057-0.02,0.086-0.029
|
||||
c0.035-0.012,0.07-0.023,0.105-0.033C7.414,4.934,7.453,4.922,7.49,4.912c0.023-0.006,0.047-0.01,0.068-0.016
|
||||
c0.033-0.008,0.064-0.016,0.096-0.021c0.023-0.006,0.049-0.012,0.072-0.016c0.031-0.006,0.064-0.012,0.096-0.016
|
||||
c0.023-0.004,0.049-0.01,0.072-0.012c0.033-0.004,0.066-0.01,0.1-0.014c0.023-0.002,0.047-0.004,0.068-0.006
|
||||
C8.1,4.807,8.139,4.805,8.176,4.803c0.02-0.002,0.039-0.002,0.059-0.004c0.057-0.002,0.113-0.004,0.17-0.004c0,0,0.002,0,0.004,0
|
||||
l0,0l0,0c0.059,0,0.115,0.002,0.174,0.004C8.6,4.801,8.617,4.801,8.635,4.803c0.041,0.002,0.08,0.004,0.121,0.01
|
||||
c0.02,0.002,0.039,0.004,0.061,0.006c0.037,0.004,0.074,0.01,0.109,0.014c0.021,0.002,0.043,0.008,0.063,0.01
|
||||
c0.037,0.006,0.074,0.014,0.109,0.02c0.02,0.004,0.039,0.008,0.059,0.012C9.197,4.881,9.236,4.891,9.275,4.9
|
||||
C9.291,4.904,9.305,4.908,9.32,4.91c0.055,0.016,0.107,0.029,0.162,0.047c0,0,0,0.002,0.002,0.002
|
||||
C9.537,4.975,9.588,4.992,9.639,5.01C9.654,5.018,9.67,5.023,9.686,5.027C9.723,5.041,9.758,5.057,9.793,5.07
|
||||
C9.811,5.078,9.83,5.086,9.848,5.094c0.033,0.016,0.064,0.029,0.096,0.045c0.02,0.008,0.039,0.016,0.059,0.027
|
||||
c0.029,0.014,0.061,0.029,0.092,0.047c0.018,0.008,0.035,0.018,0.055,0.027c0.031,0.018,0.063,0.037,0.096,0.057
|
||||
c0.016,0.008,0.029,0.018,0.045,0.025c0.047,0.029,0.09,0.057,0.135,0.086c0.014,0.01,0.027,0.02,0.039,0.029
|
||||
c0.031,0.021,0.063,0.043,0.092,0.066c0.02,0.014,0.039,0.027,0.057,0.043c0.023,0.018,0.047,0.035,0.07,0.053
|
||||
c0.021,0.018,0.041,0.035,0.061,0.053s0.041,0.033,0.063,0.051c0.02,0.02,0.039,0.037,0.061,0.057
|
||||
c0.018,0.018,0.037,0.035,0.055,0.053c0.021,0.02,0.041,0.039,0.061,0.061c0.018,0.018,0.033,0.035,0.051,0.051
|
||||
c0.02,0.023,0.041,0.043,0.061,0.066c0.004,0.004,0.006,0.006,0.01,0.01c0.053,0.059,0.102,0.119,0.152,0.184
|
||||
c0.01,0.014,0.021,0.027,0.033,0.041c0.02,0.027,0.039,0.055,0.059,0.082c0.012,0.016,0.023,0.031,0.033,0.047
|
||||
c0.02,0.027,0.039,0.057,0.057,0.084c0.01,0.016,0.021,0.031,0.031,0.049c0.018,0.027,0.037,0.057,0.055,0.088
|
||||
c0.008,0.014,0.016,0.029,0.023,0.043c0.02,0.033,0.037,0.064,0.055,0.098c0.006,0.01,0.01,0.02,0.016,0.029
|
||||
c0.061,0.117,0.115,0.238,0.164,0.363c0.004,0.008,0.006,0.018,0.01,0.025c0.014,0.037,0.027,0.074,0.039,0.111
|
||||
c0.006,0.014,0.01,0.029,0.016,0.043c0.01,0.035,0.021,0.072,0.031,0.107c0.006,0.016,0.01,0.031,0.014,0.047
|
||||
c0.01,0.037,0.02,0.072,0.029,0.109c0.002,0.004,0.002,0.01,0.004,0.016l0,0c0.064,0.27,0.1,0.551,0.1,0.842
|
||||
C12.021,10.404,10.402,12.021,8.408,12.021z"/>
|
||||
<path fill="#C94F4F" d="M8.408,0C3.765,0.001,0,3.766,0,8.408c0,4.644,3.765,8.407,8.408,8.408c4.644-0.001,8.405-3.766,8.406-8.408
|
||||
C16.813,3.766,13.052,0.001,8.408,0z M13.292,13.293c-1.253,1.251-2.975,2.023-4.884,2.023s-3.632-0.772-4.885-2.023
|
||||
C2.272,12.04,1.5,10.317,1.5,8.408c0-1.909,0.772-3.632,2.023-4.884C4.776,2.272,6.499,1.501,8.408,1.5
|
||||
c1.909,0.001,3.631,0.772,4.884,2.023c1.251,1.253,2.022,2.976,2.022,4.885S14.543,12.04,13.292,13.293z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 4.0 KiB |
BIN
img/status/dot_away_notification_2x.png
Normal file
After Width: | Height: | Size: 852 B |
BIN
img/status/dot_idle.png
Normal file
After Width: | Height: | Size: 240 B |
8
img/status/dot_idle.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="10.059px" height="10.055px" viewBox="0 0 10.059 10.055" enable-background="new 0 0 10.059 10.055" xml:space="preserve">
|
||||
<path fill="#CEBF43" d="M5.029,0C2.252,0,0,2.25,0,5.027s2.252,5.027,5.029,5.027s5.029-2.25,5.029-5.027S7.807,0,5.029,0z
|
||||
M1.416,5.027c0-1.996,1.617-3.613,3.613-3.613s3.613,1.617,3.613,3.613H1.416z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 696 B |
BIN
img/status/dot_idle_2x.png
Normal file
After Width: | Height: | Size: 376 B |
BIN
img/status/dot_idle_notification.png
Normal file
After Width: | Height: | Size: 458 B |
14
img/status/dot_idle_notification.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="16.814px" height="16.817px" viewBox="0 0 16.814 16.817" enable-background="new 0 0 16.814 16.817" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#CEBF43" d="M8.441,3.475c-2.777,0-5.029,2.25-5.029,5.028c0,2.777,2.252,5.027,5.029,5.027s5.029-2.25,5.029-5.027
|
||||
C13.47,5.725,11.218,3.475,8.441,3.475z M4.828,8.502c0-1.997,1.617-3.614,3.613-3.614s3.613,1.617,3.613,3.614H4.828z"/>
|
||||
<path fill="#CEBF43" d="M15.314,8.409c0,1.909-0.771,3.632-2.022,4.885c-1.253,1.251-2.975,2.023-4.884,2.023
|
||||
s-3.632-0.772-4.884-2.023C2.272,12.041,1.5,10.318,1.5,8.409c0-1.91,0.772-3.632,2.024-4.885C4.776,2.272,6.499,1.5,8.408,1.5
|
||||
c1.909,0,3.631,0.772,4.884,2.024C14.542,4.776,15.314,6.499,15.314,8.409h1.5C16.813,3.765,13.051,0,8.408,0
|
||||
C3.764,0,0,3.765,0,8.409c0,4.644,3.764,8.407,8.408,8.408c4.644-0.001,8.405-3.766,8.406-8.408H15.314z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
img/status/dot_idle_notification_2x.png
Normal file
After Width: | Height: | Size: 825 B |
BIN
img/status/dot_online.png
Normal file
After Width: | Height: | Size: 272 B |
7
img/status/dot_online.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="10px" height="10px" viewBox="0 0 10 10" enable-background="new 0 0 10 10" xml:space="preserve">
|
||||
<path fill="#6FC062" d="M10,5c0,2.761-2.24,5-5,5c-2.762,0-5-2.239-5-5s2.238-5,5-5C7.759,0,10,2.239,10,5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 578 B |
BIN
img/status/dot_online_2x.png
Normal file
After Width: | Height: | Size: 282 B |
BIN
img/status/dot_online_notification.png
Normal file
After Width: | Height: | Size: 424 B |
14
img/status/dot_online_notification.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="16.814px" height="16.816px" viewBox="0 0 16.814 16.816" enable-background="new 0 0 16.814 16.816" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#6FC062" d="M13.408,8.408c0,2.761-2.24,5-5,5c-2.762,0-5-2.239-5-5c0-2.761,2.238-5,5-5
|
||||
C11.168,3.408,13.408,5.646,13.408,8.408"/>
|
||||
<path fill="#6FC062" d="M15.314,8.408c0,1.909-0.771,3.632-2.022,4.885c-1.253,1.251-2.975,2.023-4.884,2.023
|
||||
s-3.632-0.772-4.884-2.023C2.272,12.04,1.5,10.317,1.5,8.408c0-1.91,0.772-3.632,2.023-4.884C4.776,2.272,6.499,1.5,8.408,1.5
|
||||
c1.909,0,3.631,0.772,4.884,2.023C14.543,4.776,15.314,6.498,15.314,8.408h1.5C16.813,3.764,13.052,0,8.408,0
|
||||
C3.765,0,0,3.764,0,8.408c0,4.644,3.765,8.407,8.408,8.408c4.644-0.001,8.405-3.766,8.406-8.408H15.314z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
img/status/dot_online_notification_2x.png
Normal file
After Width: | Height: | Size: 766 B |
17
main.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "widget.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationName("Toxgui");
|
||||
a.setOrganizationName("Tox");
|
||||
Widget* w = Widget::getInstance();
|
||||
w->show();
|
||||
|
||||
int errorcode = a.exec();
|
||||
|
||||
delete w;
|
||||
|
||||
return errorcode;
|
||||
}
|
5
res.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/conf">
|
||||
<file alias="settings.ini">res/settings.ini</file>
|
||||
</qresource>
|
||||
</RCC>
|
55
res/settings.ini
Normal file
|
@ -0,0 +1,55 @@
|
|||
[DHT%20Server]
|
||||
dhtServerList\size=13
|
||||
dhtServerList\1\name=benwaffle
|
||||
dhtServerList\1\userId=8E6667FF967EA30B3DC3DB57A4B533152476E7AAE090158B9C2D9DF58ECC7B78
|
||||
dhtServerList\1\address=192.3.30.132
|
||||
dhtServerList\1\port=33445
|
||||
dhtServerList\2\name=zlacki RU #1
|
||||
dhtServerList\2\userId=D59F99384592DE4C8AB9D534D5197DB90F4755CC9E975ED0C565E18468A1445B
|
||||
dhtServerList\2\address=31.192.105.19
|
||||
dhtServerList\2\port=33445
|
||||
dhtServerList\3\name=aitjcize
|
||||
dhtServerList\3\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
||||
dhtServerList\3\address=54.199.139.199
|
||||
dhtServerList\3\port=33445
|
||||
dhtServerList\4\name=zlacki US
|
||||
dhtServerList\4\userId=9430A83211A7AD1C294711D069D587028CA0B4782FA43CB9B30008247A43C944
|
||||
dhtServerList\4\address=69.42.220.58
|
||||
dhtServerList\4\port=33445
|
||||
dhtServerList\5\name=platos
|
||||
dhtServerList\5\userId=B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E
|
||||
dhtServerList\5\address=66.175.223.88
|
||||
dhtServerList\5\port=33445
|
||||
dhtServerList\6\name=stqism
|
||||
dhtServerList\6\userId=951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
|
||||
dhtServerList\6\address=192.254.75.98
|
||||
dhtServerList\6\port=33445
|
||||
dhtServerList\7\name=nurupo
|
||||
dhtServerList\7\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
||||
dhtServerList\7\address=192.210.149.121
|
||||
dhtServerList\7\port=33445
|
||||
dhtServerList\8\name=JmanGuy
|
||||
dhtServerList\8\userId=20C797E098701A848B07D0384222416B0EFB60D08CECB925B860CAEAAB572067
|
||||
dhtServerList\8\address=66.74.15.98
|
||||
dhtServerList\8\port=33445
|
||||
dhtServerList\9\name=zlacki NL
|
||||
dhtServerList\9\userId=CC2B02636A2ADBC2871D6EC57C5E9589D4FD5E6F98A14743A4B949914CF26D39
|
||||
dhtServerList\9\address=5.39.218.35
|
||||
dhtServerList\9\port=33445
|
||||
dhtServerList\10\name=zlacki RU #2
|
||||
dhtServerList\10\userId=AE27E1E72ADA3DC423C60EEBACA241456174048BE76A283B41AD32D953182D49
|
||||
dhtServerList\10\address=193.107.16.73
|
||||
dhtServerList\10\port=33445
|
||||
dhtServerList\11\name=stal
|
||||
dhtServerList\11\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
dhtServerList\11\address=23.226.230.47
|
||||
dhtServerList\11\port=33445
|
||||
dhtServerList\12\name=sonOfRa
|
||||
dhtServerList\12\userId=DDCF277B8B45B0D357D78AA4E201766932DF6CDB7179FC7D5C9F3C2E8E705326
|
||||
dhtServerList\12\address=144.76.60.215
|
||||
dhtServerList\12\port=33445
|
||||
dhtServerList\13\name=anonymous
|
||||
dhtServerList\13\userId=5CD7EB176C19A2FD840406CD56177BB8E75587BB366F7BB3004B19E3EDC04143
|
||||
dhtServerList\13\address=192.184.81.118
|
||||
dhtServerList\13\port=33445
|
||||
|
343
settings.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
|
||||
const QString Settings::FILENAME = "settings.ini";
|
||||
|
||||
Settings::Settings() :
|
||||
loaded(false)
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
Settings& Settings::getInstance()
|
||||
{
|
||||
static Settings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
void Settings::load()
|
||||
{
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString filePath = getSettingsDirPath() + '/' + FILENAME;
|
||||
|
||||
//if no settings file exist -- use the default one
|
||||
QFile file(filePath);
|
||||
if (!file.exists()) {
|
||||
filePath = ":/conf/" + FILENAME;
|
||||
}
|
||||
|
||||
QSettings s(filePath, QSettings::IniFormat);
|
||||
s.beginGroup("DHT Server");
|
||||
int serverListSize = s.beginReadArray("dhtServerList");
|
||||
for (int i = 0; i < serverListSize; i ++) {
|
||||
s.setArrayIndex(i);
|
||||
DhtServer server;
|
||||
server.name = s.value("name").toString();
|
||||
server.userId = s.value("userId").toString();
|
||||
server.address = s.value("address").toString();
|
||||
server.port = s.value("port").toInt();
|
||||
dhtServerList << server;
|
||||
}
|
||||
s.endArray();
|
||||
s.endGroup();
|
||||
|
||||
//NOTE: uncomment when logging will be implemented
|
||||
/*
|
||||
s.beginGroup("Logging");
|
||||
enableLogging = s.value("enableLogging", false).toBool();
|
||||
encryptLogs = s.value("encryptLogs", true).toBool();
|
||||
s.endGroup();
|
||||
*/
|
||||
|
||||
s.beginGroup("General");
|
||||
username = s.value("username", "My name").toString();
|
||||
statusMessage = s.value("statusMessage", "My status").toString();
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Widgets");
|
||||
QList<QString> objectNames = s.childKeys();
|
||||
for (const QString& name : objectNames) {
|
||||
widgetSettings[name] = s.value(name).toByteArray();
|
||||
}
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("GUI");
|
||||
enableSmoothAnimation = s.value("smoothAnimation", true).toBool();
|
||||
smileyPack = s.value("smileyPack").toByteArray();
|
||||
customEmojiFont = s.value("customEmojiFont", true).toBool();
|
||||
emojiFontFamily = s.value("emojiFontFamily", "DejaVu Sans").toString();
|
||||
emojiFontPointSize = s.value("emojiFontPointSize", QApplication::font().pointSize()).toInt();
|
||||
firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt();
|
||||
secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt();
|
||||
timestampFormat = s.value("timestampFormat", "hh:mm").toString();
|
||||
minimizeOnClose = s.value("minimizeOnClose", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Privacy");
|
||||
typingNotification = s.value("typingNotification", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
void Settings::save()
|
||||
{
|
||||
QString filePath = getSettingsDirPath() + '/' + FILENAME;
|
||||
|
||||
QSettings s(filePath, QSettings::IniFormat);
|
||||
|
||||
s.clear();
|
||||
|
||||
s.beginGroup("DHT Server");
|
||||
s.beginWriteArray("dhtServerList", dhtServerList.size());
|
||||
for (int i = 0; i < dhtServerList.size(); i ++) {
|
||||
s.setArrayIndex(i);
|
||||
s.setValue("name", dhtServerList[i].name);
|
||||
s.setValue("userId", dhtServerList[i].userId);
|
||||
s.setValue("address", dhtServerList[i].address);
|
||||
s.setValue("port", dhtServerList[i].port);
|
||||
}
|
||||
s.endArray();
|
||||
s.endGroup();
|
||||
|
||||
//NOTE: uncomment when logging will be implemented
|
||||
/*
|
||||
s.beginGroup("Logging");
|
||||
s.setValue("storeLogs", enableLogging);
|
||||
s.setValue("encryptLogs", encryptLogs);
|
||||
s.endGroup();
|
||||
*/
|
||||
|
||||
s.beginGroup("General");
|
||||
s.setValue("username", username);
|
||||
s.setValue("statusMessage", statusMessage);
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Widgets");
|
||||
const QList<QString> widgetNames = widgetSettings.keys();
|
||||
for (const QString& name : widgetNames) {
|
||||
s.setValue(name, widgetSettings.value(name));
|
||||
}
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("GUI");
|
||||
s.setValue("smoothAnimation", enableSmoothAnimation);
|
||||
s.setValue("smileyPack", smileyPack);
|
||||
s.setValue("customEmojiFont", customEmojiFont);
|
||||
s.setValue("emojiFontFamily", emojiFontFamily);
|
||||
s.setValue("emojiFontPointSize", emojiFontPointSize);
|
||||
s.setValue("firstColumnHandlePos", firstColumnHandlePos);
|
||||
s.setValue("secondColumnHandlePosFromRight", secondColumnHandlePosFromRight);
|
||||
s.setValue("timestampFormat", timestampFormat);
|
||||
s.setValue("minimizeOnClose", minimizeOnClose);
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Privacy");
|
||||
s.setValue("typingNotification", typingNotification);
|
||||
s.endGroup();
|
||||
}
|
||||
|
||||
QString Settings::getSettingsDirPath()
|
||||
{
|
||||
// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
|
||||
#ifdef Q_OS_WIN
|
||||
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
#else
|
||||
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + '/' + qApp->organizationName() + '/' + qApp->applicationName();
|
||||
#endif
|
||||
}
|
||||
|
||||
const QList<Settings::DhtServer>& Settings::getDhtServerList() const
|
||||
{
|
||||
return dhtServerList;
|
||||
}
|
||||
|
||||
void Settings::setDhtServerList(const QList<DhtServer>& newDhtServerList)
|
||||
{
|
||||
dhtServerList = newDhtServerList;
|
||||
emit dhtServerListChanged();
|
||||
}
|
||||
|
||||
QString Settings::getUsername() const
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
void Settings::setUsername(const QString& newUsername)
|
||||
{
|
||||
username = newUsername;
|
||||
}
|
||||
|
||||
QString Settings::getStatusMessage() const
|
||||
{
|
||||
return statusMessage;
|
||||
}
|
||||
|
||||
void Settings::setStatusMessage(const QString& newMessage)
|
||||
{
|
||||
statusMessage = newMessage;
|
||||
}
|
||||
|
||||
bool Settings::getEnableLogging() const
|
||||
{
|
||||
return enableLogging;
|
||||
}
|
||||
|
||||
void Settings::setEnableLogging(bool newValue)
|
||||
{
|
||||
enableLogging = newValue;
|
||||
}
|
||||
|
||||
bool Settings::getEncryptLogs() const
|
||||
{
|
||||
return encryptLogs;
|
||||
}
|
||||
|
||||
void Settings::setEncryptLogs(bool newValue)
|
||||
{
|
||||
encryptLogs = newValue;
|
||||
}
|
||||
|
||||
void Settings::setWidgetData(const QString& uniqueName, const QByteArray& data)
|
||||
{
|
||||
widgetSettings[uniqueName] = data;
|
||||
}
|
||||
|
||||
QByteArray Settings::getWidgetData(const QString& uniqueName) const
|
||||
{
|
||||
return widgetSettings.value(uniqueName);
|
||||
}
|
||||
|
||||
bool Settings::isAnimationEnabled() const
|
||||
{
|
||||
return enableSmoothAnimation;
|
||||
}
|
||||
|
||||
void Settings::setAnimationEnabled(bool newValue)
|
||||
{
|
||||
enableSmoothAnimation = newValue;
|
||||
}
|
||||
|
||||
QByteArray Settings::getSmileyPack() const
|
||||
{
|
||||
return smileyPack;
|
||||
}
|
||||
|
||||
void Settings::setSmileyPack(const QByteArray &value)
|
||||
{
|
||||
smileyPack = value;
|
||||
emit smileyPackChanged();
|
||||
}
|
||||
|
||||
bool Settings::isCurstomEmojiFont() const
|
||||
{
|
||||
return customEmojiFont;
|
||||
}
|
||||
|
||||
void Settings::setCurstomEmojiFont(bool value)
|
||||
{
|
||||
customEmojiFont = value;
|
||||
emit emojiFontChanged();
|
||||
}
|
||||
|
||||
int Settings::getEmojiFontPointSize() const
|
||||
{
|
||||
return emojiFontPointSize;
|
||||
}
|
||||
|
||||
void Settings::setEmojiFontPointSize(int value)
|
||||
{
|
||||
emojiFontPointSize = value;
|
||||
emit emojiFontChanged();
|
||||
}
|
||||
|
||||
int Settings::getFirstColumnHandlePos() const
|
||||
{
|
||||
return firstColumnHandlePos;
|
||||
}
|
||||
|
||||
void Settings::setFirstColumnHandlePos(const int pos)
|
||||
{
|
||||
firstColumnHandlePos = pos;
|
||||
}
|
||||
|
||||
int Settings::getSecondColumnHandlePosFromRight() const
|
||||
{
|
||||
return secondColumnHandlePosFromRight;
|
||||
}
|
||||
|
||||
void Settings::setSecondColumnHandlePosFromRight(const int pos)
|
||||
{
|
||||
secondColumnHandlePosFromRight = pos;
|
||||
}
|
||||
|
||||
const QString &Settings::getTimestampFormat() const
|
||||
{
|
||||
return timestampFormat;
|
||||
}
|
||||
|
||||
void Settings::setTimestampFormat(const QString &format)
|
||||
{
|
||||
timestampFormat = format;
|
||||
emit timestampFormatChanged();
|
||||
}
|
||||
|
||||
QString Settings::getEmojiFontFamily() const
|
||||
{
|
||||
return emojiFontFamily;
|
||||
}
|
||||
|
||||
void Settings::setEmojiFontFamily(const QString &value)
|
||||
{
|
||||
emojiFontFamily = value;
|
||||
emit emojiFontChanged();
|
||||
}
|
||||
|
||||
bool Settings::isMinimizeOnCloseEnabled() const
|
||||
{
|
||||
return minimizeOnClose;
|
||||
}
|
||||
|
||||
void Settings::setMinimizeOnClose(bool newValue)
|
||||
{
|
||||
minimizeOnClose = newValue;
|
||||
}
|
||||
|
||||
bool Settings::isTypingNotificationEnabled() const
|
||||
{
|
||||
return typingNotification;
|
||||
}
|
||||
|
||||
void Settings::setTypingNotification(bool enabled)
|
||||
{
|
||||
typingNotification = enabled;
|
||||
}
|
163
settings.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
|
||||
This file is part of Tox Qt GUI.
|
||||
|
||||
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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef SETTINGS_HPP
|
||||
#define SETTINGS_HPP
|
||||
|
||||
#include <QHash>
|
||||
#include <QMainWindow>
|
||||
#include <QSplitter>
|
||||
|
||||
class Settings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static Settings& getInstance();
|
||||
~Settings();
|
||||
|
||||
void executeSettingsDialog(QWidget* parent);
|
||||
|
||||
static QString getSettingsDirPath();
|
||||
|
||||
struct DhtServer
|
||||
{
|
||||
QString name;
|
||||
QString userId;
|
||||
QString address;
|
||||
int port;
|
||||
};
|
||||
|
||||
const QList<DhtServer>& getDhtServerList() const;
|
||||
void setDhtServerList(const QList<DhtServer>& newDhtServerList);
|
||||
|
||||
QString getUsername() const;
|
||||
void setUsername(const QString& newUsername);
|
||||
|
||||
QString getStatusMessage() const;
|
||||
void setStatusMessage(const QString& newMessage);
|
||||
|
||||
bool getEnableLogging() const;
|
||||
void setEnableLogging(bool newValue);
|
||||
|
||||
bool getEncryptLogs() const;
|
||||
void setEncryptLogs(bool newValue);
|
||||
|
||||
// Assume all widgets have unique names
|
||||
// Don't use it to save every single thing you want to save, use it
|
||||
// for some general purpose widgets, such as MainWindows or Splitters,
|
||||
// which have widget->saveX() and widget->loadX() methods.
|
||||
QByteArray getWidgetData(const QString& uniqueName) const;
|
||||
void setWidgetData(const QString& uniqueName, const QByteArray& data);
|
||||
|
||||
// Wrappers around getWidgetData() and setWidgetData()
|
||||
// Assume widget has a unique objectName set
|
||||
template <class T>
|
||||
void restoreGeometryState(T* widget) const
|
||||
{
|
||||
widget->restoreGeometry(getWidgetData(widget->objectName() + "Geometry"));
|
||||
widget->restoreState(getWidgetData(widget->objectName() + "State"));
|
||||
}
|
||||
template <class T>
|
||||
void saveGeometryState(const T* widget)
|
||||
{
|
||||
setWidgetData(widget->objectName() + "Geometry", widget->saveGeometry());
|
||||
setWidgetData(widget->objectName() + "State", widget->saveState());
|
||||
}
|
||||
|
||||
bool isAnimationEnabled() const;
|
||||
void setAnimationEnabled(bool newValue);
|
||||
|
||||
QByteArray getSmileyPack() const;
|
||||
void setSmileyPack(const QByteArray &value);
|
||||
|
||||
bool isCurstomEmojiFont() const;
|
||||
void setCurstomEmojiFont(bool value);
|
||||
|
||||
QString getEmojiFontFamily() const;
|
||||
void setEmojiFontFamily(const QString &value);
|
||||
|
||||
int getEmojiFontPointSize() const;
|
||||
void setEmojiFontPointSize(int value);
|
||||
|
||||
// ChatView
|
||||
int getFirstColumnHandlePos() const;
|
||||
void setFirstColumnHandlePos(const int pos);
|
||||
|
||||
int getSecondColumnHandlePosFromRight() const;
|
||||
void setSecondColumnHandlePosFromRight(const int pos);
|
||||
|
||||
const QString &getTimestampFormat() const;
|
||||
void setTimestampFormat(const QString &format);
|
||||
|
||||
bool isMinimizeOnCloseEnabled() const;
|
||||
void setMinimizeOnClose(bool newValue);
|
||||
|
||||
// Privacy
|
||||
bool isTypingNotificationEnabled() const;
|
||||
void setTypingNotification(bool enabled);
|
||||
|
||||
private:
|
||||
Settings();
|
||||
Settings(Settings &settings) = delete;
|
||||
Settings& operator=(const Settings&) = delete;
|
||||
|
||||
void save();
|
||||
void load();
|
||||
|
||||
|
||||
|
||||
static const QString FILENAME;
|
||||
|
||||
bool loaded;
|
||||
|
||||
QList<DhtServer> dhtServerList;
|
||||
int dhtServerId;
|
||||
bool dontShowDhtDialog;
|
||||
|
||||
QString username;
|
||||
QString statusMessage;
|
||||
|
||||
bool enableLogging;
|
||||
bool encryptLogs;
|
||||
|
||||
QHash<QString, QByteArray> widgetSettings;
|
||||
|
||||
// GUI
|
||||
bool enableSmoothAnimation;
|
||||
QByteArray smileyPack;
|
||||
bool customEmojiFont;
|
||||
QString emojiFontFamily;
|
||||
int emojiFontPointSize;
|
||||
bool minimizeOnClose;
|
||||
|
||||
// ChatView
|
||||
int firstColumnHandlePos;
|
||||
int secondColumnHandlePosFromRight;
|
||||
QString timestampFormat;
|
||||
|
||||
// Privacy
|
||||
bool typingNotification;
|
||||
|
||||
signals:
|
||||
//void dataChanged();
|
||||
void dhtServerListChanged();
|
||||
void logStorageOptsChanged();
|
||||
void smileyPackChanged();
|
||||
void emojiFontChanged();
|
||||
void timestampFormatChanged();
|
||||
};
|
||||
|
||||
#endif // SETTINGS_HPP
|