Add prototype room settings menu

This commit is contained in:
Konstantinos Sideris 2018-04-30 21:41:47 +03:00
parent 21c68c5824
commit 3097037c3d
14 changed files with 309 additions and 12 deletions

View file

@ -106,6 +106,7 @@ set(SRC_FILES
src/dialogs/Logout.cc src/dialogs/Logout.cc
src/dialogs/ReadReceipts.cc src/dialogs/ReadReceipts.cc
src/dialogs/ReCaptcha.cpp src/dialogs/ReCaptcha.cpp
src/dialogs/RoomSettings.cpp
# Emoji # Emoji
src/emoji/Category.cc src/emoji/Category.cc
@ -222,6 +223,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/dialogs/Logout.h include/dialogs/Logout.h
include/dialogs/ReadReceipts.h include/dialogs/ReadReceipts.h
include/dialogs/ReCaptcha.hpp include/dialogs/ReCaptcha.hpp
include/dialogs/RoomSettings.hpp
# Emoji # Emoji
include/emoji/Category.h include/emoji/Category.h

View file

@ -64,6 +64,8 @@ struct RoomInfo
std::string avatar_url; std::string avatar_url;
//! Whether or not the room is an invite. //! Whether or not the room is an invite.
bool is_invite = false; bool is_invite = false;
//! Total number of members in the room.
int16_t member_count = 0;
}; };
inline void inline void
@ -73,6 +75,9 @@ to_json(json &j, const RoomInfo &info)
j["topic"] = info.topic; j["topic"] = info.topic;
j["avatar_url"] = info.avatar_url; j["avatar_url"] = info.avatar_url;
j["is_invite"] = info.is_invite; j["is_invite"] = info.is_invite;
if (info.member_count != 0)
j["member_count"] = info.member_count;
} }
inline void inline void
@ -82,6 +87,9 @@ from_json(const json &j, RoomInfo &info)
info.topic = j.at("topic"); info.topic = j.at("topic");
info.avatar_url = j.at("avatar_url"); info.avatar_url = j.at("avatar_url");
info.is_invite = j.at("is_invite"); info.is_invite = j.at("is_invite");
if (j.count("member_count"))
info.member_count = j.at("member_count");
} }
//! Basic information per member; //! Basic information per member;

View file

@ -80,6 +80,7 @@ public:
} }
QSharedPointer<UserSettings> userSettings() { return userSettings_; } QSharedPointer<UserSettings> userSettings() { return userSettings_; }
QSharedPointer<Cache> cache() { return cache_; }
signals: signals:
void contentLoaded(); void contentLoaded();

View file

@ -50,6 +50,7 @@ class JoinRoom;
class LeaveRoom; class LeaveRoom;
class Logout; class Logout;
class ReCaptcha; class ReCaptcha;
class RoomSettings;
} }
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
@ -68,6 +69,7 @@ public:
std::function<void(const mtx::requests::CreateRoom &request)> callback); std::function<void(const mtx::requests::CreateRoom &request)> callback);
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback); void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
void openLogoutDialog(std::function<void()> callback); void openLogoutDialog(std::function<void()> callback);
void openRoomSettings(const QString &room_id = "");
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
@ -147,4 +149,8 @@ private:
QSharedPointer<OverlayModal> logoutModal_; QSharedPointer<OverlayModal> logoutModal_;
//! Logout dialog. //! Logout dialog.
QSharedPointer<dialogs::Logout> logoutDialog_; QSharedPointer<dialogs::Logout> logoutDialog_;
//! Room settings modal.
QSharedPointer<OverlayModal> roomSettingsModal_;
//! Room settings dialog.
QSharedPointer<dialogs::RoomSettings> roomSettingsDialog_;
}; };

View file

@ -21,7 +21,6 @@
#include <QIcon> #include <QIcon>
#include <QImage> #include <QImage>
#include <QLabel> #include <QLabel>
#include <QMenu>
#include <QPaintEvent> #include <QPaintEvent>
#include <QSharedPointer> #include <QSharedPointer>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -66,8 +65,9 @@ private:
QLabel *nameLabel_; QLabel *nameLabel_;
Label *topicLabel_; Label *topicLabel_;
QMenu *menu_; Menu *menu_;
QAction *leaveRoom_; QAction *leaveRoom_;
QAction *roomSettings_;
QAction *inviteUsers_; QAction *inviteUsers_;
FlatButton *settingsBtn_; FlatButton *settingsBtn_;

View file

@ -0,0 +1,88 @@
#pragma once
#include <QFrame>
#include <QImage>
#include "Cache.h"
class FlatButton;
class TextField;
class Avatar;
class QPixmap;
class QLayout;
class QLabel;
template<class T>
class QSharedPointer;
class TopSection : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
public:
TopSection(const RoomInfo &info, const QImage &img, QWidget *parent = nullptr)
: QWidget{parent}
, info_{std::move(info)}
{
textColor_ = palette().color(QPalette::Text);
avatar_ = QPixmap::fromImage(img.scaled(
AvatarSize, AvatarSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
QSize sizeHint() const override
{
QFont font;
font.setPixelSize(18);
return QSize(200, AvatarSize + QFontMetrics(font).ascent() + 6 * Padding);
}
QColor textColor() const { return textColor_; }
void setTextColor(QColor &color) { textColor_ = color; }
protected:
void paintEvent(QPaintEvent *event) override;
private:
static constexpr int AvatarSize = 72;
static constexpr int Padding = 5;
RoomInfo info_;
QPixmap avatar_;
QColor textColor_;
};
namespace dialogs {
class RoomSettings : public QFrame
{
Q_OBJECT
public:
RoomSettings(const QString &room_id,
QSharedPointer<Cache> cache,
QWidget *parent = nullptr);
signals:
void closing();
protected:
void paintEvent(QPaintEvent *event) override;
private:
static constexpr int AvatarSize = 64;
void setAvatar(const QImage &img) { avatarImg_ = img; }
QSharedPointer<Cache> cache_;
// Button section
FlatButton *saveBtn_;
FlatButton *cancelBtn_;
RoomInfo info_;
QString room_id_;
QImage avatarImg_;
};
} // dialogs

View file

@ -103,7 +103,7 @@ public:
drawPixmap(region, pix); drawPixmap(region, pix);
} }
void drawLetterAvatar(const QChar &c, void drawLetterAvatar(const QString &c,
const QColor &penColor, const QColor &penColor,
const QColor &brushColor, const QColor &brushColor,
int w, int w,

View file

@ -136,6 +136,7 @@ dialogs--Logout,
dialogs--ReCaptcha, dialogs--ReCaptcha,
dialogs--LeaveRoom, dialogs--LeaveRoom,
dialogs--CreateRoom, dialogs--CreateRoom,
dialogs--RoomSettings,
dialogs--InviteUsers, dialogs--InviteUsers,
dialogs--ReadReceipts, dialogs--ReadReceipts,
dialogs--JoinRoom, dialogs--JoinRoom,
@ -147,6 +148,10 @@ dialogs--JoinRoom > QLineEdit {
color: #caccd1; color: #caccd1;
} }
TopSection {
qproperty-textColor: #caccd1;
}
QListWidget, QListWidget,
WelcomePage, WelcomePage,
LoginPage, LoginPage,

View file

@ -138,6 +138,7 @@ dialogs--Logout,
dialogs--ReCaptcha, dialogs--ReCaptcha,
dialogs--LeaveRoom, dialogs--LeaveRoom,
dialogs--CreateRoom, dialogs--CreateRoom,
dialogs--RoomSettings,
dialogs--InviteUsers, dialogs--InviteUsers,
dialogs--ReadReceipts, dialogs--ReadReceipts,
dialogs--JoinRoom, dialogs--JoinRoom,
@ -147,6 +148,10 @@ QListWidget {
color: #333; color: #333;
} }
TopSection {
qproperty-textColor: #333;
}
WelcomePage, WelcomePage,
LoginPage, LoginPage,
RegisterPage { RegisterPage {

View file

@ -538,9 +538,10 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
// Check if the room is joined. // Check if the room is joined.
if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room), data)) { if (lmdb::dbi_get(txn, roomsDb_, lmdb::val(room), data)) {
try { try {
room_info.emplace( RoomInfo tmp = json::parse(std::string(data.data(), data.size()));
QString::fromStdString(room), tmp.member_count = getMembersDb(txn, room).size(txn);
json::parse(std::string(data.data(), data.size())));
room_info.emplace(QString::fromStdString(room), std::move(tmp));
} catch (const json::exception &e) { } catch (const json::exception &e) {
qWarning() qWarning()
<< "failed to parse room info:" << QString::fromStdString(room) << "failed to parse room info:" << QString::fromStdString(room)
@ -550,9 +551,12 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
// Check if the room is an invite. // Check if the room is an invite.
if (lmdb::dbi_get(txn, invitesDb_, lmdb::val(room), data)) { if (lmdb::dbi_get(txn, invitesDb_, lmdb::val(room), data)) {
try { try {
room_info.emplace( RoomInfo tmp =
QString::fromStdString(room), json::parse(std::string(data.data(), data.size()));
json::parse(std::string(data.data(), data.size()))); tmp.member_count = getInviteMembersDb(txn, room).size(txn);
room_info.emplace(QString::fromStdString(room),
std::move(tmp));
} catch (const json::exception &e) { } catch (const json::exception &e) {
qWarning() << "failed to parse room info for invite:" qWarning() << "failed to parse room info for invite:"
<< QString::fromStdString(room) << QString::fromStdString(room)
@ -582,6 +586,7 @@ Cache::roomInfo(bool withInvites)
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_); auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
while (roomsCursor.get(room_id, room_data, MDB_NEXT)) { while (roomsCursor.get(room_id, room_data, MDB_NEXT)) {
RoomInfo tmp = json::parse(std::move(room_data)); RoomInfo tmp = json::parse(std::move(room_data));
tmp.member_count = getMembersDb(txn, room_id).size(txn);
result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp)); result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp));
} }
roomsCursor.close(); roomsCursor.close();
@ -591,6 +596,7 @@ Cache::roomInfo(bool withInvites)
auto invitesCursor = lmdb::cursor::open(txn, invitesDb_); auto invitesCursor = lmdb::cursor::open(txn, invitesDb_);
while (invitesCursor.get(room_id, room_data, MDB_NEXT)) { while (invitesCursor.get(room_id, room_data, MDB_NEXT)) {
RoomInfo tmp = json::parse(room_data); RoomInfo tmp = json::parse(room_data);
tmp.member_count = getInviteMembersDb(txn, room_id).size(txn);
result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp)); result.insert(QString::fromStdString(std::move(room_id)), std::move(tmp));
} }
invitesCursor.close(); invitesCursor.close();

View file

@ -2,6 +2,7 @@
#include "Painter.h" #include "Painter.h"
#include "Ripple.h" #include "Ripple.h"
#include "RippleOverlay.h" #include "RippleOverlay.h"
#include "Utils.h"
CommunitiesListItem::CommunitiesListItem(QSharedPointer<Community> community, CommunitiesListItem::CommunitiesListItem(QSharedPointer<Community> community,
QString community_id, QString community_id,
@ -74,7 +75,7 @@ CommunitiesListItem::paintEvent(QPaintEvent *)
font.setPixelSize(conf::roomlist::fonts::communityBubble); font.setPixelSize(conf::roomlist::fonts::communityBubble);
p.setFont(font); p.setFont(font);
p.drawLetterAvatar(community_->getName()[0], p.drawLetterAvatar(utils::firstChar(community_->getName()),
avatarFgColor_, avatarFgColor_,
avatarBgColor_, avatarBgColor_,
width(), width(),

View file

@ -41,6 +41,7 @@
#include "dialogs/JoinRoom.h" #include "dialogs/JoinRoom.h"
#include "dialogs/LeaveRoom.h" #include "dialogs/LeaveRoom.h"
#include "dialogs/Logout.h" #include "dialogs/Logout.h"
#include "dialogs/RoomSettings.hpp"
MainWindow *MainWindow::instance_ = nullptr; MainWindow *MainWindow::instance_ = nullptr;
@ -262,6 +263,27 @@ MainWindow::hasActiveUser()
settings.contains("auth/user_id"); settings.contains("auth/user_id");
} }
void
MainWindow::openRoomSettings(const QString &room_id)
{
const auto roomToSearch = room_id.isEmpty() ? chat_page_->currentRoom() : "";
qDebug() << "room settings" << roomToSearch;
roomSettingsDialog_ = QSharedPointer<dialogs::RoomSettings>(
new dialogs::RoomSettings(roomToSearch, chat_page_->cache(), this));
connect(roomSettingsDialog_.data(), &dialogs::RoomSettings::closing, this, [this]() {
roomSettingsModal_->hide();
});
roomSettingsModal_ =
QSharedPointer<OverlayModal>(new OverlayModal(this, roomSettingsDialog_.data()));
roomSettingsModal_->setColor(QColor(30, 30, 30, 170));
roomSettingsModal_->show();
}
void void
MainWindow::openLeaveRoomDialog(const QString &room_id) MainWindow::openLeaveRoomDialog(const QString &room_id)
{ {

View file

@ -95,8 +95,14 @@ TopRoomBar::TopRoomBar(QWidget *parent)
MainWindow::instance()->openLeaveRoomDialog(); MainWindow::instance()->openLeaveRoomDialog();
}); });
roomSettings_ = new QAction(tr("Settings"), this);
connect(roomSettings_, &QAction::triggered, this, []() {
MainWindow::instance()->openRoomSettings();
});
menu_->addAction(inviteUsers_); menu_->addAction(inviteUsers_);
menu_->addAction(leaveRoom_); menu_->addAction(leaveRoom_);
menu_->addAction(roomSettings_);
connect(settingsBtn_, &QPushButton::clicked, this, [this]() { connect(settingsBtn_, &QPushButton::clicked, this, [this]() {
auto pos = mapToGlobal(settingsBtn_->pos()); auto pos = mapToGlobal(settingsBtn_->pos());

View file

@ -0,0 +1,147 @@
#include "Avatar.h"
#include "Config.h"
#include "FlatButton.h"
#include "Painter.h"
#include "Utils.h"
#include "dialogs/RoomSettings.hpp"
#include <QComboBox>
#include <QLabel>
#include <QPainter>
#include <QPixmap>
#include <QSharedPointer>
#include <QStyleOption>
#include <QVBoxLayout>
using namespace dialogs;
RoomSettings::RoomSettings(const QString &room_id, QSharedPointer<Cache> cache, QWidget *parent)
: QFrame(parent)
, cache_{cache}
, room_id_{std::move(room_id)}
{
setMaximumWidth(385);
try {
auto res = cache_->getRoomInfo({room_id_.toStdString()});
info_ = res[room_id_];
setAvatar(QImage::fromData(cache_->image(info_.avatar_url)));
} catch (const lmdb::error &e) {
qWarning() << "failed to retrieve room info from cache" << room_id;
}
auto layout = new QVBoxLayout(this);
layout->setSpacing(30);
layout->setMargin(20);
saveBtn_ = new FlatButton("SAVE", this);
saveBtn_->setFontSize(conf::btn::fontSize);
cancelBtn_ = new FlatButton(tr("CANCEL"), this);
cancelBtn_->setFontSize(conf::btn::fontSize);
auto btnLayout = new QHBoxLayout();
btnLayout->setSpacing(0);
btnLayout->setMargin(0);
btnLayout->addStretch(1);
btnLayout->addWidget(saveBtn_);
btnLayout->addWidget(cancelBtn_);
auto notifOptionLayout_ = new QHBoxLayout;
notifOptionLayout_->setMargin(5);
auto themeLabel_ = new QLabel(tr("Notifications"), this);
auto notifCombo = new QComboBox(this);
notifCombo->addItem("Nothing");
notifCombo->addItem("Mentions only");
notifCombo->addItem("All messages");
themeLabel_->setStyleSheet("font-size: 15px;");
notifOptionLayout_->addWidget(themeLabel_);
notifOptionLayout_->addWidget(notifCombo, 0, Qt::AlignBottom | Qt::AlignRight);
layout->addWidget(new TopSection(info_, avatarImg_, this));
layout->addLayout(notifOptionLayout_);
layout->addLayout(btnLayout);
connect(cancelBtn_, &FlatButton::clicked, this, &RoomSettings::closing);
connect(saveBtn_, &FlatButton::clicked, this, [this]() { emit closing(); });
}
void
RoomSettings::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
void
TopSection::paintEvent(QPaintEvent *)
{
Painter p(this);
PainterHighQualityEnabler hq(p);
constexpr int textPadding = 23;
constexpr int textStartX = AvatarSize + 5 * Padding;
const int availableTextWidth = width() - textStartX;
constexpr int nameFont = 15;
constexpr int membersFont = 14;
constexpr int labelFont = 18;
QFont font;
font.setPixelSize(labelFont);
font.setWeight(70);
p.setFont(font);
p.setPen(textColor());
p.drawTextLeft(Padding, Padding, "Room settings");
p.translate(0, textPadding + QFontMetrics(p.font()).ascent());
p.save();
p.translate(textStartX, 2 * Padding);
// Draw the name.
font.setPixelSize(membersFont);
const auto members = QString("%1 members").arg(info_.member_count);
font.setPixelSize(nameFont);
const auto name = QFontMetrics(font).elidedText(
QString::fromStdString(info_.name), Qt::ElideRight, availableTextWidth - 4 * Padding);
font.setWeight(60);
p.setFont(font);
p.drawTextLeft(0, 0, name);
// Draw the number of members
p.translate(0, QFontMetrics(p.font()).ascent() + 2 * Padding);
font.setPixelSize(membersFont);
font.setWeight(50);
p.setFont(font);
p.drawTextLeft(0, 0, members);
p.restore();
if (avatar_.isNull()) {
font.setPixelSize(AvatarSize / 2);
font.setWeight(60);
p.setFont(font);
p.translate(Padding, Padding);
p.drawLetterAvatar(utils::firstChar(name),
QColor("white"),
QColor("black"),
AvatarSize + Padding,
AvatarSize + Padding,
AvatarSize);
} else {
QRect avatarRegion(Padding, Padding, AvatarSize, AvatarSize);
QPainterPath pp;
pp.addEllipse(avatarRegion.center(), AvatarSize, AvatarSize);
p.setClipPath(pp);
p.drawPixmap(avatarRegion, avatar_);
}
}