mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-05-06 20:23:08 +00:00
Fix file transfert and notification behaviour
- Add External Image Provider to avoid having error message when we try to show a file that is not an image (used to show an attachment where it can be a regular file). - When creating an image, try to read the headers of a file when the extension is not consistent with contents. - Build if not exists, a thumbnail image if the file has been displayed when filling a message - When trying to open the file, test if it was downloaded by reading the flag - Add a status for File Transfert In Progress - Use non-deprecated function to get file path from ChatMessage - Use FileSize in addtion of content Size to get the full size of a message - Show a progressbar when downloading a file - Show the image in notification when downloaded or the file name if it is not an image
This commit is contained in:
parent
dbf1f6801a
commit
d6f5a7f0ce
10 changed files with 177 additions and 77 deletions
|
|
@ -99,6 +99,7 @@ set(SOURCES
|
|||
src/app/paths/Paths.cpp
|
||||
src/app/providers/AvatarProvider.cpp
|
||||
src/app/providers/ImageProvider.cpp
|
||||
src/app/providers/ExternalImageProvider.cpp
|
||||
src/app/providers/ThumbnailProvider.cpp
|
||||
src/app/translator/DefaultTranslator.cpp
|
||||
src/components/assistant/AssistantModel.cpp
|
||||
|
|
@ -156,6 +157,7 @@ set(HEADERS
|
|||
src/app/paths/Paths.hpp
|
||||
src/app/providers/AvatarProvider.hpp
|
||||
src/app/providers/ImageProvider.hpp
|
||||
src/app/providers/ExternalImageProvider.hpp
|
||||
src/app/providers/ThumbnailProvider.hpp
|
||||
src/app/single-application/SingleApplication.hpp
|
||||
src/app/translator/DefaultTranslator.hpp
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "paths/Paths.hpp"
|
||||
#include "providers/AvatarProvider.hpp"
|
||||
#include "providers/ImageProvider.hpp"
|
||||
#include "providers/ExternalImageProvider.hpp"
|
||||
#include "providers/ThumbnailProvider.hpp"
|
||||
#include "translator/DefaultTranslator.hpp"
|
||||
#include "utils/LinphoneUtils.hpp"
|
||||
|
|
@ -316,6 +317,7 @@ void App::initContentApp () {
|
|||
// Provide avatars/thumbnails providers.
|
||||
mEngine->addImageProvider(AvatarProvider::ProviderId, new AvatarProvider());
|
||||
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
|
||||
mEngine->addImageProvider(ExternalImageProvider::ProviderId, new ExternalImageProvider());
|
||||
mEngine->addImageProvider(ThumbnailProvider::ProviderId, new ThumbnailProvider());
|
||||
|
||||
mEngine->rootContext()->setContextProperty("applicationUrl", APPLICATION_URL);
|
||||
|
|
|
|||
49
linphone-app/src/app/providers/ExternalImageProvider.cpp
Normal file
49
linphone-app/src/app/providers/ExternalImageProvider.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "ExternalImageProvider.hpp"
|
||||
|
||||
#include <QImageReader>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
const QString ExternalImageProvider::ProviderId = "external";
|
||||
|
||||
ExternalImageProvider::ExternalImageProvider () : QQuickImageProvider(
|
||||
QQmlImageProviderBase::Image,
|
||||
QQmlImageProviderBase::ForceAsynchronousImageLoading
|
||||
) {
|
||||
}
|
||||
|
||||
QImage ExternalImageProvider::requestImage (const QString &id, QSize *size, const QSize &) {
|
||||
QImage image(id);
|
||||
if(image.isNull()){// Try to determine format from headers instead of using suffix
|
||||
QImageReader reader(id);
|
||||
reader.setDecideFormatFromContent(true);
|
||||
QByteArray format = reader.format();
|
||||
if(!format.isEmpty())
|
||||
image = QImage(id, format);
|
||||
}
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
37
linphone-app/src/app/providers/ExternalImageProvider.hpp
Normal file
37
linphone-app/src/app/providers/ExternalImageProvider.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXTERNAL_IMAGE_PROVIDER_H_
|
||||
#define EXTERNAL_IMAGE_PROVIDER_H_
|
||||
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ExternalImageProvider : public QQuickImageProvider {
|
||||
public:
|
||||
ExternalImageProvider ();
|
||||
|
||||
QImage requestImage (const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
|
||||
static const QString ProviderId;
|
||||
};
|
||||
|
||||
#endif // EXTERNAL_IMAGE_PROVIDER_H_
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
#include <QMessageBox>
|
||||
#include <QUrlQuery>
|
||||
#include <QImageReader>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
|
|
@ -129,45 +131,46 @@ static inline void createThumbnail (const shared_ptr<linphone::ChatMessage> &mes
|
|||
std::list<std::shared_ptr<linphone::Content> > contents = message->getContents();
|
||||
if( contents.size() > 0)
|
||||
{
|
||||
MessageAppData thumbnailData;
|
||||
MessageAppData thumbnailData;
|
||||
thumbnailData.m_path = Utils::coreStringToAppString(contents.front()->getFilePath());
|
||||
QImage image(thumbnailData.m_path);
|
||||
if (image.isNull())
|
||||
return;
|
||||
|
||||
int rotation = 0;
|
||||
QExifImageHeader exifImageHeader;
|
||||
if (exifImageHeader.loadFromJpeg(thumbnailData.m_path))
|
||||
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
|
||||
|
||||
QImage thumbnail = image.scaled(
|
||||
ThumbnailImageFileWidth, ThumbnailImageFileHeight,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation
|
||||
);
|
||||
|
||||
if (rotation != 0) {
|
||||
QTransform transform;
|
||||
if (rotation == 3 || rotation == 4)
|
||||
transform.rotate(180);
|
||||
else if (rotation == 5 || rotation == 6)
|
||||
transform.rotate(90);
|
||||
else if (rotation == 7 || rotation == 8)
|
||||
transform.rotate(-90);
|
||||
|
||||
thumbnail = thumbnail.transformed(transform);
|
||||
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
|
||||
thumbnail = thumbnail.mirrored(true, false);
|
||||
}
|
||||
|
||||
QString uuid = QUuid::createUuid().toString();
|
||||
thumbnailData.m_id = QStringLiteral("%1.jpg").arg(uuid.mid(1, uuid.length() - 2));
|
||||
|
||||
if (!thumbnail.save(Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + thumbnailData.m_id , "jpg", 100)) {
|
||||
qWarning() << QStringLiteral("Unable to create thumbnail of: `%1`.").arg(thumbnailData.m_path);
|
||||
return;
|
||||
}
|
||||
|
||||
message->setAppdata(Utils::appStringToCoreString(thumbnailData.toString()));
|
||||
QImage image(thumbnailData.m_path);
|
||||
if( image.isNull()){// Try to determine format from headers
|
||||
QImageReader reader(thumbnailData.m_path);
|
||||
reader.setDecideFormatFromContent(true);
|
||||
QByteArray format = reader.format();
|
||||
if(!format.isEmpty())
|
||||
image = QImage(thumbnailData.m_path, format);
|
||||
}
|
||||
if (!image.isNull()){
|
||||
int rotation = 0;
|
||||
QExifImageHeader exifImageHeader;
|
||||
if (exifImageHeader.loadFromJpeg(thumbnailData.m_path))
|
||||
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
|
||||
QImage thumbnail = image.scaled(
|
||||
ThumbnailImageFileWidth, ThumbnailImageFileHeight,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation
|
||||
);
|
||||
|
||||
if (rotation != 0) {
|
||||
QTransform transform;
|
||||
if (rotation == 3 || rotation == 4)
|
||||
transform.rotate(180);
|
||||
else if (rotation == 5 || rotation == 6)
|
||||
transform.rotate(90);
|
||||
else if (rotation == 7 || rotation == 8)
|
||||
transform.rotate(-90);
|
||||
thumbnail = thumbnail.transformed(transform);
|
||||
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
|
||||
thumbnail = thumbnail.mirrored(true, false);
|
||||
}
|
||||
QString uuid = QUuid::createUuid().toString();
|
||||
thumbnailData.m_id = QStringLiteral("%1.jpg").arg(uuid.mid(1, uuid.length() - 2));
|
||||
|
||||
if (!thumbnail.save(Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + thumbnailData.m_id , "jpg", 100)) {
|
||||
qWarning() << QStringLiteral("Unable to create thumbnail of: `%1`.").arg(thumbnailData.m_path);
|
||||
}
|
||||
}
|
||||
message->setAppdata(Utils::appStringToCoreString(thumbnailData.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +180,7 @@ static inline void removeFileMessageThumbnail (const shared_ptr<linphone::ChatMe
|
|||
MessageAppData thumbnailFile = getMessageAppData(message);
|
||||
if(thumbnailFile.m_id.size() > 0)
|
||||
{
|
||||
QString thumbnailPath = Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + thumbnailFile.m_id;
|
||||
QString thumbnailPath = Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + thumbnailFile.m_id;
|
||||
if (!QFile::remove(thumbnailPath))
|
||||
qWarning() << QStringLiteral("Unable to remove `%1`.").arg(thumbnailPath);
|
||||
}
|
||||
|
|
@ -202,10 +205,11 @@ static inline void fillMessageEntry (QVariantMap &dest, const shared_ptr<linphon
|
|||
shared_ptr<const linphone::Content> content = message->getFileTransferInformation();
|
||||
if (content) {
|
||||
dest["fileSize"] = quint64(content->getFileSize());
|
||||
dest["fileName"] = Utils::coreStringToAppString(content->getName());
|
||||
dest["wasDownloaded"] = ::fileWasDownloaded(message);
|
||||
|
||||
fillThumbnailProperty(dest, message);
|
||||
dest["fileName"] =Utils::coreStringToAppString(content->getName());
|
||||
if (state==linphone::ChatMessage::State::Displayed)
|
||||
createThumbnail(message);
|
||||
fillThumbnailProperty(dest, message);
|
||||
dest["wasDownloaded"] = ::fileWasDownloaded(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,9 +289,7 @@ private:
|
|||
if (state == linphone::ChatMessage::State::FileTransferDone && !message->isOutgoing()) {
|
||||
createThumbnail(message);
|
||||
fillThumbnailProperty((*it).first, message);
|
||||
|
||||
(*it).first["wasDownloaded"] = true;
|
||||
|
||||
App::getInstance()->getNotifier()->notifyReceivedFileMessage(message);
|
||||
}
|
||||
|
||||
|
|
@ -518,12 +520,10 @@ void ChatModel::sendFileMessage (const QString &path) {
|
|||
content->setType(Utils::appStringToCoreString(mimeType[0]));
|
||||
content->setSubtype(Utils::appStringToCoreString(mimeType[1]));
|
||||
}
|
||||
|
||||
content->setSize(size_t(fileSize));
|
||||
content->setName(Utils::appStringToCoreString(QFileInfo(file).fileName()));
|
||||
|
||||
content->setSize(size_t(fileSize));
|
||||
content->setName(Utils::appStringToCoreString( QFileInfo(file).fileName()));
|
||||
shared_ptr<linphone::ChatMessage> message = mChatRoom->createFileTransferMessage(content);
|
||||
message->getContents().front()->setFilePath(Utils::appStringToCoreString(path));// Sending only one File Path?
|
||||
message->getContents().front()->setFilePath(Utils::appStringToCoreString(path));
|
||||
message->addListener(mMessageHandlers);
|
||||
|
||||
createThumbnail(message);
|
||||
|
|
@ -570,9 +570,9 @@ void ChatModel::downloadFile (int id) {
|
|||
|
||||
message->getContents().front()->setFilePath(Utils::appStringToCoreString(safeFilePath));
|
||||
|
||||
if( !message->isFileTransfer())
|
||||
QMessageBox::warning(nullptr, "Download File", "This file was already downloaded and is no more on the server. Your peer have to resend it if you want to get it");
|
||||
else
|
||||
if( !message->isFileTransfer()){
|
||||
QMessageBox::warning(nullptr, "Download File", "This file was already downloaded and is no more on the server. Your peer have to resend it if you want to get it");
|
||||
}else
|
||||
{
|
||||
if (!message->downloadContent(message->getFileTransferInformation()))
|
||||
qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(id);
|
||||
|
|
@ -585,15 +585,14 @@ void ChatModel::openFile (int id, bool showDirectory) {
|
|||
return;
|
||||
|
||||
shared_ptr<linphone::ChatMessage> message = static_pointer_cast<linphone::ChatMessage>(entry.second);
|
||||
if (!::fileWasDownloaded(message)) {
|
||||
if (!entry.first["wasDownloaded"].toBool()) {
|
||||
downloadFile(id);
|
||||
return;
|
||||
}else{
|
||||
QFileInfo info(getMessageAppData(message).m_path);
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath()))
|
||||
);
|
||||
}
|
||||
|
||||
QFileInfo info(getMessageAppData(message).m_path);
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath()))
|
||||
);
|
||||
}
|
||||
|
||||
bool ChatModel::fileWasDownloaded (int id) {
|
||||
|
|
|
|||
|
|
@ -61,9 +61,11 @@ public:
|
|||
MessageStatusDisplayed = int(linphone::ChatMessage::State::Displayed),
|
||||
MessageStatusFileTransferDone = int(linphone::ChatMessage::State::FileTransferDone),
|
||||
MessageStatusFileTransferError = int(linphone::ChatMessage::State::FileTransferError),
|
||||
MessageStatusFileTransferInProgress = int(linphone::ChatMessage::State::FileTransferInProgress),
|
||||
MessageStatusIdle = int(linphone::ChatMessage::State::Idle),
|
||||
MessageStatusInProgress = int(linphone::ChatMessage::State::InProgress),
|
||||
MessageStatusNotDelivered = int(linphone::ChatMessage::State::NotDelivered)
|
||||
|
||||
};
|
||||
Q_ENUM(MessageStatus);
|
||||
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ void Notifier::deleteNotification (QVariant notification) {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &message) {
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedMessage);
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedMessage)
|
||||
|
||||
QVariantMap map;
|
||||
map["message"] = message->getFileTransferInformation()
|
||||
|
|
@ -240,21 +240,21 @@ void Notifier::notifyReceivedMessage (const shared_ptr<linphone::ChatMessage> &m
|
|||
map["localAddress"] = Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly());
|
||||
map["window"].setValue(App::getInstance()->getMainWindow());
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
void Notifier::notifyReceivedFileMessage (const shared_ptr<linphone::ChatMessage> &message) {
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedFileMessage);
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedFileMessage)
|
||||
|
||||
QVariantMap map;
|
||||
map["fileUri"] = Utils::coreStringToAppString(message->getFileTransferFilepath());
|
||||
map["fileSize"] = quint64(message->getFileTransferInformation()->getSize());
|
||||
map["fileUri"] = Utils::coreStringToAppString(message->getFileTransferInformation()->getFilePath());
|
||||
map["fileSize"] = quint64(message->getFileTransferInformation()->getSize() +message->getFileTransferInformation()->getFileSize());
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
void Notifier::notifyReceivedCall (const shared_ptr<linphone::Call> &call) {
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedCall);
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedCall)
|
||||
|
||||
CallModel *callModel = &call->getData<CallModel>("call-model");
|
||||
|
||||
|
|
@ -266,35 +266,35 @@ void Notifier::notifyReceivedCall (const shared_ptr<linphone::Call> &call) {
|
|||
QVariantMap map;
|
||||
map["call"].setValue(callModel);
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
void Notifier::notifyNewVersionAvailable (const QString &version, const QString &url) {
|
||||
CREATE_NOTIFICATION(Notifier::NewVersionAvailable);
|
||||
CREATE_NOTIFICATION(Notifier::NewVersionAvailable)
|
||||
|
||||
QVariantMap map;
|
||||
map["message"] = tr("newVersionAvailable").arg(version);
|
||||
map["url"] = url;
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
void Notifier::notifySnapshotWasTaken (const QString &filePath) {
|
||||
CREATE_NOTIFICATION(Notifier::SnapshotWasTaken);
|
||||
CREATE_NOTIFICATION(Notifier::SnapshotWasTaken)
|
||||
|
||||
QVariantMap map;
|
||||
map["filePath"] = filePath;
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
void Notifier::notifyRecordingCompleted (const QString &filePath) {
|
||||
CREATE_NOTIFICATION(Notifier::RecordingCompleted);
|
||||
CREATE_NOTIFICATION(Notifier::RecordingCompleted)
|
||||
|
||||
QVariantMap map;
|
||||
map["filePath"] = filePath;
|
||||
|
||||
SHOW_NOTIFICATION(map);
|
||||
SHOW_NOTIFICATION(map)
|
||||
}
|
||||
|
||||
#undef SHOW_NOTIFICATION
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ Row {
|
|||
|
||||
to: $chatEntry.fileSize
|
||||
value: $chatEntry.fileOffset || 0
|
||||
visible: $chatEntry.status === ChatModel.MessageStatusInProgress
|
||||
visible: $chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
|
||||
|
||||
background: Rectangle {
|
||||
color: ChatStyle.entry.message.file.status.bar.background.color
|
||||
|
|
@ -322,7 +322,7 @@ Row {
|
|||
|
||||
sourceComponent: $chatEntry.isOutgoing
|
||||
? (
|
||||
$chatEntry.status === ChatModel.MessageStatusInProgress
|
||||
$chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
|
||||
? indicator
|
||||
: icon
|
||||
) : undefined
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ Item {
|
|||
height: ChatStyle.entry.lineHeight
|
||||
width: ChatStyle.entry.message.outgoing.areaSize
|
||||
|
||||
sourceComponent: $chatEntry.status === ChatModel.MessageStatusInProgress
|
||||
sourceComponent: $chatEntry.status === ChatModel.MessageStatusInProgress || $chatEntry.status === ChatModel.MessageStatusFileTransferInProgress
|
||||
? indicator
|
||||
: icon
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ Notification {
|
|||
elide: Text.ElideRight
|
||||
font.pointSize: NotificationReceivedFileMessageStyle.fileName.pointSize
|
||||
text: Utils.basename(notification.fileUri)
|
||||
visible:!image.visible
|
||||
}
|
||||
Image{
|
||||
id:image
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "image://external/"+notification.fileUri
|
||||
visible: image.status == Image.Ready
|
||||
}
|
||||
|
||||
Text {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue