Skip to content
Snippets Groups Projects
InputBar.cpp 40.2 KiB
Newer Older
Nicolas Werner's avatar
Nicolas Werner committed
              url,
              mime,
              size,
              upload->duration(),
              upload->dimensions(),
              upload->thumbnailEncryptedFile_(),
              upload->thumbnailUrl(),
              upload->thumbnailSize(),
              upload->thumbnailImg().size(),
              upload->blurhash());
    else
        file(filename, encryptedFile, url, mime, size);
    removeRunUpload(upload);
}

void
InputBar::removeRunUpload(MediaUpload *upload)
{
    auto it = std::find_if(runningUploads.begin(),
                           runningUploads.end(),
                           [upload](const UploadHandle &h) { return h.get() == upload; });
    if (it != runningUploads.end())
        runningUploads.erase(it);

    if (runningUploads.empty())
        setUploading(false);
    else
        runningUploads.front()->startUpload();
}

void
InputBar::startUploadFromPath(const QString &path)
{
    if (path.isEmpty())
        return;

    auto file = std::make_unique<QFile>(path);

    if (!file->open(QIODevice::ReadOnly)) {
        nhlog::ui()->warn(
          "Failed to open file ({}): {}", path.toStdString(), file->errorString().toStdString());
        return;
    }

    QMimeDatabase db;
    auto mime = db.mimeTypeForFileNameAndData(path, file.get());

    startUpload(std::move(file), path, mime.name());
}

void
InputBar::startUploadFromMimeData(const QMimeData &source, const QString &format)
{
    auto file = std::make_unique<QBuffer>();
    file->setData(source.data(format));

    if (!file->open(QIODevice::ReadOnly)) {
        nhlog::ui()->warn("Failed to open buffer: {}", file->errorString().toStdString());
        return;
    }

    QMimeDatabase db;
    auto mime        = db.mimeTypeForName(format);
    auto suffix      = mime.preferredSuffix();
    QString filename = QStringLiteral("clipboard");

    startUpload(std::move(file), suffix.isEmpty() ? filename : (filename + "." + suffix), format);
}
void
InputBar::startUpload(std::unique_ptr<QIODevice> dev, const QString &orgPath, const QString &format)
{
    auto upload =
      UploadHandle(new MediaUpload(std::move(dev), format, orgPath, room->isEncrypted(), this));
    connect(upload.get(), &MediaUpload::uploadComplete, this, &InputBar::finalizeUpload);

    unconfirmedUploads.push_back(std::move(upload));

Nicolas Werner's avatar
Nicolas Werner committed
    nhlog::ui()->debug("Uploads {}", unconfirmedUploads.size());
    emit uploadsChanged();
}

void
InputBar::acceptUploads()
{
    if (unconfirmedUploads.empty())
        return;

    bool wasntRunning = runningUploads.empty();
    runningUploads.insert(runningUploads.end(),
                          std::make_move_iterator(unconfirmedUploads.begin()),
                          std::make_move_iterator(unconfirmedUploads.end()));
    unconfirmedUploads.clear();
    emit uploadsChanged();

    if (wasntRunning) {
        setUploading(true);
        runningUploads.front()->startUpload();
    }
}

void
InputBar::declineUploads()
{
    unconfirmedUploads.clear();
    emit uploadsChanged();
}

QVariantList
InputBar::uploads() const
{
    QVariantList l;
    l.reserve((int)unconfirmedUploads.size());

    for (auto &e : unconfirmedUploads)
        l.push_back(QVariant::fromValue(e.get()));
    return l;
Nicolas Werner's avatar
Nicolas Werner committed
}
void
InputBar::startTyping()
{
    if (!typingRefresh_.isActive()) {
        typingRefresh_.start();

        if (ChatPage::instance()->userSettings()->typingNotifications()) {
            http::client()->start_typing(
              room->roomId().toStdString(), 10'000, [](mtx::http::RequestErr err) {
                  if (err) {
                      nhlog::net()->warn("failed to send typing notification: {}",
                                         err->matrix_error.error);
                  }
              });
    }
    typingTimeout_.start();
}
void
InputBar::stopTyping()
{
    typingRefresh_.stop();
    typingTimeout_.stop();
    if (!ChatPage::instance()->userSettings()->typingNotifications())
        return;
    http::client()->stop_typing(room->roomId().toStdString(), [](mtx::http::RequestErr err) {
        if (err) {
            nhlog::net()->warn("failed to stop typing notifications: {}", err->matrix_error.error);
        }
    });

void
InputBar::reaction(const QString &reactedEvent, const QString &reactionKey)
{
    auto reactions = room->reactions(reactedEvent.toStdString());
    QString selfReactedEvent;
    for (const auto &reaction : reactions) {
        if (reactionKey == reaction.key_) {
            selfReactedEvent = reaction.selfReactedEvent_;
            break;
    if (selfReactedEvent.startsWith(QLatin1String("m")))
        return;

    // If selfReactedEvent is empty, that means we haven't previously reacted
    if (selfReactedEvent.isEmpty()) {
        mtx::events::msg::Reaction reaction;
        mtx::common::Relation rel;
        rel.rel_type = mtx::common::RelationType::Annotation;
        rel.event_id = reactedEvent.toStdString();
        rel.key      = reactionKey.toStdString();
        reaction.relations.relations.push_back(rel);

        room->sendMessageEvent(reaction, mtx::events::EventType::Reaction);

        auto recents = UserSettings::instance()->recentReactions();
        if (recents.contains(reactionKey))
            recents.removeOne(reactionKey);
        else if (recents.size() >= 6)
            recents.removeLast();
        recents.push_front(reactionKey);
        UserSettings::instance()->setRecentReactions(recents);
        // Otherwise, we have previously reacted and the reaction should be redacted
    } else {
        room->redactEvent(selfReactedEvent);
    }