Add Qt6 desktop uploader
A native Qt6/C++ desktop client for the gallery's POST /upload API, in desktop/ with its own flake (kept separate from the Go server module the same way android/ is). Single-photo parity with the Android app: - multipart upload with preemptive HTTP Basic auth and retry-aware outcome classification (uploadclient) - JPEG/PNG metadata stripped byte-for-byte to drop embedded GPS, EXIF orientation baked in, and a quality/scale valve for the 20M nginx cap; HEIC decodes via the qtimageformats plugin (imageprep) - base URL / username in QSettings, password in the system keychain via qtkeychain; https required and a trailing /upload stripped (settings) - settings and post screens in a QStackedWidget (mainwindow) Native Wayland or xcb is selected at runtime. Bulk upload, EXIF capture-date prefill, and moving image prep off the UI thread are left as follow-ups.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
|
||||
// Talks to the gallery's POST /upload endpoint, which sits behind nginx HTTP
|
||||
// Basic auth. The credentials go out preemptively in the Authorization header
|
||||
// on every request (never via QNetworkAccessManager's authenticationRequired
|
||||
// signal, which only fires on a 401 and would replay a multipart body already
|
||||
// streamed off disk).
|
||||
//
|
||||
// Asynchronous: results arrive via signals so the UI stays responsive during an
|
||||
// upload over a slow link.
|
||||
class UploadClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class Result {
|
||||
Success, // uploaded; slug/url populated
|
||||
AuthFailed, // wrong credentials — a retry will not help
|
||||
Rejected, // server said no for a reason a retry won't change
|
||||
Transient, // network trouble or a 5xx — worth retrying
|
||||
};
|
||||
|
||||
UploadClient(QString baseUrl, QString username, QString password, QObject *parent = nullptr);
|
||||
|
||||
// The filename matters: server.go derives the slug from it, so re-sending
|
||||
// the same name overwrites the same post instead of duplicating it.
|
||||
void upload(const QString &filePath, const QString &fileName,
|
||||
const QString &caption, const QString &date);
|
||||
|
||||
// Credential check via GET /upload (same Basic-auth gate the POST uses).
|
||||
// /health is not usable: nginx only proxies location /upload.
|
||||
void testConnection();
|
||||
|
||||
signals:
|
||||
void uploadFinished(UploadClient::Result result, const QString &slug,
|
||||
const QString &url, const QString &message);
|
||||
// errorMessage is empty on success.
|
||||
void testFinished(const QString &errorMessage);
|
||||
|
||||
private:
|
||||
QByteArray authHeader() const;
|
||||
|
||||
QString m_base;
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
QNetworkAccessManager *m_net;
|
||||
};
|
||||
Reference in New Issue
Block a user