Add backend for new room creation dialogs

This commit is contained in:
Nicolas Werner 2022-03-29 04:50:25 +02:00
parent d7cb2bd647
commit 6d1416fb6e
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
14 changed files with 125 additions and 275 deletions

View file

@ -309,7 +309,6 @@ configure_file(cmake/nheko.h config/nheko.h)
#
set(SRC_FILES
# Dialogs
src/dialogs/CreateRoom.cpp
src/dialogs/FallbackAuth.cpp
src/dialogs/ReCaptcha.cpp
@ -404,7 +403,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG v0.7.0
GIT_TAG 817ae6e110829cfec39cd367a133a628ab923bb4
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
@ -506,7 +505,6 @@ feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAG
qt5_wrap_cpp(MOC_HEADERS
# Dialogs
src/dialogs/CreateRoom.h
src/dialogs/FallbackAuth.h
src/dialogs/ReCaptcha.h

View file

@ -176,8 +176,8 @@ modules:
buildsystem: cmake-ninja
name: mtxclient
sources:
- commit: 9eb9c152faf3461237d4b97ffe12503e367c8809
tag: v0.7.0
- commit: 817ae6e110829cfec39cd367a133a628ab923bb4
#tag: v0.7.0
type: git
url: https://github.com/Nheko-Reborn/mtxclient.git
- config-opts:

View file

@ -15,36 +15,26 @@ ApplicationWindow {
id: createDirectRoot
title: qsTr("Create Direct Chat")
property var profile
property bool otherUserHasE2ee: profile? dMod.count > 0 : true
minimumHeight: layout.implicitHeight+2*layout.anchors.margins+footer.height
minimumWidth: footer.width
property bool otherUserHasE2ee: profile? profile.deviceList.rowCount() > 0 : true
minimumHeight: layout.implicitHeight + footer.implicitHeight + Nheko.paddingLarge*2
minimumWidth: Math.max(footer.implicitWidth, layout.implicitWidth)
modality: Qt.NonModal
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
onVisibilityChanged: {
userID.forceActiveFocus();
}
Shortcut {
sequence: StandardKey.Cancel
onActivated: roomDirectoryWindow.close()
}
DelegateModel {
id: dMod
model: profile? profile.deviceList : undefined
onActivated: createDirectRoot.close()
}
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Nheko.paddingSmall
MatrixTextField {
id: userID
property bool isValidMxid: text.match("@.+?:.{3,}")
Layout.fillWidth: true
focus: true
placeholderText: qsTr("Name")
onTextChanged: {
if(isValidMxid) {
profile = TimelineManager.getGlobalUserProfile(text);
} else
profile = null;
}
}
anchors.margins: Nheko.paddingLarge
spacing: userID.height/4
GridLayout {
Layout.fillWidth: true
@ -58,7 +48,7 @@ ApplicationWindow {
Layout.preferredWidth: Nheko.avatarSize
Layout.preferredHeight: Nheko.avatarSize
Layout.alignment: Qt.AlignLeft
userid: profile? profile.mxid : ""
userid: profile? profile.userid : ""
url: profile? profile.avatarUrl.replace("mxc://", "image://MxcImage/") : null
displayName: profile? profile.displayName : ""
enabled: false
@ -77,6 +67,22 @@ ApplicationWindow {
font.pointSize: fontMetrics.font.pointSize * 0.9
}
}
MatrixTextField {
id: userID
property bool isValidMxid: text.match("@.+?:.{3,}")
Layout.fillWidth: true
focus: true
label: qsTr("User to invite")
placeholderText: qsTr("@user:server.tld")
onTextChanged: {
if(isValidMxid) {
profile = TimelineManager.getGlobalUserProfile(text);
} else
profile = null;
}
}
RowLayout {
Layout.fillWidth: true
Label {
@ -91,6 +97,8 @@ ApplicationWindow {
checked: otherUserHasE2ee
}
}
Item {Layout.fillHeight: true}
}
footer: DialogButtonBox {
standardButtons: DialogButtonBox.Cancel
@ -101,7 +109,7 @@ ApplicationWindow {
}
onRejected: createDirectRoot.close();
onAccepted: {
profile.startChat()
profile.startChat(encryption.checked)
createDirectRoot.close()
}
}

View file

@ -13,8 +13,15 @@ import im.nheko 1.0
ApplicationWindow {
id: createRoomRoot
title: qsTr("Create Room")
minimumWidth: rootLayout.implicitWidth+2*rootLayout.anchors.margins
minimumWidth: Math.max(rootLayout.implicitWidth+2*rootLayout.anchors.margins, footer.implicitWidth + Nheko.paddingLarge)
minimumHeight: rootLayout.implicitHeight+footer.implicitHeight+2*rootLayout.anchors.margins
modality: Qt.NonModal
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
onVisibilityChanged: {
newRoomName.forceActiveFocus();
}
Shortcut {
sequence: StandardKey.Cancel
onActivated: createRoomRoot.close()
@ -22,15 +29,18 @@ ApplicationWindow {
GridLayout {
id: rootLayout
anchors.fill: parent
anchors.margins: Nheko.paddingSmall
anchors.margins: Nheko.paddingLarge
columns: 2
rowSpacing: Nheko.paddingMedium
MatrixTextField {
id: newRoomName
Layout.columnSpan: 2
Layout.fillWidth: true
focus: true
placeholderText: qsTr("Name")
label: qsTr("Name")
placeholderText: qsTr("No name")
}
MatrixTextField {
id: newRoomTopic
@ -38,8 +48,14 @@ ApplicationWindow {
Layout.fillWidth: true
focus: true
placeholderText: qsTr("Topic")
label: qsTr("Topic")
placeholderText: qsTr("No topic")
}
Item {
Layout.preferredHeight: newRoomName.height / 2
}
RowLayout {
Layout.columnSpan: 2
Layout.fillWidth: true
@ -63,20 +79,20 @@ ApplicationWindow {
Label {
Layout.preferredWidth: implicitWidth
Layout.alignment: Qt.AlignLeft
text: qsTr("Private")
text: qsTr("Public")
color: Nheko.colors.text
HoverHandler {
id: privateHover
}
ToolTip.visible: privateHover.hovered
ToolTip.text: qsTr("Only invited users can join the room")
ToolTip.text: qsTr("Public rooms can be joined by anyone, private rooms need explicit invites.")
ToolTip.delay: Nheko.tooltipDelay
}
ToggleButton {
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: implicitWidth
id: isPrivate
checked: true
id: isPublic
checked: false
}
Label {
Layout.preferredWidth: implicitWidth
@ -95,7 +111,7 @@ ApplicationWindow {
Layout.preferredWidth: implicitWidth
id: isTrusted
checked: false
enabled: isPrivate.checked
enabled: !isPublic.checked
}
Label {
Layout.preferredWidth: implicitWidth
@ -115,6 +131,8 @@ ApplicationWindow {
id: isEncrypted
checked: false
}
Item {Layout.fillHeight: true}
}
footer: DialogButtonBox {
standardButtons: DialogButtonBox.Cancel
@ -123,6 +141,17 @@ ApplicationWindow {
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
onRejected: createRoomRoot.close();
//onAccepted: createRoom(newRoomName.text, newRoomTopic.text, newRoomAlias.text, newRoomVisibility.index, newRoomPreset.index)
onAccepted: {
var preset = 0;
if (isPublic.checked) {
preset = 1;
}
else {
preset = isTrusted.checked ? 2 : 0;
}
Nheko.createRoom(newRoomName.text, newRoomTopic.text, newRoomAlias.text, isEncrypted.checked, preset)
createRoomRoot.close();
}
}
}

View file

@ -1187,7 +1187,7 @@ ChatPage::decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescriptio
}
void
ChatPage::startChat(QString userid)
ChatPage::startChat(QString userid, std::optional<bool> encryptionEnabled)
{
auto joined_rooms = cache::joinedRooms();
auto room_infos = cache::getRoomInfo(joined_rooms);
@ -1213,6 +1213,14 @@ ChatPage::startChat(QString userid)
mtx::requests::CreateRoom req;
req.preset = mtx::requests::Preset::PrivateChat;
req.visibility = mtx::common::RoomVisibility::Private;
if (encryptionEnabled.value_or(false)) {
mtx::events::StrippedEvent<mtx::events::state::Encryption> enc;
enc.type = mtx::events::EventType::RoomEncryption;
enc.content.algorithm = mtx::crypto::MEGOLM_ALGO;
req.initial_state.emplace_back(std::move(enc));
}
if (utils::localUser() != userid) {
req.invite = {userid.toStdString()};
req.is_direct = true;

View file

@ -74,12 +74,13 @@ public:
// TODO(Nico): Get rid of this!
QString currentRoom() const;
void startChat(QString userid, std::optional<bool> encryptionEnabled);
public slots:
bool handleMatrixUri(QString uri);
bool handleMatrixUri(const QUrl &uri);
void startChat(QString userid);
void startChat(QString userid) { startChat(userid, std::nullopt); }
void leaveRoom(const QString &room_id);
void createRoom(const mtx::requests::CreateRoom &req);
void joinRoom(const QString &room);

View file

@ -54,8 +54,6 @@
#include "ui/UIA.h"
#include "voip/WebRTCSession.h"
#include "dialogs/CreateRoom.h"
Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
Q_DECLARE_METATYPE(std::vector<mtx::responses::PublicRoomsChunk>)
@ -404,19 +402,6 @@ MainWindow::hasActiveUser()
settings->contains(prefix + "auth/user_id");
}
void
MainWindow::openCreateRoomDialog(
std::function<void(const mtx::requests::CreateRoom &request)> callback)
{
auto dialog = new dialogs::CreateRoom(nullptr);
connect(dialog,
&dialogs::CreateRoom::createRoom,
this,
[callback](const mtx::requests::CreateRoom &request) { callback(request); });
showDialog(dialog);
}
bool
MainWindow::pageSupportsTray() const
{

View file

@ -47,8 +47,6 @@ public:
static MainWindow *instance() { return instance_; }
void saveCurrentWindowSize();
void
openCreateRoomDialog(std::function<void(const mtx::requests::CreateRoom &request)> callback);
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
MxcImageProvider *imageProvider() { return imgProvider; }

View file

@ -1,159 +0,0 @@
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include "dialogs/CreateRoom.h"
#include "Config.h"
#include "ui/TextField.h"
#include "ui/ToggleButton.h"
using namespace dialogs;
CreateRoom::CreateRoom(QWidget *parent)
: QFrame(parent)
{
setAutoFillBackground(true);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
setWindowModality(Qt::WindowModal);
setAttribute(Qt::WA_DeleteOnClose, true);
QFont largeFont;
largeFont.setPointSizeF(largeFont.pointSizeF() * 1.5);
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
setMinimumHeight(conf::window::minHeight);
setMinimumWidth(conf::window::minModalWidth);
auto layout = new QVBoxLayout(this);
layout->setSpacing(conf::modals::WIDGET_SPACING);
layout->setContentsMargins(conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN);
buttonBox_ = new QDialogButtonBox(QDialogButtonBox::Cancel);
confirmBtn_ = new QPushButton(tr("Create room"), this);
confirmBtn_->setDefault(true);
buttonBox_->addButton(confirmBtn_, QDialogButtonBox::AcceptRole);
QFont font;
font.setPointSizeF(font.pointSizeF() * 1.3);
nameInput_ = new TextField(this);
nameInput_->setLabel(tr("Name"));
topicInput_ = new TextField(this);
topicInput_->setLabel(tr("Topic"));
aliasInput_ = new TextField(this);
aliasInput_->setLabel(tr("Alias"));
auto visibilityLayout = new QHBoxLayout;
visibilityLayout->setContentsMargins(0, 10, 0, 10);
auto presetLayout = new QHBoxLayout;
presetLayout->setContentsMargins(0, 10, 0, 10);
auto visibilityLabel = new QLabel(tr("Room Visibility"), this);
visibilityCombo_ = new QComboBox(this);
visibilityCombo_->addItem(tr("Private"));
visibilityCombo_->addItem(tr("Public"));
visibilityLayout->addWidget(visibilityLabel);
visibilityLayout->addWidget(visibilityCombo_, 0, Qt::AlignBottom | Qt::AlignRight);
auto presetLabel = new QLabel(tr("Room Preset"), this);
presetCombo_ = new QComboBox(this);
presetCombo_->addItem(tr("Private Chat"));
presetCombo_->addItem(tr("Public Chat"));
presetCombo_->addItem(tr("Trusted Private Chat"));
presetLayout->addWidget(presetLabel);
presetLayout->addWidget(presetCombo_, 0, Qt::AlignBottom | Qt::AlignRight);
auto directLabel_ = new QLabel(tr("Direct Chat"), this);
directToggle_ = new Toggle(this);
directToggle_->setActiveColor(QColor(0x38, 0xA3, 0xD8));
directToggle_->setInactiveColor(QColor("gray"));
directToggle_->setState(false);
auto directLayout = new QHBoxLayout;
directLayout->setContentsMargins(0, 10, 0, 10);
directLayout->addWidget(directLabel_);
directLayout->addWidget(directToggle_, 0, Qt::AlignBottom | Qt::AlignRight);
layout->addWidget(nameInput_);
layout->addWidget(topicInput_);
layout->addWidget(aliasInput_);
layout->addLayout(visibilityLayout);
layout->addLayout(presetLayout);
layout->addLayout(directLayout);
layout->addWidget(buttonBox_);
connect(buttonBox_, &QDialogButtonBox::accepted, this, [this]() {
request_.name = nameInput_->text().toStdString();
request_.topic = topicInput_->text().toStdString();
request_.room_alias_name = aliasInput_->text().toStdString();
emit createRoom(request_);
clearFields();
emit close();
});
connect(buttonBox_, &QDialogButtonBox::rejected, this, [this]() {
clearFields();
emit close();
});
connect(visibilityCombo_,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
[this](int idx) {
if (idx == 0) {
request_.visibility = mtx::common::RoomVisibility::Private;
} else {
request_.visibility = mtx::common::RoomVisibility::Public;
}
});
connect(presetCombo_,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
[this](int idx) {
if (idx == 0) {
request_.preset = mtx::requests::Preset::PrivateChat;
} else if (idx == 1) {
request_.preset = mtx::requests::Preset::PublicChat;
} else {
request_.preset = mtx::requests::Preset::TrustedPrivateChat;
}
});
connect(directToggle_, &Toggle::toggled, this, [this](bool isEnabled) {
request_.is_direct = isEnabled;
});
}
void
CreateRoom::clearFields()
{
nameInput_->clear();
topicInput_->clear();
aliasInput_->clear();
}
void
CreateRoom::showEvent(QShowEvent *event)
{
nameInput_->setFocus();
QFrame::showEvent(event);
}

View file

@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QDialogButtonBox>
#include <QFrame>
#include <mtx/requests.hpp>
class QPushButton;
class TextField;
class QComboBox;
class Toggle;
namespace dialogs {
class CreateRoom : public QFrame
{
Q_OBJECT
public:
CreateRoom(QWidget *parent = nullptr);
signals:
void createRoom(const mtx::requests::CreateRoom &request);
protected:
void showEvent(QShowEvent *event) override;
private:
void clearFields();
QComboBox *visibilityCombo_;
QComboBox *presetCombo_;
Toggle *directToggle_;
QPushButton *confirmBtn_;
QDialogButtonBox *buttonBox_;
TextField *nameInput_;
TextField *topicInput_;
TextField *aliasInput_;
mtx::requests::CreateRoom request_;
};
} // dialogs

View file

@ -13,7 +13,6 @@
#include "Cache_p.h"
#include "ChatPage.h"
#include "Logging.h"
#include "MainWindow.h"
#include "UserSettingsPage.h"
#include "Utils.h"
#include "voip/WebRTCSession.h"
@ -129,8 +128,32 @@ Nheko::logout() const
}
void
Nheko::openCreateRoomDialog() const
Nheko::createRoom(QString name, QString topic, QString aliasLocalpart, bool isEncrypted, int preset)
{
MainWindow::instance()->openCreateRoomDialog(
[](const mtx::requests::CreateRoom &req) { ChatPage::instance()->createRoom(req); });
mtx::requests::CreateRoom req;
switch (preset) {
case 1:
req.preset = mtx::requests::Preset::PublicChat;
break;
case 2:
req.preset = mtx::requests::Preset::TrustedPrivateChat;
break;
case 0:
default:
req.preset = mtx::requests::Preset::PrivateChat;
}
req.name = name.toStdString();
req.topic = topic.toStdString();
req.room_alias_name = aliasLocalpart.toStdString();
if (isEncrypted) {
mtx::events::StrippedEvent<mtx::events::state::Encryption> enc;
enc.type = mtx::events::EventType::RoomEncryption;
enc.content.algorithm = mtx::crypto::MEGOLM_ALGO;
req.initial_state.emplace_back(std::move(enc));
}
emit ChatPage::instance()->createRoom(req);
}

View file

@ -52,7 +52,8 @@ public:
Q_INVOKABLE void setStatusMessage(QString msg) const;
Q_INVOKABLE void showUserSettingsPage() const;
Q_INVOKABLE void logout() const;
Q_INVOKABLE void openCreateRoomDialog() const;
Q_INVOKABLE void
createRoom(QString name, QString topic, QString aliasLocalpart, bool isEncrypted, int preset);
public slots:
void updateUserProfile();

View file

@ -53,6 +53,9 @@ UserProfile::UserProfile(QString roomid,
emit verificationStatiChanged();
});
connect(this, &UserProfile::devicesChanged, [this]() {
nhlog::net()->critical("Device list: {}", deviceList_.rowCount());
});
fetchDeviceList(this->userid_);
}
@ -187,7 +190,6 @@ UserProfile::fetchDeviceList(const QString &userID)
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
// Ensure local key cache is up to date
@ -201,7 +203,6 @@ UserProfile::fetchDeviceList(const QString &userID)
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
emit verificationStatiChanged();
@ -312,10 +313,16 @@ UserProfile::kickUser()
ChatPage::instance()->kickUser(this->userid_, QLatin1String(""));
}
void
UserProfile::startChat(bool encryption)
{
ChatPage::instance()->startChat(this->userid_, encryption);
}
void
UserProfile::startChat()
{
ChatPage::instance()->startChat(this->userid_);
ChatPage::instance()->startChat(this->userid_, std::nullopt);
}
void

View file

@ -143,6 +143,7 @@ public:
// Q_INVOKABLE void ignoreUser();
Q_INVOKABLE void kickUser();
Q_INVOKABLE void startChat();
Q_INVOKABLE void startChat(bool encryptionEnabled);
Q_INVOKABLE void changeUsername(QString username);
Q_INVOKABLE void changeDeviceName(QString deviceID, QString deviceName);
Q_INVOKABLE void changeAvatar();