From b9d8311e91b41745c259e437cdde0a826d256f93 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 13 Jun 2017 15:37:18 +0200 Subject: [PATCH] feat(ui/modules/Linphone/Chat/FileMessage): user friendly download \o/ --- .../src/components/chat/ChatModel.cpp | 98 +++++++++++++++---- .../src/components/chat/ChatModel.hpp | 8 ++ .../src/components/chat/ChatProxyModel.cpp | 41 ++++---- .../src/components/chat/ChatProxyModel.hpp | 2 + .../ui/modules/Linphone/Chat/FileMessage.qml | 17 ++-- 5 files changed, 118 insertions(+), 48 deletions(-) diff --git a/linphone-desktop/src/components/chat/ChatModel.cpp b/linphone-desktop/src/components/chat/ChatModel.cpp index 30e95fce9..1a7fb56dd 100644 --- a/linphone-desktop/src/components/chat/ChatModel.cpp +++ b/linphone-desktop/src/components/chat/ChatModel.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -48,11 +49,24 @@ using namespace std; // ============================================================================= +inline QString getFileId (const shared_ptr &message) { + return ::Utils::coreStringToAppString(message->getAppdata()).section(':', 0, 0); +} + +inline QString getDownloadPath (const shared_ptr &message) { + return ::Utils::coreStringToAppString(message->getAppdata()).section(':', 1); +} + +inline bool fileWasDownloaded (const std::shared_ptr &message) { + const QString &path = getDownloadPath(message); + return !path.isEmpty() && QFileInfo(path).isFile(); +} + inline void fillThumbnailProperty (QVariantMap &dest, const shared_ptr &message) { - string fileId = message->getAppdata(); - if (!fileId.empty() && !dest.contains("thumbnail")) + QString fileId = getFileId(message); + if (!fileId.isEmpty() && !dest.contains("thumbnail")) dest["thumbnail"] = QStringLiteral("image://%1/%2") - .arg(ThumbnailProvider::PROVIDER_ID).arg(::Utils::coreStringToAppString(fileId)); + .arg(ThumbnailProvider::PROVIDER_ID).arg(fileId); } inline void createThumbnail (const shared_ptr &message) { @@ -156,6 +170,12 @@ private: if (state == linphone::ChatMessageStateFileTransferDone && !message->isOutgoing()) { createThumbnail(message); fillThumbnailProperty((*it).first, message); + + message->setAppdata( + ::Utils::appStringToCoreString(getFileId(message)) + ':' + message->getFileTransferFilepath() + ); + (*it).first["wasDownloaded"] = true; + App::getInstance()->getNotifier()->notifyReceivedFileMessage(message); } @@ -310,6 +330,8 @@ void ChatModel::removeAllEntries () { emit allEntriesRemoved(); } +// ----------------------------------------------------------------------------- + void ChatModel::sendMessage (const QString &message) { if (!mChatRoom) return; @@ -388,26 +410,14 @@ void ChatModel::sendFileMessage (const QString &path) { emit messageSent(message); } +// ----------------------------------------------------------------------------- + void ChatModel::downloadFile (int id) { - if (!mChatRoom) + const ChatEntryData &entry = getFileMessageEntry(id); + if (!entry.second) return; - if (id < 0 || id > mEntries.count()) { - qWarning() << QStringLiteral("Entry %1 not exists.").arg(id); - return; - } - - const ChatEntryData &entry = mEntries[id]; - if (entry.first["type"] != EntryType::MessageEntry) { - qWarning() << QStringLiteral("Unable to download entry %1. It's not a message.").arg(id); - return; - } - shared_ptr message = static_pointer_cast(entry.second); - if (!message->getFileTransferInformation()) { - qWarning() << QStringLiteral("Entry %1 is not a file message.").arg(id); - return; - } switch (message->getState()) { case MessageStatusDelivered: @@ -441,6 +451,54 @@ void ChatModel::downloadFile (int id) { qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(id); } +void ChatModel::openFile (int id, bool showDirectory) { + const ChatEntryData &entry = getFileMessageEntry(id); + if (!entry.second) + return; + + shared_ptr message = static_pointer_cast(entry.second); + if (!::fileWasDownloaded(message)) { + downloadFile(id); + return; + } + + QFileInfo info(getDownloadPath(message)); + QDesktopServices::openUrl( + QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath())) + ); +} + +bool ChatModel::fileWasDownloaded (int id) { + const ChatEntryData &entry = getFileMessageEntry(id); + return entry.second && ::fileWasDownloaded(static_pointer_cast(entry.second)); +} + +// ----------------------------------------------------------------------------- + +const ChatModel::ChatEntryData ChatModel::getFileMessageEntry (int id) { + if (!mChatRoom) + return ChatEntryData(); + + if (id < 0 || id > mEntries.count()) { + qWarning() << QStringLiteral("Entry %1 not exists.").arg(id); + return ChatEntryData(); + } + + const ChatEntryData &entry = mEntries[id]; + if (entry.first["type"] != EntryType::MessageEntry) { + qWarning() << QStringLiteral("Unable to download entry %1. It's not a message.").arg(id); + return ChatEntryData(); + } + + shared_ptr message = static_pointer_cast(entry.second); + if (!message->getFileTransferInformation()) { + qWarning() << QStringLiteral("Entry %1 is not a file message.").arg(id); + return ChatEntryData(); + } + + return entry; +} + // ----------------------------------------------------------------------------- void ChatModel::fillMessageEntry (QVariantMap &dest, const shared_ptr &message) { @@ -454,6 +512,8 @@ void ChatModel::fillMessageEntry (QVariantMap &dest, const shared_ptr(content->getSize()); dest["fileName"] = ::Utils::coreStringToAppString(content->getName()); + dest["wasDownloaded"] = ::fileWasDownloaded(message); + fillThumbnailProperty(dest, message); } } diff --git a/linphone-desktop/src/components/chat/ChatModel.hpp b/linphone-desktop/src/components/chat/ChatModel.hpp index 23d46aa10..ce18ec315 100644 --- a/linphone-desktop/src/components/chat/ChatModel.hpp +++ b/linphone-desktop/src/components/chat/ChatModel.hpp @@ -98,6 +98,12 @@ public: void sendFileMessage (const QString &path); void downloadFile (int id); + void openFile (int id, bool showDirectory = false); + void openFileDirectory (int id) { + openFile(id, true); + } + + bool fileWasDownloaded (int id); signals: void sipAddressChanged (const QString &sipAddress); @@ -111,6 +117,8 @@ signals: private: typedef QPair > ChatEntryData; + const ChatEntryData getFileMessageEntry (int id); + void fillMessageEntry (QVariantMap &dest, const std::shared_ptr &message); void fillCallStartEntry (QVariantMap &dest, const std::shared_ptr &callLog); void fillCallEndEntry (QVariantMap &dest, const std::shared_ptr &callLog); diff --git a/linphone-desktop/src/components/chat/ChatProxyModel.cpp b/linphone-desktop/src/components/chat/ChatProxyModel.cpp index 30bcd32e4..565a337b0 100644 --- a/linphone-desktop/src/components/chat/ChatProxyModel.cpp +++ b/linphone-desktop/src/components/chat/ChatProxyModel.cpp @@ -78,6 +78,26 @@ ChatProxyModel::ChatProxyModel (QObject *parent) : QSortFilterProxyModel(parent) }); } +// ----------------------------------------------------------------------------- + +#define CREATE_CALL_MODEL_FUNCTION_WITH_ID(METHOD) \ + void ChatProxyModel::METHOD(int id) { \ + QModelIndex sourceIndex = mapToSource(index(id, 0)); \ + static_cast(mChatModelFilter->sourceModel())->METHOD( \ + mChatModelFilter->mapToSource(sourceIndex).row() \ + ); \ + } + +CREATE_CALL_MODEL_FUNCTION_WITH_ID(downloadFile); +CREATE_CALL_MODEL_FUNCTION_WITH_ID(openFile); +CREATE_CALL_MODEL_FUNCTION_WITH_ID(openFileDirectory); +CREATE_CALL_MODEL_FUNCTION_WITH_ID(removeEntry); +CREATE_CALL_MODEL_FUNCTION_WITH_ID(resendMessage); + +#undef CREATE_CALL_MODEL_FUNCTION_WITH_ID + +// ----------------------------------------------------------------------------- + void ChatProxyModel::loadMoreEntries () { int count = rowCount(); int parentCount = mChatModelFilter->rowCount(); @@ -103,13 +123,6 @@ void ChatProxyModel::setEntryTypeFilter (ChatModel::EntryType type) { } } -void ChatProxyModel::removeEntry (int id) { - QModelIndex sourceIndex = mapToSource(index(id, 0)); - static_cast(mChatModelFilter->sourceModel())->removeEntry( - mChatModelFilter->mapToSource(sourceIndex).row() - ); -} - void ChatProxyModel::removeAllEntries () { static_cast(mChatModelFilter->sourceModel())->removeAllEntries(); } @@ -118,24 +131,10 @@ void ChatProxyModel::sendMessage (const QString &message) { static_cast(mChatModelFilter->sourceModel())->sendMessage(message); } -void ChatProxyModel::resendMessage (int id) { - QModelIndex sourceIndex = mapToSource(index(id, 0)); - static_cast(mChatModelFilter->sourceModel())->resendMessage( - mChatModelFilter->mapToSource(sourceIndex).row() - ); -} - void ChatProxyModel::sendFileMessage (const QString &path) { static_cast(mChatModelFilter->sourceModel())->sendFileMessage(path); } -void ChatProxyModel::downloadFile (int id) { - QModelIndex sourceIndex = mapToSource(index(id, 0)); - static_cast(mChatModelFilter->sourceModel())->downloadFile( - mChatModelFilter->mapToSource(sourceIndex).row() - ); -} - // ----------------------------------------------------------------------------- bool ChatProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) const { diff --git a/linphone-desktop/src/components/chat/ChatProxyModel.hpp b/linphone-desktop/src/components/chat/ChatProxyModel.hpp index fd58c69df..042babaab 100644 --- a/linphone-desktop/src/components/chat/ChatProxyModel.hpp +++ b/linphone-desktop/src/components/chat/ChatProxyModel.hpp @@ -51,6 +51,8 @@ public: Q_INVOKABLE void sendFileMessage (const QString &path); Q_INVOKABLE void downloadFile (int id); + Q_INVOKABLE void openFile (int id); + Q_INVOKABLE void openFileDirectory (int id); signals: void sipAddressChanged (const QString &sipAddress); diff --git a/linphone-desktop/ui/modules/Linphone/Chat/FileMessage.qml b/linphone-desktop/ui/modules/Linphone/Chat/FileMessage.qml index 11e62d980..bb742a84e 100644 --- a/linphone-desktop/ui/modules/Linphone/Chat/FileMessage.qml +++ b/linphone-desktop/ui/modules/Linphone/Chat/FileMessage.qml @@ -240,7 +240,7 @@ Row { icon: 'download' iconSize: ChatStyle.entry.message.file.iconSize - visible: !$chatEntry.isOutgoing + visible: !$chatEntry.isOutgoing && !$chatEntry.wasDownloaded } MouseArea { @@ -257,18 +257,19 @@ Row { hoverEnabled: true visible: !rectangle.isNotDelivered && !$chatEntry.isOutgoing - onMouseXChanged: handleMouseMove.call(this, mouse) - onMouseYChanged: handleMouseMove.call(this, mouse) - onExited: thumbnailProvider.state = '' - onClicked: { - // TODO: Handle open. - if (false && Utils.pointIsInItem(this, thumbnailProvider, mouse)) { + if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) { proxyModel.openFile(index) - } else { + } else if ($chatEntry.wasDownloaded) { + proxyModel.openFileDirectory(index) + } else { proxyModel.downloadFile(index) } } + + onExited: thumbnailProvider.state = '' + onMouseXChanged: handleMouseMove.call(this, mouse) + onMouseYChanged: handleMouseMove.call(this, mouse) } }