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.
102 lines
3.1 KiB
C++
102 lines
3.1 KiB
C++
#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;
|
|
}
|
|
}
|