Add menu to invite users

This commit is contained in:
Konstantinos Sideris 2017-12-10 23:59:50 +02:00
parent 19bae2a2e6
commit ef0b0f6879
17 changed files with 360 additions and 4 deletions

View file

@ -142,6 +142,7 @@ endif()
set(SRC_FILES set(SRC_FILES
# Dialogs # Dialogs
src/dialogs/ImageOverlay.cc src/dialogs/ImageOverlay.cc
src/dialogs/InviteUsers.cc
src/dialogs/JoinRoom.cc src/dialogs/JoinRoom.cc
src/dialogs/LeaveRoom.cc src/dialogs/LeaveRoom.cc
src/dialogs/Logout.cc src/dialogs/Logout.cc
@ -185,6 +186,7 @@ set(SRC_FILES
src/Cache.cc src/Cache.cc
src/ChatPage.cc src/ChatPage.cc
src/Deserializable.cc src/Deserializable.cc
src/InviteeItem.cc
src/InputValidator.cc src/InputValidator.cc
src/Login.cc src/Login.cc
src/LoginPage.cc src/LoginPage.cc
@ -218,6 +220,7 @@ include_directories(${LMDB_INCLUDE_DIR})
qt5_wrap_cpp(MOC_HEADERS qt5_wrap_cpp(MOC_HEADERS
# Dialogs # Dialogs
include/dialogs/ImageOverlay.h include/dialogs/ImageOverlay.h
include/dialogs/InviteUsers.h
include/dialogs/JoinRoom.h include/dialogs/JoinRoom.h
include/dialogs/LeaveRoom.h include/dialogs/LeaveRoom.h
include/dialogs/Logout.h include/dialogs/Logout.h
@ -259,6 +262,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/ChatPage.h include/ChatPage.h
include/LoginPage.h include/LoginPage.h
include/MainWindow.h include/MainWindow.h
include/InviteeItem.h
include/MatrixClient.h include/MatrixClient.h
include/QuickSwitcher.h include/QuickSwitcher.h
include/RegisterPage.h include/RegisterPage.h

27
include/InviteeItem.h Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <QLabel>
#include <QWidget>
#include "mtx.hpp"
class FlatButton;
class InviteeItem : public QWidget
{
Q_OBJECT
public:
InviteeItem(mtx::identifiers::User user, QWidget *parent = nullptr);
QString userID() { return user_; }
signals:
void removeItem();
private:
QString user_;
QLabel *name_;
FlatButton *removeUserBtn_;
};

View file

@ -60,6 +60,7 @@ public:
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000); void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
void removeTypingNotification(const QString &roomid); void removeTypingNotification(const QString &roomid);
void readEvent(const QString &room_id, const QString &event_id); void readEvent(const QString &room_id, const QString &event_id);
void inviteUser(const QString &room_id, const QString &user);
QUrl getHomeServer() { return server_; }; QUrl getHomeServer() { return server_; };
int transactionId() { return txn_id_; }; int transactionId() { return txn_id_; };
@ -84,6 +85,7 @@ signals:
void versionError(const QString &error); void versionError(const QString &error);
void loggedOut(); void loggedOut();
void invitedUser(const QString &room_id, const QString &user);
void loginSuccess(const QString &userid, const QString &homeserver, const QString &token); void loginSuccess(const QString &userid, const QString &homeserver, const QString &token);
void registerSuccess(const QString &userid, void registerSuccess(const QString &userid,

View file

@ -26,6 +26,7 @@
#include <QSharedPointer> #include <QSharedPointer>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "dialogs/InviteUsers.h"
#include "dialogs/LeaveRoom.h" #include "dialogs/LeaveRoom.h"
class Avatar; class Avatar;
@ -56,6 +57,7 @@ public:
signals: signals:
void leaveRoom(); void leaveRoom();
void inviteUsers(QStringList users);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
@ -76,12 +78,16 @@ private:
QMenu *menu_; QMenu *menu_;
QAction *toggleNotifications_; QAction *toggleNotifications_;
QAction *leaveRoom_; QAction *leaveRoom_;
QAction *inviteUsers_;
FlatButton *settingsBtn_; FlatButton *settingsBtn_;
QSharedPointer<OverlayModal> leaveRoomModal_; QSharedPointer<OverlayModal> leaveRoomModal_;
QSharedPointer<dialogs::LeaveRoom> leaveRoomDialog_; QSharedPointer<dialogs::LeaveRoom> leaveRoomDialog_;
QSharedPointer<OverlayModal> inviteUsersModal_;
QSharedPointer<dialogs::InviteUsers> inviteUsersDialog_;
Avatar *avatar_; Avatar *avatar_;
int buttonSize_; int buttonSize_;

View file

@ -0,0 +1,41 @@
#pragma once
#include <QFrame>
#include <QLabel>
#include <QListWidgetItem>
#include <QStringList>
class FlatButton;
class TextField;
class QListWidget;
namespace dialogs {
class InviteUsers : public QFrame
{
Q_OBJECT
public:
explicit InviteUsers(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
signals:
void closing(bool isLeaving, QStringList invitees);
private slots:
void removeInvitee(QListWidgetItem *item);
private:
void addUser();
QStringList invitedUsers() const;
FlatButton *confirmBtn_;
FlatButton *cancelBtn_;
TextField *inviteeInput_;
QLabel *errorLabel_;
QListWidget *inviteeList_;
};
} // dialogs

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

View file

@ -30,6 +30,8 @@
<file>icons/ui/play-sign@2x.png</file> <file>icons/ui/play-sign@2x.png</file>
<file>icons/ui/pause-symbol.png</file> <file>icons/ui/pause-symbol.png</file>
<file>icons/ui/pause-symbol@2x.png</file> <file>icons/ui/pause-symbol@2x.png</file>
<file>icons/ui/remove-symbol.png</file>
<file>icons/ui/remove-symbol@2x.png</file>
<file>icons/emoji-categories/people.png</file> <file>icons/emoji-categories/people.png</file>
<file>icons/emoji-categories/people@2x.png</file> <file>icons/emoji-categories/people@2x.png</file>

View file

@ -79,11 +79,17 @@ Avatar {
dialogs--Logout, dialogs--Logout,
dialogs--LeaveRoom, dialogs--LeaveRoom,
dialogs--InviteUsers,
dialogs--JoinRoom { dialogs--JoinRoom {
background-color: #383c4a; background-color: #383c4a;
color: #caccd1; color: #caccd1;
} }
QListWidget {
background-color: #383c4a;
color: #caccd1;
}
WelcomePage, WelcomePage,
LoginPage, LoginPage,
RegisterPage { RegisterPage {

View file

@ -81,11 +81,17 @@ Avatar {
dialogs--Logout, dialogs--Logout,
dialogs--LeaveRoom, dialogs--LeaveRoom,
dialogs--InviteUsers,
dialogs--JoinRoom { dialogs--JoinRoom {
background-color: white; background-color: white;
color: #333; color: #333;
} }
QListWidget {
background-color: white;
color: #333;
}
WelcomePage, WelcomePage,
LoginPage, LoginPage,
RegisterPage { RegisterPage {

View file

@ -89,3 +89,8 @@ ScrollBar {
qproperty-handleColor: palette(text); qproperty-handleColor: palette(text);
qproperty-backgroundColor: palette(window); qproperty-backgroundColor: palette(window);
} }
QListWidget {
background-color: palette(window);
color: palette(text);
}

View file

@ -109,6 +109,13 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect( connect(
top_bar_, &TopRoomBar::leaveRoom, this, [=]() { client_->leaveRoom(current_room_); }); top_bar_, &TopRoomBar::leaveRoom, this, [=]() { client_->leaveRoom(current_room_); });
connect(top_bar_, &TopRoomBar::inviteUsers, this, [=](QStringList users) {
for (int ii = 0; ii < users.size(); ++ii) {
QTimer::singleShot(ii * 1000, this, [=]() {
client_->inviteUser(current_room_, users.at(ii));
});
}
});
connect(room_list_, &RoomList::roomChanged, this, [=](const QString &roomid) { connect(room_list_, &RoomList::roomChanged, this, [=](const QString &roomid) {
QStringList users; QStringList users;
@ -258,6 +265,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() { connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() {
emit showNotification("You joined the room."); emit showNotification("You joined the room.");
}); });
connect(client_.data(), &MatrixClient::invitedUser, this, [=](QString, QString user) {
emit showNotification(QString("Invited user %1").arg(user));
});
connect(client_.data(), &MatrixClient::leftRoom, this, &ChatPage::removeRoom); connect(client_.data(), &MatrixClient::leftRoom, this, &ChatPage::removeRoom);
showContentTimer_ = new QTimer(this); showContentTimer_ = new QTimer(this);

37
src/InviteeItem.cc Normal file
View file

@ -0,0 +1,37 @@
#include <QHBoxLayout>
#include "FlatButton.h"
#include "InviteeItem.h"
#include "Theme.h"
constexpr int SidePadding = 10;
constexpr int IconSize = 13;
InviteeItem::InviteeItem(mtx::identifiers::User user, QWidget *parent)
: QWidget{parent}
, user_{QString::fromStdString(user.toString())}
{
auto topLayout_ = new QHBoxLayout(this);
topLayout_->setSpacing(0);
topLayout_->setContentsMargins(SidePadding, 0, 3 * SidePadding, 0);
QFont font;
font.setPixelSize(15);
name_ = new QLabel(user_, this);
name_->setFont(font);
QIcon removeUserIcon;
removeUserIcon.addFile(":/icons/icons/ui/remove-symbol.png");
removeUserBtn_ = new FlatButton(this);
removeUserBtn_->setIcon(removeUserIcon);
removeUserBtn_->setIconSize(QSize(IconSize, IconSize));
removeUserBtn_->setFixedSize(QSize(IconSize, IconSize));
removeUserBtn_->setRippleStyle(ui::RippleStyle::NoRipple);
topLayout_->addWidget(name_);
topLayout_->addWidget(removeUserBtn_);
connect(removeUserBtn_, &FlatButton::clicked, this, &InviteeItem::removeItem);
}

View file

@ -860,6 +860,36 @@ MatrixClient::leaveRoom(const QString &roomId)
}); });
} }
void
MatrixClient::inviteUser(const QString &roomId, const QString &user)
{
QUrlQuery query;
query.addQueryItem("access_token", token_);
QUrl endpoint(server_);
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/invite").arg(roomId));
endpoint.setQuery(query);
QNetworkRequest request(endpoint);
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
QJsonObject body{{"user_id", user}};
auto reply = post(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
connect(reply, &QNetworkReply::finished, this, [this, reply, roomId, user]() {
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status == 0 || status >= 400) {
// TODO: Handle failure.
qWarning() << reply->errorString();
return;
}
emit invitedUser(roomId, user);
});
}
void void
MatrixClient::sendTypingNotification(const QString &roomid, int timeoutInMillis) MatrixClient::sendTypingNotification(const QString &roomid, int timeoutInMillis)
{ {

View file

@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <QDebug>
#include <QStyleOption> #include <QStyleOption>
#include "Avatar.h" #include "Avatar.h"
@ -88,6 +89,33 @@ TopRoomBar::TopRoomBar(QWidget *parent)
roomSettings_->toggleNotifications(); roomSettings_->toggleNotifications();
}); });
inviteUsers_ = new QAction(tr("Invite users"), this);
connect(inviteUsers_, &QAction::triggered, this, [=]() {
if (inviteUsersDialog_.isNull()) {
inviteUsersDialog_ =
QSharedPointer<dialogs::InviteUsers>(new dialogs::InviteUsers(this));
connect(inviteUsersDialog_.data(),
&dialogs::InviteUsers::closing,
this,
[=](bool isSending, QStringList invitees) {
inviteUsersModal_->fadeOut();
if (isSending && !invitees.isEmpty())
emit inviteUsers(invitees);
});
}
if (inviteUsersModal_.isNull()) {
inviteUsersModal_ = QSharedPointer<OverlayModal>(
new OverlayModal(MainWindow::instance(), inviteUsersDialog_.data()));
inviteUsersModal_->setDuration(0);
inviteUsersModal_->setColor(QColor(30, 30, 30, 170));
}
inviteUsersModal_->fadeIn();
});
leaveRoom_ = new QAction(tr("Leave room"), this); leaveRoom_ = new QAction(tr("Leave room"), this);
connect(leaveRoom_, &QAction::triggered, this, [=]() { connect(leaveRoom_, &QAction::triggered, this, [=]() {
if (leaveRoomDialog_.isNull()) { if (leaveRoomDialog_.isNull()) {
@ -111,6 +139,7 @@ TopRoomBar::TopRoomBar(QWidget *parent)
}); });
menu_->addAction(toggleNotifications_); menu_->addAction(toggleNotifications_);
menu_->addAction(inviteUsers_);
menu_->addAction(leaveRoom_); menu_->addAction(leaveRoom_);
connect(settingsBtn_, &QPushButton::clicked, this, [=]() { connect(settingsBtn_, &QPushButton::clicked, this, [=]() {
@ -171,9 +200,9 @@ TopRoomBar::paintEvent(QPaintEvent *event)
QPainter painter(this); QPainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this); style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this);
// Number of pixels that we can move sidebar splitter per frame. If label contains text // Number of pixels that we can move sidebar splitter per frame. If label contains
// which fills entire it's width then label starts blocking it's layout from shrinking. // text which fills entire it's width then label starts blocking it's layout from
// Making label little bit shorter leaves some space for it to shrink. // shrinking. Making label little bit shorter leaves some space for it to shrink.
const auto perFrameResize = 20; const auto perFrameResize = 20;
QString elidedText = QString elidedText =

149
src/dialogs/InviteUsers.cc Normal file
View file

@ -0,0 +1,149 @@
#include <QDebug>
#include <QIcon>
#include <QListWidget>
#include <QListWidgetItem>
#include <QStyleOption>
#include <QTimer>
#include <QVBoxLayout>
#include "Config.h"
#include "FlatButton.h"
#include "TextField.h"
#include "InviteeItem.h"
#include "dialogs/InviteUsers.h"
#include "mtx.hpp"
using namespace dialogs;
InviteUsers::InviteUsers(QWidget *parent)
: QFrame(parent)
{
setMaximumSize(400, 350);
auto layout = new QVBoxLayout(this);
layout->setSpacing(30);
layout->setMargin(20);
auto buttonLayout = new QHBoxLayout();
buttonLayout->setSpacing(0);
buttonLayout->setMargin(0);
confirmBtn_ = new FlatButton("INVITE", this);
confirmBtn_->setFontSize(conf::btn::fontSize);
cancelBtn_ = new FlatButton(tr("CANCEL"), this);
cancelBtn_->setFontSize(conf::btn::fontSize);
buttonLayout->addStretch(1);
buttonLayout->addWidget(confirmBtn_);
buttonLayout->addWidget(cancelBtn_);
QFont font;
font.setPixelSize(conf::headerFontSize);
inviteeInput_ = new TextField(this);
inviteeInput_->setLabel(tr("User ID to invite"));
inviteeList_ = new QListWidget;
inviteeList_->setFrameStyle(QFrame::NoFrame);
inviteeList_->setSelectionMode(QAbstractItemView::NoSelection);
inviteeList_->setAttribute(Qt::WA_MacShowFocusRect, 0);
inviteeList_->setSpacing(5);
errorLabel_ = new QLabel(this);
errorLabel_->setAlignment(Qt::AlignCenter);
font.setPixelSize(12);
errorLabel_->setFont(font);
layout->addWidget(inviteeInput_);
layout->addWidget(errorLabel_);
layout->addWidget(inviteeList_);
layout->addLayout(buttonLayout);
connect(inviteeInput_, &TextField::returnPressed, this, &InviteUsers::addUser);
connect(confirmBtn_, &QPushButton::clicked, [=]() {
emit closing(true, invitedUsers());
inviteeInput_->clear();
inviteeList_->clear();
errorLabel_->hide();
});
connect(cancelBtn_, &QPushButton::clicked, [=]() {
QStringList emptyList;
emit closing(false, emptyList);
inviteeInput_->clear();
inviteeList_->clear();
errorLabel_->hide();
});
}
void
InviteUsers::addUser()
{
auto user_id = inviteeInput_->text();
try {
namespace ids = mtx::identifiers;
auto user = ids::parse<ids::User>(user_id.toStdString());
auto item = new QListWidgetItem(inviteeList_);
auto invitee = new InviteeItem(user, this);
item->setSizeHint(invitee->minimumSizeHint());
item->setFlags(Qt::NoItemFlags);
item->setTextAlignment(Qt::AlignCenter);
inviteeList_->setItemWidget(item, invitee);
connect(invitee, &InviteeItem::removeItem, this, [this, item]() {
emit removeInvitee(item);
});
errorLabel_->hide();
inviteeInput_->clear();
} catch (std::exception &e) {
errorLabel_->setText(e.what());
errorLabel_->show();
}
}
void
InviteUsers::removeInvitee(QListWidgetItem *item)
{
int row = inviteeList_->row(item);
auto widget = inviteeList_->takeItem(row);
inviteeList_->removeItemWidget(widget);
}
void
InviteUsers::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
QStringList
InviteUsers::invitedUsers() const
{
QStringList users;
for (int ii = 0; ii < inviteeList_->count(); ++ii) {
auto item = inviteeList_->item(ii);
auto widget = inviteeList_->itemWidget(item);
auto invitee = qobject_cast<InviteeItem *>(widget);
if (invitee)
users << invitee->userID();
else
qDebug() << "Cast InviteeItem failed";
}
return users;
}

View file

@ -18,7 +18,9 @@ SnackBar::SnackBar(QWidget *parent)
offset_ = STARTING_OFFSET; offset_ = STARTING_OFFSET;
position_ = SnackBarPosition::Top; position_ = SnackBarPosition::Top;
QFont font("Open Sans", 14, QFont::Medium); QFont font("Open Sans");
font.setPixelSize(14);
font.setWeight(50);
setFont(font); setFont(font);
showTimer_ = new QTimer(); showTimer_ = new QTimer();