matrixion/src/timeline/InputBar.h

316 lines
10 KiB
C
Raw Normal View History

// SPDX-FileCopyrightText: Nheko Contributors
2021-03-05 02:35:15 +03:00
//
// SPDX-License-Identifier: GPL-3.0-or-later
2020-11-01 01:24:07 +03:00
#pragma once
2022-03-21 02:48:27 +03:00
#include <QAbstractVideoSurface>
2022-03-21 00:49:33 +03:00
#include <QIODevice>
2022-03-21 02:48:27 +03:00
#include <QImage>
2020-11-01 01:24:07 +03:00
#include <QObject>
2022-03-21 00:49:33 +03:00
#include <QSize>
2021-12-28 22:09:08 +03:00
#include <QStringList>
2020-11-17 04:37:43 +03:00
#include <QTimer>
#include <QUrl>
2022-03-21 00:49:33 +03:00
#include <QVariantList>
2020-11-09 05:12:37 +03:00
#include <deque>
2022-03-21 00:49:33 +03:00
#include <memory>
2020-11-01 01:24:07 +03:00
2020-11-15 06:52:49 +03:00
#include <mtx/common.hpp>
#include <mtx/responses/messages.hpp>
2020-11-01 01:24:07 +03:00
class TimelineModel;
2021-07-21 02:03:38 +03:00
class CombinedImagePackModel;
2020-11-15 06:52:49 +03:00
class QMimeData;
2020-11-25 19:02:23 +03:00
class QDropEvent;
2020-11-01 01:24:07 +03:00
struct DeleteLaterDeleter
{
void operator()(QObject *p)
{
if (p)
p->deleteLater();
}
};
enum class MarkdownOverride
{
2021-09-18 01:22:33 +03:00
NOT_SPECIFIED, // no override set
ON,
OFF,
CMARK,
};
2022-10-10 15:38:29 +03:00
class InputVideoSurface final : public QAbstractVideoSurface
2022-03-21 02:48:27 +03:00
{
Q_OBJECT
public:
InputVideoSurface(QObject *parent)
: QAbstractVideoSurface(parent)
2022-09-25 21:05:08 +03:00
{
}
2022-03-21 02:48:27 +03:00
2022-03-21 03:24:53 +03:00
bool present(const QVideoFrame &frame) override;
2022-03-21 02:48:27 +03:00
QList<QVideoFrame::PixelFormat>
2022-03-21 03:24:53 +03:00
supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override;
2022-03-21 02:48:27 +03:00
signals:
void newImage(QImage img);
};
2022-10-10 15:38:29 +03:00
class MediaUpload final : public QObject
2022-03-21 00:49:33 +03:00
{
Q_OBJECT
2022-03-21 07:05:29 +03:00
Q_PROPERTY(int mediaType READ type NOTIFY mediaTypeChanged)
// https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646
Q_PROPERTY(QUrl thumbnail READ thumbnailDataUrl NOTIFY thumbnailChanged)
2022-03-21 00:49:33 +03:00
// Q_PROPERTY(QString humanSize READ humanSize NOTIFY huSizeChanged)
2022-03-21 07:05:29 +03:00
Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)
2022-03-21 00:49:33 +03:00
// thumbnail video
// https://stackoverflow.com/questions/26229633/display-on-screen-using-qabstractvideosurface
public:
enum MediaType
{
File,
Image,
Video,
Audio,
};
2022-03-21 07:05:29 +03:00
Q_ENUM(MediaType)
2022-03-21 00:49:33 +03:00
explicit MediaUpload(std::unique_ptr<QIODevice> data,
const QString &mimetype,
const QString &originalFilename,
2022-03-21 00:49:33 +03:00
bool encrypt,
QObject *parent = nullptr);
2022-03-21 07:05:29 +03:00
[[nodiscard]] int type() const
{
if (mimeClass_ == u"video")
return MediaType::Video;
else if (mimeClass_ == u"audio")
return MediaType::Audio;
else if (mimeClass_ == u"image")
return MediaType::Image;
else
return MediaType::File;
}
2022-03-21 00:49:33 +03:00
[[nodiscard]] QString url() const { return url_; }
[[nodiscard]] QString mimetype() const { return mimetype_; }
[[nodiscard]] QString mimeClass() const { return mimeClass_; }
[[nodiscard]] QString filename() const { return originalFilename_; }
[[nodiscard]] QString blurhash() const { return blurhash_; }
[[nodiscard]] uint64_t size() const { return size_; }
2022-03-21 02:48:27 +03:00
[[nodiscard]] uint64_t duration() const { return duration_; }
2022-03-21 00:49:33 +03:00
[[nodiscard]] std::optional<mtx::crypto::EncryptedFile> encryptedFile_()
{
return encryptedFile;
}
2022-03-21 03:24:53 +03:00
[[nodiscard]] std::optional<mtx::crypto::EncryptedFile> thumbnailEncryptedFile_()
{
return thumbnailEncryptedFile;
}
2022-03-21 00:49:33 +03:00
[[nodiscard]] QSize dimensions() const { return dimensions_; }
2022-03-21 03:24:53 +03:00
QImage thumbnailImg() const { return thumbnail_; }
QString thumbnailUrl() const { return thumbnailUrl_; }
QUrl thumbnailDataUrl() const;
2022-03-21 03:24:53 +03:00
[[nodiscard]] uint64_t thumbnailSize() const { return thumbnailSize_; }
2022-03-21 07:05:29 +03:00
void setFilename(QString fn)
{
if (fn != originalFilename_) {
originalFilename_ = std::move(fn);
emit filenameChanged();
}
}
2022-03-21 00:49:33 +03:00
signals:
void uploadComplete(MediaUpload *self, QString url);
void uploadFailed(MediaUpload *self);
2022-03-21 07:05:29 +03:00
void filenameChanged();
void thumbnailChanged();
2022-03-21 07:05:29 +03:00
void mediaTypeChanged();
2022-03-21 00:49:33 +03:00
public slots:
void startUpload();
private slots:
void setThumbnail(QImage img)
{
this->thumbnail_ = std::move(img);
emit thumbnailChanged();
}
2022-03-21 00:49:33 +03:00
public:
// void uploadThumbnail(QImage img);
std::unique_ptr<QIODevice> source;
QByteArray data;
QString mimetype_;
QString mimeClass_;
QString originalFilename_;
QString blurhash_;
QString thumbnailUrl_;
QString url_;
2022-03-21 03:24:53 +03:00
std::optional<mtx::crypto::EncryptedFile> encryptedFile, thumbnailEncryptedFile;
2022-03-21 00:49:33 +03:00
2022-03-21 02:48:27 +03:00
QImage thumbnail_;
2022-03-21 00:49:33 +03:00
QSize dimensions_;
2022-03-21 03:24:53 +03:00
uint64_t size_ = 0;
uint64_t thumbnailSize_ = 0;
uint64_t duration_ = 0;
2022-03-21 00:49:33 +03:00
bool encrypt_;
};
2022-10-10 15:38:29 +03:00
class InputBar final : public QObject
2020-11-09 05:12:37 +03:00
{
2021-09-18 01:22:33 +03:00
Q_OBJECT
Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged)
Q_PROPERTY(bool containsAtRoom READ containsAtRoom NOTIFY containsAtRoomChanged)
Q_PROPERTY(
bool containsInvalidCommand READ containsInvalidCommand NOTIFY containsInvalidCommandChanged)
2023-03-08 03:10:42 +03:00
Q_PROPERTY(bool containsIncompleteCommand READ containsIncompleteCommand NOTIFY
containsIncompleteCommandChanged)
Q_PROPERTY(QString currentCommand READ currentCommand NOTIFY currentCommandChanged)
2021-09-18 01:22:33 +03:00
Q_PROPERTY(QString text READ text NOTIFY textChanged)
2022-03-21 00:49:33 +03:00
Q_PROPERTY(QVariantList uploads READ uploads NOTIFY uploadsChanged)
2020-11-01 01:24:07 +03:00
public:
explicit InputBar(TimelineModel *parent)
2021-09-18 01:22:33 +03:00
: QObject()
, room(parent)
{
typingRefresh_.setInterval(10'000);
typingRefresh_.setSingleShot(true);
typingTimeout_.setInterval(5'000);
typingTimeout_.setSingleShot(true);
connect(&typingRefresh_, &QTimer::timeout, this, &InputBar::startTyping);
connect(&typingTimeout_, &QTimer::timeout, this, &InputBar::stopTyping);
}
2020-11-01 01:24:07 +03:00
2022-03-21 00:49:33 +03:00
QVariantList uploads() const;
2020-11-01 01:24:07 +03:00
public slots:
[[nodiscard]] QString text() const;
2021-09-18 01:22:33 +03:00
QString previousText();
QString nextText();
2021-12-03 03:54:43 +03:00
void setText(const QString &newText);
2021-09-18 01:22:33 +03:00
[[nodiscard]] bool containsAtRoom() const { return containsAtRoom_; }
bool containsInvalidCommand() const { return containsInvalidCommand_; }
2023-03-08 03:10:42 +03:00
bool containsIncompleteCommand() const { return containsIncompleteCommand_; }
QString currentCommand() const { return currentCommand_; }
2021-09-18 01:22:33 +03:00
void send();
2022-06-13 14:16:49 +03:00
bool tryPasteAttachment(bool fromMouse);
bool insertMimeData(const QMimeData *data);
2021-12-03 03:54:43 +03:00
void updateState(int selectionStart, int selectionEnd, int cursorPosition, const QString &text);
2021-09-18 01:22:33 +03:00
void openFileSelection();
[[nodiscard]] bool uploading() const { return uploading_; }
2021-12-03 03:54:43 +03:00
void message(const QString &body,
2021-09-18 01:22:33 +03:00
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
bool rainbowify = false);
void reaction(const QString &reactedEvent, const QString &reactionKey);
void sticker(CombinedImagePackModel *model, int row);
2020-11-01 01:24:07 +03:00
2022-03-21 00:49:33 +03:00
void acceptUploads();
void declineUploads();
2020-11-17 04:37:43 +03:00
private slots:
2021-09-18 01:22:33 +03:00
void startTyping();
void stopTyping();
2020-11-17 04:37:43 +03:00
void finalizeUpload(MediaUpload *upload, const QString &url);
2022-03-21 00:49:33 +03:00
void removeRunUpload(MediaUpload *upload);
2020-11-09 05:12:37 +03:00
signals:
2021-09-18 01:22:33 +03:00
void textChanged(QString newText);
void uploadingChanged(bool value);
void containsAtRoomChanged();
void containsInvalidCommandChanged();
2023-03-08 03:10:42 +03:00
void containsIncompleteCommandChanged();
void currentCommandChanged();
2022-03-21 00:49:33 +03:00
void uploadsChanged();
2020-11-09 05:12:37 +03:00
2020-11-01 01:24:07 +03:00
private:
2021-12-03 03:54:43 +03:00
void emote(const QString &body, bool rainbowify);
void notice(const QString &body, bool rainbowify);
void confetti(const QString &body, bool rainbowify);
void rainfall(const QString &body, bool rainbowify);
2023-03-22 02:44:00 +03:00
void customMsgtype(const QString &msgtype, const QString &body, bool rainbowify);
2023-03-02 01:04:17 +03:00
bool command(const QString &name, QString args);
2021-09-18 01:22:33 +03:00
void image(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
uint64_t dsize,
const QSize &dimensions,
const std::optional<mtx::crypto::EncryptedFile> &thumbnailEncryptedFile,
const QString &thumbnailUrl,
uint64_t thumbnailSize,
const QSize &thumbnailDimensions,
2021-09-18 01:22:33 +03:00
const QString &blurhash);
void file(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
const QString &url,
const QString &mime,
uint64_t dsize);
void audio(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
2022-03-21 02:48:27 +03:00
uint64_t dsize,
uint64_t duration);
2021-09-18 01:22:33 +03:00
void video(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
2022-03-21 02:48:27 +03:00
uint64_t dsize,
uint64_t duration,
2022-03-21 03:24:53 +03:00
const QSize &dimensions,
const std::optional<mtx::crypto::EncryptedFile> &thumbnailEncryptedFile,
const QString &thumbnailUrl,
uint64_t thumbnailSize,
const QSize &thumbnailDimensions,
const QString &blurhash);
2021-09-18 01:22:33 +03:00
2023-03-08 03:10:42 +03:00
QPair<QString, QString> getCommandAndArgs() const { return getCommandAndArgs(text()); }
QPair<QString, QString> getCommandAndArgs(const QString &currentText) const;
2022-09-30 04:27:05 +03:00
mtx::common::Relations generateRelations() const;
2022-03-21 00:49:33 +03:00
void startUploadFromPath(const QString &path);
void startUploadFromMimeData(const QMimeData &source, const QString &format);
void startUpload(std::unique_ptr<QIODevice> dev, const QString &orgPath, const QString &format);
2021-09-18 01:22:33 +03:00
void setUploading(bool value)
{
if (value != uploading_) {
uploading_ = value;
emit uploadingChanged(value);
2020-11-15 06:52:49 +03:00
}
2021-09-18 01:22:33 +03:00
}
void updateTextContentProperties(const QString &t);
2021-09-18 01:22:33 +03:00
QTimer typingRefresh_;
QTimer typingTimeout_;
TimelineModel *room;
std::deque<QString> history_;
std::size_t history_index_ = 0;
int selectionStart = 0, selectionEnd = 0, cursorPosition = 0;
2023-03-08 03:10:42 +03:00
bool uploading_ = false;
bool containsAtRoom_ = false;
bool containsInvalidCommand_ = false;
bool containsIncompleteCommand_ = false;
QString currentCommand_;
2022-03-21 00:49:33 +03:00
using UploadHandle = std::unique_ptr<MediaUpload, DeleteLaterDeleter>;
std::vector<UploadHandle> unconfirmedUploads;
std::vector<UploadHandle> runningUploads;
2020-11-01 01:24:07 +03:00
};