Skip to content
Snippets Groups Projects
TimelineViewManager.cpp 11.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • Nicolas Werner's avatar
    Nicolas Werner committed
    #include "TimelineViewManager.h"
    
    #include <QMetaType>
    #include <QPalette>
    #include <QQmlContext>
    
    #include "ChatPage.h"
    #include "ColorImageProvider.h"
    #include "DelegateChooser.h"
    
    #include "Logging.h"
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    #include "MxcImageProvider.h"
    #include "UserSettingsPage.h"
    #include "dialogs/ImageOverlay.h"
    
    Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
    
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::updateColorPalette()
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            UserSettings settings;
            if (settings.theme() == "light") {
                    QPalette lightActive(/*windowText*/ QColor("#333"),
                                         /*button*/ QColor("#333"),
                                         /*light*/ QColor(),
                                         /*dark*/ QColor(220, 220, 220, 120),
                                         /*mid*/ QColor(),
                                         /*text*/ QColor("#333"),
                                         /*bright_text*/ QColor(),
                                         /*base*/ QColor("white"),
                                         /*window*/ QColor("white"));
                    view->rootContext()->setContextProperty("currentActivePalette", lightActive);
                    view->rootContext()->setContextProperty("currentInactivePalette", lightActive);
            } else if (settings.theme() == "dark") {
                    QPalette darkActive(/*windowText*/ QColor("#caccd1"),
                                        /*button*/ QColor("#caccd1"),
                                        /*light*/ QColor(),
                                        /*dark*/ QColor(45, 49, 57, 120),
                                        /*mid*/ QColor(),
                                        /*text*/ QColor("#caccd1"),
                                        /*bright_text*/ QColor(),
                                        /*base*/ QColor("#202228"),
                                        /*window*/ QColor("#202228"));
                    darkActive.setColor(QPalette::Highlight, QColor("#e7e7e9"));
                    view->rootContext()->setContextProperty("currentActivePalette", darkActive);
                    view->rootContext()->setContextProperty("currentInactivePalette", darkActive);
            } else {
                    view->rootContext()->setContextProperty("currentActivePalette", QPalette());
                    view->rootContext()->setContextProperty("currentInactivePalette", nullptr);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::TimelineViewManager(QWidget *parent)
      : imgProvider(new MxcImageProvider())
      , colorImgProvider(new ColorImageProvider())
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                             1,
                                             0,
                                             "MtxEvent",
                                             "Can't instantiate enum!");
    
            qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
            qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
    
            qRegisterMetaType<mtx::events::collections::TimelineEvents>();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    
    #ifdef USE_QUICK_VIEW
            view      = new QQuickView();
            container = QWidget::createWindowContainer(view, parent);
    #else
            view      = new QQuickWidget(parent);
            container = view;
            view->setResizeMode(QQuickWidget::SizeRootObjectToView);
            container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
            connect(view, &QQuickWidget::statusChanged, this, [](QQuickWidget::Status status) {
                    nhlog::ui()->debug("Status changed to {}", status);
            });
    #endif
            container->setMinimumSize(200, 200);
            view->rootContext()->setContextProperty("timelineManager", this);
            updateColorPalette();
            view->engine()->addImageProvider("MxcImage", imgProvider);
            view->engine()->addImageProvider("colorimage", colorImgProvider);
            view->setSource(QUrl("qrc:///qml/TimelineView.qml"));
    
            connect(dynamic_cast<ChatPage *>(parent),
                    &ChatPage::themeChanged,
                    this,
                    &TimelineViewManager::updateColorPalette);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            for (auto it = rooms.join.cbegin(); it != rooms.join.cend(); ++it) {
                    // addRoom will only add the room, if it doesn't exist
                    addRoom(QString::fromStdString(it->first));
                    models.value(QString::fromStdString(it->first))->addEvents(it->second.timeline);
            }
    
    
            this->isInitialSync_ = false;
            emit initialSyncChanged(false);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::addRoom(const QString &room_id)
    
            if (!models.contains(room_id)) {
                    QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id));
                    connect(newRoom.data(),
                            &TimelineModel::newEncryptedImage,
                            imgProvider,
                            &MxcImageProvider::addEncryptionInfo);
                    models.insert(room_id, std::move(newRoom));
            }
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::setHistoryView(const QString &room_id)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            auto room = models.find(room_id);
            if (room != models.end()) {
                    timeline_ = room.value().data();
                    emit activeTimelineChanged(timeline_);
                    nhlog::ui()->info("Activated room {}", room_id.toStdString());
            }
    
    TimelineViewManager::openImageOverlay(QString mxcUrl, QString eventId) const
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            QQuickImageResponse *imgResponse =
              imgProvider->requestImageResponse(mxcUrl.remove("mxc://"), QSize());
    
            connect(imgResponse, &QQuickImageResponse::finished, this, [this, eventId, imgResponse]() {
                    if (!imgResponse->errorString().isEmpty()) {
                            nhlog::ui()->error("Error when retrieving image for overlay: {}",
                                               imgResponse->errorString().toStdString());
                            return;
                    }
                    auto pixmap = QPixmap::fromImage(imgResponse->textureFactory()->image());
    
                    auto imgDialog = new dialogs::ImageOverlay(pixmap);
                    imgDialog->show();
                    connect(imgDialog, &dialogs::ImageOverlay::saving, timeline_, [this, eventId]() {
                            timeline_->saveMedia(eventId);
                    });
            });
    
    void
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::updateReadReceipts(const QString &room_id,
                                            const std::vector<QString> &event_ids)
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            auto room = models.find(room_id);
            if (room != models.end()) {
                    room.value()->markEventsAsRead(event_ids);
    
    void
    TimelineViewManager::initWithMessages(const std::map<QString, mtx::responses::Timeline> &msgs)
    {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            for (const auto &e : msgs) {
                    addRoom(e.first);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                    models.value(e.first)->addEvents(e.second);
    
    void
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::queueTextMessage(const QString &msg)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Text text = {};
            text.body                   = msg.trimmed().toStdString();
            text.format                 = "org.matrix.custom.html";
            text.formatted_body         = utils::markdownToHtml(msg).toStdString();
    
            if (timeline_)
                    timeline_->sendMessage(text);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::queueReplyMessage(const QString &reply, const RelatedInfo &related)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Text text = {};
    
            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);
                    }
            }
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            text.body   = QString("%1\n%2").arg(body).arg(reply).toStdString();
            text.format = "org.matrix.custom.html";
            text.formatted_body =
              utils::getFormattedQuoteBody(related, utils::markdownToHtml(reply)).toStdString();
            text.relates_to.in_reply_to.event_id = related.related_event;
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            if (timeline_)
                    timeline_->sendMessage(text);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::queueEmoteMessage(const QString &msg)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            auto html = utils::markdownToHtml(msg);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Emote emote;
            emote.body = msg.trimmed().toStdString();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            if (html != msg.trimmed().toHtmlEscaped())
                    emote.formatted_body = html.toStdString();
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            if (timeline_)
                    timeline_->sendMessage(emote);
    
    void
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    TimelineViewManager::queueImageMessage(const QString &roomid,
                                           const QString &filename,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const std::optional<mtx::crypto::EncryptedFile> &file,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const QString &url,
                                           const QString &mime,
                                           uint64_t dsize,
                                           const QSize &dimensions)
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Image image;
            image.info.mimetype = mime.toStdString();
            image.info.size     = dsize;
            image.body          = filename.toStdString();
            image.url           = url.toStdString();
            image.info.h        = dimensions.height();
            image.info.w        = dimensions.width();
    
            image.file          = file;
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            models.value(roomid)->sendMessage(image);
    
    void
    
    TimelineViewManager::queueFileMessage(
      const QString &roomid,
      const QString &filename,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
      const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
    
      const QString &url,
      const QString &mime,
      uint64_t dsize)
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::File file;
            file.info.mimetype = mime.toStdString();
            file.info.size     = dsize;
            file.body          = filename.toStdString();
            file.url           = url.toStdString();
    
            file.file          = encryptedFile;
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            models.value(roomid)->sendMessage(file);
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    }
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    void
    TimelineViewManager::queueAudioMessage(const QString &roomid,
                                           const QString &filename,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const std::optional<mtx::crypto::EncryptedFile> &file,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const QString &url,
                                           const QString &mime,
                                           uint64_t dsize)
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Audio audio;
            audio.info.mimetype = mime.toStdString();
            audio.info.size     = dsize;
            audio.body          = filename.toStdString();
            audio.url           = url.toStdString();
    
            audio.file          = file;
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            models.value(roomid)->sendMessage(audio);
    
    Nicolas Werner's avatar
    Nicolas Werner committed
    void
    TimelineViewManager::queueVideoMessage(const QString &roomid,
                                           const QString &filename,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const std::optional<mtx::crypto::EncryptedFile> &file,
    
    Nicolas Werner's avatar
    Nicolas Werner committed
                                           const QString &url,
                                           const QString &mime,
                                           uint64_t dsize)
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    {
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            mtx::events::msg::Video video;
            video.info.mimetype = mime.toStdString();
            video.info.size     = dsize;
            video.body          = filename.toStdString();
            video.url           = url.toStdString();
    
            video.file          = file;
    
    Nicolas Werner's avatar
    Nicolas Werner committed
            models.value(roomid)->sendMessage(video);
    
    Konstantinos Sideris's avatar
    Konstantinos Sideris committed
    }