diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 3b80d020..d0356e15 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -1,6 +1,7 @@
#include "TimelineViewManager.h"
#include <QDesktopServices>
+#include <QDropEvent>
#include <QMetaType>
#include <QPalette>
#include <QQmlContext>
@@ -20,6 +21,7 @@
#include "dialogs/ImageOverlay.h"
#include "emoji/EmojiModel.h"
#include "emoji/Provider.h"
+#include "ui/NhekoDropArea.h"
#include <iostream> //only for debugging
@@ -115,6 +117,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
+ qmlRegisterType<NhekoDropArea>("im.nheko", 1, 0, "NhekoDropArea");
qmlRegisterUncreatableType<DeviceVerificationFlow>(
"im.nheko", 1, 0, "DeviceVerificationFlow", "Can't create verification flow from QML!");
qmlRegisterUncreatableType<UserProfile>(
@@ -244,6 +247,26 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
&CallManager::newVideoCallState,
this,
&TimelineViewManager::videoCallChanged);
+
+ connect(&WebRTCSession::instance(),
+ &WebRTCSession::stateChanged,
+ this,
+ &TimelineViewManager::onCallChanged);
+}
+
+bool
+TimelineViewManager::isOnCall() const
+{
+ return callManager_->onActiveCall();
+}
+bool
+TimelineViewManager::callsSupported() const
+{
+#ifdef GSTREAMER_AVAILABLE
+ return true;
+#else
+ return false;
+#endif
}
void
@@ -313,6 +336,7 @@ TimelineViewManager::setHistoryView(const QString &room_id)
if (room != models.end()) {
timeline_ = room.value().data();
emit activeTimelineChanged(timeline_);
+ container->setFocus();
nhlog::ui()->info("Activated room {}", room_id.toStdString());
}
}
@@ -475,81 +499,6 @@ TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
}
void
-TimelineViewManager::queueTextMessage(const QString &msg)
-{
- if (!timeline_)
- return;
-
- mtx::events::msg::Text text = {};
- text.body = msg.trimmed().toStdString();
-
- if (ChatPage::instance()->userSettings()->markdown()) {
- text.formatted_body = utils::markdownToHtml(msg).toStdString();
-
- // Don't send formatted_body, when we don't need to
- if (text.formatted_body.find("<") == std::string::npos)
- text.formatted_body = "";
- else
- text.format = "org.matrix.custom.html";
- }
-
- if (!timeline_->reply().isEmpty()) {
- auto related = timeline_->relatedInfo(timeline_->reply());
-
- QString body;
- bool firstLine = true;
- for (const auto &line : related.quoted_body.split("\n")) {
- if (firstLine) {
- firstLine = false;
- body = QString("> <%1> %2\n").arg(related.quoted_user).arg(line);
- } else {
- body = QString("%1\n> %2\n").arg(body).arg(line);
- }
- }
-
- text.body = QString("%1\n%2").arg(body).arg(msg).toStdString();
-
- // NOTE(Nico): rich replies always need a formatted_body!
- text.format = "org.matrix.custom.html";
- if (ChatPage::instance()->userSettings()->markdown())
- text.formatted_body =
- utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg))
- .toStdString();
- else
- text.formatted_body =
- utils::getFormattedQuoteBody(related, msg.toHtmlEscaped()).toStdString();
-
- text.relates_to.in_reply_to.event_id = related.related_event;
- timeline_->resetReply();
- }
-
- timeline_->sendMessageEvent(text, mtx::events::EventType::RoomMessage);
-}
-
-void
-TimelineViewManager::queueEmoteMessage(const QString &msg)
-{
- auto html = utils::markdownToHtml(msg);
-
- mtx::events::msg::Emote emote;
- emote.body = msg.trimmed().toStdString();
-
- if (html != msg.trimmed().toHtmlEscaped() &&
- ChatPage::instance()->userSettings()->markdown()) {
- emote.formatted_body = html.toStdString();
- emote.format = "org.matrix.custom.html";
- }
-
- if (!timeline_->reply().isEmpty()) {
- emote.relates_to.in_reply_to.event_id = timeline_->reply().toStdString();
- timeline_->resetReply();
- }
-
- if (timeline_)
- timeline_->sendMessageEvent(emote, mtx::events::EventType::RoomMessage);
-}
-
-void
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
{
if (!timeline_)
@@ -581,122 +530,6 @@ TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QSt
timeline_->redactEvent(selfReactedEvent);
}
}
-
-void
-TimelineViewManager::queueImageMessage(const QString &roomid,
- const QString &filename,
- const std::optional<mtx::crypto::EncryptedFile> &file,
- const QString &url,
- const QString &mime,
- uint64_t dsize,
- const QSize &dimensions,
- const QString &blurhash)
-{
- mtx::events::msg::Image image;
- image.info.mimetype = mime.toStdString();
- image.info.size = dsize;
- image.info.blurhash = blurhash.toStdString();
- image.body = filename.toStdString();
- image.info.h = dimensions.height();
- image.info.w = dimensions.width();
-
- if (file)
- image.file = file;
- else
- image.url = url.toStdString();
-
- auto model = models.value(roomid);
- if (!model->reply().isEmpty()) {
- image.relates_to.in_reply_to.event_id = model->reply().toStdString();
- model->resetReply();
- }
-
- model->sendMessageEvent(image, mtx::events::EventType::RoomMessage);
-}
-
-void
-TimelineViewManager::queueFileMessage(
- const QString &roomid,
- const QString &filename,
- const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
- const QString &url,
- const QString &mime,
- uint64_t dsize)
-{
- mtx::events::msg::File file;
- file.info.mimetype = mime.toStdString();
- file.info.size = dsize;
- file.body = filename.toStdString();
-
- if (encryptedFile)
- file.file = encryptedFile;
- else
- file.url = url.toStdString();
-
- auto model = models.value(roomid);
- if (!model->reply().isEmpty()) {
- file.relates_to.in_reply_to.event_id = model->reply().toStdString();
- model->resetReply();
- }
-
- model->sendMessageEvent(file, mtx::events::EventType::RoomMessage);
-}
-
-void
-TimelineViewManager::queueAudioMessage(const QString &roomid,
- const QString &filename,
- const std::optional<mtx::crypto::EncryptedFile> &file,
- const QString &url,
- const QString &mime,
- uint64_t dsize)
-{
- mtx::events::msg::Audio audio;
- audio.info.mimetype = mime.toStdString();
- audio.info.size = dsize;
- audio.body = filename.toStdString();
- audio.url = url.toStdString();
-
- if (file)
- audio.file = file;
- else
- audio.url = url.toStdString();
-
- auto model = models.value(roomid);
- if (!model->reply().isEmpty()) {
- audio.relates_to.in_reply_to.event_id = model->reply().toStdString();
- model->resetReply();
- }
-
- model->sendMessageEvent(audio, mtx::events::EventType::RoomMessage);
-}
-
-void
-TimelineViewManager::queueVideoMessage(const QString &roomid,
- const QString &filename,
- const std::optional<mtx::crypto::EncryptedFile> &file,
- const QString &url,
- const QString &mime,
- uint64_t dsize)
-{
- mtx::events::msg::Video video;
- video.info.mimetype = mime.toStdString();
- video.info.size = dsize;
- video.body = filename.toStdString();
-
- if (file)
- video.file = file;
- else
- video.url = url.toStdString();
-
- auto model = models.value(roomid);
- if (!model->reply().isEmpty()) {
- video.relates_to.in_reply_to.event_id = model->reply().toStdString();
- model->resetReply();
- }
-
- model->sendMessageEvent(video, mtx::events::EventType::RoomMessage);
-}
-
void
TimelineViewManager::queueCallMessage(const QString &roomid,
const mtx::events::msg::CallInvite &callInvite)
|