mirror of
https://gitlab.com/comunic/comunicmessages
synced 2024-12-04 19:24:11 +00:00
Can send image to conversations
This commit is contained in:
parent
0148f7aaa5
commit
9100c14dfd
@ -1,4 +1,5 @@
|
|||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
#include "apirequest.h"
|
#include "apirequest.h"
|
||||||
|
|
||||||
@ -38,6 +39,31 @@ void APIRequest::addBool(QString name, bool value)
|
|||||||
mArguments.append(APIRequestParameter(name, value ? "true" : "false"));
|
mArguments.append(APIRequestParameter(name, value ? "true" : "false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void APIRequest::addFileFromPath(const QString &name, const QString &path, const QString &fileType)
|
||||||
|
{
|
||||||
|
//Determine files name for the request
|
||||||
|
QString partName = name;
|
||||||
|
partName.replace("\"", "\\\"");
|
||||||
|
QString fileName = ("/"+path).split("/").last();
|
||||||
|
fileName.replace("\"", "\\\"");
|
||||||
|
|
||||||
|
QHttpPart part;
|
||||||
|
part.setHeader(QNetworkRequest::ContentTypeHeader, fileType);
|
||||||
|
part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\""+partName+"\"; filename=\""+fileName+"\""));
|
||||||
|
|
||||||
|
QFile *file = new QFile(path);
|
||||||
|
if(!file->open(QIODevice::ReadOnly)){
|
||||||
|
qWarning("Could not open file to send: %s !", path.toStdString().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.setBodyDevice(file);
|
||||||
|
mParts.append(part);
|
||||||
|
|
||||||
|
//Automatically delete file object once request is completed
|
||||||
|
file->setParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
QList<APIRequestParameter> APIRequest::arguments() const
|
QList<APIRequestParameter> APIRequest::arguments() const
|
||||||
{
|
{
|
||||||
return mArguments;
|
return mArguments;
|
||||||
@ -52,3 +78,13 @@ void APIRequest::setNetworkReply(QNetworkReply *networkReply)
|
|||||||
{
|
{
|
||||||
mNetworkReply = networkReply;
|
mNetworkReply = networkReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QHttpPart> *APIRequest::parts()
|
||||||
|
{
|
||||||
|
return &mParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool APIRequest::hasParts() const
|
||||||
|
{
|
||||||
|
return mParts.size() > 0;
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QHttpPart>
|
||||||
|
|
||||||
#include "apirequestparameter.h"
|
#include "apirequestparameter.h"
|
||||||
|
|
||||||
@ -50,6 +51,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
void addBool(QString name, bool value);
|
void addBool(QString name, bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file from filesystem path
|
||||||
|
*
|
||||||
|
* @param name The name of the file to add
|
||||||
|
* @param path The path to the file
|
||||||
|
* @param fileType The type of the file to add
|
||||||
|
*/
|
||||||
|
void addFileFromPath(const QString &name, const QString &path, const QString &fileType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the entire list of arguments of the request
|
* Get the entire list of arguments of the request
|
||||||
*
|
*
|
||||||
@ -57,6 +67,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<APIRequestParameter> arguments() const;
|
QList<APIRequestParameter> arguments() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of HTTP parts included with this request
|
||||||
|
*
|
||||||
|
* @return Pointer on the list containing the list of parts
|
||||||
|
*/
|
||||||
|
QList<QHttpPart> *parts();
|
||||||
|
bool hasParts() const;
|
||||||
|
|
||||||
//Get and set network reply associated with the request
|
//Get and set network reply associated with the request
|
||||||
QNetworkReply *networkReply() const;
|
QNetworkReply *networkReply() const;
|
||||||
void setNetworkReply(QNetworkReply *networkReply);
|
void setNetworkReply(QNetworkReply *networkReply);
|
||||||
@ -91,6 +109,7 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
QString mURI;
|
QString mURI;
|
||||||
QList<APIRequestParameter> mArguments;
|
QList<APIRequestParameter> mArguments;
|
||||||
|
QList<QHttpPart> mParts;
|
||||||
QNetworkReply *mNetworkReply = nullptr;
|
QNetworkReply *mNetworkReply = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,3 +24,18 @@ void NewConversationMessage::setMessage(const QString &message)
|
|||||||
{
|
{
|
||||||
mMessage = message;
|
mMessage = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString NewConversationMessage::imagePath() const
|
||||||
|
{
|
||||||
|
return mImagePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NewConversationMessage::hasImage() const
|
||||||
|
{
|
||||||
|
return !mImagePath.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewConversationMessage::setImagePath(const QString &imagePath)
|
||||||
|
{
|
||||||
|
mImagePath = imagePath;
|
||||||
|
}
|
||||||
|
@ -22,9 +22,14 @@ public:
|
|||||||
QString message() const;
|
QString message() const;
|
||||||
void setMessage(const QString &message);
|
void setMessage(const QString &message);
|
||||||
|
|
||||||
|
QString imagePath() const;
|
||||||
|
bool hasImage() const;
|
||||||
|
void setImagePath(const QString &imagePath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mIDConversation;
|
int mIDConversation;
|
||||||
QString mMessage;
|
QString mMessage;
|
||||||
|
QString mImagePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NEWCONVERSATIONMESSAGE_H
|
#endif // NEWCONVERSATIONMESSAGE_H
|
||||||
|
@ -30,16 +30,49 @@ void APIHelper::execute(APIRequest *request)
|
|||||||
request->addString("userToken2", tokens.token2());
|
request->addString("userToken2", tokens.token2());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Prepare request
|
QNetworkReply *reply = nullptr;
|
||||||
//See this SO question to learn more : https://stackoverflow.com/questions/2599423
|
|
||||||
QUrlQuery queryData;
|
|
||||||
for(APIRequestParameter param : request->arguments())
|
|
||||||
queryData.addQueryItem(param.name(), param.value());
|
|
||||||
|
|
||||||
//Send request
|
//Prepare request
|
||||||
QNetworkRequest networkRequest((QUrl(requestURL)));
|
//Check if the request contains files or not
|
||||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
if(!request->hasParts()){
|
||||||
QNetworkReply *reply = mNetworkManager.post(networkRequest, queryData.toString(QUrl::FullyEncoded).toUtf8());
|
|
||||||
|
//See this SO question to learn more : https://stackoverflow.com/questions/2599423
|
||||||
|
QUrlQuery queryData;
|
||||||
|
for(APIRequestParameter param : request->arguments())
|
||||||
|
queryData.addQueryItem(param.name(), param.value());
|
||||||
|
|
||||||
|
//Send request
|
||||||
|
QNetworkRequest networkRequest((QUrl(requestURL)));
|
||||||
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
reply = mNetworkManager.post(networkRequest, queryData.toString(QUrl::FullyEncoded).toUtf8());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Multiple entries request
|
||||||
|
else {
|
||||||
|
|
||||||
|
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||||
|
|
||||||
|
//Process the list of "normal" arguments
|
||||||
|
for(APIRequestParameter param : request->arguments()){
|
||||||
|
QHttpPart part;
|
||||||
|
part.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\""+param.name()+"\"");
|
||||||
|
part.setBody(param.value().toStdString().c_str());
|
||||||
|
multiPart->append(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Append all the other parts
|
||||||
|
for(int i = 0; i < request->parts()->size(); i++)
|
||||||
|
multiPart->append(request->parts()->at(i));
|
||||||
|
|
||||||
|
//Send request
|
||||||
|
QNetworkRequest networkRequest((QUrl(requestURL)));
|
||||||
|
reply = mNetworkManager.post(networkRequest, multiPart);
|
||||||
|
|
||||||
|
//Delete multipart as soon as the request ends
|
||||||
|
multiPart->setParent(reply);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Make connections
|
//Make connections
|
||||||
connect(reply, &QNetworkReply::finished, this, &APIHelper::finished);
|
connect(reply, &QNetworkReply::finished, this, &APIHelper::finished);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "apihelper.h"
|
#include "apihelper.h"
|
||||||
#include "conversationhelper.h"
|
#include "conversationhelper.h"
|
||||||
#include "../data/apirequest.h"
|
#include "../data/apirequest.h"
|
||||||
|
#include "../utils/filesutils.h"
|
||||||
|
|
||||||
ConversationHelper::ConversationHelper(QObject *parent) : QObject(parent)
|
ConversationHelper::ConversationHelper(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
@ -17,6 +18,14 @@ void ConversationHelper::sendMessage(const NewConversationMessage &message)
|
|||||||
request->addInt("conversationID", message.iDConversation());
|
request->addInt("conversationID", message.iDConversation());
|
||||||
request->addString("message", message.message());
|
request->addString("message", message.message());
|
||||||
|
|
||||||
|
//Add image (if any)
|
||||||
|
if(message.hasImage()){
|
||||||
|
|
||||||
|
//Add image to request
|
||||||
|
request->addFileFromPath("image", message.imagePath(), FilesUtils::GetFileMimeType(message.imagePath()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
connect(request, &APIRequest::finished, this, &ConversationHelper::sendMessageFinished);
|
connect(request, &APIRequest::finished, this, &ConversationHelper::sendMessageFinished);
|
||||||
mAPIHelper->execute(request);
|
mAPIHelper->execute(request);
|
||||||
}
|
}
|
||||||
|
BIN
res/baseline_insert_photo_black_48dp.png
Executable file
BIN
res/baseline_insert_photo_black_48dp.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 509 B |
@ -3,5 +3,6 @@
|
|||||||
<file>baseline_people_black_48dp.png</file>
|
<file>baseline_people_black_48dp.png</file>
|
||||||
<file>baseline_access_time_black_48dp.png</file>
|
<file>baseline_access_time_black_48dp.png</file>
|
||||||
<file>baseline_person_black_48dp.png</file>
|
<file>baseline_person_black_48dp.png</file>
|
||||||
|
<file>baseline_insert_photo_black_48dp.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
|
||||||
#include "filesutils.h"
|
#include "filesutils.h"
|
||||||
|
|
||||||
@ -17,3 +18,8 @@ bool FilesUtils::CreateDirectoryIfNotExists(const QString &path)
|
|||||||
|
|
||||||
return dir.mkpath(".");
|
return dir.mkpath(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FilesUtils::GetFileMimeType(const QString &filePath)
|
||||||
|
{
|
||||||
|
return (QMimeDatabase()).mimeTypeForFile(filePath).name();
|
||||||
|
}
|
||||||
|
@ -23,6 +23,14 @@ public:
|
|||||||
* FALSE else
|
* FALSE else
|
||||||
*/
|
*/
|
||||||
static bool CreateDirectoryIfNotExists(const QString &path);
|
static bool CreateDirectoryIfNotExists(const QString &path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mime type of a file
|
||||||
|
*
|
||||||
|
* @param filePath The path of the file to determine
|
||||||
|
* @return File type
|
||||||
|
*/
|
||||||
|
static QString GetFileMimeType(const QString &filePath);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILESUTILS_H
|
#endif // FILESUTILS_H
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
#include "conversationwidget.h"
|
#include "conversationwidget.h"
|
||||||
#include "ui_conversationwidget.h"
|
#include "ui_conversationwidget.h"
|
||||||
@ -40,6 +41,31 @@ ConversationWidget::~ConversationWidget()
|
|||||||
delete mTimer;
|
delete mTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConversationWidget::setMessageFormImage()
|
||||||
|
{
|
||||||
|
//Check if an image has already been selected by the user
|
||||||
|
if(hasUserSelectedImageToSend()){
|
||||||
|
|
||||||
|
//Ask user confirmation
|
||||||
|
if(QMessageBox::question(
|
||||||
|
this,
|
||||||
|
tr("Unselect image"),
|
||||||
|
tr("Are you sure to remove currently selected image from message ?")
|
||||||
|
) != QMessageBox::Yes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mPathToCurrentImageInForm = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Pick an image
|
||||||
|
else
|
||||||
|
mPathToCurrentImageInForm = QFileDialog::getOpenFileName(this,
|
||||||
|
tr("Choose image to include in the message"), "", tr("Image Files (*.png *.jpg *.jpeg, *.gif)"));
|
||||||
|
|
||||||
|
//Check if we have an image selected
|
||||||
|
refreshPickImageButton();
|
||||||
|
}
|
||||||
|
|
||||||
void ConversationWidget::sendMessage()
|
void ConversationWidget::sendMessage()
|
||||||
{
|
{
|
||||||
if(isSendMessageFormLocked()){
|
if(isSendMessageFormLocked()){
|
||||||
@ -50,7 +76,7 @@ void ConversationWidget::sendMessage()
|
|||||||
QString content = ui->messageContentInput->text();
|
QString content = ui->messageContentInput->text();
|
||||||
|
|
||||||
//Check message length
|
//Check message length
|
||||||
if(content.length() < CONVERSATION_MESSAGE_MIN_LENGTH){
|
if(content.length() < CONVERSATION_MESSAGE_MIN_LENGTH && !hasUserSelectedImageToSend()){
|
||||||
QMessageBox::warning(this, tr("Invalid message!"), tr("Specified message is too short!"));
|
QMessageBox::warning(this, tr("Invalid message!"), tr("Specified message is too short!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -63,6 +89,10 @@ void ConversationWidget::sendMessage()
|
|||||||
newMessage.setIDConversation(mConversation.iD());
|
newMessage.setIDConversation(mConversation.iD());
|
||||||
newMessage.setMessage(content);
|
newMessage.setMessage(content);
|
||||||
|
|
||||||
|
//Include user image (if any)
|
||||||
|
if(hasUserSelectedImageToSend())
|
||||||
|
newMessage.setImagePath(mPathToCurrentImageInForm);
|
||||||
|
|
||||||
//Request the message to be sent
|
//Request the message to be sent
|
||||||
mConversationHelper->sendMessage(newMessage);
|
mConversationHelper->sendMessage(newMessage);
|
||||||
}
|
}
|
||||||
@ -135,6 +165,7 @@ void ConversationWidget::setSendMessageFormLocked(bool lock)
|
|||||||
{
|
{
|
||||||
ui->sendMessageButton->setEnabled(!lock);
|
ui->sendMessageButton->setEnabled(!lock);
|
||||||
ui->messageContentInput->setEnabled(!lock);
|
ui->messageContentInput->setEnabled(!lock);
|
||||||
|
ui->addImageButton->setEnabled(!lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConversationWidget::isSendMessageFormLocked()
|
bool ConversationWidget::isSendMessageFormLocked()
|
||||||
@ -145,4 +176,21 @@ bool ConversationWidget::isSendMessageFormLocked()
|
|||||||
void ConversationWidget::resetSendMessageForm()
|
void ConversationWidget::resetSendMessageForm()
|
||||||
{
|
{
|
||||||
ui->messageContentInput->setText("");
|
ui->messageContentInput->setText("");
|
||||||
|
mPathToCurrentImageInForm = "";
|
||||||
|
refreshPickImageButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConversationWidget::refreshPickImageButton()
|
||||||
|
{
|
||||||
|
ui->addImageButton->setFlat(hasUserSelectedImageToSend());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConversationWidget::on_addImageButton_clicked()
|
||||||
|
{
|
||||||
|
setMessageFormImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConversationWidget::hasUserSelectedImageToSend()
|
||||||
|
{
|
||||||
|
return !mPathToCurrentImageInForm.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,17 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the user to choose an image to send with the form
|
||||||
|
*/
|
||||||
|
void setMessageFormImage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the message entered by the user in the form
|
* Send the message entered by the user in the form
|
||||||
*/
|
*/
|
||||||
void sendMessage();
|
void sendMessage();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,8 +71,18 @@ private slots:
|
|||||||
|
|
||||||
void on_messageContentInput_returnPressed();
|
void on_messageContentInput_returnPressed();
|
||||||
|
|
||||||
|
void on_addImageButton_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check out whether the user has selected an image to include
|
||||||
|
* to the next message he will send through the form
|
||||||
|
*
|
||||||
|
* @return TRUE if the user has selected an image / FALSE else
|
||||||
|
*/
|
||||||
|
bool hasUserSelectedImageToSend();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods to get and set send message form
|
* Methods to get and set send message form
|
||||||
* lock state
|
* lock state
|
||||||
@ -76,9 +90,11 @@ private:
|
|||||||
void setSendMessageFormLocked(bool lock);
|
void setSendMessageFormLocked(bool lock);
|
||||||
bool isSendMessageFormLocked();
|
bool isSendMessageFormLocked();
|
||||||
void resetSendMessageForm();
|
void resetSendMessageForm();
|
||||||
|
void refreshPickImageButton();
|
||||||
|
|
||||||
//Private fields
|
//Private fields
|
||||||
Ui::ConversationWidget *ui;
|
Ui::ConversationWidget *ui;
|
||||||
|
QString mPathToCurrentImageInForm;
|
||||||
QTimer *mTimer;
|
QTimer *mTimer;
|
||||||
ConversationHelper *mConversationHelper;
|
ConversationHelper *mConversationHelper;
|
||||||
Conversation mConversation;
|
Conversation mConversation;
|
||||||
|
@ -54,6 +54,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addImageButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../res/ressources.qrc">
|
||||||
|
<normaloff>:/baseline_insert_photo_black_48dp.png</normaloff>:/baseline_insert_photo_black_48dp.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="sendMessageButton">
|
<widget class="QPushButton" name="sendMessageButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -65,6 +79,8 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources>
|
||||||
|
<include location="../res/ressources.qrc"/>
|
||||||
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
Loading…
Reference in New Issue
Block a user