mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-05-07 14:44:01 +00:00
feat(app): download directly file chat message (without dialogs)
This commit is contained in:
parent
64f0ab733d
commit
519e85158e
14 changed files with 120 additions and 57 deletions
|
|
@ -760,13 +760,6 @@ Server url not configured.</translation>
|
|||
<translation>It's necessary to restart the application. Do you want to restart now?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FileMessage</name>
|
||||
<message>
|
||||
<source>downloadFileTitle</source>
|
||||
<translation>Download file</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Home</name>
|
||||
<message>
|
||||
|
|
@ -1292,6 +1285,10 @@ your friend's SIP address or username.</translation>
|
|||
<source>cleanAvatarsDescription</source>
|
||||
<translation>Are you sure you want to clean all avatars?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>downloadLabel</source>
|
||||
<translation>Download folder</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsVideo</name>
|
||||
|
|
|
|||
|
|
@ -760,13 +760,6 @@ Url du serveur non configurée.</translation>
|
|||
<translation>Voulez-vous redémarrer maintenant pour prendre en compte ces modifications ?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FileMessage</name>
|
||||
<message>
|
||||
<source>downloadFileTitle</source>
|
||||
<translation>Télécharger le fichier</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Home</name>
|
||||
<message>
|
||||
|
|
@ -1291,6 +1284,10 @@ un chat ou ajouter un contact.</translation>
|
|||
<source>cleanAvatarsDescription</source>
|
||||
<translation>Voulez-vous vraiment supprimer tous les avatars ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>downloadLabel</source>
|
||||
<translation>Dossier des téléchargements</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SettingsVideo</name>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <QtDebug>
|
||||
|
||||
#include "../../utils/Utils.hpp"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "Paths.hpp"
|
||||
|
|
@ -167,7 +168,7 @@ string Paths::getAvatarsDirPath () {
|
|||
}
|
||||
|
||||
string Paths::getCallHistoryFilePath () {
|
||||
return getWritableFilePath(getAppCallHistoryFilePath());
|
||||
return getWritableFilePath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + PATH_AVATARS);
|
||||
}
|
||||
|
||||
string Paths::getCapturesDirPath () {
|
||||
|
|
@ -189,6 +190,10 @@ string Paths::getFriendsListFilePath () {
|
|||
return getWritableFilePath(getAppFriendsFilePath());
|
||||
}
|
||||
|
||||
std::string Paths::getDownloadDirPath () {
|
||||
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||
}
|
||||
|
||||
string Paths::getLogsDirPath () {
|
||||
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + PATH_LOGS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace Paths {
|
|||
std::string getConfigFilePath (const QString &configPath = QString());
|
||||
std::string getFactoryConfigFilePath ();
|
||||
std::string getFriendsListFilePath ();
|
||||
std::string getDownloadDirPath ();
|
||||
std::string getLogsDirPath ();
|
||||
std::string getMessageHistoryFilePath ();
|
||||
std::string getPackageDataDirPath ();
|
||||
|
|
|
|||
|
|
@ -106,11 +106,9 @@ public:
|
|||
|
||||
private:
|
||||
QList<ChatEntryData>::iterator findMessageEntry (const shared_ptr<linphone::ChatMessage> &message) {
|
||||
return find_if(
|
||||
mChatModel->mEntries.begin(), mChatModel->mEntries.end(), [&message](const ChatEntryData &pair) {
|
||||
return find_if(mChatModel->mEntries.begin(), mChatModel->mEntries.end(), [&message](const ChatEntryData &pair) {
|
||||
return pair.second == message;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void signalDataChanged (const QList<ChatEntryData>::iterator &it) {
|
||||
|
|
@ -390,7 +388,7 @@ void ChatModel::sendFileMessage (const QString &path) {
|
|||
emit messageSent(message);
|
||||
}
|
||||
|
||||
void ChatModel::downloadFile (int id, const QString &downloadPath) {
|
||||
void ChatModel::downloadFile (int id) {
|
||||
if (!mChatRoom)
|
||||
return;
|
||||
|
||||
|
|
@ -423,7 +421,20 @@ void ChatModel::downloadFile (int id, const QString &downloadPath) {
|
|||
return;
|
||||
}
|
||||
|
||||
message->setFileTransferFilepath(::Utils::appStringToCoreString(downloadPath));
|
||||
bool soFarSoGood;
|
||||
const QString &safeFilePath = ::Utils::getSafeFilePath(
|
||||
QStringLiteral("%1%2")
|
||||
.arg(CoreManager::getInstance()->getSettingsModel()->getDownloadFolder())
|
||||
.arg(entry.first["fileName"].toString()),
|
||||
&soFarSoGood
|
||||
);
|
||||
|
||||
if (!soFarSoGood) {
|
||||
qWarning() << QStringLiteral("Unable to create safe file path for: %1.").arg(id);
|
||||
return;
|
||||
}
|
||||
|
||||
message->setFileTransferFilepath(::Utils::appStringToCoreString(safeFilePath));
|
||||
message->setListener(mMessageHandlers);
|
||||
|
||||
if (message->downloadFile() < 0)
|
||||
|
|
@ -486,16 +497,14 @@ void ChatModel::removeEntry (ChatEntryData &pair) {
|
|||
// We are between `beginRemoveRows` and `endRemoveRows`.
|
||||
// A solution is to schedule a `removeEntry` call in the Qt main loop.
|
||||
shared_ptr<void> linphonePtr = pair.second;
|
||||
QTimer::singleShot(
|
||||
0, this, [this, linphonePtr]() {
|
||||
QTimer::singleShot(0, this, [this, linphonePtr]() {
|
||||
auto it = find_if(mEntries.begin(), mEntries.end(), [linphonePtr](const ChatEntryData &pair) {
|
||||
return pair.second == linphonePtr;
|
||||
});
|
||||
|
||||
if (it != mEntries.end())
|
||||
removeEntry(static_cast<int>(distance(mEntries.begin(), it)));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
CoreManager::getInstance()->getCore()->removeCallLog(static_pointer_cast<linphone::CallLog>(pair.second));
|
||||
|
|
@ -525,12 +534,9 @@ void ChatModel::insertCall (const shared_ptr<linphone::CallLog> &callLog) {
|
|||
const ChatEntryData &pair,
|
||||
const QList<ChatEntryData>::iterator *start = NULL
|
||||
) {
|
||||
auto it = lower_bound(
|
||||
start ? *start : mEntries.begin(), mEntries.end(), pair,
|
||||
[](const ChatEntryData &a, const ChatEntryData &b) {
|
||||
auto it = lower_bound(start ? *start : mEntries.begin(), mEntries.end(), pair, [](const ChatEntryData &a, const ChatEntryData &b) {
|
||||
return a.first["timestamp"] < b.first["timestamp"];
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
int row = static_cast<int>(distance(mEntries.begin(), it));
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public:
|
|||
|
||||
void sendFileMessage (const QString &path);
|
||||
|
||||
void downloadFile (int id, const QString &downloadPath);
|
||||
void downloadFile (int id);
|
||||
|
||||
signals:
|
||||
void sipAddressChanged (const QString &sipAddress);
|
||||
|
|
|
|||
|
|
@ -69,17 +69,13 @@ ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent)
|
|||
|
||||
ChatModel *chat = static_cast<ChatModel *>(mChatModelFilter->sourceModel());
|
||||
|
||||
QObject::connect(
|
||||
chat, &ChatModel::messageReceived, this, [this](const shared_ptr<linphone::ChatMessage> &) {
|
||||
QObject::connect(chat, &ChatModel::messageReceived, this, [this](const shared_ptr<linphone::ChatMessage> &) {
|
||||
mMaxDisplayedEntries++;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
chat, &ChatModel::messageSent, this, [this](const shared_ptr<linphone::ChatMessage> &) {
|
||||
QObject::connect(chat, &ChatModel::messageSent, this, [this](const shared_ptr<linphone::ChatMessage> &) {
|
||||
mMaxDisplayedEntries++;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void ChatProxyModel::loadMoreEntries () {
|
||||
|
|
@ -133,10 +129,10 @@ void ChatProxyModel::sendFileMessage (const QString &path) {
|
|||
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->sendFileMessage(path);
|
||||
}
|
||||
|
||||
void ChatProxyModel::downloadFile (int id, const QString &downloadPath) {
|
||||
void ChatProxyModel::downloadFile (int id) {
|
||||
QModelIndex sourceIndex = mapToSource(index(id, 0));
|
||||
static_cast<ChatModel *>(mChatModelFilter->sourceModel())->downloadFile(
|
||||
mChatModelFilter->mapToSource(sourceIndex).row(), downloadPath
|
||||
mChatModelFilter->mapToSource(sourceIndex).row()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
Q_INVOKABLE void sendFileMessage (const QString &path);
|
||||
|
||||
Q_INVOKABLE void downloadFile (int id, const QString &downloadPath);
|
||||
Q_INVOKABLE void downloadFile (int id);
|
||||
|
||||
signals:
|
||||
void sipAddressChanged (const QString &sipAddress);
|
||||
|
|
|
|||
|
|
@ -640,10 +640,27 @@ QString SettingsModel::getSavedVideosFolder () const {
|
|||
}
|
||||
|
||||
void SettingsModel::setSavedVideosFolder (const QString &folder) {
|
||||
QString _folder = QDir::cleanPath(folder) + QDir::separator();
|
||||
QString cleanedFolder = QDir::cleanPath(folder) + QDir::separator();
|
||||
|
||||
mConfig->setString(UI_SECTION, "saved_videos_folder", ::Utils::appStringToCoreString(_folder));
|
||||
emit savedVideosFolderChanged(_folder);
|
||||
mConfig->setString(UI_SECTION, "saved_videos_folder", ::Utils::appStringToCoreString(cleanedFolder));
|
||||
emit savedVideosFolderChanged(cleanedFolder);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QString SettingsModel::getDownloadFolder () const {
|
||||
return QDir::cleanPath(
|
||||
::Utils::coreStringToAppString(
|
||||
mConfig->getString(UI_SECTION, "download_folder", Paths::getDownloadDirPath())
|
||||
)
|
||||
) + QDir::separator();
|
||||
}
|
||||
|
||||
void SettingsModel::setDownloadFolder (const QString &folder) {
|
||||
QString cleanedFolder = QDir::cleanPath(folder) + QDir::separator();
|
||||
|
||||
mConfig->setString(UI_SECTION, "download_folder", ::Utils::appStringToCoreString(cleanedFolder));
|
||||
emit downloadFolderChanged(cleanedFolder);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class SettingsModel : public QObject {
|
|||
|
||||
Q_PROPERTY(QString savedScreenshotsFolder READ getSavedScreenshotsFolder WRITE setSavedScreenshotsFolder NOTIFY savedScreenshotsFolderChanged);
|
||||
Q_PROPERTY(QString savedVideosFolder READ getSavedVideosFolder WRITE setSavedVideosFolder NOTIFY savedVideosFolderChanged);
|
||||
Q_PROPERTY(QString downloadFolder READ getDownloadFolder WRITE setDownloadFolder NOTIFY downloadFolderChanged);
|
||||
|
||||
public:
|
||||
enum MediaEncryption {
|
||||
|
|
@ -264,6 +265,9 @@ public:
|
|||
QString getSavedVideosFolder () const;
|
||||
void setSavedVideosFolder (const QString &folder);
|
||||
|
||||
QString getDownloadFolder () const;
|
||||
void setDownloadFolder (const QString &folder);
|
||||
|
||||
QString getRemoteProvisioning () const;
|
||||
void setRemoteProvisioning (const QString &remoteProvisioning);
|
||||
|
||||
|
|
@ -339,6 +343,7 @@ signals:
|
|||
|
||||
void savedScreenshotsFolderChanged (const QString &folder);
|
||||
void savedVideosFolderChanged (const QString &folder);
|
||||
void downloadFolderChanged (const QString &folder);
|
||||
|
||||
void remoteProvisioningChanged (const QString &remoteProvisioning);
|
||||
void remoteProvisioningNotChanged (const QString &remoteProvisioning);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
* Author: Ronan Abhamon
|
||||
*/
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -38,3 +40,32 @@ char *Utils::rstrstr (const char *a, const char *b) {
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define SAFE_FILE_PATH_LIMIT 100
|
||||
|
||||
QString Utils::getSafeFilePath (const QString &filePath, bool *soFarSoGood) {
|
||||
if (soFarSoGood)
|
||||
*soFarSoGood = true;
|
||||
|
||||
QFileInfo info(filePath);
|
||||
if (!info.exists())
|
||||
return filePath;
|
||||
|
||||
const QString &prefix = QStringLiteral("%1/%2").arg(info.absolutePath()).arg(info.baseName());
|
||||
const QString &ext = info.completeSuffix();
|
||||
|
||||
for (int i = 1; i < SAFE_FILE_PATH_LIMIT; ++i) {
|
||||
QString safePath = QStringLiteral("%1 (%3).%4").arg(prefix).arg(i).arg(ext);
|
||||
if (!QFileInfo::exists(safePath))
|
||||
return safePath;
|
||||
}
|
||||
|
||||
if (soFarSoGood)
|
||||
*soFarSoGood = false;
|
||||
|
||||
return QStringLiteral("");
|
||||
}
|
||||
|
||||
#undef SAFE_FILE_PATH_LIMIT
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ namespace Utils {
|
|||
|
||||
// Reverse function of strstr.
|
||||
char *rstrstr (const char *a, const char *b);
|
||||
|
||||
// Returns the same path given in parameter if `filePath` exists.
|
||||
// Otherwise returns a safe path with a unique number before the extension.
|
||||
QString getSafeFilePath (const QString &filePath, bool *soFarSoGood = nullptr);
|
||||
}
|
||||
|
||||
#endif // UTILS_H_
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import Common 1.0
|
||||
|
|
@ -179,23 +178,13 @@ Row {
|
|||
}
|
||||
|
||||
MouseArea {
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
|
||||
folder: shortcuts.home
|
||||
selectExisting: false
|
||||
title: qsTr('downloadFileTitle')
|
||||
|
||||
onAccepted: proxyModel.downloadFile(index, App.convertUrlToLocalPath(fileUrl))
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: containsMouse
|
||||
? Qt.PointingHandCursor
|
||||
: Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: fileDialog.open()
|
||||
onClicked: proxyModel.downloadFile(index)
|
||||
visible: !rectangle.isNotDelivered && !$chatEntry.isOutgoing
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,9 @@ TabContainer {
|
|||
onAccepted: SettingsModel.savedScreenshotsFolder = selectedFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormLine {
|
||||
FormGroup {
|
||||
label: qsTr('savedVideosLabel')
|
||||
|
||||
|
|
@ -109,6 +111,19 @@ TabContainer {
|
|||
}
|
||||
}
|
||||
|
||||
FormLine {
|
||||
FormGroup {
|
||||
label: qsTr('downloadLabel')
|
||||
|
||||
FileChooserButton {
|
||||
selectedFile: SettingsModel.downloadFolder
|
||||
selectFolder: true
|
||||
|
||||
onAccepted: SettingsModel.downloadFolder = selectedFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormEmptyLine {}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue