Skip to content

Commit a291925

Browse files
committed
Implement attachment captioning
Starting with Client-Server API v1.10 [0], the `body` field in messages of type `m.image`, `m.audio`, `m.video` and `m.file` can be used as the caption of the attachment. This is fact the way that Nheko rends captions on images, for example. This commit introduces a field in the `UploadHandle`s awaiting upload on the timeline's `InputBar` which holds a caption taken from the input text area. The decision is as follows: - If text bar is empty or full of blanks, send all media with no caption - If the text is an incomplete command, fail - If there are no pending uploads, proceed as done previously (if there is no command recognized send the text, or try and execute the command and if it fails send the text) - If there are pending uploads, only accept uploads if nothing resembling a command name is in the text area. That text becomes the caption for all pending media. Otherwise, try and execute the command, and, if it fails, send it as text. While this workflow for captioning so far is a bit jank, it is the least effort implementation. Links: [0]: https://spec.matrix.org/v1.10/client-server-api/#mimage Signed-off-by: lymkwi <[email protected]>
1 parent f465a5b commit a291925

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

src/timeline/InputBar.cpp

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ InputBar::send()
394394
{
395395
QInputMethod *im = QGuiApplication::inputMethod();
396396
im->commit();
397+
// If the input from the UI is only blanks or no text, this trigger should
398+
// be used to confirm media upload. If that is not the case however, but
399+
// but there are pending uploads, we fall into one of the cases seen later.
397400
if (text().trimmed().isEmpty()) {
398401
acceptUploads();
399402
return;
@@ -407,8 +410,18 @@ InputBar::send()
407410
updateTextContentProperties(text());
408411
if (containsIncompleteCommand_)
409412
return;
410-
if (commandName.isEmpty() || !command(commandName, args))
411-
message(text());
413+
if (unconfirmedUploads.empty()) {
414+
if (commandName.isEmpty() || !command(commandName, args)) {
415+
message(text());
416+
}
417+
} else {
418+
if (commandName.isEmpty()) {
419+
// This is a set of uploads with text
420+
acceptUploadsWithCaption(text());
421+
} else if (!command(commandName, args)) {
422+
message(text());
423+
}
424+
}
412425

413426
if (!wasEdit) {
414427
history_.push_front(QLatin1String(""));
@@ -708,6 +721,7 @@ void
708721
InputBar::image(const QString &filename,
709722
const std::optional<mtx::crypto::EncryptedFile> &file,
710723
const QString &url,
724+
const std::optional<QString> &caption,
711725
const QString &mime,
712726
uint64_t dsize,
713727
const QSize &dimensions,
@@ -721,9 +735,10 @@ InputBar::image(const QString &filename,
721735
image.info.mimetype = mime.toStdString();
722736
image.info.size = dsize;
723737
image.info.blurhash = blurhash.toStdString();
724-
image.body = filename.toStdString();
725-
image.info.h = dimensions.height();
726-
image.info.w = dimensions.width();
738+
// Depending on the input bar's situation, retrieve the text
739+
image.body = caption.has_value() ? caption.value().toStdString() : filename.toStdString();
740+
image.info.h = dimensions.height();
741+
image.info.w = dimensions.width();
727742

728743
if (file)
729744
image.file = file;
@@ -752,13 +767,14 @@ void
752767
InputBar::file(const QString &filename,
753768
const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
754769
const QString &url,
770+
const std::optional<QString> &caption,
755771
const QString &mime,
756772
uint64_t dsize)
757773
{
758774
mtx::events::msg::File file;
759775
file.info.mimetype = mime.toStdString();
760776
file.info.size = dsize;
761-
file.body = filename.toStdString();
777+
file.body = caption.has_value() ? caption.value().toStdString() : filename.toStdString();
762778

763779
if (encryptedFile)
764780
file.file = encryptedFile;
@@ -775,15 +791,16 @@ void
775791
InputBar::audio(const QString &filename,
776792
const std::optional<mtx::crypto::EncryptedFile> &file,
777793
const QString &url,
794+
const std::optional<QString> &caption,
778795
const QString &mime,
779796
uint64_t dsize,
780797
uint64_t duration)
781798
{
782799
mtx::events::msg::Audio audio;
783800
audio.info.mimetype = mime.toStdString();
784801
audio.info.size = dsize;
785-
audio.body = filename.toStdString();
786-
audio.url = url.toStdString();
802+
audio.body = caption.has_value() ? caption.value().toStdString() : filename.toStdString();
803+
audio.url = url.toStdString();
787804

788805
if (duration > 0)
789806
audio.info.duration = duration;
@@ -803,6 +820,7 @@ void
803820
InputBar::video(const QString &filename,
804821
const std::optional<mtx::crypto::EncryptedFile> &file,
805822
const QString &url,
823+
const std::optional<QString> &caption,
806824
const QString &mime,
807825
uint64_t dsize,
808826
uint64_t duration,
@@ -817,7 +835,7 @@ InputBar::video(const QString &filename,
817835
video.info.mimetype = mime.toStdString();
818836
video.info.size = dsize;
819837
video.info.blurhash = blurhash.toStdString();
820-
video.body = filename.toStdString();
838+
video.body = caption.has_value() ? caption.value().toStdString() : filename.toStdString();
821839

822840
if (duration > 0)
823841
video.info.duration = duration;
@@ -1282,10 +1300,12 @@ InputBar::finalizeUpload(MediaUpload *upload, const QString &url)
12821300
auto mimeClass = upload->mimeClass();
12831301
auto size = upload->size();
12841302
auto encryptedFile = upload->encryptedFile_();
1303+
auto caption = upload->caption();
12851304
if (mimeClass == u"image")
12861305
image(filename,
12871306
encryptedFile,
12881307
url,
1308+
caption,
12891309
mime,
12901310
size,
12911311
upload->dimensions(),
@@ -1295,11 +1315,12 @@ InputBar::finalizeUpload(MediaUpload *upload, const QString &url)
12951315
upload->thumbnailImg().size(),
12961316
upload->blurhash());
12971317
else if (mimeClass == u"audio")
1298-
audio(filename, encryptedFile, url, mime, size, upload->duration());
1318+
audio(filename, encryptedFile, url, caption, mime, size, upload->duration());
12991319
else if (mimeClass == u"video")
13001320
video(filename,
13011321
encryptedFile,
13021322
url,
1323+
caption,
13031324
mime,
13041325
size,
13051326
upload->duration(),
@@ -1310,7 +1331,7 @@ InputBar::finalizeUpload(MediaUpload *upload, const QString &url)
13101331
upload->thumbnailImg().size(),
13111332
upload->blurhash());
13121333
else
1313-
file(filename, encryptedFile, url, mime, size);
1334+
file(filename, encryptedFile, url, caption, mime, size);
13141335

13151336
removeRunUpload(upload);
13161337
}
@@ -1405,6 +1426,15 @@ InputBar::acceptUploads()
14051426
}
14061427
}
14071428

1429+
void
1430+
InputBar::acceptUploadsWithCaption(QString caption)
1431+
{
1432+
for (UploadHandle &upload : unconfirmedUploads) {
1433+
upload->caption_ = std::optional(caption);
1434+
}
1435+
acceptUploads();
1436+
}
1437+
14081438
void
14091439
InputBar::declineUploads()
14101440
{

src/timeline/InputBar.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class MediaUpload final : public QObject
8686
return MediaType::File;
8787
}
8888
[[nodiscard]] QString url() const { return url_; }
89+
[[nodiscard]] std::optional<QString> caption() const { return caption_; }
8990
[[nodiscard]] QString mimetype() const { return mimetype_; }
9091
[[nodiscard]] QString mimeClass() const { return mimeClass_; }
9192
[[nodiscard]] QString filename() const { return originalFilename_; }
@@ -143,6 +144,7 @@ private slots:
143144
QString blurhash_;
144145
QString thumbnailUrl_;
145146
QString url_;
147+
std::optional<QString> caption_;
146148
std::optional<mtx::crypto::EncryptedFile> encryptedFile, thumbnailEncryptedFile;
147149

148150
QImage thumbnail_;
@@ -236,6 +238,7 @@ public slots:
236238
void sticker(QStringList descriptor);
237239

238240
void acceptUploads();
241+
void acceptUploadsWithCaption(QString);
239242
void declineUploads();
240243

241244
private slots:
@@ -264,6 +267,7 @@ private slots:
264267
void image(const QString &filename,
265268
const std::optional<mtx::crypto::EncryptedFile> &file,
266269
const QString &url,
270+
const std::optional<QString> &caption,
267271
const QString &mime,
268272
uint64_t dsize,
269273
const QSize &dimensions,
@@ -275,17 +279,20 @@ private slots:
275279
void file(const QString &filename,
276280
const std::optional<mtx::crypto::EncryptedFile> &encryptedFile,
277281
const QString &url,
282+
const std::optional<QString> &caption,
278283
const QString &mime,
279284
uint64_t dsize);
280285
void audio(const QString &filename,
281286
const std::optional<mtx::crypto::EncryptedFile> &file,
282287
const QString &url,
288+
const std::optional<QString> &caption,
283289
const QString &mime,
284290
uint64_t dsize,
285291
uint64_t duration);
286292
void video(const QString &filename,
287293
const std::optional<mtx::crypto::EncryptedFile> &file,
288294
const QString &url,
295+
const std::optional<QString> &caption,
289296
const QString &mime,
290297
uint64_t dsize,
291298
uint64_t duration,

0 commit comments

Comments
 (0)