Add bulk multi-photo upload to the desktop app
Mirror the Android bulk feature in the Qt uploader: choose several photos at once, each a card with its own caption, date, and upload status, and post the batch. - Per-photo cards (PhotoItemWidget) in a scrollable list; retry re-posts only the failures. - One upload per photo with a per-item UUID slug suffix so a batch posted in the same second cannot collide. - Image prep runs off the UI thread via QtConcurrent so the window stays responsive. - A "Simultaneous uploads" setting (1–8, default 3) caps how many photos are prepared/uploaded at once; the rest queue and fill freed slots.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#include "photoitemwidget.h"
|
||||
|
||||
#include <QDate>
|
||||
#include <QDateEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QImageReader>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace {
|
||||
constexpr int kThumbSize = 72;
|
||||
}
|
||||
|
||||
PhotoItemWidget::PhotoItemWidget(QString sourcePath, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_sourcePath(std::move(sourcePath))
|
||||
{
|
||||
auto *row = new QHBoxLayout(this);
|
||||
row->setContentsMargins(0, 4, 0, 4);
|
||||
|
||||
m_thumb = new QLabel;
|
||||
m_thumb->setFixedSize(kThumbSize, kThumbSize);
|
||||
m_thumb->setAlignment(Qt::AlignCenter);
|
||||
m_thumb->setFrameShape(QFrame::Box);
|
||||
{
|
||||
QImageReader reader(m_sourcePath);
|
||||
reader.setAutoTransform(true);
|
||||
const QImage image = reader.read();
|
||||
if (!image.isNull())
|
||||
m_thumb->setPixmap(QPixmap::fromImage(image).scaled(
|
||||
kThumbSize, kThumbSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
|
||||
else
|
||||
m_thumb->setText(QStringLiteral("?"));
|
||||
}
|
||||
row->addWidget(m_thumb);
|
||||
|
||||
auto *fields = new QVBoxLayout;
|
||||
m_caption = new QLineEdit;
|
||||
m_caption->setPlaceholderText(QStringLiteral("Caption (defaults to the filename)"));
|
||||
fields->addWidget(m_caption);
|
||||
|
||||
m_date = new QDateEdit(QDate::currentDate());
|
||||
m_date->setCalendarPopup(true);
|
||||
m_date->setDisplayFormat(QStringLiteral("yyyy-MM-dd"));
|
||||
fields->addWidget(m_date);
|
||||
|
||||
m_statusLabel = new QLabel;
|
||||
m_statusLabel->setOpenExternalLinks(true);
|
||||
m_statusLabel->setWordWrap(true);
|
||||
fields->addWidget(m_statusLabel);
|
||||
row->addLayout(fields, 1);
|
||||
|
||||
m_remove = new QPushButton(QStringLiteral("✕"));
|
||||
m_remove->setFlat(true);
|
||||
m_remove->setFixedWidth(32);
|
||||
connect(m_remove, &QPushButton::clicked, this, [this]() { emit removeRequested(this); });
|
||||
row->addWidget(m_remove, 0, Qt::AlignTop);
|
||||
}
|
||||
|
||||
QString PhotoItemWidget::caption() const
|
||||
{
|
||||
return m_caption->text();
|
||||
}
|
||||
|
||||
QString PhotoItemWidget::date() const
|
||||
{
|
||||
return m_date->date().toString(QStringLiteral("yyyy-MM-dd"));
|
||||
}
|
||||
|
||||
void PhotoItemWidget::setStatus(Status status, const QString &message, const QString &url)
|
||||
{
|
||||
m_status = status;
|
||||
|
||||
// Inputs are frozen once the photo is in flight; the remove button stays
|
||||
// usable except mid-transfer.
|
||||
const bool editable = status == Status::Pending || status == Status::Error;
|
||||
m_caption->setEnabled(editable);
|
||||
m_date->setEnabled(editable);
|
||||
m_remove->setEnabled(status != Status::Preparing && status != Status::Uploading);
|
||||
|
||||
switch (status) {
|
||||
case Status::Pending:
|
||||
m_statusLabel->clear();
|
||||
break;
|
||||
case Status::Preparing:
|
||||
m_statusLabel->setText(QStringLiteral("Preparing…"));
|
||||
break;
|
||||
case Status::Uploading:
|
||||
m_statusLabel->setText(QStringLiteral("Uploading…"));
|
||||
break;
|
||||
case Status::Success:
|
||||
m_statusLabel->setText(QStringLiteral("Posted — <a href=\"%1\">View</a>").arg(url));
|
||||
break;
|
||||
case Status::Error:
|
||||
m_statusLabel->setText(QStringLiteral("<span style=\"color:#fb4934\">%1</span>").arg(message));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user