From a89b673b40f8ba7c5e658b276ee80f34a7517bf9 Mon Sep 17 00:00:00 2001 From: sudden6 Date: Sat, 20 Feb 2016 22:32:57 +0100 Subject: [PATCH] Revert "Revert changes from merge of #2092 pull request" This reverts commit 06611d618e4306b2402717bc4a62d505b0a77200. --- qtox.pro | 4 + src/core/core.cpp | 11 +- src/core/core.h | 2 +- src/mainwindow.ui | 2 +- src/persistence/settings.cpp | 74 ++++++++++++- src/persistence/settings.h | 10 ++ src/widget/form/addfriendform.cpp | 126 ++++++++++++++++++++-- src/widget/form/addfriendform.h | 25 +++++ src/widget/form/groupinviteform.cpp | 155 ++++++++++++++++++++++++++++ src/widget/form/groupinviteform.h | 78 ++++++++++++++ src/widget/friendwidget.cpp | 15 ++- src/widget/widget.cpp | 132 ++++++++++++++++++----- src/widget/widget.h | 11 ++ ui/window/statusPanel.css | 21 ++++ 14 files changed, 622 insertions(+), 44 deletions(-) create mode 100644 src/widget/form/groupinviteform.cpp create mode 100644 src/widget/form/groupinviteform.h diff --git a/qtox.pro b/qtox.pro index e73351388..911b7bf1d 100644 --- a/qtox.pro +++ b/qtox.pro @@ -531,6 +531,8 @@ SOURCES += \ src/widget/about/aboutuser.cpp \ src/persistence/db/rawdatabase.cpp \ src/persistence/history.cpp + src/widget/tool/removefrienddialog.cpp \ + src/widget/form/groupinviteform.cpp HEADERS += \ src/audio/audio.h \ @@ -587,3 +589,5 @@ HEADERS += \ src/widget/about/aboutuser.h \ src/persistence/db/rawdatabase.h \ src/persistence/history.h + src/widget/tool/removefrienddialog.h \ + src/widget/form/groupinviteform.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 5effc718e..cfddb23b3 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -1030,19 +1030,24 @@ void Core::groupInviteFriend(uint32_t friendId, int groupId) tox_invite_friend(tox, friendId, groupId); } -void Core::createGroup(uint8_t type) +int Core::createGroup(uint8_t type) { if (type == TOX_GROUPCHAT_TYPE_TEXT) { - emit emptyGroupCreated(tox_add_groupchat(tox)); + int group = tox_add_groupchat(tox); + emit emptyGroupCreated(group); + return group; } else if (type == TOX_GROUPCHAT_TYPE_AV) { - emit emptyGroupCreated(toxav_add_av_groupchat(tox, &Audio::playGroupAudioQueued, this)); + int group = toxav_add_av_groupchat(tox, &Audio::playGroupAudioQueued, this); + emit emptyGroupCreated(group); + return group; } else { qWarning() << "createGroup: Unknown type "<0 - + 0 diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index e5dd2dc86..2ac12d8ca 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -324,6 +324,21 @@ void Settings::loadPersonal(Profile* profile) ps.endArray(); ps.endGroup(); + ps.beginGroup("Requests"); + unreadFriendRequests = ps.value("unread", 0).toUInt(); + size = ps.beginReadArray("Request"); + friendLst.reserve(size); + for (int i = 0; i < size; i ++) + { + ps.setArrayIndex(i); + QPair request; + request.first = ps.value("addr").toString(); + request.second = ps.value("message").toString(); + friendRequests.push_back(request); + } + ps.endArray(); + ps.endGroup(); + ps.beginGroup("General"); compactLayout = ps.value("compactLayout", true).toBool(); ps.endGroup(); @@ -495,7 +510,22 @@ void Settings::savePersonal(QString profileName, QString password) if (getEnableLogging()) ps.setValue("activity", frnd.activity); - index++; + ++index; + } + ps.endArray(); + ps.endGroup(); + + ps.beginGroup("Requests"); + ps.setValue("unread", unreadFriendRequests); + ps.beginWriteArray("Request", friendRequests.size()); + index = 0; + for (auto& request : friendRequests) + { + ps.setArrayIndex(index); + ps.setValue("addr", request.first); + ps.setValue("message", request.second); + + ++index; } ps.endArray(); ps.endGroup(); @@ -1503,6 +1533,48 @@ void Settings::setCircleExpanded(int id, bool expanded) circleLst[id].expanded = expanded; } +void Settings::addFriendRequest(const QString &friendAddress, const QString &message) +{ + QMutexLocker locker{&bigLock}; + QPair request(friendAddress, message); + + if (friendRequests.indexOf(request) != -1) + return; + + friendRequests.push_back(request); + ++unreadFriendRequests; +} + +unsigned int Settings::getUnreadFriendRequests() const +{ + QMutexLocker locker{&bigLock}; + return unreadFriendRequests; +} + +QPair Settings::getFriendRequest(int index) const +{ + QMutexLocker locker{&bigLock}; + return friendRequests.at(index); +} + +int Settings::getFriendRequestSize() const +{ + QMutexLocker locker{&bigLock}; + return friendRequests.size(); +} + +void Settings::clearUnreadFriendRequests() +{ + QMutexLocker locker{&bigLock}; + unreadFriendRequests = 0; +} + +void Settings::removeFriendRequest(int index) +{ + QMutexLocker locker{&bigLock}; + friendRequests.removeAt(index); +} + int Settings::removeCircle(int id) { // Replace index with last one and remove last one instead. diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 411238cd7..eaa53f19e 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -275,6 +275,13 @@ public: bool getCircleExpanded(int id) const; void setCircleExpanded(int id, bool expanded); + void addFriendRequest(const QString &friendAddress, const QString &message); + unsigned int getUnreadFriendRequests() const; + QPair getFriendRequest(int index) const; + int getFriendRequestSize() const; + void clearUnreadFriendRequests(); + void removeFriendRequest(int index); + // 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, @@ -354,6 +361,9 @@ private: bool autoSaveEnabled; QString globalAutoAcceptDir; + QList> friendRequests; + unsigned int unreadFriendRequests; + // GUI QString smileyPack; int emojiFontPointSize; diff --git a/src/widget/form/addfriendform.cpp b/src/widget/form/addfriendform.cpp index e5de57e48..c69e00cfc 100644 --- a/src/widget/form/addfriendform.cpp +++ b/src/widget/form/addfriendform.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include "src/nexus.h" #include "src/core/core.h" @@ -39,13 +41,21 @@ AddFriendForm::AddFriendForm() { - main = new QWidget(), head = new QWidget(); + tabWidget = new QTabWidget(); + main = new QWidget(tabWidget), head = new QWidget(); QFont bold; bold.setBold(true); headLabel.setFont(bold); toxIdLabel.setTextFormat(Qt::RichText); - retranslateUi(); + tabWidget->addTab(main, QString()); + QScrollArea* scrollArea = new QScrollArea(tabWidget); + QWidget* requestWidget = new QWidget(tabWidget); + scrollArea->setWidget(requestWidget); + scrollArea->setWidgetResizable(true); + requestsLayout = new QVBoxLayout(requestWidget); + requestsLayout->addStretch(1); + tabWidget->addTab(scrollArea, QString()); main->setLayout(&layout); layout.addWidget(&toxIdLabel); @@ -59,17 +69,28 @@ AddFriendForm::AddFriendForm() connect(&toxId, &QLineEdit::returnPressed, this, &AddFriendForm::onSendTriggered); connect(&toxId, &QLineEdit::textChanged, this, &AddFriendForm::onIdChanged); + connect(tabWidget, &QTabWidget::currentChanged, this, &AddFriendForm::onCurrentChanged); + connect(&toxId,&QLineEdit::returnPressed, this, &AddFriendForm::onSendTriggered); connect(&sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); connect(Nexus::getCore(), &Core::usernameSet, this, &AddFriendForm::onUsernameSet); + retranslateUi(); Translator::registerHandler(std::bind(&AddFriendForm::retranslateUi, this), this); + + int size = Settings::getInstance().getFriendRequestSize(); + + for (int i = 0; i < size; ++i) + { + QPair request = Settings::getInstance().getFriendRequest(i); + addFriendRequestWidget(request.first, request.second); + } } AddFriendForm::~AddFriendForm() { Translator::unregister(this); head->deleteLater(); - main->deleteLater(); + tabWidget->deleteLater(); } bool AddFriendForm::isShown() const @@ -85,9 +106,9 @@ bool AddFriendForm::isShown() const void AddFriendForm::show(ContentLayout* contentLayout) { - contentLayout->mainContent->layout()->addWidget(main); - contentLayout->mainHead->layout()->addWidget(head); - main->show(); + ui.mainContent->layout()->addWidget(tabWidget); + ui.mainHead->layout()->addWidget(head); + tabWidget->show(); head->show(); setIdFromClipboard(); toxId.setFocus(); @@ -99,6 +120,18 @@ QString AddFriendForm::getMessage() const return !msg.isEmpty() ? msg : message.placeholderText(); } +void AddFriendForm::setMode(Mode mode) +{ + tabWidget->setCurrentIndex(mode); +} + +void AddFriendForm::addFriendRequest(const QString &friendAddress, const QString &message) +{ + addFriendRequestWidget(friendAddress, message); + Settings::getInstance().addFriendRequest(friendAddress, message); + onCurrentChanged(tabWidget->currentIndex()); +} + void AddFriendForm::onUsernameSet(const QString& username) { lastUsername = username; @@ -181,6 +214,37 @@ void AddFriendForm::setIdFromClipboard() } } +void AddFriendForm::onFriendRequestAccepted() +{ + QWidget* friendWidget = static_cast(sender()); + int index = requestsLayout->indexOf(friendWidget); + friendWidget->deleteLater(); + requestsLayout->removeWidget(friendWidget); + emit friendRequestAccepted(Settings::getInstance().getFriendRequest(requestsLayout->count() - index - 1).first); + Settings::getInstance().removeFriendRequest(requestsLayout->count() - index - 1); + Settings::getInstance().savePersonal(); +} + +void AddFriendForm::onFriendRequestRejected() +{ + QWidget* friendWidget = static_cast(sender()); + int index = requestsLayout->indexOf(friendWidget); + friendWidget->deleteLater(); + requestsLayout->removeWidget(friendWidget); + Settings::getInstance().removeFriendRequest(requestsLayout->count() - index - 1); + Settings::getInstance().savePersonal(); +} + +void AddFriendForm::onCurrentChanged(int index) +{ + if (index == FriendRequest && Settings::getInstance().getUnreadFriendRequests() != 0) + { + Settings::getInstance().clearUnreadFriendRequests(); + Settings::getInstance().savePersonal(); + emit friendRequestsSeen(); + } +} + void AddFriendForm::retranslateUi() { headLabel.setText(tr("Add Friends")); @@ -191,4 +255,54 @@ void AddFriendForm::retranslateUi() .arg(lastUsername)); onIdChanged(toxId.text()); + + tabWidget->setTabText(0, tr("Add a friend")); + tabWidget->setTabText(1, tr("Friend requests")); + + for (QPushButton* acceptButton : acceptButtons) + retranslateAcceptButton(acceptButton); + + for (QPushButton* rejectButton : rejectButtons) + retranslateRejectButton(rejectButton); +} + +void AddFriendForm::addFriendRequestWidget(const QString &friendAddress, const QString &message) +{ + QWidget* friendWidget = new QWidget(tabWidget); + QHBoxLayout* friendLayout = new QHBoxLayout(friendWidget); + QVBoxLayout* horLayout = new QVBoxLayout(); + horLayout->setMargin(0); + friendLayout->addLayout(horLayout); + + CroppingLabel* friendLabel = new CroppingLabel(friendWidget); + friendLabel->setText("" + friendAddress + ""); + horLayout->addWidget(friendLabel); + + QLabel* messageLabel = new QLabel(message); + messageLabel->setWordWrap(true); + horLayout->addWidget(messageLabel, 1); + + QPushButton* acceptButton = new QPushButton(friendWidget); + acceptButtons.insert(acceptButton); + connect(acceptButton, &QPushButton::released, this, &AddFriendForm::onFriendRequestAccepted); + friendLayout->addWidget(acceptButton); + retranslateAcceptButton(acceptButton); + + QPushButton* rejectButton = new QPushButton(friendWidget); + acceptButtons.insert(acceptButton); + connect(acceptButton, &QPushButton::released, this, &AddFriendForm::onFriendRequestAccepted); + friendLayout->addWidget(rejectButton); + retranslateRejectButton(rejectButton); + + requestsLayout->insertWidget(0, friendWidget); +} + +void AddFriendForm::retranslateAcceptButton(QPushButton *acceptButton) +{ + acceptButton->setText(tr("Accept")); +} + +void AddFriendForm::retranslateRejectButton(QPushButton *rejectButton) +{ + rejectButton->setText(tr("Reject")); } diff --git a/src/widget/form/addfriendform.h b/src/widget/form/addfriendform.h index ab061cec6..20e3052cc 100644 --- a/src/widget/form/addfriendform.h +++ b/src/widget/form/addfriendform.h @@ -25,6 +25,9 @@ #include #include #include +#include + +class QTabWidget; class ContentLayout; @@ -32,6 +35,13 @@ class AddFriendForm : public QObject { Q_OBJECT public: + enum Mode + { + AddFriend = 0, + FriendRequest = 1, + GroupInvite = 2 + }; + AddFriendForm(); AddFriendForm(const AddFriendForm&) = delete; AddFriendForm& operator=(const AddFriendForm&) = delete; @@ -40,9 +50,14 @@ public: bool isShown() const; void show(ContentLayout* contentLayout); QString getMessage() const; + void setMode(Mode mode); + + void addFriendRequest(const QString& friendAddress, const QString& message); signals: void friendRequested(const QString& friendAddress, const QString& message); + void friendRequestAccepted(const QString& friendAddress); + void friendRequestsSeen(); public slots: void onUsernameSet(const QString& userName); @@ -50,9 +65,15 @@ public slots: private slots: void onSendTriggered(); void onIdChanged(const QString &id); + void onFriendRequestAccepted(); + void onFriendRequestRejected(); + void onCurrentChanged(int index); private: void retranslateUi(); + void addFriendRequestWidget(const QString& friendAddress, const QString& message); + void retranslateAcceptButton(QPushButton* acceptButton); + void retranslateRejectButton(QPushButton* rejectButton); private: void setIdFromClipboard(); @@ -63,6 +84,10 @@ private: QVBoxLayout layout, headLayout; QWidget *head, *main; QString lastUsername; // Cached username so we can retranslate the invite message + QTabWidget* tabWidget; + QVBoxLayout* requestsLayout; + QSet acceptButtons; + QSet rejectButtons; }; #endif // ADDFRIENDFORM_H diff --git a/src/widget/form/groupinviteform.cpp b/src/widget/form/groupinviteform.cpp new file mode 100644 index 000000000..0961986a2 --- /dev/null +++ b/src/widget/form/groupinviteform.cpp @@ -0,0 +1,155 @@ +/* + Copyright © 2015 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre 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. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see . +*/ + +#include "groupinviteform.h" + +#include +#include +#include +#include +#include +#include +#include +#include "ui_mainwindow.h" +#include "src/widget/tool/croppinglabel.h" +#include "src/widget/translator.h" +#include "src/nexus.h" +#include "src/core/core.h" + +GroupInviteForm::GroupInviteForm() +{ + QVBoxLayout* layout = new QVBoxLayout(this); + createButton = new QPushButton(this); + connect(createButton, &QPushButton::released, [this]() + { + emit groupCreate(TOX_GROUPCHAT_TYPE_AV); + }); + + inviteBox = new QGroupBox(this); + inviteLayout = new QVBoxLayout(inviteBox); + inviteLayout->addStretch(1); + + layout->addWidget(createButton); + layout->addWidget(inviteBox); + + QFont bold; + bold.setBold(true); + + headLabel = new QLabel(this); + headLabel->setFont(bold); + headWidget = new QWidget(this); + QHBoxLayout* headLayout = new QHBoxLayout(headWidget); + headLayout->addWidget(headLabel); + + retranslateUi(); + Translator::registerHandler(std::bind(&GroupInviteForm::retranslateUi, this), this); +} + +void GroupInviteForm::show(Ui::MainWindow &ui) +{ + ui.mainContent->layout()->addWidget(this); + ui.mainHead->layout()->addWidget(headWidget); + QWidget::show(); + headWidget->show(); +} + +void GroupInviteForm::addGroupInvite(int32_t friendId, uint8_t type, QByteArray invite) +{ + QWidget* groupWidget = new QWidget(this); + QHBoxLayout* groupLayout = new QHBoxLayout(groupWidget); + + CroppingLabel* groupLabel = new CroppingLabel(this); + groupLabel->setText(tr("Invited by %1 on %2.").arg(Nexus::getCore()->getFriendUsername(friendId), QDateTime::currentDateTime().toString())); + groupLayout->addWidget(groupLabel); + + QPushButton* acceptButton = new QPushButton(this); + acceptButtons.insert(acceptButton); + connect(acceptButton, &QPushButton::released, this, &GroupInviteForm::onGroupInviteAccepted); + groupLayout->addWidget(acceptButton); + retranslateAcceptButton(acceptButton); + + QPushButton* rejectButton = new QPushButton(this); + rejectButtons.insert(rejectButton); + connect(rejectButton, &QPushButton::released, this, &GroupInviteForm::onGroupInviteRejected); + groupLayout->addWidget(rejectButton); + retranslateRejectButton(rejectButton); + + inviteLayout->insertWidget(0, groupWidget); + + GroupInvite group; + group.friendId = friendId; + group.type = type; + group.invite = invite; + groupInvites.push_front(group); + + if (isVisible()) + emit groupInvitesSeen(); +} + +void GroupInviteForm::showEvent(QShowEvent* event) +{ + QWidget::showEvent(event); + emit groupInvitesSeen(); +} + +void GroupInviteForm::onGroupInviteAccepted() +{ + QWidget* groupWidget = static_cast(sender()); + int index = inviteLayout->indexOf(groupWidget); + GroupInvite invite = groupInvites.at(index); + groupInvites.removeAt(index); + + groupWidget->deleteLater(); + inviteLayout->removeWidget(groupWidget); + + emit groupInviteAccepted(invite.friendId, invite.type, invite.invite); +} + +void GroupInviteForm::onGroupInviteRejected() +{ + QWidget* groupWidget = static_cast(sender()); + int index = inviteLayout->indexOf(groupWidget); + groupInvites.removeAt(index); + + groupWidget->deleteLater(); + inviteLayout->removeWidget(groupWidget); +} + +void GroupInviteForm::retranslateUi() +{ + headLabel->setText(tr("Groups")); + createButton->setText(tr("Create new group")); + inviteBox->setTitle(tr("Group invites")); + + for (QPushButton* acceptButton : acceptButtons) + retranslateAcceptButton(acceptButton); + + for (QPushButton* rejectButton : rejectButtons) + retranslateRejectButton(rejectButton); +} + +void GroupInviteForm::retranslateAcceptButton(QPushButton *acceptButton) +{ + acceptButton->setText(tr("Join")); +} + +void GroupInviteForm::retranslateRejectButton(QPushButton *rejectButton) +{ + rejectButton->setText(tr("Decline")); +} diff --git a/src/widget/form/groupinviteform.h b/src/widget/form/groupinviteform.h new file mode 100644 index 000000000..538b950da --- /dev/null +++ b/src/widget/form/groupinviteform.h @@ -0,0 +1,78 @@ +/* + Copyright © 2015 by The qTox Project + + This file is part of qTox, a Qt-based graphical interface for Tox. + + qTox is libre 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. + + qTox is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with qTox. If not, see . +*/ + +#ifndef GROUPINVITEFORM_H +#define GROUPINVITEFORM_H + +#include +#include + +class QLabel; +class QVBoxLayout; +class QPushButton; +class QGroupBox; +class QSignalMapper; + +namespace Ui {class MainWindow;} + +class GroupInviteForm : public QWidget +{ + Q_OBJECT +public: + GroupInviteForm(); + + void show(Ui::MainWindow &ui); + void addGroupInvite(int32_t friendId, uint8_t type, QByteArray invite); + +signals: + void groupCreate(uint8_t type); + void groupInviteAccepted(int32_t friendId, uint8_t type, QByteArray invite); + void groupInvitesSeen(); + +protected: + void showEvent(QShowEvent* event) final override; + +private slots: + void onGroupInviteAccepted(); + void onGroupInviteRejected(); + +private: + void retranslateUi(); + void retranslateAcceptButton(QPushButton* acceptButton); + void retranslateRejectButton(QPushButton* rejectButton); + +private: + struct GroupInvite + { + int32_t friendId; + uint8_t type; + QByteArray invite; + }; + + QWidget* headWidget; + QLabel* headLabel; + QPushButton* createButton; + QGroupBox* inviteBox; + QVBoxLayout* inviteLayout; + QSet acceptButtons; + QSet rejectButtons; + QList groupInvites; +}; + +#endif // GROUPINVITEFORM_H diff --git a/src/widget/friendwidget.cpp b/src/widget/friendwidget.cpp index c8e5e06cb..5646fd9a8 100644 --- a/src/widget/friendwidget.cpp +++ b/src/widget/friendwidget.cpp @@ -83,17 +83,16 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) menu.addSeparator(); QMenu* inviteMenu = menu.addMenu(tr("Invite to group","Menu to invite a friend to a groupchat")); + QAction* newGroupAction = inviteMenu->addAction(tr("To new group")); + inviteMenu->addSeparator(); QMap groupActions; for (Group* group : GroupList::getAllGroups()) { - QAction* groupAction = inviteMenu->addAction(group->getGroupWidget()->getName()); + QAction* groupAction = inviteMenu->addAction(tr("Invite to group '%1'").arg(group->getGroupWidget()->getName())); groupActions[groupAction] = group; } - if (groupActions.isEmpty()) - inviteMenu->setEnabled(false); - int circleId = Settings::getInstance().getFriendCircleID(FriendList::findFriend(friendId)->getToxId()); CircleWidget *circleWidget = CircleWidget::getFromID(circleId); @@ -200,11 +199,17 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) Settings::getInstance().setAutoAcceptDir(id, dir); } } - else if (selectedItem == aboutWindow) { + else if (selectedItem == aboutWindow) + { AboutUser *aboutUser = new AboutUser(id, Widget::getInstance()); aboutUser->setFriend(FriendList::findFriend(friendId)); aboutUser->show(); } + else if (selectedItem == newGroupAction) + { + int groupId = Core::getInstance()->createGroup(); + Core::getInstance()->groupInviteFriend(friendId, groupId); + } else if (selectedItem == newCircleAction) { if (circleWidget != nullptr) diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index d2677077e..373ded1c4 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -47,6 +47,7 @@ #include "src/persistence/offlinemsgengine.h" #include "src/widget/translator.h" #include "src/widget/form/addfriendform.h" +#include "src/widget/form/groupinviteform.h" #include "src/widget/form/filesform.h" #include "src/widget/form/profileform.h" #include "src/widget/form/settingswidget.h" @@ -232,6 +233,7 @@ void Widget::init() filesForm = new FilesForm(); addFriendForm = new AddFriendForm; + groupInviteForm = new GroupInviteForm; profileForm = new ProfileForm(); settingsWidget = new SettingsWidget(); @@ -252,6 +254,7 @@ void Widget::init() connect(ui->statusLabel, &CroppingLabel::editFinished, this, &Widget::onStatusMessageChanged); connect(ui->mainSplitter, &QSplitter::splitterMoved, this, &Widget::onSplitterMoved); connect(addFriendForm, &AddFriendForm::friendRequested, this, &Widget::friendRequested); + connect(groupInviteForm, &GroupInviteForm::groupCreate, Core::getInstance(), &Core::createGroup); connect(timer, &QTimer::timeout, this, &Widget::onUserAwayCheck); connect(timer, &QTimer::timeout, this, &Widget::onEventIconTick); connect(timer, &QTimer::timeout, this, &Widget::onTryCreateTrayIcon); @@ -356,6 +359,7 @@ void Widget::init() onSeparateWindowChanged(Settings::getInstance().getSeparateWindow(), false); ui->addButton->setCheckable(true); + ui->groupButton->setCheckable(true); ui->transferButton->setCheckable(true); ui->settingsButton->setCheckable(true); @@ -384,6 +388,15 @@ void Widget::init() AutoUpdater::checkUpdatesAsyncInteractive(); #endif + friendRequestsButton = nullptr; + groupInvitesButton = nullptr; + unreadGroupInvites = 0; + + connect(addFriendForm, &AddFriendForm::friendRequestsSeen, this, &Widget::friendRequestsUpdate); + connect(addFriendForm, &AddFriendForm::friendRequestAccepted, this, &Widget::friendRequestAccepted); + connect(groupInviteForm, &GroupInviteForm::groupInvitesSeen, this, &Widget::groupInvitesClear); + connect(groupInviteForm, &GroupInviteForm::groupInviteAccepted, this, &Widget::onGroupInviteAccepted); + retranslateUi(); Translator::registerHandler(std::bind(&Widget::retranslateUi, this), this); @@ -470,6 +483,7 @@ Widget::~Widget() delete profileForm; delete settingsWidget; delete addFriendForm; + delete groupInviteForm; delete filesForm; delete timer; delete offlineMsgTimer; @@ -689,25 +703,22 @@ void Widget::forceShow() void Widget::onAddClicked() { - if (Settings::getInstance().getSeparateWindow()) - { - if (!addFriendForm->isShown()) - addFriendForm->show(createContentDialog(AddDialog)); + //TODO: handle multiple windows mode - setActiveToolMenuButton(Widget::None); - } - else - { - hideMainForms(nullptr); - addFriendForm->show(contentLayout); - setWindowTitle(fromDialogType(AddDialog)); - setActiveToolMenuButton(Widget::AddButton); - } + addFriendForm->setMode(AddFriendForm::AddFriend); + addFriendForm->show(*ui); + setWindowTitle(tr("Add friend")); + setActiveToolMenuButton(Widget::AddButton); + activeChatroomWidget = nullptr; } void Widget::onGroupClicked() { - Nexus::getCore()->createGroup(); + hideMainForms(); + groupInviteForm->show(*ui); + setWindowTitle(tr("Group invites")); + setActiveToolMenuButton(Widget::GroupButton); + activeChatroomWidget = nullptr; } void Widget::onTransferClicked() @@ -1251,10 +1262,9 @@ bool Widget::newMessageAlert(QWidget* currentWindow, bool isActive, bool sound, void Widget::onFriendRequestReceived(const QString& userId, const QString& message) { - FriendRequestDialog dialog(this, userId, message); - - if (dialog.exec() == QDialog::Accepted) - emit friendRequestAccepted(userId); + QApplication::alert(this); + eventFlag = true; + friendRequestRecieved(userId, message); } void Widget::updateFriendActivity(Friend *frnd) @@ -1420,15 +1430,9 @@ void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray in { if (type == TOX_GROUPCHAT_TYPE_TEXT || type == TOX_GROUPCHAT_TYPE_AV) { - if (GUI::askQuestion(tr("Group invite", "popup title"), tr("%1 has invited you to a groupchat. Would you like to join?", "popup text").arg(Nexus::getCore()->getFriendUsername(friendId).toHtmlEscaped()), true, false)) - { - int groupId = Nexus::getCore()->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length()); - if (groupId < 0) - { - qWarning() << "onGroupInviteReceived: Unable to accept group invite"; - return; - } - } + ++unreadGroupInvites; + groupInvitesUpdate(); + groupInviteForm->addGroupInvite(friendId, type, invite); } else { @@ -1437,6 +1441,16 @@ void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray in } } +void Widget::onGroupInviteAccepted(int32_t friendId, uint8_t type, QByteArray invite) +{ + int groupId = Nexus::getCore()->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length()); + if (groupId < 0) + { + qWarning() << "onGroupInviteAccepted: Unable to accept group invite"; + return; + } +} + void Widget::onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction) { Group* g = GroupList::findGroup(groupnumber); @@ -2031,11 +2045,71 @@ bool Widget::groupsVisible() const void Widget::friendListContextMenu(const QPoint &pos) { QMenu menu(this); + QAction *createGroupAction = menu.addAction(tr("Create new group...")); QAction *addCircleAction = menu.addAction(tr("Add new circle...")); QAction *chosenAction = menu.exec(ui->friendList->mapToGlobal(pos)); if (chosenAction == addCircleAction) contactListWidget->addCircleWidget(); + else if (chosenAction == createGroupAction) + Nexus::getCore()->createGroup(); +} + +void Widget::friendRequestRecieved(const QString& friendAddress, const QString& message) +{ + addFriendForm->addFriendRequest(friendAddress, message); + friendRequestsUpdate(); +} + +void Widget::friendRequestsUpdate() +{ + unsigned int unreadFriendRequests = Settings::getInstance().getUnreadFriendRequests(); + + if (unreadFriendRequests == 0) + { + delete friendRequestsButton; + friendRequestsButton = nullptr; + } + else if (!friendRequestsButton) + { + friendRequestsButton = new QPushButton(this); + friendRequestsButton->setObjectName("green"); + ui->statusLayout->insertWidget(2, friendRequestsButton); + + connect(friendRequestsButton, &QPushButton::released, [this]() + { + onGroupClicked(); + }); + } + + if (friendRequestsButton) + friendRequestsButton->setText(tr("%n New Friend Request(s)", "", unreadFriendRequests)); +} + +void Widget::groupInvitesUpdate() +{ + if (unreadGroupInvites == 0) + { + delete groupInvitesButton; + groupInvitesButton = nullptr; + } + else if (!groupInvitesButton) + { + groupInvitesButton = new QPushButton(this); + groupInvitesButton->setObjectName("green"); + ui->statusLayout->insertWidget(2, groupInvitesButton); + + connect(groupInvitesButton, &QPushButton::released, this, &Widget::onGroupClicked); + } + + if (groupInvitesButton) + groupInvitesButton->setText(tr("%n New Group Invite(s)", "", unreadGroupInvites)); +} + +void Widget::groupInvitesClear() +{ + unreadGroupInvites = 0; + groupInvitesUpdate(); } void Widget::setActiveToolMenuButton(ActiveToolMenuButton newActiveButton) @@ -2077,6 +2151,10 @@ void Widget::retranslateUi() if (!Settings::getInstance().getSeparateWindow()) setWindowTitle(fromDialogType(SettingDialog)); + friendRequestsUpdate(); + groupInvitesUpdate(); + + #ifdef Q_OS_MAC Nexus::getInstance().retranslateUi(); diff --git a/src/widget/widget.h b/src/widget/widget.h index 07327feda..a42fcef02 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -49,10 +49,12 @@ class FilesForm; class ProfileForm; class SettingsWidget; class AddFriendForm; +class GroupInviteForm; class CircleWidget; class QActionGroup; class ContentLayout; class ContentDialog; +class QPushButton; class Widget final : public QMainWindow { @@ -130,6 +132,7 @@ public slots: void onReceiptRecieved(int friendId, int receipt); void onEmptyGroupCreated(int groupId); void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite); + void onGroupInviteAccepted(int32_t friendId, uint8_t type, QByteArray invite); void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction); void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title); @@ -180,6 +183,10 @@ private slots: void onSplitterMoved(int pos, int index); void processOfflineMsgs(); void friendListContextMenu(const QPoint &pos); + void friendRequestRecieved(const QString& friendAddress, const QString& message); + void friendRequestsUpdate(); + void groupInvitesUpdate(); + void groupInvitesClear(); private: int icon_size; @@ -249,6 +256,7 @@ private: QPoint dragPosition; ContentLayout* contentLayout; AddFriendForm *addFriendForm; + GroupInviteForm* groupInviteForm; ProfileForm *profileForm; SettingsWidget *settingsWidget; FilesForm *filesForm; @@ -263,6 +271,9 @@ private: bool eventFlag; bool eventIcon; bool wasMaximized = false; + QPushButton* friendRequestsButton; + QPushButton* groupInvitesButton; + unsigned int unreadGroupInvites; #ifdef Q_OS_MAC QAction* fileMenu; diff --git a/ui/window/statusPanel.css b/ui/window/statusPanel.css index 6af24a53e..0a350b975 100644 --- a/ui/window/statusPanel.css +++ b/ui/window/statusPanel.css @@ -25,6 +25,26 @@ QToolButton::menu-indicator { image: none } +QPushButton#green { + background: none; + background-color: #6bc260; + color: white; + border-style: none; + border-radius: 4px; + padding: 4px; + margin: 4px 8px; +} + +QPushButton#green:hover +{ + background-color: #79c76f; +} + +QPushButton#green:pressed +{ + background-color: #51b244; +} + /** Uncomment this after https://github.com/tux3/qTox/pull/1640 is merged! @@ -96,3 +116,4 @@ QListView { position: relative; bottom: 2px; } +