mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-29 22:28:49 +03:00
commit
fd4f173966
33 changed files with 257 additions and 250 deletions
|
@ -340,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG 6432e89a3465e58ed838dd2abdcb0f91bd4f05b0
|
GIT_TAG ed6315563409ce9d47978ff2a2d771b863e375c5
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(MatrixClient)
|
FetchContent_MakeAvailable(MatrixClient)
|
||||||
else()
|
else()
|
||||||
|
@ -600,6 +600,7 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
||||||
target_precompile_headers(nheko
|
target_precompile_headers(nheko
|
||||||
PRIVATE
|
PRIVATE
|
||||||
<string>
|
<string>
|
||||||
|
<algorithm>
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,7 @@ hunter_config(
|
||||||
VERSION "1.70.0-p1"
|
VERSION "1.70.0-p1"
|
||||||
CMAKE_ARGS IOSTREAMS_NO_BZIP2=1
|
CMAKE_ARGS IOSTREAMS_NO_BZIP2=1
|
||||||
)
|
)
|
||||||
|
hunter_config(
|
||||||
|
nlohmann_json
|
||||||
|
CMAKE_ARGS JSON_MultipleHeaders=ON
|
||||||
|
)
|
||||||
|
|
|
@ -146,7 +146,7 @@
|
||||||
"name": "mtxclient",
|
"name": "mtxclient",
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"commit": "6432e89a3465e58ed838dd2abdcb0f91bd4f05b0",
|
"commit": "ed6315563409ce9d47978ff2a2d771b863e375c5",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Nheko-Reborn/mtxclient.git"
|
"url": "https://github.com/Nheko-Reborn/mtxclient.git"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1469,22 +1469,22 @@ Cache::getRoomInfo(const std::vector<std::string> &rooms)
|
||||||
return room_info;
|
return room_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline>
|
std::vector<QString>
|
||||||
Cache::roomMessages()
|
Cache::roomIds()
|
||||||
{
|
{
|
||||||
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline> msgs;
|
std::vector<QString> rooms;
|
||||||
std::string room_id, unused;
|
std::string room_id, unused;
|
||||||
|
|
||||||
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
|
auto roomsCursor = lmdb::cursor::open(txn, roomsDb_);
|
||||||
while (roomsCursor.get(room_id, unused, MDB_NEXT))
|
while (roomsCursor.get(room_id, unused, MDB_NEXT))
|
||||||
msgs.emplace(QString::fromStdString(room_id), mtx::responses::Timeline());
|
rooms.push_back(QString::fromStdString(room_id));
|
||||||
|
|
||||||
roomsCursor.close();
|
roomsCursor.close();
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
return msgs;
|
return rooms;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
QMap<QString, mtx::responses::Notifications>
|
||||||
|
@ -3376,6 +3376,46 @@ Cache::markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::query_keys(const std::string &user_id,
|
||||||
|
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb)
|
||||||
|
{
|
||||||
|
auto cache_ = cache::userKeys(user_id);
|
||||||
|
|
||||||
|
if (cache_.has_value()) {
|
||||||
|
if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) {
|
||||||
|
cb(cache_.value(), {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx::requests::QueryKeys req;
|
||||||
|
req.device_keys[user_id] = {};
|
||||||
|
|
||||||
|
std::string last_changed;
|
||||||
|
if (cache_)
|
||||||
|
last_changed = cache_->last_changed;
|
||||||
|
req.token = last_changed;
|
||||||
|
|
||||||
|
http::client()->query_keys(req,
|
||||||
|
[cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
nhlog::net()->warn(
|
||||||
|
"failed to query device keys: {},{}",
|
||||||
|
err->matrix_error.errcode,
|
||||||
|
static_cast<int>(err->status_code));
|
||||||
|
cb({}, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache::updateUserKeys(last_changed, res);
|
||||||
|
|
||||||
|
auto keys = cache::userKeys(user_id);
|
||||||
|
cb(keys.value_or(UserKeyCache{}), err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
to_json(json &j, const VerificationCache &info)
|
to_json(json &j, const VerificationCache &info)
|
||||||
{
|
{
|
||||||
|
@ -3927,10 +3967,10 @@ setCurrentFormat()
|
||||||
instance_->setCurrentFormat();
|
instance_->setCurrentFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline>
|
std::vector<QString>
|
||||||
roomMessages()
|
roomIds()
|
||||||
{
|
{
|
||||||
return instance_->roomMessages();
|
return instance_->roomIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
QMap<QString, mtx::responses::Notifications>
|
||||||
|
|
28
src/Cache.h
28
src/Cache.h
|
@ -28,11 +28,18 @@
|
||||||
#include <lmdb++.h>
|
#include <lmdb++.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/events/event_type.hpp>
|
||||||
|
#include <mtx/events/presence.hpp>
|
||||||
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
#include <mtxclient/crypto/types.hpp>
|
||||||
|
|
||||||
#include "CacheCryptoStructs.h"
|
#include "CacheCryptoStructs.h"
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
|
|
||||||
|
namespace mtx::responses {
|
||||||
|
struct Notifications;
|
||||||
|
}
|
||||||
|
|
||||||
namespace cache {
|
namespace cache {
|
||||||
void
|
void
|
||||||
init(const QString &user_id);
|
init(const QString &user_id);
|
||||||
|
@ -94,8 +101,6 @@ getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
std::vector<RoomMember>
|
std::vector<RoomMember>
|
||||||
getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
|
getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
|
||||||
|
|
||||||
void
|
|
||||||
saveState(const mtx::responses::Sync &res);
|
|
||||||
bool
|
bool
|
||||||
isInitialized();
|
isInitialized();
|
||||||
|
|
||||||
|
@ -128,9 +133,6 @@ setCurrentFormat();
|
||||||
bool
|
bool
|
||||||
runMigrations();
|
runMigrations();
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline>
|
|
||||||
roomMessages();
|
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
QMap<QString, mtx::responses::Notifications>
|
||||||
getTimelineMentions();
|
getTimelineMentions();
|
||||||
|
|
||||||
|
@ -182,22 +184,8 @@ saveImage(const QString &url, const QByteArray &data);
|
||||||
|
|
||||||
RoomInfo
|
RoomInfo
|
||||||
singleRoomInfo(const std::string &room_id);
|
singleRoomInfo(const std::string &room_id);
|
||||||
std::vector<std::string>
|
|
||||||
roomsWithStateUpdates(const mtx::responses::Sync &res);
|
|
||||||
std::vector<std::string>
|
|
||||||
roomsWithTagUpdates(const mtx::responses::Sync &res);
|
|
||||||
std::map<QString, RoomInfo>
|
std::map<QString, RoomInfo>
|
||||||
getRoomInfo(const std::vector<std::string> &rooms);
|
getRoomInfo(const std::vector<std::string> &rooms);
|
||||||
inline std::map<QString, RoomInfo>
|
|
||||||
roomUpdates(const mtx::responses::Sync &sync)
|
|
||||||
{
|
|
||||||
return getRoomInfo(roomsWithStateUpdates(sync));
|
|
||||||
}
|
|
||||||
inline std::map<QString, RoomInfo>
|
|
||||||
roomTagUpdates(const mtx::responses::Sync &sync)
|
|
||||||
{
|
|
||||||
return getRoomInfo(roomsWithTagUpdates(sync));
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Calculates which the read status of a room.
|
//! Calculates which the read status of a room.
|
||||||
//! Whether all the events in the timeline have been read.
|
//! Whether all the events in the timeline have been read.
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
//#include <nlohmann/json.hpp>
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
#include <mtxclient/crypto/objects.hpp>
|
||||||
#include <mtx/responses.hpp>
|
|
||||||
#include <mtxclient/crypto/client.hpp>
|
|
||||||
|
|
||||||
// Extra information associated with an outbound megolm session.
|
// Extra information associated with an outbound megolm session.
|
||||||
struct OutboundGroupSessionData
|
struct OutboundGroupSessionData
|
||||||
|
|
|
@ -33,8 +33,11 @@
|
||||||
#endif
|
#endif
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/responses/messages.hpp>
|
||||||
|
#include <mtx/responses/notifications.hpp>
|
||||||
|
#include <mtx/responses/sync.hpp>
|
||||||
#include <mtxclient/crypto/client.hpp>
|
#include <mtxclient/crypto/client.hpp>
|
||||||
|
#include <mtxclient/http/client.hpp>
|
||||||
|
|
||||||
#include "CacheCryptoStructs.h"
|
#include "CacheCryptoStructs.h"
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
|
@ -65,6 +68,8 @@ public:
|
||||||
void deleteUserKeys(lmdb::txn &txn,
|
void deleteUserKeys(lmdb::txn &txn,
|
||||||
lmdb::dbi &db,
|
lmdb::dbi &db,
|
||||||
const std::vector<std::string> &user_ids);
|
const std::vector<std::string> &user_ids);
|
||||||
|
void query_keys(const std::string &user_id,
|
||||||
|
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
|
||||||
|
|
||||||
// device & user verification cache
|
// device & user verification cache
|
||||||
VerificationStatus verificationStatus(const std::string &user_id);
|
VerificationStatus verificationStatus(const std::string &user_id);
|
||||||
|
@ -113,8 +118,7 @@ public:
|
||||||
void setCurrentFormat();
|
void setCurrentFormat();
|
||||||
bool runMigrations();
|
bool runMigrations();
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline> roomMessages();
|
std::vector<QString> roomIds();
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications> getTimelineMentions();
|
QMap<QString, mtx::responses::Notifications> getTimelineMentions();
|
||||||
|
|
||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
|
#include "Utils.h"
|
||||||
#include "WebRTCSession.h"
|
#include "WebRTCSession.h"
|
||||||
#include "dialogs/AcceptCall.h"
|
#include "dialogs/AcceptCall.h"
|
||||||
|
|
||||||
|
@ -33,8 +34,8 @@ std::vector<std::string>
|
||||||
getTurnURIs(const mtx::responses::TurnServer &turnServer);
|
getTurnURIs(const mtx::responses::TurnServer &turnServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallManager::CallManager(QSharedPointer<UserSettings> userSettings)
|
CallManager::CallManager(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
||||||
: QObject()
|
: QObject(parent)
|
||||||
, session_(WebRTCSession::instance())
|
, session_(WebRTCSession::instance())
|
||||||
, turnServerTimer_(this)
|
, turnServerTimer_(this)
|
||||||
, settings_(userSettings)
|
, settings_(userSettings)
|
||||||
|
|
|
@ -24,7 +24,7 @@ class CallManager : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CallManager(QSharedPointer<UserSettings>);
|
CallManager(QSharedPointer<UserSettings>, QObject *);
|
||||||
|
|
||||||
void sendInvite(const QString &roomid);
|
void sendInvite(const QString &roomid);
|
||||||
void hangUp(
|
void hangUp(
|
||||||
|
|
185
src/ChatPage.cpp
185
src/ChatPage.cpp
|
@ -22,9 +22,12 @@
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
|
#include <mtx/responses.hpp>
|
||||||
|
|
||||||
#include "AvatarProvider.h"
|
#include "AvatarProvider.h"
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
|
#include "CallManager.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
#include "DeviceVerificationFlow.h"
|
#include "DeviceVerificationFlow.h"
|
||||||
#include "EventAccessors.h"
|
#include "EventAccessors.h"
|
||||||
|
@ -69,7 +72,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
, isConnected_(true)
|
, isConnected_(true)
|
||||||
, userSettings_{userSettings}
|
, userSettings_{userSettings}
|
||||||
, notificationsManager(this)
|
, notificationsManager(this)
|
||||||
, callManager_(userSettings)
|
, callManager_(new CallManager(userSettings, this))
|
||||||
{
|
{
|
||||||
setObjectName("chatPage");
|
setObjectName("chatPage");
|
||||||
|
|
||||||
|
@ -126,7 +129,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
contentLayout_->setSpacing(0);
|
contentLayout_->setSpacing(0);
|
||||||
contentLayout_->setMargin(0);
|
contentLayout_->setMargin(0);
|
||||||
|
|
||||||
view_manager_ = new TimelineViewManager(&callManager_, this);
|
view_manager_ = new TimelineViewManager(callManager_, this);
|
||||||
|
|
||||||
contentLayout_->addWidget(view_manager_->getWidget());
|
contentLayout_->addWidget(view_manager_->getWidget());
|
||||||
|
|
||||||
|
@ -434,8 +437,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(text_input_, &TextInputWidget::callButtonPress, this, [this]() {
|
connect(text_input_, &TextInputWidget::callButtonPress, this, [this]() {
|
||||||
if (callManager_.onActiveCall()) {
|
if (callManager_->onActiveCall()) {
|
||||||
callManager_.hangUp();
|
callManager_->hangUp();
|
||||||
} else {
|
} else {
|
||||||
if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString());
|
if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString());
|
||||||
roomInfo.member_count != 2) {
|
roomInfo.member_count != 2) {
|
||||||
|
@ -454,7 +457,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
userSettings_,
|
userSettings_,
|
||||||
MainWindow::instance());
|
MainWindow::instance());
|
||||||
connect(dialog, &dialogs::PlaceCall::voice, this, [this]() {
|
connect(dialog, &dialogs::PlaceCall::voice, this, [this]() {
|
||||||
callManager_.sendInvite(current_room_);
|
callManager_->sendInvite(current_room_);
|
||||||
});
|
});
|
||||||
utils::centerWidget(dialog, MainWindow::instance());
|
utils::centerWidget(dialog, MainWindow::instance());
|
||||||
dialog->show();
|
dialog->show();
|
||||||
|
@ -692,7 +695,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
||||||
const bool isInitialized = cache::isInitialized();
|
const bool isInitialized = cache::isInitialized();
|
||||||
const auto cacheVersion = cache::formatVersion();
|
const auto cacheVersion = cache::formatVersion();
|
||||||
|
|
||||||
callManager_.refreshTurnServer();
|
callManager_->refreshTurnServer();
|
||||||
|
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
cache::setCurrentFormat();
|
cache::setCurrentFormat();
|
||||||
|
@ -762,7 +765,7 @@ ChatPage::loadStateFromCache()
|
||||||
cache::restoreSessions();
|
cache::restoreSessions();
|
||||||
olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
|
olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
|
||||||
|
|
||||||
emit initializeEmptyViews(cache::roomMessages());
|
emit initializeEmptyViews(cache::client()->roomIds());
|
||||||
emit initializeRoomList(cache::roomInfo());
|
emit initializeRoomList(cache::roomInfo());
|
||||||
emit initializeMentions(cache::getTimelineMentions());
|
emit initializeMentions(cache::getTimelineMentions());
|
||||||
emit syncTags(cache::roomInfo().toStdMap());
|
emit syncTags(cache::roomInfo().toStdMap());
|
||||||
|
@ -969,13 +972,64 @@ ChatPage::startInitialSync()
|
||||||
opts.set_presence = currentPresence();
|
opts.set_presence = currentPresence();
|
||||||
|
|
||||||
http::client()->sync(
|
http::client()->sync(
|
||||||
opts,
|
opts, [this](const mtx::responses::Sync &res, mtx::http::RequestErr err) {
|
||||||
std::bind(
|
// TODO: Initial Sync should include mentions as well...
|
||||||
&ChatPage::initialSyncHandler, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
|
if (err) {
|
||||||
|
const auto error = QString::fromStdString(err->matrix_error.error);
|
||||||
|
const auto msg = tr("Please try to login again: %1").arg(error);
|
||||||
|
const auto err_code = mtx::errors::to_string(err->matrix_error.errcode);
|
||||||
|
const int status_code = static_cast<int>(err->status_code);
|
||||||
|
|
||||||
|
nhlog::net()->error("initial sync error: {} {}", status_code, err_code);
|
||||||
|
|
||||||
|
// non http related errors
|
||||||
|
if (status_code <= 0 || status_code >= 600) {
|
||||||
|
startInitialSync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status_code) {
|
||||||
|
case 502:
|
||||||
|
case 504:
|
||||||
|
case 524: {
|
||||||
|
startInitialSync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
emit dropToLoginPageCb(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nhlog::net()->info("initial sync completed");
|
||||||
|
|
||||||
|
try {
|
||||||
|
cache::client()->saveState(res);
|
||||||
|
|
||||||
|
olm::handle_to_device_messages(res.to_device.events);
|
||||||
|
|
||||||
|
emit initializeViews(std::move(res.rooms));
|
||||||
|
emit initializeRoomList(cache::roomInfo());
|
||||||
|
emit initializeMentions(cache::getTimelineMentions());
|
||||||
|
|
||||||
|
cache::calculateRoomReadStatus();
|
||||||
|
emit syncTags(cache::roomInfo().toStdMap());
|
||||||
|
} catch (const lmdb::error &e) {
|
||||||
|
nhlog::db()->error("failed to save state after initial sync: {}",
|
||||||
|
e.what());
|
||||||
|
startInitialSync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit trySyncCb();
|
||||||
|
emit contentLoaded();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::handleSyncResponse(mtx::responses::Sync res)
|
ChatPage::handleSyncResponse(const mtx::responses::Sync &res)
|
||||||
{
|
{
|
||||||
nhlog::net()->debug("sync completed: {}", res.next_batch);
|
nhlog::net()->debug("sync completed: {}", res.next_batch);
|
||||||
|
|
||||||
|
@ -984,16 +1038,16 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res)
|
||||||
|
|
||||||
// TODO: fine grained error handling
|
// TODO: fine grained error handling
|
||||||
try {
|
try {
|
||||||
cache::saveState(res);
|
cache::client()->saveState(res);
|
||||||
olm::handle_to_device_messages(res.to_device.events);
|
olm::handle_to_device_messages(res.to_device.events);
|
||||||
|
|
||||||
auto updates = cache::roomUpdates(res);
|
auto updates = cache::getRoomInfo(cache::client()->roomsWithStateUpdates(res));
|
||||||
|
|
||||||
emit syncRoomlist(updates);
|
emit syncRoomlist(updates);
|
||||||
|
|
||||||
emit syncUI(res.rooms);
|
emit syncUI(res.rooms);
|
||||||
|
|
||||||
emit syncTags(cache::roomTagUpdates(res));
|
emit syncTags(cache::getRoomInfo(cache::client()->roomsWithTagUpdates(res)));
|
||||||
|
|
||||||
// if we process a lot of syncs (1 every 200ms), this means we clean the
|
// if we process a lot of syncs (1 every 200ms), this means we clean the
|
||||||
// db every 100s
|
// db every 100s
|
||||||
|
@ -1068,7 +1122,7 @@ ChatPage::joinRoom(const QString &room)
|
||||||
const auto room_id = room.toStdString();
|
const auto room_id = room.toStdString();
|
||||||
|
|
||||||
http::client()->join_room(
|
http::client()->join_room(
|
||||||
room_id, [this, room_id](const nlohmann::json &, mtx::http::RequestErr err) {
|
room_id, [this, room_id](const mtx::responses::RoomId &, mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
emit showNotification(
|
emit showNotification(
|
||||||
tr("Failed to join room: %1")
|
tr("Failed to join room: %1")
|
||||||
|
@ -1114,7 +1168,8 @@ void
|
||||||
ChatPage::leaveRoom(const QString &room_id)
|
ChatPage::leaveRoom(const QString &room_id)
|
||||||
{
|
{
|
||||||
http::client()->leave_room(
|
http::client()->leave_room(
|
||||||
room_id.toStdString(), [this, room_id](const json &, mtx::http::RequestErr err) {
|
room_id.toStdString(),
|
||||||
|
[this, room_id](const mtx::responses::Empty &, mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
emit showNotification(
|
emit showNotification(
|
||||||
tr("Failed to leave room: %1")
|
tr("Failed to leave room: %1")
|
||||||
|
@ -1289,62 +1344,6 @@ ChatPage::currentPresence() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err)
|
|
||||||
{
|
|
||||||
// TODO: Initial Sync should include mentions as well...
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
const auto error = QString::fromStdString(err->matrix_error.error);
|
|
||||||
const auto msg = tr("Please try to login again: %1").arg(error);
|
|
||||||
const auto err_code = mtx::errors::to_string(err->matrix_error.errcode);
|
|
||||||
const int status_code = static_cast<int>(err->status_code);
|
|
||||||
|
|
||||||
nhlog::net()->error("initial sync error: {} {}", status_code, err_code);
|
|
||||||
|
|
||||||
// non http related errors
|
|
||||||
if (status_code <= 0 || status_code >= 600) {
|
|
||||||
startInitialSync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (status_code) {
|
|
||||||
case 502:
|
|
||||||
case 504:
|
|
||||||
case 524: {
|
|
||||||
startInitialSync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
emit dropToLoginPageCb(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nhlog::net()->info("initial sync completed");
|
|
||||||
|
|
||||||
try {
|
|
||||||
cache::saveState(res);
|
|
||||||
|
|
||||||
olm::handle_to_device_messages(res.to_device.events);
|
|
||||||
|
|
||||||
emit initializeViews(std::move(res.rooms));
|
|
||||||
emit initializeRoomList(cache::roomInfo());
|
|
||||||
emit initializeMentions(cache::getTimelineMentions());
|
|
||||||
|
|
||||||
cache::calculateRoomReadStatus();
|
|
||||||
emit syncTags(cache::roomInfo().toStdMap());
|
|
||||||
} catch (const lmdb::error &e) {
|
|
||||||
nhlog::db()->error("failed to save state after initial sync: {}", e.what());
|
|
||||||
startInitialSync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit trySyncCb();
|
|
||||||
emit contentLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts)
|
ChatPage::ensureOneTimeKeyCount(const std::map<std::string, uint16_t> &counts)
|
||||||
{
|
{
|
||||||
|
@ -1453,51 +1452,11 @@ ChatPage::initiateLogout()
|
||||||
emit showOverlayProgressBar();
|
emit showOverlayProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ChatPage::query_keys(const std::string &user_id,
|
|
||||||
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb)
|
|
||||||
{
|
|
||||||
auto cache_ = cache::userKeys(user_id);
|
|
||||||
|
|
||||||
if (cache_.has_value()) {
|
|
||||||
if (!cache_->updated_at.empty() && cache_->updated_at == cache_->last_changed) {
|
|
||||||
cb(cache_.value(), {});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mtx::requests::QueryKeys req;
|
|
||||||
req.device_keys[user_id] = {};
|
|
||||||
|
|
||||||
std::string last_changed;
|
|
||||||
if (cache_)
|
|
||||||
last_changed = cache_->last_changed;
|
|
||||||
req.token = last_changed;
|
|
||||||
|
|
||||||
http::client()->query_keys(req,
|
|
||||||
[cb, user_id, last_changed](const mtx::responses::QueryKeys &res,
|
|
||||||
mtx::http::RequestErr err) {
|
|
||||||
if (err) {
|
|
||||||
nhlog::net()->warn(
|
|
||||||
"failed to query device keys: {},{}",
|
|
||||||
err->matrix_error.errcode,
|
|
||||||
static_cast<int>(err->status_code));
|
|
||||||
cb({}, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache::updateUserKeys(last_changed, res);
|
|
||||||
|
|
||||||
auto keys = cache::userKeys(user_id);
|
|
||||||
cb(keys.value_or(UserKeyCache{}), err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void
|
void
|
||||||
ChatPage::connectCallMessage()
|
ChatPage::connectCallMessage()
|
||||||
{
|
{
|
||||||
connect(&callManager_,
|
connect(callManager_,
|
||||||
qOverload<const QString &, const T &>(&CallManager::newMessage),
|
qOverload<const QString &, const T &>(&CallManager::newMessage),
|
||||||
view_manager_,
|
view_manager_,
|
||||||
qOverload<const QString &, const T &>(&TimelineViewManager::queueCallMessage));
|
qOverload<const QString &, const T &>(&TimelineViewManager::queueCallMessage));
|
||||||
|
|
|
@ -23,9 +23,10 @@
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include <mtx/common.hpp>
|
#include <mtx/common.hpp>
|
||||||
#include <mtx/requests.hpp>
|
#include <mtx/events.hpp>
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/events/encrypted.hpp>
|
||||||
#include <mtxclient/http/errors.hpp>
|
#include <mtx/events/member.hpp>
|
||||||
|
#include <mtx/events/presence.hpp>
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
@ -37,11 +38,8 @@
|
||||||
|
|
||||||
#include "CacheCryptoStructs.h"
|
#include "CacheCryptoStructs.h"
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
#include "CallManager.h"
|
|
||||||
#include "CommunitiesList.h"
|
#include "CommunitiesList.h"
|
||||||
#include "Utils.h"
|
|
||||||
#include "notifications/Manager.h"
|
#include "notifications/Manager.h"
|
||||||
#include "popups/UserMentions.h"
|
|
||||||
|
|
||||||
class OverlayModal;
|
class OverlayModal;
|
||||||
class QuickSwitcher;
|
class QuickSwitcher;
|
||||||
|
@ -54,13 +52,25 @@ class UserInfoWidget;
|
||||||
class UserSettings;
|
class UserSettings;
|
||||||
class NotificationsManager;
|
class NotificationsManager;
|
||||||
class TimelineModel;
|
class TimelineModel;
|
||||||
|
class CallManager;
|
||||||
|
|
||||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||||
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
||||||
|
|
||||||
namespace mtx::http {
|
namespace mtx::requests {
|
||||||
using RequestErr = const std::optional<mtx::http::ClientError> &;
|
struct CreateRoom;
|
||||||
|
}
|
||||||
|
namespace mtx::responses {
|
||||||
|
struct Notifications;
|
||||||
|
struct Sync;
|
||||||
|
struct Timeline;
|
||||||
|
struct Rooms;
|
||||||
|
struct LeftRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace popups {
|
||||||
|
class UserMentions;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatPage : public QWidget
|
class ChatPage : public QWidget
|
||||||
|
@ -89,8 +99,6 @@ public:
|
||||||
//! Show the room/group list (if it was visible).
|
//! Show the room/group list (if it was visible).
|
||||||
void showSideBars();
|
void showSideBars();
|
||||||
void initiateLogout();
|
void initiateLogout();
|
||||||
void query_keys(const std::string &req,
|
|
||||||
std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
|
|
||||||
void focusMessageInput();
|
void focusMessageInput();
|
||||||
|
|
||||||
QString status() const;
|
QString status() const;
|
||||||
|
@ -145,12 +153,12 @@ signals:
|
||||||
void trySyncCb();
|
void trySyncCb();
|
||||||
void tryDelayedSyncCb();
|
void tryDelayedSyncCb();
|
||||||
void tryInitialSyncCb();
|
void tryInitialSyncCb();
|
||||||
void newSyncResponse(mtx::responses::Sync res);
|
void newSyncResponse(const mtx::responses::Sync &res);
|
||||||
void leftRoom(const QString &room_id);
|
void leftRoom(const QString &room_id);
|
||||||
|
|
||||||
void initializeRoomList(QMap<QString, RoomInfo>);
|
void initializeRoomList(QMap<QString, RoomInfo>);
|
||||||
void initializeViews(const mtx::responses::Rooms &rooms);
|
void initializeViews(const mtx::responses::Rooms &rooms);
|
||||||
void initializeEmptyViews(const std::map<QString, mtx::responses::Timeline> &msgs);
|
void initializeEmptyViews(const std::vector<QString> &roomIds);
|
||||||
void initializeMentions(const QMap<QString, mtx::responses::Notifications> ¬ifs);
|
void initializeMentions(const QMap<QString, mtx::responses::Notifications> ¬ifs);
|
||||||
void syncUI(const mtx::responses::Rooms &rooms);
|
void syncUI(const mtx::responses::Rooms &rooms);
|
||||||
void syncRoomlist(const std::map<QString, RoomInfo> &updates);
|
void syncRoomlist(const std::map<QString, RoomInfo> &updates);
|
||||||
|
@ -194,14 +202,11 @@ private slots:
|
||||||
|
|
||||||
void joinRoom(const QString &room);
|
void joinRoom(const QString &room);
|
||||||
void sendTypingNotifications();
|
void sendTypingNotifications();
|
||||||
void handleSyncResponse(mtx::responses::Sync res);
|
void handleSyncResponse(const mtx::responses::Sync &res);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ChatPage *instance_;
|
static ChatPage *instance_;
|
||||||
|
|
||||||
//! Handler callback for initial sync. It doesn't run on the main thread so all
|
|
||||||
//! communication with the GUI should be done through signals.
|
|
||||||
void initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err);
|
|
||||||
void startInitialSync();
|
void startInitialSync();
|
||||||
void tryInitialSync();
|
void tryInitialSync();
|
||||||
void trySync();
|
void trySync();
|
||||||
|
@ -276,7 +281,7 @@ private:
|
||||||
QSharedPointer<UserSettings> userSettings_;
|
QSharedPointer<UserSettings> userSettings_;
|
||||||
|
|
||||||
NotificationsManager notificationsManager;
|
NotificationsManager notificationsManager;
|
||||||
CallManager callManager_;
|
CallManager *callManager_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Collection>
|
template<class Collection>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Splitter.h"
|
#include "Splitter.h"
|
||||||
|
|
||||||
#include <mtx/responses/groups.hpp>
|
#include <mtx/responses/groups.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "DeviceVerificationFlow.h"
|
#include "DeviceVerificationFlow.h"
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
|
#include "Cache_p.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
#include "Utils.h"
|
||||||
#include "timeline/TimelineModel.h"
|
#include "timeline/TimelineModel.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
@ -39,7 +41,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
||||||
|
|
||||||
auto user_id = userID.toStdString();
|
auto user_id = userID.toStdString();
|
||||||
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(user_id);
|
this->toClient = mtx::identifiers::parse<mtx::identifiers::User>(user_id);
|
||||||
ChatPage::instance()->query_keys(
|
cache::client()->query_keys(
|
||||||
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
user_id, [user_id, this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
nhlog::net()->warn("failed to query device keys: {},{}",
|
nhlog::net()->warn("failed to query device keys: {},{}",
|
||||||
|
@ -57,7 +59,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
|
||||||
this->their_keys = res;
|
this->their_keys = res;
|
||||||
});
|
});
|
||||||
|
|
||||||
ChatPage::instance()->query_keys(
|
cache::client()->query_keys(
|
||||||
http::client()->user_id().to_string(),
|
http::client()->user_id().to_string(),
|
||||||
[this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
[this](const UserKeyCache &res, mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <mtx/responses/crypto.hpp>
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "CacheCryptoStructs.h"
|
#include "CacheCryptoStructs.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "EventAccessors.h"
|
#include "EventAccessors.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
|
|
||||||
#include <mtx/requests.hpp>
|
#include <mtx/requests.hpp>
|
||||||
|
#include <mtx/responses/login.hpp>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
@ -54,8 +55,8 @@
|
||||||
MainWindow *MainWindow::instance_ = nullptr;
|
MainWindow *MainWindow::instance_ = nullptr;
|
||||||
|
|
||||||
MainWindow::MainWindow(const QString profile, QWidget *parent)
|
MainWindow::MainWindow(const QString profile, QWidget *parent)
|
||||||
: QMainWindow(parent),
|
: QMainWindow(parent)
|
||||||
profile_{ profile }
|
, profile_{profile}
|
||||||
{
|
{
|
||||||
setWindowTitle(0);
|
setWindowTitle(0);
|
||||||
setObjectName("MainWindow");
|
setObjectName("MainWindow");
|
||||||
|
@ -104,8 +105,7 @@ MainWindow::MainWindow(const QString profile, QWidget *parent)
|
||||||
connect(chat_page_, &ChatPage::closing, this, &MainWindow::showWelcomePage);
|
connect(chat_page_, &ChatPage::closing, this, &MainWindow::showWelcomePage);
|
||||||
connect(
|
connect(
|
||||||
chat_page_, &ChatPage::showOverlayProgressBar, this, &MainWindow::showOverlayProgressBar);
|
chat_page_, &ChatPage::showOverlayProgressBar, this, &MainWindow::showOverlayProgressBar);
|
||||||
connect(
|
connect(chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle);
|
||||||
chat_page_, &ChatPage::unreadMessages, this, &MainWindow::setWindowTitle);
|
|
||||||
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int)));
|
connect(chat_page_, SIGNAL(unreadMessages(int)), trayIcon_, SLOT(setUnreadCount(int)));
|
||||||
connect(chat_page_, &ChatPage::showLoginPage, this, [this](const QString &msg) {
|
connect(chat_page_, &ChatPage::showLoginPage, this, [this](const QString &msg) {
|
||||||
login_page_->loginError(msg);
|
login_page_->loginError(msg);
|
||||||
|
@ -185,8 +185,7 @@ MainWindow::setWindowTitle(int notificationCount)
|
||||||
QString name = "nheko";
|
QString name = "nheko";
|
||||||
if (!profile_.isEmpty())
|
if (!profile_.isEmpty())
|
||||||
name += " | " + profile_;
|
name += " | " + profile_;
|
||||||
if (notificationCount > 0)
|
if (notificationCount > 0) {
|
||||||
{
|
|
||||||
name.append(QString{" (%1)"}.arg(notificationCount));
|
name.append(QString{" (%1)"}.arg(notificationCount));
|
||||||
}
|
}
|
||||||
QMainWindow::setWindowTitle(name);
|
QMainWindow::setWindowTitle(name);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "MxcImageProvider.h"
|
#include "MxcImageProvider.h"
|
||||||
|
|
||||||
|
#include <mtxclient/crypto/client.hpp>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
|
16
src/Olm.cpp
16
src/Olm.cpp
|
@ -1,6 +1,7 @@
|
||||||
#include "Olm.h"
|
#include "Olm.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
|
@ -20,6 +21,21 @@ auto client_ = std::make_unique<mtx::crypto::OlmClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace olm {
|
namespace olm {
|
||||||
|
void
|
||||||
|
from_json(const nlohmann::json &obj, OlmMessage &msg)
|
||||||
|
{
|
||||||
|
if (obj.at("type") != "m.room.encrypted")
|
||||||
|
throw std::invalid_argument("invalid type for olm message");
|
||||||
|
|
||||||
|
if (obj.at("content").at("algorithm") != OLM_ALGO)
|
||||||
|
throw std::invalid_argument("invalid algorithm for olm message");
|
||||||
|
|
||||||
|
msg.sender = obj.at("sender");
|
||||||
|
msg.sender_key = obj.at("content").at("sender_key");
|
||||||
|
msg.ciphertext = obj.at("content")
|
||||||
|
.at("ciphertext")
|
||||||
|
.get<std::map<std::string, mtx::events::msg::OlmCipherContent>>();
|
||||||
|
}
|
||||||
|
|
||||||
mtx::crypto::OlmClient *
|
mtx::crypto::OlmClient *
|
||||||
client()
|
client()
|
||||||
|
|
17
src/Olm.h
17
src/Olm.h
|
@ -40,21 +40,8 @@ struct OlmMessage
|
||||||
std::map<RecipientKey, mtx::events::msg::OlmCipherContent> ciphertext;
|
std::map<RecipientKey, mtx::events::msg::OlmCipherContent> ciphertext;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void
|
void
|
||||||
from_json(const nlohmann::json &obj, OlmMessage &msg)
|
from_json(const nlohmann::json &obj, OlmMessage &msg);
|
||||||
{
|
|
||||||
if (obj.at("type") != "m.room.encrypted")
|
|
||||||
throw std::invalid_argument("invalid type for olm message");
|
|
||||||
|
|
||||||
if (obj.at("content").at("algorithm") != OLM_ALGO)
|
|
||||||
throw std::invalid_argument("invalid algorithm for olm message");
|
|
||||||
|
|
||||||
msg.sender = obj.at("sender");
|
|
||||||
msg.sender_key = obj.at("content").at("sender_key");
|
|
||||||
msg.ciphertext = obj.at("content")
|
|
||||||
.at("ciphertext")
|
|
||||||
.get<std::map<std::string, mtx::events::msg::OlmCipherContent>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
mtx::crypto::OlmClient *
|
mtx::crypto::OlmClient *
|
||||||
client();
|
client();
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/responses/sync.hpp>
|
||||||
|
|
||||||
#include "CacheStructs.h"
|
#include "CacheStructs.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFontComboBox>
|
#include <QFontComboBox>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QtQml>
|
#include <QtQml>
|
||||||
#include <QCoreApplication>
|
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
@ -450,7 +450,8 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
||||||
|
|
||||||
auto versionInfo = new QLabel(QString("%1 | %2").arg(nheko::version).arg(nheko::build_os));
|
auto versionInfo = new QLabel(QString("%1 | %2").arg(nheko::version).arg(nheko::build_os));
|
||||||
if (QCoreApplication::applicationName() != "nheko")
|
if (QCoreApplication::applicationName() != "nheko")
|
||||||
versionInfo->setText(versionInfo->text() + " | " + tr("profile: %1").arg(QCoreApplication::applicationName()));
|
versionInfo->setText(versionInfo->text() + " | " +
|
||||||
|
tr("profile: %1").arg(QCoreApplication::applicationName()));
|
||||||
versionInfo->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
versionInfo->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
|
|
||||||
topBarLayout_ = new QHBoxLayout;
|
topBarLayout_ = new QHBoxLayout;
|
||||||
|
@ -904,11 +905,7 @@ UserSettingsPage::importSessionKeys()
|
||||||
auto sessions =
|
auto sessions =
|
||||||
mtx::crypto::decrypt_exported_sessions(payload, password.toStdString());
|
mtx::crypto::decrypt_exported_sessions(payload, password.toStdString());
|
||||||
cache::importSessionKeys(std::move(sessions));
|
cache::importSessionKeys(std::move(sessions));
|
||||||
} catch (const mtx::crypto::sodium_exception &e) {
|
} catch (const std::exception &e) {
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
|
||||||
} catch (const lmdb::error &e) {
|
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
|
||||||
} catch (const nlohmann::json::exception &e) {
|
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
QMessageBox::warning(this, tr("Error"), e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -956,11 +953,7 @@ UserSettingsPage::exportSessionKeys()
|
||||||
QTextStream out(&file);
|
QTextStream out(&file);
|
||||||
out << prefix << newline << b64 << newline << suffix;
|
out << prefix << newline << b64 << newline << suffix;
|
||||||
file.close();
|
file.close();
|
||||||
} catch (const mtx::crypto::sodium_exception &e) {
|
} catch (const std::exception &e) {
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
|
||||||
} catch (const lmdb::error &e) {
|
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
|
||||||
} catch (const nlohmann::json::exception &e) {
|
|
||||||
QMessageBox::warning(this, tr("Error"), e.what());
|
QMessageBox::warning(this, tr("Error"), e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "dialogs/RoomSettings.h"
|
#include "dialogs/RoomSettings.h"
|
||||||
|
#include <mtx/responses/common.hpp>
|
||||||
|
#include <mtx/responses/media.hpp>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -107,29 +107,24 @@ main(int argc, char *argv[])
|
||||||
// needed for settings so need to register before any settings are read to prevent warnings
|
// needed for settings so need to register before any settings are read to prevent warnings
|
||||||
qRegisterMetaType<UserSettings::Presence>();
|
qRegisterMetaType<UserSettings::Presence>();
|
||||||
|
|
||||||
// This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name parsed
|
// This is some hacky programming, but it's necessary (AFAIK?) to get the unique config name
|
||||||
// before the app name is set.
|
// parsed before the app name is set.
|
||||||
QString appName{"nheko"};
|
QString appName{"nheko"};
|
||||||
for (int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i) {
|
||||||
{
|
if (QString{argv[i]}.startsWith("--profile=")) {
|
||||||
if (QString{argv[i]}.startsWith("--profile="))
|
|
||||||
{
|
|
||||||
QString q{argv[i]};
|
QString q{argv[i]};
|
||||||
q.remove("--profile=");
|
q.remove("--profile=");
|
||||||
appName += "-" + q;
|
appName += "-" + q;
|
||||||
}
|
} else if (QString{argv[i]}.startsWith("--p=")) {
|
||||||
else if (QString{argv[i]}.startsWith("--p="))
|
|
||||||
{
|
|
||||||
QString q{argv[i]};
|
QString q{argv[i]};
|
||||||
q.remove("-p=");
|
q.remove("-p=");
|
||||||
appName += "-" + q;
|
appName += "-" + q;
|
||||||
}
|
} else if (QString{argv[i]} == "--profile" || QString{argv[i]} == "-p") {
|
||||||
else if (QString{argv[i]} == "--profile" || QString{argv[i]} == "-p")
|
if (i < argc - 1) // if i is less than argc - 1, we still have a parameter
|
||||||
{
|
// left to process as the name
|
||||||
if (i < argc -1) // if i is less than argc - 1, we still have a parameter left to process as the name
|
|
||||||
{
|
{
|
||||||
++i; // the next arg is the name, so increment
|
++i; // the next arg is the name, so increment
|
||||||
appName += "-" + QString {argv[i]};
|
appName += "-" + QString{argv[i]};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,9 +163,13 @@ main(int argc, char *argv[])
|
||||||
// This option is not actually parsed via Qt due to the need to parse it before the app
|
// This option is not actually parsed via Qt due to the need to parse it before the app
|
||||||
// name is set. It only exists to keep Qt from complaining about the --profile/-p
|
// name is set. It only exists to keep Qt from complaining about the --profile/-p
|
||||||
// option and thereby crashing the app.
|
// option and thereby crashing the app.
|
||||||
QCommandLineOption configName(QStringList() << "p" << "profile",
|
QCommandLineOption configName(
|
||||||
QCoreApplication::tr("Create a unique profile, which allows you to log into several accounts at the same time and start multiple instances of nheko."),
|
QStringList() << "p"
|
||||||
QCoreApplication::tr("profile"), QCoreApplication::tr("profile name"));
|
<< "profile",
|
||||||
|
QCoreApplication::tr("Create a unique profile, which allows you to log into several "
|
||||||
|
"accounts at the same time and start multiple instances of nheko."),
|
||||||
|
QCoreApplication::tr("profile"),
|
||||||
|
QCoreApplication::tr("profile name"));
|
||||||
parser.addOption(configName);
|
parser.addOption(configName);
|
||||||
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
@ -217,7 +216,7 @@ main(int argc, char *argv[])
|
||||||
appTranslator.load(QLocale(), "nheko", "_", ":/translations");
|
appTranslator.load(QLocale(), "nheko", "_", ":/translations");
|
||||||
app.installTranslator(&appTranslator);
|
app.installTranslator(&appTranslator);
|
||||||
|
|
||||||
MainWindow w{ (appName == "nheko" ? "" : appName.remove("nheko-")) };
|
MainWindow w{(appName == "nheko" ? "" : appName.remove("nheko-"))};
|
||||||
|
|
||||||
// Move the MainWindow to the center
|
// Move the MainWindow to the center
|
||||||
w.move(screenCenter(w.width(), w.height()));
|
w.move(screenCenter(w.width(), w.height()));
|
||||||
|
|
|
@ -19,6 +19,12 @@ SuggestionsPopup::SuggestionsPopup(QWidget *parent)
|
||||||
layout_->setSpacing(0);
|
layout_->setSpacing(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
SuggestionsPopup::displayName(QString room, QString user)
|
||||||
|
{
|
||||||
|
return cache::displayName(room, user);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
|
SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
|
|
||||||
const auto &widget = qobject_cast<Item *>(item->widget());
|
const auto &widget = qobject_cast<Item *>(item->widget());
|
||||||
emit itemSelected(
|
emit itemSelected(
|
||||||
cache::displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
|
displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
|
||||||
|
|
||||||
resetSelection();
|
resetSelection();
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ signals:
|
||||||
void itemSelected(const QString &user);
|
void itemSelected(const QString &user);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString displayName(QString roomid, QString userid);
|
||||||
void hoverSelection();
|
void hoverSelection();
|
||||||
void resetSelection() { selectedItem_ = -1; }
|
void resetSelection() { selectedItem_ = -1; }
|
||||||
void selectFirstItem() { selectedItem_ = 0; }
|
void selectFirstItem() { selectedItem_ = 0; }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/responses/notifications.hpp>
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <mtx/responses/common.hpp>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
@ -10,6 +12,7 @@
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "Olm.h"
|
#include "Olm.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Reaction)
|
Q_DECLARE_METATYPE(Reaction)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
#include "ColorImageProvider.h"
|
#include "ColorImageProvider.h"
|
||||||
#include "DelegateChooser.h"
|
#include "DelegateChooser.h"
|
||||||
|
#include "DeviceVerificationFlow.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
@ -450,13 +451,10 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs)
|
TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
|
||||||
{
|
{
|
||||||
for (const auto &e : msgs) {
|
for (const auto &roomId : roomIds)
|
||||||
addRoom(e.first);
|
addRoom(roomId);
|
||||||
|
|
||||||
models.value(e.first)->addEvents(e.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <mtx/common.hpp>
|
#include <mtx/common.hpp>
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/responses/messages.hpp>
|
||||||
|
#include <mtx/responses/sync.hpp>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "CallManager.h"
|
#include "CallManager.h"
|
||||||
#include "DeviceVerificationFlow.h"
|
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "TimelineModel.h"
|
#include "TimelineModel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
@ -24,6 +24,7 @@ class BlurhashProvider;
|
||||||
class ColorImageProvider;
|
class ColorImageProvider;
|
||||||
class UserSettings;
|
class UserSettings;
|
||||||
class ChatPage;
|
class ChatPage;
|
||||||
|
class DeviceVerificationFlow;
|
||||||
|
|
||||||
class TimelineViewManager : public QObject
|
class TimelineViewManager : public QObject
|
||||||
{
|
{
|
||||||
|
@ -93,7 +94,7 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||||
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
|
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
|
||||||
void initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs);
|
void initWithMessages(const std::vector<QString> &roomIds);
|
||||||
|
|
||||||
void setHistoryView(const QString &room_id);
|
void setHistoryView(const QString &room_id);
|
||||||
void updateColorPalette();
|
void updateColorPalette();
|
||||||
|
|
|
@ -117,7 +117,7 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
{
|
{
|
||||||
auto localUser = utils::localUser();
|
auto localUser = utils::localUser();
|
||||||
|
|
||||||
ChatPage::instance()->query_keys(
|
cache::client()->query_keys(
|
||||||
userID.toStdString(),
|
userID.toStdString(),
|
||||||
[other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
|
[other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
|
||||||
mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
|
@ -129,7 +129,7 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finding if the User is Verified or not based on the Signatures
|
// Finding if the User is Verified or not based on the Signatures
|
||||||
ChatPage::instance()->query_keys(
|
cache::client()->query_keys(
|
||||||
utils::localUser().toStdString(),
|
utils::localUser().toStdString(),
|
||||||
[other_user_id, other_user_keys, this](const UserKeyCache &res,
|
[other_user_id, other_user_keys, this](const UserKeyCache &res,
|
||||||
mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
|
||||||
|
|
||||||
namespace verification {
|
namespace verification {
|
||||||
Q_NAMESPACE
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
@ -116,8 +114,4 @@ private:
|
||||||
bool isUserVerified = false;
|
bool isUserVerified = false;
|
||||||
TimelineViewManager *manager;
|
TimelineViewManager *manager;
|
||||||
TimelineModel *model;
|
TimelineModel *model;
|
||||||
|
|
||||||
void callback_fn(const mtx::responses::QueryKeys &res,
|
|
||||||
mtx::http::RequestErr err,
|
|
||||||
std::string user_id);
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue