View
@@ -16,11 +16,11 @@
*/
#include <QBuffer>
-#include <QDebug>
#include <QObject>
#include <QTimer>
#include "Cache.h"
+#include "Logging.hpp"
#include "MainWindow.h"
#include "MatrixClient.h"
#include "OverlayModal.h"
@@ -55,18 +55,7 @@ RoomList::RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent)
scrollArea_->setWidget(scrollAreaContents_);
topLayout_->addWidget(scrollArea_);
- connect(http::client(),
- &MatrixClient::roomAvatarRetrieved,
- this,
- [this](const QString &room_id,
- const QPixmap &img,
- const QString &url,
- const QByteArray &data) {
- if (cache::client())
- cache::client()->saveImage(url, data);
-
- updateRoomAvatar(room_id, img);
- });
+ connect(this, &RoomList::updateRoomAvatarCb, this, &RoomList::updateRoomAvatar);
}
void
@@ -101,7 +90,28 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
savedImgData = cache::client()->image(url);
if (savedImgData.isEmpty()) {
- http::client()->fetchRoomAvatar(room_id, url);
+ mtx::http::ThumbOpts opts;
+ opts.mxc_url = url.toStdString();
+ http::v2::client()->get_thumbnail(
+ opts, [room_id, opts, this](const std::string &res, mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn(
+ "failed to download room avatar: {} {} {}",
+ opts.mxc_url,
+ mtx::errors::to_string(err->matrix_error.errcode),
+ err->matrix_error.error);
+ return;
+ }
+
+ if (cache::client())
+ cache::client()->saveImage(opts.mxc_url, res);
+
+ auto data = QByteArray(res.data(), res.size());
+ QPixmap pixmap;
+ pixmap.loadFromData(data);
+
+ emit updateRoomAvatarCb(room_id, pixmap);
+ });
} else {
QPixmap img;
img.loadFromData(savedImgData);
@@ -131,7 +141,8 @@ void
RoomList::updateUnreadMessageCount(const QString &roomid, int count)
{
if (!roomExists(roomid)) {
- qWarning() << "UpdateUnreadMessageCount: Unknown roomid";
+ nhlog::ui()->warn("updateUnreadMessageCount: unknown room_id {}",
+ roomid.toStdString());
return;
}
@@ -156,7 +167,7 @@ RoomList::calculateUnreadMessageCount()
void
RoomList::initialize(const QMap<QString, RoomInfo> &info)
{
- qDebug() << "initialize room list";
+ nhlog::ui()->info("initialize room list");
rooms_.clear();
@@ -209,7 +220,7 @@ RoomList::highlightSelectedRoom(const QString &room_id)
emit roomChanged(room_id);
if (!roomExists(room_id)) {
- qDebug() << "RoomList: clicked unknown roomid";
+ nhlog::ui()->warn("roomlist: clicked unknown room_id");
return;
}
@@ -232,7 +243,8 @@ void
RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
{
if (!roomExists(roomid)) {
- qWarning() << "Avatar update on non existent room" << roomid;
+ nhlog::ui()->warn("avatar update on non-existent room_id: {}",
+ roomid.toStdString());
return;
}
@@ -246,7 +258,9 @@ void
RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info)
{
if (!roomExists(roomid)) {
- qWarning() << "Description update on non existent room" << roomid << info.body;
+ nhlog::ui()->warn("description update on non-existent room_id: {}, {}",
+ roomid.toStdString(),
+ info.body.toStdString());
return;
}
@@ -314,7 +328,7 @@ RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias)
joinRoomModal_->hide();
if (isJoining)
- http::client()->joinRoom(roomAlias);
+ emit joinRoom(roomAlias);
}
void
View
@@ -71,8 +71,6 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent)
this,
&FilteredTextEdit::uploadData);
- qRegisterMetaType<SearchResult>();
- qRegisterMetaType<QVector<SearchResult>>();
connect(this, &FilteredTextEdit::resultsRetrieved, this, &FilteredTextEdit::showResults);
connect(&popup_, &SuggestionsPopup::itemSelected, this, [this](const QString &text) {
popup_.hide();
View
@@ -17,22 +17,22 @@
#include <QApplication>
#include <QBuffer>
-#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QHBoxLayout>
#include <QMimeDatabase>
#include <QVBoxLayout>
#include "Config.h"
+#include "Logging.hpp"
#include "Utils.h"
#include "dialogs/PreviewUploadOverlay.h"
using namespace dialogs;
-static constexpr const char *DEFAULT = "Upload %1?";
-static constexpr const char *ERROR = "Failed to load image type '%1'. Continue upload?";
+constexpr const char *DEFAULT = "Upload %1?";
+constexpr const char *ERR_MSG = "Failed to load image type '%1'. Continue upload?";
PreviewUploadOverlay::PreviewUploadOverlay(QWidget *parent)
: QWidget{parent}
@@ -105,7 +105,7 @@ PreviewUploadOverlay::setLabels(const QString &type, const QString &mime, uint64
{
if (mediaType_ == "image") {
if (!image_.loadFromData(data_)) {
- titleLabel_.setText(QString{tr(ERROR)}.arg(type));
+ titleLabel_.setText(QString{tr(ERR_MSG)}.arg(type));
} else {
titleLabel_.setText(QString{tr(DEFAULT)}.arg(mediaType_));
}
@@ -142,8 +142,9 @@ PreviewUploadOverlay::setPreview(const QString &path)
QFile file{path};
if (!file.open(QIODevice::ReadOnly)) {
- qWarning() << "Failed to open file from:" << path;
- qWarning() << "Reason:" << file.errorString();
+ nhlog::ui()->warn("Failed to open file ({}): {}",
+ path.toStdString(),
+ file.errorString().toStdString());
close();
return;
}
@@ -152,7 +153,7 @@ PreviewUploadOverlay::setPreview(const QString &path)
auto mime = db.mimeTypeForFileNameAndData(path, &file);
if ((data_ = file.readAll()).isEmpty()) {
- qWarning() << "Failed to read media:" << file.errorString();
+ nhlog::ui()->warn("Failed to read media: {}", file.errorString().toStdString());
close();
return;
}
View
@@ -6,14 +6,15 @@
#include "Config.h"
#include "FlatButton.h"
+#include "MatrixClient.h"
#include "RaisedButton.h"
#include "Theme.h"
#include "dialogs/ReCaptcha.hpp"
using namespace dialogs;
-ReCaptcha::ReCaptcha(const QString &server, const QString &session, QWidget *parent)
+ReCaptcha::ReCaptcha(const QString &session, QWidget *parent)
: QWidget(parent)
{
setAutoFillBackground(true);
@@ -51,12 +52,12 @@ ReCaptcha::ReCaptcha(const QString &server, const QString &session, QWidget *par
layout->addWidget(label);
layout->addLayout(buttonLayout);
- connect(openCaptchaBtn_, &QPushButton::clicked, [server, session]() {
- const auto url =
- QString(
- "https://%1/_matrix/client/r0/auth/m.login.recaptcha/fallback/web?session=%2")
- .arg(server)
- .arg(session);
+ connect(openCaptchaBtn_, &QPushButton::clicked, [session]() {
+ const auto url = QString("https://%1:%2/_matrix/client/r0/auth/m.login.recaptcha/"
+ "fallback/web?session=%3")
+ .arg(QString::fromStdString(http::v2::client()->server()))
+ .arg(http::v2::client()->port())
+ .arg(session);
QDesktopServices::openUrl(url);
});
View
@@ -1,16 +1,20 @@
#include "Avatar.h"
+#include "ChatPage.h"
#include "Config.h"
#include "FlatButton.h"
+#include "Logging.hpp"
#include "MatrixClient.h"
#include "Painter.h"
#include "TextField.h"
#include "Theme.h"
#include "Utils.h"
#include "dialogs/RoomSettings.hpp"
+#include "ui/ToggleButton.h"
#include <QApplication>
#include <QComboBox>
#include <QLabel>
+#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QSettings>
@@ -67,6 +71,20 @@ EditModal::EditModal(const QString &roomId, QWidget *parent)
labelLayout->addWidget(errorField_);
layout->addLayout(labelLayout);
+ connect(this, &EditModal::stateEventErrorCb, this, [this](const QString &msg) {
+ errorField_->setText(msg);
+ errorField_->show();
+ });
+ connect(this, &EditModal::nameEventSentCb, this, [this](const QString &newName) {
+ errorField_->hide();
+ emit nameChanged(newName);
+ close();
+ });
+ connect(this, &EditModal::topicEventSentCb, this, [this]() {
+ errorField_->hide();
+ close();
+ });
+
connect(applyBtn_, &QPushButton::clicked, [this]() {
// Check if the values are changed from the originals.
auto newName = nameInput_->text().trimmed();
@@ -85,53 +103,37 @@ EditModal::EditModal(const QString &roomId, QWidget *parent)
state::Name body;
body.name = newName.toStdString();
- auto proxy =
- http::client()->sendStateEvent<state::Name, EventType::RoomName>(body,
- roomId_);
- connect(proxy.get(),
- &StateEventProxy::stateEventSent,
- this,
- [this, proxy, newName]() {
- Q_UNUSED(proxy);
- errorField_->hide();
- emit nameChanged(newName);
- close();
- });
-
- connect(proxy.get(),
- &StateEventProxy::stateEventError,
- this,
- [this, proxy, newName](const QString &msg) {
- Q_UNUSED(proxy);
- errorField_->setText(msg);
- errorField_->show();
- });
+ http::v2::client()->send_state_event<state::Name, EventType::RoomName>(
+ roomId_.toStdString(),
+ body,
+ [this, newName](const mtx::responses::EventId &,
+ mtx::http::RequestErr err) {
+ if (err) {
+ emit stateEventErrorCb(
+ QString::fromStdString(err->matrix_error.error));
+ return;
+ }
+
+ emit nameEventSentCb(newName);
+ });
}
if (newTopic != initialTopic_ && !newTopic.isEmpty()) {
state::Topic body;
body.topic = newTopic.toStdString();
- auto proxy =
- http::client()->sendStateEvent<state::Topic, EventType::RoomTopic>(
- body, roomId_);
- connect(proxy.get(),
- &StateEventProxy::stateEventSent,
- this,
- [this, proxy, newTopic]() {
- Q_UNUSED(proxy);
- errorField_->hide();
- close();
- });
-
- connect(proxy.get(),
- &StateEventProxy::stateEventError,
- this,
- [this, proxy, newTopic](const QString &msg) {
- Q_UNUSED(proxy);
- errorField_->setText(msg);
- errorField_->show();
- });
+ http::v2::client()->send_state_event<state::Topic, EventType::RoomTopic>(
+ roomId_.toStdString(),
+ body,
+ [this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ if (err) {
+ emit stateEventErrorCb(
+ QString::fromStdString(err->matrix_error.error));
+ return;
+ }
+
+ emit topicEventSentCb();
+ });
}
});
connect(cancelBtn_, &QPushButton::clicked, this, &EditModal::close);
@@ -190,16 +192,16 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
layout->setSpacing(15);
layout->setMargin(20);
- saveBtn_ = new FlatButton("SAVE", this);
- saveBtn_->setFontSize(conf::btn::fontSize);
+ okBtn_ = new FlatButton(tr("OK"), this);
+ okBtn_->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(okBtn_);
btnLayout->addWidget(cancelBtn_);
auto notifOptionLayout_ = new QHBoxLayout;
@@ -238,6 +240,61 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
accessOptionLayout->addWidget(accessLabel);
accessOptionLayout->addWidget(accessCombo);
+ auto encryptionOptionLayout = new QHBoxLayout;
+ encryptionOptionLayout->setMargin(SettingsMargin);
+ auto encryptionLabel = new QLabel(tr("Encryption"), this);
+ encryptionLabel->setStyleSheet("font-size: 15px;");
+ encryptionToggle_ = new Toggle(this);
+ connect(encryptionToggle_, &Toggle::toggled, this, [this](bool isOn) {
+ if (isOn)
+ return;
+
+ QFont font;
+ font.setPixelSize(conf::fontSize);
+
+ QMessageBox msgBox;
+ msgBox.setIcon(QMessageBox::Question);
+ msgBox.setFont(font);
+ msgBox.setWindowTitle(tr("End-to-End Encryption"));
+ msgBox.setText(tr(
+ "Encryption is currently experimental and things might break unexpectedly. <br>"
+ "Please take note that it can't be disabled afterwards."));
+ msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Save);
+ int ret = msgBox.exec();
+
+ switch (ret) {
+ case QMessageBox::Ok: {
+ encryptionToggle_->setState(false);
+ encryptionToggle_->setEnabled(false);
+ enableEncryption();
+ break;
+ }
+ default: {
+ encryptionToggle_->setState(true);
+ encryptionToggle_->setEnabled(true);
+ break;
+ }
+ }
+ });
+
+ encryptionOptionLayout->addWidget(encryptionLabel);
+ encryptionOptionLayout->addWidget(encryptionToggle_, 0, Qt::AlignBottom | Qt::AlignRight);
+
+ // Disable encryption button.
+ if (usesEncryption_) {
+ encryptionToggle_->setState(false);
+ encryptionToggle_->setEnabled(false);
+ } else {
+ encryptionToggle_->setState(true);
+ }
+
+ // Hide encryption option for public rooms.
+ if (!usesEncryption_ && (info_.join_rule == JoinRule::Public)) {
+ encryptionToggle_->hide();
+ encryptionLabel->hide();
+ }
+
QFont font;
font.setPixelSize(18);
font.setWeight(70);
@@ -257,10 +314,18 @@ RoomSettings::RoomSettings(const QString &room_id, QWidget *parent)
layout->addLayout(editLayout_);
layout->addLayout(notifOptionLayout_);
layout->addLayout(accessOptionLayout);
+ layout->addLayout(encryptionOptionLayout);
layout->addLayout(btnLayout);
connect(cancelBtn_, &QPushButton::clicked, this, &RoomSettings::closing);
- connect(saveBtn_, &QPushButton::clicked, this, &RoomSettings::saveSettings);
+ connect(okBtn_, &QPushButton::clicked, this, &RoomSettings::saveSettings);
+
+ connect(this, &RoomSettings::enableEncryptionError, this, [this](const QString &msg) {
+ encryptionToggle_->setState(true);
+ encryptionToggle_->setEnabled(true);
+
+ emit ChatPage::instance()->showNotification(msg);
+ });
}
void
@@ -273,7 +338,7 @@ RoomSettings::setupEditButton()
hasEditRights_ = cache::client()->hasEnoughPowerLevel(
{EventType::RoomName, EventType::RoomTopic}, room_id_.toStdString(), userId);
} catch (const lmdb::error &e) {
- qWarning() << "lmdb error" << e.what();
+ nhlog::db()->warn("lmdb error: {}", e.what());
}
constexpr int buttonSize = 36;
@@ -310,10 +375,12 @@ void
RoomSettings::retrieveRoomInfo()
{
try {
- info_ = cache::client()->singleRoomInfo(room_id_.toStdString());
+ usesEncryption_ = cache::client()->isRoomEncrypted(room_id_.toStdString());
+ info_ = cache::client()->singleRoomInfo(room_id_.toStdString());
setAvatar(QImage::fromData(cache::client()->image(info_.avatar_url)));
} catch (const lmdb::error &e) {
- qWarning() << "failed to retrieve room info from cache" << room_id_;
+ nhlog::db()->warn("failed to retrieve room info from cache: {}",
+ room_id_.toStdString());
}
}
@@ -341,6 +408,28 @@ RoomSettings::saveSettings()
closing();
}
+void
+RoomSettings::enableEncryption()
+{
+ const auto room_id = room_id_.toStdString();
+ http::v2::client()->enable_encryption(
+ room_id, [room_id, this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ if (err) {
+ int status_code = static_cast<int>(err->status_code);
+ nhlog::net()->warn("failed to enable encryption in room ({}): {} {}",
+ room_id,
+ err->matrix_error.error,
+ status_code);
+ emit enableEncryptionError(
+ tr("Failed to enable encryption: %1")
+ .arg(QString::fromStdString(err->matrix_error.error)));
+ return;
+ }
+
+ nhlog::net()->info("enabled encryption on room ({})", room_id);
+ });
+}
+
void
RoomSettings::paintEvent(QPaintEvent *)
{
View
@@ -17,20 +17,23 @@
#include <QApplication>
#include <QDesktopWidget>
+#include <QDir>
#include <QFile>
#include <QFontDatabase>
#include <QLabel>
#include <QLayout>
#include <QLibraryInfo>
-#include <QNetworkProxy>
#include <QPalette>
#include <QPoint>
#include <QPushButton>
#include <QSettings>
+#include <QStandardPaths>
#include <QTranslator>
#include "Config.h"
+#include "Logging.hpp"
#include "MainWindow.h"
+#include "MatrixClient.h"
#include "RaisedButton.h"
#include "RunGuard.h"
#include "version.hpp"
@@ -47,28 +50,13 @@ screenCenter(int width, int height)
}
void
-setupProxy()
+createCacheDirectory()
{
- QSettings settings;
+ auto dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
- /**
- To set up a SOCKS proxy:
- [user]
- proxy\socks\host=<>
- proxy\socks\port=<>
- proxy\socks\user=<>
- proxy\socks\password=<>
- **/
- if (settings.contains("user/proxy/socks/host")) {
- QNetworkProxy proxy;
- proxy.setType(QNetworkProxy::Socks5Proxy);
- proxy.setHostName(settings.value("user/proxy/socks/host").toString());
- proxy.setPort(settings.value("user/proxy/socks/port").toInt());
- if (settings.contains("user/proxy/socks/user"))
- proxy.setUser(settings.value("user/proxy/socks/user").toString());
- if (settings.contains("user/proxy/socks/password"))
- proxy.setPassword(settings.value("user/proxy/socks/password").toString());
- QNetworkProxy::setApplicationProxy(proxy);
+ if (!QDir().mkpath(dir)) {
+ throw std::runtime_error(
+ ("Unable to create state directory:" + dir).toStdString().c_str());
}
}
@@ -133,7 +121,19 @@ main(int argc, char *argv[])
QFontDatabase::addApplicationFont(":/fonts/fonts/EmojiOne/emojione-android.ttf");
app.setWindowIcon(QIcon(":/logos/nheko.png"));
- qSetMessagePattern("%{time process}: [%{type}] - %{message}");
+
+ http::init();
+
+ createCacheDirectory();
+
+ try {
+ nhlog::init(QString("%1/nheko.log")
+ .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
+ .toStdString());
+ } catch (const spdlog::spdlog_ex &ex) {
+ std::cout << "Log initialization failed: " << ex.what() << std::endl;
+ std::exit(1);
+ }
QSettings settings;
@@ -154,8 +154,6 @@ main(int argc, char *argv[])
appTranslator.load("nheko_" + lang, ":/translations");
app.installTranslator(&appTranslator);
- setupProxy();
-
MainWindow w;
// Move the MainWindow to the center
@@ -165,7 +163,16 @@ main(int argc, char *argv[])
!settings.value("user/window/tray", true).toBool())
w.show();
- QObject::connect(&app, &QApplication::aboutToQuit, &w, &MainWindow::saveCurrentWindowSize);
+ QObject::connect(&app, &QApplication::aboutToQuit, &w, [&w]() {
+ w.saveCurrentWindowSize();
+ if (http::v2::client() != nullptr) {
+ nhlog::net()->info("shutting down all I/O threads & open connections");
+ http::v2::client()->shutdown();
+ http::v2::client()->close(true);
+ }
+ });
+
+ nhlog::ui()->info("starting nheko {}", nheko::version);
return app.exec();
}
View
@@ -23,6 +23,7 @@
#include "Avatar.h"
#include "ChatPage.h"
#include "Config.h"
+#include "Logging.hpp"
#include "timeline/TimelineItem.h"
#include "timeline/widgets/AudioItem.h"
@@ -62,9 +63,27 @@ TimelineItem::init()
ChatPage::instance()->showReadReceipts(event_id_);
});
+ connect(this, &TimelineItem::eventRedacted, this, [this](const QString &event_id) {
+ emit ChatPage::instance()->removeTimelineEvent(room_id_, event_id);
+ });
+ connect(this, &TimelineItem::redactionFailed, this, [](const QString &msg) {
+ emit ChatPage::instance()->showNotification(msg);
+ });
connect(redactMsg_, &QAction::triggered, this, [this]() {
if (!event_id_.isEmpty())
- http::client()->redactEvent(room_id_, event_id_);
+ http::v2::client()->redact_event(
+ room_id_.toStdString(),
+ event_id_.toStdString(),
+ [this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
+ if (err) {
+ emit redactionFailed(tr("Message redaction failed: %1")
+ .arg(QString::fromStdString(
+ err->matrix_error.error)));
+ return;
+ }
+
+ emit eventRedacted(event_id_);
+ });
});
connect(markAsRead_, &QAction::triggered, this, [this]() { sendReadReceipt(); });
@@ -413,6 +432,7 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text>
void
TimelineItem::markReceived()
{
+ isReceived_ = true;
checkmark_->setText(CHECKMARK);
checkmark_->setAlignment(Qt::AlignTop);
@@ -635,3 +655,19 @@ TimelineItem::addAvatar()
AvatarProvider::resolve(
room_id_, userid, this, [this](const QImage &img) { setUserAvatar(img); });
}
+
+void
+TimelineItem::sendReadReceipt() const
+{
+ if (!event_id_.isEmpty())
+ http::v2::client()->read_event(room_id_.toStdString(),
+ event_id_.toStdString(),
+ [this](mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn(
+ "failed to read_event ({}, {})",
+ room_id_.toStdString(),
+ event_id_.toStdString());
+ }
+ });
+}
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -18,12 +18,10 @@
#include <random>
#include <QApplication>
-#include <QDebug>
#include <QFileInfo>
#include <QSettings>
-#include "MatrixClient.h"
-
+#include "Logging.hpp"
#include "timeline/TimelineView.h"
#include "timeline/TimelineViewManager.h"
#include "timeline/widgets/AudioItem.h"
@@ -35,42 +33,15 @@ TimelineViewManager::TimelineViewManager(QWidget *parent)
: QStackedWidget(parent)
{
setStyleSheet("border: none;");
-
- connect(
- http::client(), &MatrixClient::messageSent, this, &TimelineViewManager::messageSent);
-
- connect(http::client(),
- &MatrixClient::messageSendFailed,
- this,
- &TimelineViewManager::messageSendFailed);
-
- connect(http::client(),
- &MatrixClient::redactionCompleted,
- this,
- [this](const QString &room_id, const QString &event_id) {
- auto view = views_[room_id];
-
- if (view)
- view->removeEvent(event_id);
- });
}
void
-TimelineViewManager::messageSent(const QString &event_id, const QString &roomid, int txn_id)
+TimelineViewManager::removeTimelineEvent(const QString &room_id, const QString &event_id)
{
- // We save the latest valid transaction ID for later use.
- QSettings settings;
- settings.setValue("client/transaction_id", txn_id + 1);
+ auto view = views_[room_id];
- auto view = views_[roomid];
- view->updatePendingMessage(txn_id, event_id);
-}
-
-void
-TimelineViewManager::messageSendFailed(const QString &roomid, int txn_id)
-{
- auto view = views_[roomid];
- view->handleFailedMessage(txn_id);
+ if (view)
+ view->removeEvent(event_id);
}
void
@@ -105,7 +76,7 @@ TimelineViewManager::queueImageMessage(const QString &roomid,
uint64_t size)
{
if (!timelineViewExists(roomid)) {
- qDebug() << "Cannot send m.image message to a non-managed view";
+ nhlog::ui()->warn("Cannot send m.image message to a non-managed view");
return;
}
@@ -122,7 +93,7 @@ TimelineViewManager::queueFileMessage(const QString &roomid,
uint64_t size)
{
if (!timelineViewExists(roomid)) {
- qDebug() << "Cannot send m.file message to a non-managed view";
+ nhlog::ui()->warn("cannot send m.file message to a non-managed view");
return;
}
@@ -139,7 +110,7 @@ TimelineViewManager::queueAudioMessage(const QString &roomid,
uint64_t size)
{
if (!timelineViewExists(roomid)) {
- qDebug() << "Cannot send m.audio message to a non-managed view";
+ nhlog::ui()->warn("cannot send m.audio message to a non-managed view");
return;
}
@@ -156,7 +127,7 @@ TimelineViewManager::queueVideoMessage(const QString &roomid,
uint64_t size)
{
if (!timelineViewExists(roomid)) {
- qDebug() << "Cannot send m.video message to a non-managed view";
+ nhlog::ui()->warn("cannot send m.video message to a non-managed view");
return;
}
@@ -227,7 +198,8 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
auto roomid = QString::fromStdString(room.first);
if (!timelineViewExists(roomid)) {
- qDebug() << "Ignoring event from unknown room" << roomid;
+ nhlog::ui()->warn("ignoring event from unknown room: {}",
+ roomid.toStdString());
continue;
}
@@ -241,7 +213,8 @@ void
TimelineViewManager::setHistoryView(const QString &room_id)
{
if (!timelineViewExists(room_id)) {
- qDebug() << "Room ID from RoomList is not present in ViewManager" << room_id;
+ nhlog::ui()->warn("room from RoomList is not present in ViewManager: {}",
+ room_id.toStdString());
return;
}
View
@@ -16,13 +16,13 @@
*/
#include <QBrush>
-#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFileDialog>
#include <QPainter>
#include <QPixmap>
+#include "Logging.hpp"
#include "MatrixClient.h"
#include "Utils.h"
@@ -50,21 +50,12 @@ AudioItem::init()
playIcon_.addFile(":/icons/icons/ui/play-sign.png");
pauseIcon_.addFile(":/icons/icons/ui/pause-symbol.png");
- QList<QString> url_parts = url_.toString().split("mxc://");
- if (url_parts.size() != 2) {
- qDebug() << "Invalid format for image" << url_.toString();
- return;
- }
-
- QString media_params = url_parts[1];
- url_ = QString("%1/_matrix/media/r0/download/%2")
- .arg(http::client()->getHomeServer().toString(), media_params);
-
player_ = new QMediaPlayer;
player_->setMedia(QUrl(url_));
player_->setVolume(100);
player_->setNotifyInterval(1000);
+ connect(this, &AudioItem::fileDownloadedCb, this, &AudioItem::fileDownloaded);
connect(player_, &QMediaPlayer::stateChanged, this, [this](QMediaPlayer::State state) {
if (state == QMediaPlayer::StoppedState) {
state_ = AudioState::Play;
@@ -129,14 +120,20 @@ AudioItem::mousePressEvent(QMouseEvent *event)
if (filenameToSave_.isEmpty())
return;
- auto proxy = http::client()->downloadFile(url_);
- connect(proxy.data(),
- &DownloadMediaProxy::fileDownloaded,
- this,
- [proxy, this](const QByteArray &data) {
- proxy->deleteLater();
- fileDownloaded(data);
- });
+ http::v2::client()->download(
+ url_.toString().toStdString(),
+ [this](const std::string &data,
+ const std::string &,
+ const std::string &,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->info("failed to retrieve m.audio content: {}",
+ url_.toString().toStdString());
+ return;
+ }
+
+ emit fileDownloadedCb(QByteArray(data.data(), data.size()));
+ });
}
}
@@ -151,8 +148,8 @@ AudioItem::fileDownloaded(const QByteArray &data)
file.write(data);
file.close();
- } catch (const std::exception &ex) {
- qDebug() << "Error while saving file to:" << ex.what();
+ } catch (const std::exception &e) {
+ nhlog::ui()->warn("error while saving file: {}", e.what());
}
}
View
@@ -16,13 +16,13 @@
*/
#include <QBrush>
-#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFileDialog>
#include <QPainter>
#include <QPixmap>
+#include "Logging.hpp"
#include "MatrixClient.h"
#include "Utils.h"
@@ -49,17 +49,9 @@ FileItem::init()
icon_.addFile(":/icons/icons/ui/arrow-pointing-down.png");
- QList<QString> url_parts = url_.toString().split("mxc://");
- if (url_parts.size() != 2) {
- qDebug() << "Invalid format for image" << url_.toString();
- return;
- }
-
- QString media_params = url_parts[1];
- url_ = QString("%1/_matrix/media/r0/download/%2")
- .arg(http::client()->getHomeServer().toString(), media_params);
-
setFixedHeight(Height);
+
+ connect(this, &FileItem::fileDownloadedCb, this, &FileItem::fileDownloaded);
}
FileItem::FileItem(const mtx::events::RoomEvent<mtx::events::msg::File> &event, QWidget *parent)
@@ -89,8 +81,15 @@ FileItem::openUrl()
if (url_.toString().isEmpty())
return;
- if (!QDesktopServices::openUrl(url_))
- qWarning() << "Could not open url" << url_.toString();
+ auto mxc_parts = mtx::client::utils::parse_mxc_url(url_.toString().toStdString());
+ auto urlToOpen = QString("https://%1:%2/_matrix/media/r0/download/%3/%4")
+ .arg(QString::fromStdString(http::v2::client()->server()))
+ .arg(http::v2::client()->port())
+ .arg(QString::fromStdString(mxc_parts.server))
+ .arg(QString::fromStdString(mxc_parts.media_id));
+
+ if (!QDesktopServices::openUrl(urlToOpen))
+ nhlog::ui()->warn("Could not open url: {}", urlToOpen.toStdString());
}
QSize
@@ -115,14 +114,20 @@ FileItem::mousePressEvent(QMouseEvent *event)
if (filenameToSave_.isEmpty())
return;
- auto proxy = http::client()->downloadFile(url_);
- connect(proxy.data(),
- &DownloadMediaProxy::fileDownloaded,
- this,
- [proxy, this](const QByteArray &data) {
- proxy->deleteLater();
- fileDownloaded(data);
- });
+ http::v2::client()->download(
+ url_.toString().toStdString(),
+ [this](const std::string &data,
+ const std::string &,
+ const std::string &,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::ui()->warn("failed to retrieve m.file content: {}",
+ url_.toString().toStdString());
+ return;
+ }
+
+ emit fileDownloadedCb(QByteArray(data.data(), data.size()));
+ });
} else {
openUrl();
}
@@ -139,8 +144,8 @@ FileItem::fileDownloaded(const QByteArray &data)
file.write(data);
file.close();
- } catch (const std::exception &ex) {
- qDebug() << "Error while saving file to:" << ex.what();
+ } catch (const std::exception &e) {
+ nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
}
View
@@ -16,7 +16,6 @@
*/
#include <QBrush>
-#include <QDebug>
#include <QDesktopServices>
#include <QFileDialog>
#include <QFileInfo>
@@ -25,42 +24,71 @@
#include <QUuid>
#include "Config.h"
+#include "Logging.hpp"
#include "MatrixClient.h"
#include "Utils.h"
#include "dialogs/ImageOverlay.h"
#include "timeline/widgets/ImageItem.h"
-ImageItem::ImageItem(const mtx::events::RoomEvent<mtx::events::msg::Image> &event, QWidget *parent)
- : QWidget(parent)
- , event_{event}
+void
+ImageItem::downloadMedia(const QUrl &url)
{
- setMouseTracking(true);
- setCursor(Qt::PointingHandCursor);
- setAttribute(Qt::WA_Hover, true);
+ http::v2::client()->download(url.toString().toStdString(),
+ [this, url](const std::string &data,
+ const std::string &,
+ const std::string &,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn(
+ "failed to retrieve image {}: {} {}",
+ url.toString().toStdString(),
+ err->matrix_error.error,
+ static_cast<int>(err->status_code));
+ return;
+ }
+
+ QPixmap img;
+ img.loadFromData(QByteArray(data.data(), data.size()));
+ emit imageDownloaded(img);
+ });
+}
- url_ = QString::fromStdString(event.content.url);
- text_ = QString::fromStdString(event.content.body);
+void
+ImageItem::saveImage(const QString &filename, const QByteArray &data)
+{
+ try {
+ QFile file(filename);
- QList<QString> url_parts = url_.toString().split("mxc://");
+ if (!file.open(QIODevice::WriteOnly))
+ return;
- if (url_parts.size() != 2) {
- qDebug() << "Invalid format for image" << url_.toString();
- return;
+ file.write(data);
+ file.close();
+ } catch (const std::exception &e) {
+ nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
+}
- QString media_params = url_parts[1];
- url_ = QString("%1/_matrix/media/r0/download/%2")
- .arg(http::client()->getHomeServer().toString(), media_params);
+void
+ImageItem::init()
+{
+ setMouseTracking(true);
+ setCursor(Qt::PointingHandCursor);
+ setAttribute(Qt::WA_Hover, true);
- auto proxy = http::client()->downloadImage(url_);
+ connect(this, &ImageItem::imageDownloaded, this, &ImageItem::setImage);
+ connect(this, &ImageItem::imageSaved, this, &ImageItem::saveImage);
+ downloadMedia(url_);
+}
- connect(proxy.data(),
- &DownloadMediaProxy::imageDownloaded,
- this,
- [this, proxy](const QPixmap &img) {
- proxy->deleteLater();
- setImage(img);
- });
+ImageItem::ImageItem(const mtx::events::RoomEvent<mtx::events::msg::Image> &event, QWidget *parent)
+ : QWidget(parent)
+ , event_{event}
+{
+ url_ = QString::fromStdString(event.content.url);
+ text_ = QString::fromStdString(event.content.body);
+
+ init();
}
ImageItem::ImageItem(const QString &url, const QString &filename, uint64_t size, QWidget *parent)
@@ -69,31 +97,7 @@ ImageItem::ImageItem(const QString &url, const QString &filename, uint64_t size,
, text_{filename}
{
Q_UNUSED(size);
-
- setMouseTracking(true);
- setCursor(Qt::PointingHandCursor);
- setAttribute(Qt::WA_Hover, true);
-
- QList<QString> url_parts = url_.toString().split("mxc://");
-
- if (url_parts.size() != 2) {
- qDebug() << "Invalid format for image" << url_.toString();
- return;
- }
-
- QString media_params = url_parts[1];
- url_ = QString("%1/_matrix/media/r0/download/%2")
- .arg(http::client()->getHomeServer().toString(), media_params);
-
- auto proxy = http::client()->downloadImage(url_);
-
- connect(proxy.data(),
- &DownloadMediaProxy::imageDownloaded,
- this,
- [proxy, this](const QPixmap &img) {
- proxy->deleteLater();
- setImage(img);
- });
+ init();
}
void
@@ -102,8 +106,15 @@ ImageItem::openUrl()
if (url_.toString().isEmpty())
return;
- if (!QDesktopServices::openUrl(url_))
- qWarning() << "Could not open url" << url_.toString();
+ auto mxc_parts = mtx::client::utils::parse_mxc_url(url_.toString().toStdString());
+ auto urlToOpen = QString("https://%1:%2/_matrix/media/r0/download/%3/%4")
+ .arg(QString::fromStdString(http::v2::client()->server()))
+ .arg(http::v2::client()->port())
+ .arg(QString::fromStdString(mxc_parts.server))
+ .arg(QString::fromStdString(mxc_parts.media_id));
+
+ if (!QDesktopServices::openUrl(urlToOpen))
+ nhlog::ui()->warn("could not open url: {}", urlToOpen.toStdString());
}
QSize
@@ -231,23 +242,22 @@ ImageItem::saveAs()
if (filename.isEmpty())
return;
- auto proxy = http::client()->downloadFile(url_);
- connect(proxy.data(),
- &DownloadMediaProxy::fileDownloaded,
- this,
- [proxy, filename](const QByteArray &data) {
- proxy->deleteLater();
-
- try {
- QFile file(filename);
-
- if (!file.open(QIODevice::WriteOnly))
- return;
-
- file.write(data);
- file.close();
- } catch (const std::exception &ex) {
- qDebug() << "Error while saving file to:" << ex.what();
- }
- });
+ const auto url = url_.toString().toStdString();
+
+ http::v2::client()->download(
+ url,
+ [this, filename, url](const std::string &data,
+ const std::string &,
+ const std::string &,
+ mtx::http::RequestErr err) {
+ if (err) {
+ nhlog::net()->warn("failed to retrieve image {}: {} {}",
+ url,
+ err->matrix_error.error,
+ static_cast<int>(err->status_code));
+ return;
+ }
+
+ emit imageSaved(filename, QByteArray(data.data(), data.size()));
+ });
}
View
@@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <QDebug>
#include <QLabel>
#include <QVBoxLayout>
@@ -27,15 +26,15 @@
void
VideoItem::init()
{
- QList<QString> url_parts = url_.toString().split("mxc://");
- if (url_parts.size() != 2) {
- qDebug() << "Invalid format for image" << url_.toString();
- return;
- }
+ // QList<QString> url_parts = url_.toString().split("mxc://");
+ // if (url_parts.size() != 2) {
+ // qDebug() << "Invalid format for image" << url_.toString();
+ // return;
+ // }
- QString media_params = url_parts[1];
- url_ = QString("%1/_matrix/media/r0/download/%2")
- .arg(http::client()->getHomeServer().toString(), media_params);
+ // QString media_params = url_parts[1];
+ // url_ = QString("%1/_matrix/media/r0/download/%2")
+ // .arg(http::client()->getHomeServer().toString(), media_params);
}
VideoItem::VideoItem(const mtx::events::RoomEvent<mtx::events::msg::Video> &event, QWidget *parent)