1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QIODevice>
#include <QObject>
#include <QSize>
#include <QStringList>
#include <QTimer>
#include <QVariantList>
#include <deque>
#include <memory>
#include <mtx/common.hpp>
#include <mtx/responses/messages.hpp>
class TimelineModel;
class CombinedImagePackModel;
class QMimeData;
class QDropEvent;
enum class MarkdownOverride
{
NOT_SPECIFIED, // no override set
ON,
OFF,
};
class MediaUpload : public QObject
{
Q_OBJECT
// Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged)
// Q_PROPERTY(MediaType mediaType READ type NOTIFY mediaTypeChanged)
// // https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646
// Q_PROPERTY(QUrl thumbnail READ thumbnail NOTIFY thumbnailChanged)
// Q_PROPERTY(QString humanSize READ humanSize NOTIFY huSizeChanged)
// Q_PROPERTY(QString filename READ filename NOTIFY filenameChanged)
// Q_PROPERTY(QString mimetype READ mimetype NOTIFY mimetypeChanged)
// Q_PROPERTY(int height READ height NOTIFY heightChanged)
// Q_PROPERTY(int width READ width NOTIFY widthChanged)
// thumbnail video
// https://stackoverflow.com/questions/26229633/display-on-screen-using-qabstractvideosurface
public:
enum MediaType
{
File,
Image,
Video,
Audio,
};
Q_ENUM(MediaType);
explicit MediaUpload(std::unique_ptr<QIODevice> data,
QString mimetype,
QString originalFilename,
bool encrypt,
QObject *parent = nullptr);
[[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_; }
[[nodiscard]] std::optional<mtx::crypto::EncryptedFile> encryptedFile_()
{
return encryptedFile;
}
[[nodiscard]] QSize dimensions() const { return dimensions_; }
signals:
void uploadComplete(MediaUpload *self, QString url);
void uploadFailed(MediaUpload *self);
public slots:
void startUpload();
private slots:
void updateThumbnailUrl(QString url) { this->thumbnailUrl_ = std::move(url); }
public:
// void uploadThumbnail(QImage img);
std::unique_ptr<QIODevice> source;
QByteArray data;
QString mimetype_;
QString mimeClass_;
QString originalFilename_;
QString blurhash_;
QString thumbnailUrl_;
QString url_;
std::optional<mtx::crypto::EncryptedFile> encryptedFile;
QSize dimensions_;
uint64_t size_ = 0;
bool encrypt_;
};
class InputBar : public QObject
{
Q_OBJECT
Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged)
Q_PROPERTY(bool containsAtRoom READ containsAtRoom NOTIFY containsAtRoomChanged)
Q_PROPERTY(QString text READ text NOTIFY textChanged)
Q_PROPERTY(QVariantList uploads READ uploads NOTIFY uploadsChanged)
public:
explicit InputBar(TimelineModel *parent)
: 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);
}
QVariantList uploads() const;
public slots:
[[nodiscard]] QString text() const;
QString previousText();
QString nextText();
void setText(const QString &newText);
[[nodiscard]] bool containsAtRoom() const { return containsAtRoom_; }
void send();
void paste(bool fromMouse);
void insertMimeData(const QMimeData *data);
void updateState(int selectionStart, int selectionEnd, int cursorPosition, const QString &text);
void openFileSelection();
[[nodiscard]] bool uploading() const { return uploading_; }
void message(const QString &body,
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
bool rainbowify = false);
void reaction(const QString &reactedEvent, const QString &reactionKey);
void sticker(CombinedImagePackModel *model, int row);
void acceptUploads();
void declineUploads();
private slots:
void startTyping();
void stopTyping();
void finalizeUpload(MediaUpload *upload, QString url);
void removeRunUpload(MediaUpload *upload);
signals:
void insertText(QString text);
void textChanged(QString newText);
void uploadingChanged(bool value);
void containsAtRoomChanged();
void uploadsChanged();
private:
void emote(const QString &body, bool rainbowify);
void notice(const QString &body, bool rainbowify);
void command(const QString &name, QString args);
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 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,
uint64_t dsize);
void video(const QString &filename,
const std::optional<mtx::crypto::EncryptedFile> &file,
const QString &url,
const QString &mime,
uint64_t dsize);
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);
void setUploading(bool value)
{
if (value != uploading_) {
uploading_ = value;
emit uploadingChanged(value);
}
}
void updateAtRoom(const QString &t);
QTimer typingRefresh_;
QTimer typingTimeout_;
TimelineModel *room;
std::deque<QString> history_;
std::size_t history_index_ = 0;
int selectionStart = 0, selectionEnd = 0, cursorPosition = 0;
bool uploading_ = false;
bool containsAtRoom_ = false;
struct DeleteLaterDeleter
{
void operator()(QObject *p)
{
if (p)
p->deleteLater();
}
};
using UploadHandle = std::unique_ptr<MediaUpload, DeleteLaterDeleter>;
std::vector<UploadHandle> unconfirmedUploads;
std::vector<UploadHandle> runningUploads;
};
|