diff --git a/.ci/script.sh b/.ci/script.sh
index 63e7f135..f43a6efb 100755
--- a/.ci/script.sh
+++ b/.ci/script.sh
@@ -71,7 +71,6 @@ cmake -GNinja -H. -Bbuild \
-DHUNTER_ROOT=".hunter" \
-DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DHUNTER_CONFIGURATION_TYPES=RelWithDebInfo \
- -DUSE_BUNDLED_OPENSSL=OFF \
-DCI_BUILD=ON
fi
cmake --build build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b47b0af..b2b8da3b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,7 @@ option(APPVEYOR_BUILD "Build on appveyor" OFF)
option(CI_BUILD "Set when building in CI. Enables -Werror where possible" OFF)
option(ASAN "Compile with address sanitizers" OFF)
option(QML_DEBUGGING "Enable qml debugging" OFF)
+option(COMPILE_QML "Compile Qml. It will make Nheko faster, but you will need to recompile it, when you update Qt." OFF)
set(
CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/toolchain.cmake"
@@ -17,10 +18,9 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "compile as PIC by default")
option(HUNTER_ENABLED "Enable Hunter package manager" OFF)
include("cmake/HunterGate.cmake")
HunterGate(
- URL "https://github.com/cpp-pm/hunter/archive/v0.23.244.tar.gz"
- SHA1 "2c0f491fd0b80f7b09e3d21adb97237161ef9835"
- LOCAL
- )
+ URL "https://github.com/cpp-pm/hunter/archive/v0.23.260.tar.gz"
+ SHA1 "13775235910a3fa85644568d1c5be8271de72e1c"
+)
option(USE_BUNDLED_BOOST "Use the bundled version of Boost." ${HUNTER_ENABLED})
option(USE_BUNDLED_SPDLOG "Use the bundled version of spdlog."
@@ -35,8 +35,6 @@ option(USE_BUNDLED_JSON "Use the bundled version of nlohmann json."
option(USE_BUNDLED_OPENSSL "Use the bundled version of OpenSSL."
${HUNTER_ENABLED})
option(USE_BUNDLED_MTXCLIENT "Use the bundled version of the Matrix Client library." ${HUNTER_ENABLED})
-option(USE_BUNDLED_SODIUM "Use the bundled version of libsodium."
- ${HUNTER_ENABLED})
option(USE_BUNDLED_LMDB "Use the bundled version of lmdb."
${HUNTER_ENABLED})
option(USE_BUNDLED_LMDBXX "Use the bundled version of lmdb++."
@@ -334,7 +332,7 @@ find_package(Boost 1.70 REQUIRED
if(USE_BUNDLED_OPENSSL)
hunter_add_package(OpenSSL)
endif()
-find_package(OpenSSL REQUIRED)
+find_package(OpenSSL 1.1.0 REQUIRED)
if(USE_BUNDLED_MTXCLIENT)
include(FetchContent)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
@@ -342,7 +340,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
- GIT_TAG v0.3.1
+ GIT_TAG eddd95a896fad0c51fc800741d82bbc43fc6d41e
)
FetchContent_MakeAvailable(MatrixClient)
else()
diff --git a/README.md b/README.md
index cb5685d5..20340a46 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,6 @@ brew cask install nheko
- [cmark](https://github.com/commonmark/cmark) 0.29 or greater.
- Boost 1.70 or greater.
- [libolm](https://gitlab.matrix.org/matrix-org/olm)
-- [libsodium](https://github.com/jedisct1/libsodium)
- [spdlog](https://github.com/gabime/spdlog)
- A compiler that supports C++ 17:
- Clang 6 (tested on Travis CI)
@@ -136,8 +135,6 @@ The bundle flags are currently:
- USE_BUNDLED_JSON
- USE_BUNDLED_OPENSSL
- USE_BUNDLED_MTXCLIENT
-- USE_BUNDLED_SODIUM
-- USE_BUNDLED_ZLIB
- USE_BUNDLED_LMDB
- USE_BUNDLED_LMDBXX
- USE_BUNDLED_TWEENY
@@ -162,8 +159,7 @@ sudo pacman -S qt5-base \
fontconfig \
lmdb \
cmark \
- boost \
- libsodium
+ boost
```
##### Gentoo Linux
@@ -176,7 +172,7 @@ sudo emerge -a ">=dev-qt/qtgui-5.9.0" media-libs/fontconfig
```bash
# Build requirements + qml modules needed at runtime (you may not need all of them, but the following seem to work according to reports):
-sudo apt install g++ cmake zlib1g-dev libssl-dev qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt5svg5-dev libboost-system-dev libboost-thread-dev libboost-iostreams-dev libolm-dev libsodium-dev liblmdb++-dev libcmark-dev nlohmann-json3-dev libspdlog-dev libgtest-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,graphicaleffects,quick-controls2}
+sudo apt install g++ cmake zlib1g-dev libssl-dev qt{base,declarative,tools,multimedia,quickcontrols2-}5-dev libqt5svg5-dev libboost-system-dev libboost-thread-dev libboost-iostreams-dev libolm-dev liblmdb++-dev libcmark-dev nlohmann-json3-dev libspdlog-dev libgtest-dev qml-module-qt{gstreamer,multimedia,quick-extras,-labs-settings,graphicaleffects,quick-controls2}
```
This will install all dependencies, except for tweeny (use bundled tweeny)
and mtxclient (needs to be build separately).
@@ -186,7 +182,7 @@ and mtxclient (needs to be build separately).
(User report, not sure if all of those are needed)
```bash
-sudo apt install cmake gcc make automake liblmdb-dev libsodium-dev \
+sudo apt install cmake gcc make automake liblmdb-dev \
qt5-default libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev \
qml-module-qtgstreamer qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools \
qml-module-qtgraphicaleffects qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts
@@ -203,7 +199,7 @@ guix environment nheko
```bash
brew update
-brew install qt5 lmdb cmake llvm libsodium spdlog boost cmark libolm
+brew install qt5 lmdb cmake llvm spdlog boost cmark libolm
```
##### Windows
diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake
index d2f87774..7c53e0ea 100644
--- a/cmake/Hunter/config.cmake
+++ b/cmake/Hunter/config.cmake
@@ -1,5 +1,5 @@
hunter_config(
Boost
- VERSION "1.70.0-p0"
+ VERSION "1.70.0-p1"
CMAKE_ARGS IOSTREAMS_NO_BZIP2=1
)
diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake
index e78d3e89..6d9cc240 100644
--- a/cmake/HunterGate.cmake
+++ b/cmake/HunterGate.cmake
@@ -133,10 +133,14 @@ function(hunter_gate_self root version sha1 result)
string(SUBSTRING "${sha1}" 0 7 archive_id)
- set(
- hunter_self
- "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
- )
+ if(EXISTS "${root}/cmake/Hunter")
+ set(hunter_self "${root}")
+ else()
+ set(
+ hunter_self
+ "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
+ )
+ endif()
set("${result}" "${hunter_self}" PARENT_SCOPE)
endfunction()
@@ -490,37 +494,44 @@ macro(HunterGate)
)
set(_master_location "${_hunter_self}/cmake/Hunter")
- get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
- set(_done_location "${_archive_id_location}/DONE")
- set(_sha1_location "${_archive_id_location}/SHA1")
+ if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter")
+ # Hunter downloaded manually (e.g. by 'git clone')
+ set(_unused "xxxxxxxxxx")
+ set(HUNTER_GATE_SHA1 "${_unused}")
+ set(HUNTER_GATE_VERSION "${_unused}")
+ else()
+ get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
+ set(_done_location "${_archive_id_location}/DONE")
+ set(_sha1_location "${_archive_id_location}/SHA1")
- # Check Hunter already downloaded by HunterGate
- if(NOT EXISTS "${_done_location}")
- hunter_gate_download("${_archive_id_location}")
- endif()
+ # Check Hunter already downloaded by HunterGate
+ if(NOT EXISTS "${_done_location}")
+ hunter_gate_download("${_archive_id_location}")
+ endif()
- if(NOT EXISTS "${_done_location}")
- hunter_gate_internal_error("hunter_gate_download failed")
- endif()
+ if(NOT EXISTS "${_done_location}")
+ hunter_gate_internal_error("hunter_gate_download failed")
+ endif()
- if(NOT EXISTS "${_sha1_location}")
- hunter_gate_internal_error("${_sha1_location} not found")
- endif()
- file(READ "${_sha1_location}" _sha1_value)
- string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
- if(NOT _is_equal)
- hunter_gate_internal_error(
- "Short SHA1 collision:"
- " ${_sha1_value} (from ${_sha1_location})"
- " ${HUNTER_GATE_SHA1} (HunterGate)"
- )
- endif()
- if(NOT EXISTS "${_master_location}")
- hunter_gate_user_error(
- "Master file not found:"
- " ${_master_location}"
- "try to update Hunter/HunterGate"
- )
+ if(NOT EXISTS "${_sha1_location}")
+ hunter_gate_internal_error("${_sha1_location} not found")
+ endif()
+ file(READ "${_sha1_location}" _sha1_value)
+ string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
+ if(NOT _is_equal)
+ hunter_gate_internal_error(
+ "Short SHA1 collision:"
+ " ${_sha1_value} (from ${_sha1_location})"
+ " ${HUNTER_GATE_SHA1} (HunterGate)"
+ )
+ endif()
+ if(NOT EXISTS "${_master_location}")
+ hunter_gate_user_error(
+ "Master file not found:"
+ " ${_master_location}"
+ "try to update Hunter/HunterGate"
+ )
+ endif()
endif()
include("${_master_location}")
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake
index 16120219..887697a8 100644
--- a/cmake/Translations.cmake
+++ b/cmake/Translations.cmake
@@ -21,7 +21,7 @@ if(NOT EXISTS ${_qrc})
endif()
qt5_add_resources(LANG_QRC ${_qrc})
-if(Qt5QuickCompiler_FOUND)
+if(Qt5QuickCompiler_FOUND AND COMPILE_QML)
qtquick_compiler_add_resources(QRC resources/res.qrc)
else()
qt5_add_resources(QRC resources/res.qrc)
diff --git a/io.github.NhekoReborn.Nheko.json b/io.github.NhekoReborn.Nheko.json
index 33acf34b..8e4dbbe6 100644
--- a/io.github.NhekoReborn.Nheko.json
+++ b/io.github.NhekoReborn.Nheko.json
@@ -146,9 +146,9 @@
"name": "mtxclient",
"sources": [
{
- "sha256": "e4899cc4ce87397de2aef865e94ea2cdb8d9cb86253727e7d90532b925ecc770",
+ "sha256": "6334bb71821a0fde54fe24f02ad393cdb6836633557ffdd239b29c5d5108daaf",
"type": "archive",
- "url": "https://github.com/Nheko-Reborn/mtxclient/archive/v0.3.1.tar.gz"
+ "url": "https://github.com/Nheko-Reborn/mtxclient/archive/eddd95a896fad0c51fc800741d82bbc43fc6d41e.tar.gz"
}
]
},
@@ -171,7 +171,8 @@
{
"config-opts": [
"-DCMAKE_BUILD_TYPE=Release",
- "-DLMDBXX_INCLUDE_DIR=.deps/lmdbxx"
+ "-DLMDBXX_INCLUDE_DIR=.deps/lmdbxx",
+ "-DCOMPILE_QML=ON"
],
"buildsystem": "cmake-ninja",
"name": "nheko",
diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml
index 9a4f7348..d56143dd 100644
--- a/resources/qml/MatrixText.qml
+++ b/resources/qml/MatrixText.qml
@@ -16,7 +16,7 @@ TextEdit {
timelineManager.setHistoryView(match[1])
chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain)
}
- else Qt.openUrlExternally(link)
+ else timelineManager.openLink(link)
}
MouseArea
{
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 1bea8564..c83ce350 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -589,8 +589,12 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
emit notificationsRetrieved(std::move(res));
});
});
- connect(this, &ChatPage::syncRoomlist, room_list_, &RoomList::sync);
- connect(this, &ChatPage::syncTags, communitiesList_, &CommunitiesList::syncTags);
+ connect(this, &ChatPage::syncRoomlist, room_list_, &RoomList::sync, Qt::QueuedConnection);
+ connect(this,
+ &ChatPage::syncTags,
+ communitiesList_,
+ &CommunitiesList::syncTags,
+ Qt::QueuedConnection);
connect(
this, &ChatPage::syncTopBar, this, [this](const std::map<QString, RoomInfo> &updates) {
if (updates.find(currentRoom()) != updates.end())
@@ -605,11 +609,15 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
user_info_widget_->setDisplayName(name);
});
- connect(this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync);
- connect(this, &ChatPage::trySyncCb, this, &ChatPage::trySync);
- connect(this, &ChatPage::tryDelayedSyncCb, this, [this]() {
- QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync);
- });
+ connect(
+ this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync, Qt::QueuedConnection);
+ connect(this, &ChatPage::trySyncCb, this, &ChatPage::trySync, Qt::QueuedConnection);
+ connect(
+ this,
+ &ChatPage::tryDelayedSyncCb,
+ this,
+ [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
+ Qt::QueuedConnection);
connect(this, &ChatPage::dropToLoginPageCb, this, &ChatPage::dropToLoginPage);
diff --git a/src/Config.h b/src/Config.h
index f99cf36b..c0624709 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -53,9 +53,9 @@ namespace strings {
const QString url_html = "<a href=\"\\1\">\\1</a>";
const QRegularExpression url_regex(
// match an URL, that is not quoted, i.e.
- // vvvvvv match quote via negative lookahead/lookbehind vv
- // vvvv atomic match url -> fail if there is a " before or after vvv
- R"((?<!")(?>((www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'"]+[^!,\.\s<>'"\]\)\:]))(?!"))");
+ // vvvvvv match quote via negative lookahead/lookbehind vv
+ // vvvv atomic match url -> fail if there is a " before or after vvv
+ R"((?<!["'])(?>((www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'"]+[^!,\.\s<>'"\]\)\:]))(?!["']))");
}
// Window geometry.
diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index a2d8adbb..7071819b 100644
--- a/src/EventAccessors.cpp
+++ b/src/EventAccessors.cpp
@@ -85,8 +85,10 @@ struct EventFormattedBody
template<class T>
std::string operator()(const mtx::events::RoomEvent<T> &e)
{
- if constexpr (is_detected<formatted_body_t, T>::value)
- return e.content.formatted_body;
+ if constexpr (is_detected<formatted_body_t, T>::value) {
+ if (e.content.format == "org.matrix.custom.html")
+ return e.content.formatted_body;
+ }
return "";
}
};
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index cdbd36c5..aaaf7d4a 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -159,72 +159,96 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
, room_id_(room_id)
, manager_(manager)
{
+ connect(this,
+ &TimelineModel::oldMessagesRetrieved,
+ this,
+ &TimelineModel::addBackwardsEvents,
+ Qt::QueuedConnection);
connect(
- this, &TimelineModel::oldMessagesRetrieved, this, &TimelineModel::addBackwardsEvents);
- connect(this, &TimelineModel::messageFailed, this, [this](QString txn_id) {
- nhlog::ui()->error("Failed to send {}, retrying", txn_id.toStdString());
-
- QTimer::singleShot(5000, this, [this]() { emit nextPendingMessage(); });
- });
- connect(this, &TimelineModel::messageSent, this, [this](QString txn_id, QString event_id) {
- pending.removeOne(txn_id);
+ this,
+ &TimelineModel::messageFailed,
+ this,
+ [this](QString txn_id) {
+ nhlog::ui()->error("Failed to send {}, retrying", txn_id.toStdString());
- auto ev = events.value(txn_id);
+ QTimer::singleShot(5000, this, [this]() { emit nextPendingMessage(); });
+ },
+ Qt::QueuedConnection);
+ connect(
+ this,
+ &TimelineModel::messageSent,
+ this,
+ [this](QString txn_id, QString event_id) {
+ pending.removeOne(txn_id);
- if (auto reaction =
- std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&ev)) {
- QString reactedTo =
- QString::fromStdString(reaction->content.relates_to.event_id);
- auto &rModel = reactions[reactedTo];
- rModel.removeReaction(*reaction);
- auto rCopy = *reaction;
- rCopy.event_id = event_id.toStdString();
- rModel.addReaction(room_id_.toStdString(), rCopy);
- }
+ auto ev = events.value(txn_id);
- int idx = idToIndex(txn_id);
- if (idx < 0) {
- // transaction already received via sync
- return;
- }
- eventOrder[idx] = event_id;
- ev = std::visit(
- [event_id](const auto &e) -> mtx::events::collections::TimelineEvents {
- auto eventCopy = e;
- eventCopy.event_id = event_id.toStdString();
- return eventCopy;
- },
- ev);
+ if (auto reaction =
+ std::get_if<mtx::events::RoomEvent<mtx::events::msg::Reaction>>(&ev)) {
+ QString reactedTo =
+ QString::fromStdString(reaction->content.relates_to.event_id);
+ auto &rModel = reactions[reactedTo];
+ rModel.removeReaction(*reaction);
+ auto rCopy = *reaction;
+ rCopy.event_id = event_id.toStdString();
+ rModel.addReaction(room_id_.toStdString(), rCopy);
+ }
- events.remove(txn_id);
- events.insert(event_id, ev);
+ int idx = idToIndex(txn_id);
+ if (idx < 0) {
+ // transaction already received via sync
+ return;
+ }
+ eventOrder[idx] = event_id;
+ ev = std::visit(
+ [event_id](const auto &e) -> mtx::events::collections::TimelineEvents {
+ auto eventCopy = e;
+ eventCopy.event_id = event_id.toStdString();
+ return eventCopy;
+ },
+ ev);
- // mark our messages as read
- readEvent(event_id.toStdString());
+ events.remove(txn_id);
+ events.insert(event_id, ev);
- emit dataChanged(index(idx, 0), index(idx, 0));
+ // mark our messages as read
+ readEvent(event_id.toStdString());
- if (pending.size() > 0)
- emit nextPendingMessage();
- });
- connect(this, &TimelineModel::redactionFailed, this, [](const QString &msg) {
- emit ChatPage::instance()->showNotification(msg);
- });
+ emit dataChanged(index(idx, 0), index(idx, 0));
+ if (pending.size() > 0)
+ emit nextPendingMessage();
+ },
+ Qt::QueuedConnection);
connect(
- this, &TimelineModel::nextPendingMessage, this, &TimelineModel::processOnePendingMessage);
- connect(this, &TimelineModel::newMessageToSend, this, &TimelineModel::addPendingMessage);
+ this,
+ &TimelineModel::redactionFailed,
+ this,
+ [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
+ Qt::QueuedConnection);
connect(this,
- &TimelineModel::eventFetched,
+ &TimelineModel::nextPendingMessage,
this,
- [this](QString requestingEvent, mtx::events::collections::TimelineEvents event) {
- events.insert(QString::fromStdString(mtx::accessors::event_id(event)),
- event);
- auto idx = idToIndex(requestingEvent);
- if (idx >= 0)
- emit dataChanged(index(idx, 0), index(idx, 0));
- });
+ &TimelineModel::processOnePendingMessage,
+ Qt::QueuedConnection);
+ connect(this,
+ &TimelineModel::newMessageToSend,
+ this,
+ &TimelineModel::addPendingMessage,
+ Qt::QueuedConnection);
+
+ connect(
+ this,
+ &TimelineModel::eventFetched,
+ this,
+ [this](QString requestingEvent, mtx::events::collections::TimelineEvents event) {
+ events.insert(QString::fromStdString(mtx::accessors::event_id(event)), event);
+ auto idx = idToIndex(requestingEvent);
+ if (idx >= 0)
+ emit dataChanged(index(idx, 0), index(idx, 0));
+ },
+ Qt::QueuedConnection);
}
QHash<int, QByteArray>
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index b652b78e..84be895f 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -1,5 +1,6 @@
#include "TimelineViewManager.h"
+#include <QDesktopServices>
#include <QMetaType>
#include <QPalette>
#include <QQmlContext>
@@ -112,7 +113,10 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
container = view;
view->setResizeMode(QQuickWidget::SizeRootObjectToView);
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
view->quickWindow()->setTextRenderType(QQuickWindow::NativeTextRendering);
+#endif
connect(view, &QQuickWidget::statusChanged, this, [](QQuickWidget::Status status) {
nhlog::ui()->debug("Status changed to {}", status);
@@ -232,6 +236,12 @@ TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const
}
void
+TimelineViewManager::openLink(QString link) const
+{
+ QDesktopServices::openUrl(link);
+}
+
+void
TimelineViewManager::updateReadReceipts(const QString &room_id,
const std::vector<QString> &event_ids)
{
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 5224cd56..902dc047 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -50,6 +50,8 @@ public:
Q_INVOKABLE QString userPresence(QString id) const;
Q_INVOKABLE QString userStatus(QString id) const;
+ Q_INVOKABLE void openLink(QString link) const;
+
signals:
void clearRoomMessageCount(QString roomid);
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
diff --git a/src/ui/SnackBar.cpp b/src/ui/SnackBar.cpp
index 5daa697e..51a0ff38 100644
--- a/src/ui/SnackBar.cpp
+++ b/src/ui/SnackBar.cpp
@@ -63,7 +63,7 @@ SnackBar::hideMessage()
// Moving on to the next message.
messages_.pop_front();
- // Reseting the starting position of the widget.
+ // Resetting the starting position of the widget.
offset_ = STARTING_OFFSET;
if (!messages_.empty())
|