ImageUpload playground

This commit is contained in:
Dusko Angirevic 2017-07-06 00:59:00 +02:00
parent eb6f167777
commit a19d7503b0
7 changed files with 277 additions and 58 deletions

View file

@ -14,7 +14,8 @@ TARGET = harbour-tooter
CONFIG += sailfishapp
SOURCES += src/harbour-tooter.cpp
SOURCES += src/harbour-tooter.cpp \
src/imageuploader.cpp
OTHER_FILES += qml/harbour-tooter.qml \
qml/cover/CoverPage.qml \
@ -63,3 +64,6 @@ DISTFILES += \
qml/lib/Mastodon.js \
qml/lib/Worker.js \
qml/images/boosted.svg
HEADERS += \
src/imageuploader.h

View file

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.0.1, 2017-07-04T16:29:05. -->
<!-- Written by QtCreator 4.0.1, 2017-07-06T00:58:07. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{25497605-1bff-4134-a878-76c1475dd8e3}</value>
<value type="QByteArray">{41ec03ca-9430-48f3-b421-990d428b2838}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
@ -61,12 +61,12 @@
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">MerSDK-SailfishOS-i486</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">MerSDK-SailfishOS-i486</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{f49c1b5a-d715-401a-9a10-0e5fe9e5b72a}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{fd18ca89-dfc9-4054-9c53-c67be7689951}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">2</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_i486-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -138,7 +138,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_i486-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -210,7 +210,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_i486-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_i486-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -396,7 +396,7 @@
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="MerRunConfiguration.QmlLiveBenchWorkspace">C:/Users/dysko/SF/harbour-tooter</value>
<value type="QString" key="MerRunConfiguration.QmlLiveBenchWorkspace">/Users/dysko/GIT/harbour-tooter</value>
<value type="bool" key="MerRunConfiguration.QmlLiveEnabled">false</value>
<value type="int" key="MerRunConfiguration.QmlLiveIpcPort">10234</value>
<value type="int" key="MerRunConfiguration.QmlLiveOptions">3</value>
@ -426,12 +426,12 @@
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">MerSDK-SailfishOS-armv7hl</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">MerSDK-SailfishOS-armv7hl</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{588087e2-ecc1-41aa-b652-86f16cba9351}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{f895389d-b51a-4d4f-8b03-5ec64bda6f66}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">2</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -503,7 +503,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -575,7 +575,7 @@
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/dysko/SF/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Users/dysko/GIT/build-harbour-tooter-MerSDK_SailfishOS_armv7hl-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -761,7 +761,7 @@
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="MerRunConfiguration.QmlLiveBenchWorkspace">C:/Users/dysko/SF/harbour-tooter</value>
<value type="QString" key="MerRunConfiguration.QmlLiveBenchWorkspace">/Users/dysko/GIT/harbour-tooter</value>
<value type="bool" key="MerRunConfiguration.QmlLiveEnabled">false</value>
<value type="int" key="MerRunConfiguration.QmlLiveIpcPort">10234</value>
<value type="int" key="MerRunConfiguration.QmlLiveOptions">3</value>

View file

@ -52,7 +52,8 @@ ApplicationWindow
}
if (Logic.conf['login']) {
Logic.api.setConfig("api_user_token", Logic.conf['api_user_token'])
pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {})
//pageStack.push(Qt.resolvedUrl("./pages/MainPage.qml"), {})
pageStack.push(Qt.resolvedUrl("./pages/Conversation.qml"), {})
} else {
pageStack.push(Qt.resolvedUrl("./pages/LoginPage.qml"), {})
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.tooter.Uploader 1.0
import "../lib/API.js" as Logic
import "./components/"
@ -99,7 +100,7 @@ Page {
}
autoScrollEnabled: true
labelVisible: false
// focus: true
// focus: true
text: description !== "" && (description.charAt(0) == '@' || description.charAt(0) == '#') ? description+' ' : ''
height: implicitHeight
horizontalAlignment: Text.AlignLeft
@ -119,12 +120,76 @@ Page {
: (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
onClicked: warningContent.visible = !warningContent.visible
}
IconButton {
id: btnAddImage
anchors {
verticalCenter: privacy.verticalCenter
left: btnContentWarning.right
leftMargin: Theme.paddingSmall
}
icon.source: "image://theme/icon-s-attach?" + (pressed
? Theme.highlightColor
: (warningContent.visible ? Theme.secondaryHighlightColor : Theme.primaryColor))
onClicked: {
//receiver.receiveFromQml(42);
//imageUploader.run()
var once = true;
var imagePicker = pageStack.push("Sailfish.Pickers.MultiImagePickerDialog", { "allowedOrientations" : Orientation.All });
imagePicker.selectedContentChanged.connect(function () {
if (once) {
for(var i = 0; i < imagePicker.selectedContent.count; i++){
var file = imagePicker.selectedContent.get(i);
console.log(JSON.stringify(file))
imageUploader.setFile(file.url);
imageUploader.setAuthorizationHeader(Logic.conf.api_user_token);
imageUploader.upload();
}
once = false;
}
/*var file = imagePicker.selectedContent + "";
//file = file.replace("file://", "");
console.log(file)
imageUploader.setFile(file);
imageUploader.setAuthorizationHeader(Logic.conf.api_user_token);
imageUploader.upload();*/
});
}
}
ImageUploader {
id: imageUploader
onProgressChanged: {
console.log("progress "+progress)
}
onSuccess: {
console.log(replyData);
}
onFailure: {
console.log(status)
console.log(statusText)
}
function run() {
imageUploader.setFile('file:///media/sdcard/686E-E026/Pictures/Camera/20170701_143819.jpg');
imageUploader.setParameters("imageUploadData.imageAlbum", "imageUploadData.imageTitle", "imageUploadData.imageDesc");
imageUploader.setAuthorizationHeader(Logic.conf.api_user_token);
imageUploader.setUserAgent("constant.userAgent");
imageUploader.upload();
}
}
ComboBox {
id: privacy
anchors {
top: toot.bottom
topMargin: -Theme.paddingSmall*2
left: btnContentWarning.right
left: btnAddImage.right
right: btnSend.left
}
menu: ContextMenu {

View file

@ -1,50 +1,23 @@
/*
Copyright (C) 2013 Jolla Ltd.
Contact: Thomas Perl <thomas.perl@jollamobile.com>
All rights reserved.
You may use this file under the terms of BSD license as follows:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Jolla Ltd nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
#include "imageuploader.h"
int main(int argc, char *argv[])
{
// SailfishApp::main() will display "qml/template.qml", if you need more
// control over initialization, you can use:
//
// - SailfishApp::application(int, char *[]) to get the QGuiApplication *
// - SailfishApp::createView() to get a new QQuickView * instance
// - SailfishApp::pathTo(QString) to get a QUrl to a resource file
//
// To display the view, call "show()" (will show fullscreen on device).
QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
QScopedPointer<QQuickView> view(SailfishApp::createView());
QQmlContext *context = view.data()->rootContext();
return SailfishApp::main(argc, argv);
qmlRegisterType<ImageUploader>("harbour.tooter.Uploader", 1, 0, "ImageUploader");
QQmlEngine* engine = view->engine();
QObject::connect(engine, SIGNAL(quit()), app.data(), SLOT(quit()));
view->setSource(SailfishApp::pathTo("qml/harbour-tooter.qml"));
view->show();
return app->exec();
}

130
src/imageuploader.cpp Normal file
View file

@ -0,0 +1,130 @@
#include "imageuploader.h"
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QHttpMultiPart>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
//static const QUrl IMGUR_UPLOAD_URL("https://httpbin.org/post");
static const QUrl IMGUR_UPLOAD_URL("https://mastodon.social/api/v1/media");
ImageUploader::ImageUploader(QObject *parent) : QObject(parent), m_networkAccessManager(0), m_reply(0) {
m_networkAccessManager = new QNetworkAccessManager(this);
}
ImageUploader::~ImageUploader() {
if (m_reply != 0) {
m_reply->disconnect();
m_reply->deleteLater();
m_reply = 0;
}
}
void ImageUploader::setFile(const QString &fileName) {
m_fileName = fileName;
}
void ImageUploader::setParameters(const QString &album, const QString &title, const QString &description) {
//if (!album.isEmpty()) {
postdata.append(QString("album=").toUtf8());
postdata.append(QUrl::toPercentEncoding(album));
//}
if (!title.isEmpty()) {
postdata.append(QString("&title=").toUtf8());
postdata.append(QUrl::toPercentEncoding(title));
}
if (!description.isEmpty()) {
postdata.append(QString("&description=").toUtf8());
postdata.append(QUrl::toPercentEncoding(description));
}
}
void ImageUploader::setAuthorizationHeader(const QString &authorizationHeader) {
m_authorizationHeader = "Bearer "+authorizationHeader.toUtf8();
}
void ImageUploader::setUserAgent(const QString &userAgent) {
m_userAgent = userAgent.toUtf8();
}
void ImageUploader::upload() {
if (!m_networkAccessManager) {
qWarning("ImageUploader::send(): networkAccessManager not set");
return;
}
if (m_reply != 0) {
m_reply->disconnect();
m_reply->deleteLater();
m_reply = 0;
}
qDebug() << "TwitterApi::uploadImage";
QUrl url = IMGUR_UPLOAD_URL;
QNetworkRequest request(url);
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
//imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\""));
QFile *file = new QFile(m_fileName);
file->open(QIODevice::ReadOnly);
QByteArray rawImage = file->readAll();
imagePart.setBody(rawImage);
file->setParent(multiPart);
multiPart->append(imagePart);
//request.setUrl(IMGUR_UPLOAD_URL);
request.setRawHeader("Authorization", m_authorizationHeader);
request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
// request.setRawHeader("User-Agent", m_userAgent);
m_reply = m_networkAccessManager->post(request, multiPart);
multiPart->setParent(m_reply);
m_reply->setObjectName("file");
connect(m_reply, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished()));
}
qreal ImageUploader::progress() const {
return m_progress;
}
void ImageUploader::uploadProgress(qint64 bytesSent, qint64 bytesTotal) {
qreal progress = qreal(bytesSent) / qreal(bytesTotal);
//qDebug("uploadProgress: %f , %f, %f", qreal(bytesSent), qreal(bytesTotal), qreal(progress));
if (m_progress != progress) {
m_progress = progress;
emit progressChanged();
}
}
void ImageUploader::replyFinished() {
if (!m_reply->error()) {
QByteArray replyData = m_reply->readAll();
emit success(replyData);
}
else {
int status = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString statusText = m_reply->errorString();
emit failure(status, statusText);
}
m_reply->deleteLater();
m_reply = 0;
postdata.clear();
}

46
src/imageuploader.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef IMAGEUPLOADER_H
#define IMAGEUPLOADER_H
#include <QtCore/QObject>
class QNetworkAccessManager;
class QNetworkReply;
class ImageUploader : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
public:
explicit ImageUploader(QObject *parent = 0);
~ImageUploader();
Q_INVOKABLE void setFile(const QString &fileName);
Q_INVOKABLE void setAuthorizationHeader(const QString &authorizationHeader);
Q_INVOKABLE void setUserAgent(const QString &userAgent);
Q_INVOKABLE void setParameters(const QString &album, const QString &title, const QString &description);
Q_INVOKABLE void upload();
qreal progress() const;
signals:
void success(const QString &replyData);
void failure(const int status, const QString &statusText);
void progressChanged();
private slots:
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
void replyFinished();
private:
qreal m_progress;
QNetworkAccessManager *m_networkAccessManager;
QString m_fileName;
QByteArray m_authorizationHeader;
QByteArray m_userAgent;
QByteArray postdata;
QNetworkReply *m_reply;
};
#endif // IMAGEUPLOADER_H