Implementing Attachment class and adding support to display the thumbnails of attachments in QML.
This commit is contained in:
parent
90a3ded076
commit
0b3d6bee85
16 changed files with 438 additions and 21 deletions
|
@ -33,7 +33,6 @@ ConversationMessage::ConversationMessage(const QVariantMap& args)
|
|||
m_threadID(args[QStringLiteral("thread_id")].toLongLong()),
|
||||
m_uID(args[QStringLiteral("_id")].toInt())
|
||||
{
|
||||
QString test = QLatin1String(args[QStringLiteral("addresses")].typeName());
|
||||
QVariantList jsonAddresses = args[QStringLiteral("addresses")].toList();
|
||||
for (const QVariant& addressField : jsonAddresses) {
|
||||
const auto& rawAddress = addressField.toMap();
|
||||
|
@ -41,6 +40,18 @@ ConversationMessage::ConversationMessage(const QVariantMap& args)
|
|||
}
|
||||
QVariantMap::const_iterator subID_it = args.find(QStringLiteral("sub_id"));
|
||||
m_subID = subID_it == args.end() ? -1 : subID_it->toLongLong();
|
||||
|
||||
if (args.contains(QStringLiteral("attachments"))) {
|
||||
QVariant attachment = args.value(QStringLiteral("attachments"));
|
||||
const QVariantList jsonAttachments = attachment.toList();
|
||||
for (const QVariant& attachmentField : jsonAttachments) {
|
||||
const auto& rawAttachment = attachmentField.toMap();
|
||||
m_attachments.append(Attachment(rawAttachment[QStringLiteral("part_id")].value<qint64>(),
|
||||
rawAttachment[QStringLiteral("mime_type")].value<QString>(),
|
||||
rawAttachment[QStringLiteral("encoded_thumbnail")].value<QString>(),
|
||||
rawAttachment[QStringLiteral("unique_identifier")].value<QString>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConversationMessage::ConversationMessage (const qint32& eventField, const QString& body,
|
||||
|
@ -48,7 +59,8 @@ ConversationMessage::ConversationMessage (const qint32& eventField, const QStrin
|
|||
const qint32& type, const qint32& read,
|
||||
const qint64& threadID,
|
||||
const qint32& uID,
|
||||
const qint64& subID)
|
||||
const qint64& subID,
|
||||
const QList<Attachment>& attachments)
|
||||
: m_eventField(eventField)
|
||||
, m_body(body)
|
||||
, m_addresses(addresses)
|
||||
|
@ -58,6 +70,7 @@ ConversationMessage::ConversationMessage (const qint32& eventField, const QStrin
|
|||
, m_threadID(threadID)
|
||||
, m_uID(uID)
|
||||
, m_subID(subID)
|
||||
, m_attachments(attachments)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -73,6 +86,13 @@ ConversationAddress::ConversationAddress(QString address)
|
|||
: m_address(address)
|
||||
{}
|
||||
|
||||
Attachment::Attachment(qint64 partID, QString mimeType, QString base64EncodedFile, QString uniqueIdentifier)
|
||||
: m_partID(partID)
|
||||
, m_mimeType(mimeType)
|
||||
, m_base64EncodedFile(base64EncodedFile)
|
||||
, m_uniqueIdentifier(uniqueIdentifier)
|
||||
{}
|
||||
|
||||
void ConversationMessage::registerDbusType()
|
||||
{
|
||||
qDBusRegisterMetaType<ConversationMessage>();
|
||||
|
@ -81,4 +101,6 @@ void ConversationMessage::registerDbusType()
|
|||
qRegisterMetaType<ConversationAddress>();
|
||||
qDBusRegisterMetaType<QList<ConversationAddress>>();
|
||||
qRegisterMetaType<QList<ConversationAddress>>();
|
||||
qDBusRegisterMetaType<Attachment>();
|
||||
qRegisterMetaType<Attachment>();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "kdeconnectinterfaces_export.h"
|
||||
|
||||
class ConversationAddress;
|
||||
class Attachment;
|
||||
|
||||
class KDECONNECTINTERFACES_EXPORT ConversationMessage
|
||||
{
|
||||
|
@ -61,7 +62,8 @@ public:
|
|||
|
||||
ConversationMessage(const qint32& eventField, const QString& body, const QList<ConversationAddress>& addresses,
|
||||
const qint64& date, const qint32& type, const qint32& read,
|
||||
const qint64& threadID, const qint32& uID, const qint64& subID);
|
||||
const qint64& threadID, const qint32& uID, const qint64& subID,
|
||||
const QList<Attachment>& attachments);
|
||||
|
||||
static ConversationMessage fromDBus(const QDBusVariant&);
|
||||
static void registerDbusType();
|
||||
|
@ -75,12 +77,14 @@ public:
|
|||
qint64 threadID() const { return m_threadID; }
|
||||
qint32 uID() const { return m_uID; }
|
||||
qint64 subID() const { return m_subID; }
|
||||
QList<Attachment> attachments() const { return m_attachments; }
|
||||
|
||||
bool containsTextBody() const { return (eventField() & ConversationMessage::EventTextMessage); }
|
||||
bool isMultitarget() const { return (eventField() & ConversationMessage::EventMultiTarget); }
|
||||
|
||||
bool isIncoming() const { return type() == MessageTypeInbox; }
|
||||
bool isOutgoing() const { return type() == MessageTypeSent; }
|
||||
bool containsAttachment() const { return !attachments().isEmpty(); }
|
||||
|
||||
/**
|
||||
* Return the address of the other party of a single-target conversation
|
||||
|
@ -135,6 +139,11 @@ protected:
|
|||
* Value which determines SIM id (optional)
|
||||
*/
|
||||
qint64 m_subID;
|
||||
|
||||
/**
|
||||
* Contains attachment related info of a MMS message (optional)
|
||||
*/
|
||||
QList<Attachment> m_attachments;
|
||||
};
|
||||
|
||||
class KDECONNECTINTERFACES_EXPORT ConversationAddress
|
||||
|
@ -148,6 +157,24 @@ private:
|
|||
QString m_address;
|
||||
};
|
||||
|
||||
class KDECONNECTINTERFACES_EXPORT Attachment
|
||||
{
|
||||
public:
|
||||
Attachment() {}
|
||||
Attachment(qint64 prtID, QString mimeType, QString base64EncodedFile, QString uniqueIdentifier);
|
||||
|
||||
qint64 partID() const { return m_partID; }
|
||||
QString mimeType() const { return m_mimeType; }
|
||||
QString base64EncodedFile() const { return m_base64EncodedFile; }
|
||||
QString uniqueIdentifier() const { return m_uniqueIdentifier; }
|
||||
|
||||
private:
|
||||
qint64 m_partID; // Part ID of the attachment of the message
|
||||
QString m_mimeType; // Type of attachment (image, video, audio etc.)
|
||||
QString m_base64EncodedFile; // Base64 encoded string of a file
|
||||
QString m_uniqueIdentifier; // unique name of the attachment
|
||||
};
|
||||
|
||||
inline QDBusArgument &operator<<(QDBusArgument &argument, const ConversationMessage &message)
|
||||
{
|
||||
argument.beginStructure();
|
||||
|
@ -159,7 +186,8 @@ inline QDBusArgument &operator<<(QDBusArgument &argument, const ConversationMess
|
|||
<< message.read()
|
||||
<< message.threadID()
|
||||
<< message.uID()
|
||||
<< message.subID();
|
||||
<< message.subID()
|
||||
<< message.attachments();
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
@ -175,6 +203,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, Conversati
|
|||
qint64 threadID;
|
||||
qint32 uID;
|
||||
qint64 m_subID;
|
||||
QList<Attachment> attachments;
|
||||
|
||||
argument.beginStructure();
|
||||
argument >> event;
|
||||
|
@ -186,9 +215,10 @@ inline const QDBusArgument &operator>>(const QDBusArgument &argument, Conversati
|
|||
argument >> threadID;
|
||||
argument >> uID;
|
||||
argument >> m_subID;
|
||||
argument >> attachments;
|
||||
argument.endStructure();
|
||||
|
||||
message = ConversationMessage(event, body, addresses, date, type, read, threadID, uID, m_subID);
|
||||
message = ConversationMessage(event, body, addresses, date, type, read, threadID, uID, m_subID, attachments);
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
@ -214,7 +244,38 @@ inline const QDBusArgument& operator>>(const QDBusArgument& argument, Conversati
|
|||
return argument;
|
||||
}
|
||||
|
||||
inline QDBusArgument& operator<<(QDBusArgument& argument, const Attachment& attachment)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << attachment.partID()
|
||||
<< attachment.mimeType()
|
||||
<< attachment.base64EncodedFile()
|
||||
<< attachment.uniqueIdentifier();
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
inline const QDBusArgument& operator>>(const QDBusArgument& argument, Attachment& attachment)
|
||||
{
|
||||
qint64 partID;
|
||||
QString mimeType;
|
||||
QString encodedFile;
|
||||
QString uniqueIdentifier;
|
||||
|
||||
argument.beginStructure();
|
||||
argument >> partID;
|
||||
argument >> mimeType;
|
||||
argument >> encodedFile;
|
||||
argument >> uniqueIdentifier;
|
||||
argument.endStructure();
|
||||
|
||||
attachment = Attachment(partID, mimeType, encodedFile, uniqueIdentifier);
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(ConversationMessage)
|
||||
Q_DECLARE_METATYPE(ConversationAddress)
|
||||
Q_DECLARE_METATYPE(Attachment)
|
||||
|
||||
#endif /* PLUGINS_TELEPHONY_CONVERSATIONMESSAGE_H_ */
|
||||
|
|
|
@ -69,6 +69,16 @@
|
|||
* // If this value is not defined or if it does not match a valid subscriber_id known by
|
||||
* // Android, we will use whatever subscriber ID Android gives us as the default
|
||||
*
|
||||
* "attachments": <List<Attachment>> // List of Attachment objects, one for each attached file in the message.
|
||||
*
|
||||
* An Attachment object looks like:
|
||||
* {
|
||||
* "part_id": <long> // part_id of the attachment used to read the file from MMS database
|
||||
* "mime_type": <int> // contains the mime type of the file (image, video, audio, etc.)
|
||||
* "encoded_thumbnail": <String> // Optional base64-encoded thumbnail preview of the content for types which support it
|
||||
* "unique_identifier": <String> // Unique name of te file
|
||||
* }
|
||||
*
|
||||
* An Address object looks like:
|
||||
* {
|
||||
* "address": <String> // Address (phone number, email address, etc.) of this object
|
||||
|
|
|
@ -41,6 +41,8 @@ add_executable(kdeconnect-sms
|
|||
conversationmodel.cpp
|
||||
conversationssortfilterproxymodel.cpp
|
||||
resources.qrc
|
||||
thumbnailsprovider.cpp
|
||||
attachmentinfo.cpp
|
||||
${sms_debug_files_SRCS})
|
||||
|
||||
target_link_libraries(kdeconnect-sms
|
||||
|
|
30
smsapp/attachmentinfo.cpp
Normal file
30
smsapp/attachmentinfo.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (C) 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "attachmentinfo.h"
|
||||
|
||||
AttachmentInfo::AttachmentInfo()
|
||||
{}
|
||||
|
||||
AttachmentInfo::AttachmentInfo(const Attachment& attachment)
|
||||
: m_partID(attachment.partID()),
|
||||
m_mimeType(attachment.mimeType()),
|
||||
m_uniqueIdentifier(attachment.uniqueIdentifier())
|
||||
{}
|
51
smsapp/attachmentinfo.h
Normal file
51
smsapp/attachmentinfo.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright (C) 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ATTACHMENTINFO_H
|
||||
#define ATTACHMENTINFO_H
|
||||
|
||||
#include "conversationmessage.h"
|
||||
|
||||
/**
|
||||
* This class is a compressed version of Attachment class
|
||||
* as it will be exposed to the QML in a list object
|
||||
*/
|
||||
class AttachmentInfo
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(qint64 partID READ partID)
|
||||
Q_PROPERTY(QString mimeType READ mimeType)
|
||||
Q_PROPERTY(QString uniqueIdentifier READ uniqueIdentifier)
|
||||
|
||||
public:
|
||||
AttachmentInfo();
|
||||
AttachmentInfo(const Attachment& attachment);
|
||||
|
||||
qint64 partID() const { return m_partID; }
|
||||
QString mimeType() const { return m_mimeType; }
|
||||
QString uniqueIdentifier() const { return m_uniqueIdentifier; }
|
||||
|
||||
private:
|
||||
qint64 m_partID;
|
||||
QString m_mimeType;
|
||||
QString m_uniqueIdentifier;
|
||||
};
|
||||
|
||||
#endif // ATTACHMENTINFO_H
|
|
@ -200,7 +200,14 @@ void ConversationListModel::createRowFromMessage(const ConversationMessage& mess
|
|||
|
||||
// TODO: Upgrade to support other kinds of media
|
||||
// Get the body that we should display
|
||||
QString displayBody = message.containsTextBody() ? message.body() : i18n("(Unsupported Message Type)");
|
||||
QString displayBody;
|
||||
if (message.containsTextBody()) {
|
||||
displayBody = message.body();
|
||||
} else if (message.containsAttachment()) {
|
||||
const QString mimeType = message.attachments().last().mimeType();
|
||||
const QString type = QStringLiteral("\"") + mimeType.left(mimeType.indexOf(QStringLiteral("/"))) + QStringLiteral(" file\"");
|
||||
displayBody = type;
|
||||
}
|
||||
|
||||
// For displaying single line subtitle out of the multiline messages to keep the ListItems consistent
|
||||
displayBody = displayBody.mid(0, displayBody.indexOf(QStringLiteral("\n")));
|
||||
|
|
|
@ -22,9 +22,12 @@
|
|||
#include "conversationmodel.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include "interfaces/conversationmessage.h"
|
||||
#include "smshelper.h"
|
||||
#include "attachmentinfo.h"
|
||||
|
||||
#include "sms_conversation_debug.h"
|
||||
|
||||
|
@ -37,6 +40,7 @@ ConversationModel::ConversationModel(QObject* parent)
|
|||
roles.insert(DateRole, "date");
|
||||
roles.insert(SenderRole, "sender");
|
||||
roles.insert(AvatarRole, "avatar");
|
||||
roles.insert(AttachmentsRole, "attachments");
|
||||
setItemRoleNames(roles);
|
||||
}
|
||||
|
||||
|
@ -59,6 +63,7 @@ void ConversationModel::setThreadId(const qint64& threadId)
|
|||
knownMessageIDs.clear();
|
||||
if (m_threadId != INVALID_THREAD_ID && !m_deviceId.isEmpty()) {
|
||||
requestMoreMessages();
|
||||
m_thumbnailsProvider->clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +86,12 @@ void ConversationModel::setDeviceId(const QString& deviceId)
|
|||
connect(m_conversationsInterface, SIGNAL(conversationUpdated(QDBusVariant)), this, SLOT(handleConversationUpdate(QDBusVariant)));
|
||||
connect(m_conversationsInterface, SIGNAL(conversationLoaded(qint64, quint64)), this, SLOT(handleConversationLoaded(qint64, quint64)));
|
||||
connect(m_conversationsInterface, SIGNAL(conversationCreated(QDBusVariant)), this, SLOT(handleConversationCreated(QDBusVariant)));
|
||||
|
||||
QQmlApplicationEngine* engine = qobject_cast<QQmlApplicationEngine*>(QQmlEngine::contextForObject(this)->engine());
|
||||
m_thumbnailsProvider = dynamic_cast<ThumbnailsProvider*>(engine->imageProvider(QStringLiteral("thumbnailsProvider")));
|
||||
|
||||
// Clear any previous data on device change
|
||||
m_thumbnailsProvider->clear();
|
||||
}
|
||||
|
||||
void ConversationModel::setAddressList(const QList<ConversationAddress>& addressList) {
|
||||
|
@ -109,7 +120,7 @@ void ConversationModel::requestMoreMessages(const quint32& howMany)
|
|||
if (m_threadId == INVALID_THREAD_ID) {
|
||||
return;
|
||||
}
|
||||
const auto& numMessages = rowCount();
|
||||
const auto& numMessages = knownMessageIDs.size();
|
||||
m_conversationsInterface->requestConversation(m_threadId, numMessages, numMessages + howMany);
|
||||
}
|
||||
|
||||
|
@ -132,18 +143,35 @@ void ConversationModel::createRowFromMessage(const ConversationMessage& message,
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Upgrade to support other kinds of media
|
||||
// Get the body that we should display
|
||||
QString displayBody = message.containsTextBody() ? message.body() : i18n("(Unsupported Message Type)");
|
||||
|
||||
ConversationAddress sender = message.addresses().first();
|
||||
QString senderName = message.isIncoming() ? SmsHelper::getTitleForAddresses({sender}) : QString();
|
||||
QString displayBody = message.body();
|
||||
|
||||
auto item = new QStandardItem;
|
||||
item->setText(displayBody);
|
||||
item->setData(message.isOutgoing(), FromMeRole);
|
||||
item->setData(message.date(), DateRole);
|
||||
item->setData(senderName, SenderRole);
|
||||
|
||||
QList<QVariant> attachmentInfoList;
|
||||
const QList<Attachment> attachmentList = message.attachments();
|
||||
|
||||
for (const Attachment& attachment : attachmentList) {
|
||||
AttachmentInfo attachmentInfo(attachment);
|
||||
attachmentInfoList.append(QVariant::fromValue(attachmentInfo));
|
||||
|
||||
if (attachment.mimeType().startsWith(QLatin1String("image")) || attachment.mimeType().startsWith(QLatin1String("video"))) {
|
||||
// The message contains thumbnail as Base64 String, convert it back into image thumbnail
|
||||
const QByteArray byteArray = attachment.base64EncodedFile().toUtf8();
|
||||
QPixmap thumbnail;
|
||||
thumbnail.loadFromData(QByteArray::fromBase64(byteArray));
|
||||
|
||||
m_thumbnailsProvider->addImage(attachment.uniqueIdentifier(), thumbnail.toImage());
|
||||
}
|
||||
}
|
||||
|
||||
item->setData(attachmentInfoList, AttachmentsRole);
|
||||
|
||||
insertRow(pos, item);
|
||||
knownMessageIDs.insert(message.uID());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "interfaces/conversationmessage.h"
|
||||
#include "interfaces/dbusinterfaces.h"
|
||||
#include "thumbnailsprovider.h"
|
||||
|
||||
#define INVALID_THREAD_ID -1
|
||||
|
||||
|
@ -47,6 +48,7 @@ public:
|
|||
SenderRole, // The sender of the message. Undefined if this is an outgoing message
|
||||
DateRole,
|
||||
AvatarRole, // URI to the avatar of the sender of the message. Undefined if outgoing.
|
||||
AttachmentsRole, // The list of attachments. Undefined if there is no attachment in a message
|
||||
};
|
||||
|
||||
Q_ENUM(Roles)
|
||||
|
@ -78,6 +80,7 @@ private:
|
|||
void createRowFromMessage(const ConversationMessage &message, int pos);
|
||||
|
||||
DeviceConversationsDbusInterface* m_conversationsInterface;
|
||||
ThumbnailsProvider* m_thumbnailsProvider;
|
||||
QString m_deviceId;
|
||||
qint64 m_threadId = INVALID_THREAD_ID;
|
||||
QList<ConversationAddress> m_addressList;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "conversationmodel.h"
|
||||
#include "conversationlistmodel.h"
|
||||
#include "conversationssortfilterproxymodel.h"
|
||||
#include "thumbnailsprovider.h"
|
||||
#include "kdeconnect-version.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -74,6 +75,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||
engine.addImageProvider(QStringLiteral("thumbnailsProvider"), new ThumbnailsProvider);
|
||||
engine.rootContext()->setContextProperties({
|
||||
{ QStringLiteral("initialMessage"), initialMessage },
|
||||
{ QStringLiteral("initialDevice"), deviceid },
|
||||
|
|
|
@ -35,6 +35,7 @@ Item {
|
|||
property date dateTime
|
||||
property string name
|
||||
property bool multiTarget
|
||||
property var attachmentList
|
||||
|
||||
signal messageCopyRequested(string message)
|
||||
|
||||
|
@ -60,6 +61,7 @@ Item {
|
|||
height: messageColumn.height
|
||||
|
||||
Rectangle {
|
||||
id: messageBox
|
||||
Layout.maximumWidth: applicationWindow().wideScreen ? Math.min(messageColumn.contentWidth, root.width * 0.6) : messageColumn.contentWidth
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: root.sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
|
@ -103,7 +105,7 @@ Item {
|
|||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
property int contentWidth: Math.max(messageLabel.implicitWidth, dateLabel.implicitWidth)
|
||||
property int contentWidth: Math.max(Math.max(messageLabel.implicitWidth, attachmentGrid.implicitWidth), dateLabel.implicitWidth)
|
||||
Label {
|
||||
id: authorLabel
|
||||
width: parent.width
|
||||
|
@ -115,8 +117,26 @@ Item {
|
|||
horizontalAlignment: messageLabel.horizontalAlignment
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: attachmentGrid
|
||||
columns: 2
|
||||
padding: attachmentList.length > 0 ? Kirigami.Units.largeSpacing : 0
|
||||
layoutDirection: root.sentByMe ? Qt.RightToLeft : Qt.LeftToRight
|
||||
|
||||
Repeater {
|
||||
model: attachmentList
|
||||
|
||||
delegate: MessageAttachments {
|
||||
mimeType: modelData.mimeType
|
||||
partID: modelData.partID
|
||||
uniqueIdentifier: modelData.uniqueIdentifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: messageLabel
|
||||
visible: messageBody != ""
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
leftPadding: Kirigami.Units.largeSpacing
|
||||
|
@ -141,8 +161,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Menu {
|
||||
id: contextMenu
|
||||
exit: Transition {PropertyAction { target: messageLabel; property: "persistentSelection"; value: false }}
|
||||
|
|
|
@ -124,6 +124,7 @@ Kirigami.ScrollablePage
|
|||
sentByMe: model.fromMe
|
||||
dateTime: new Date(model.date)
|
||||
multiTarget: isMultitarget
|
||||
attachmentList: model.attachments
|
||||
|
||||
width: viewport.width
|
||||
|
||||
|
|
96
smsapp/qml/MessageAttachments.qml
Normal file
96
smsapp/qml/MessageAttachments.qml
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* Copyright (C) 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtGraphicalEffects 1.12
|
||||
import org.kde.kirigami 2.13 as Kirigami
|
||||
import QtMultimedia 5.12
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int partID
|
||||
property string mimeType
|
||||
property string uniqueIdentifier
|
||||
property string sourcePath
|
||||
|
||||
readonly property int elementWidth: 100
|
||||
readonly property int elementHeight: 100
|
||||
|
||||
width: thumbnailElement.visible ? thumbnailElement.width : elementWidth
|
||||
height: thumbnailElement.visible ? thumbnailElement.height : elementHeight
|
||||
|
||||
Image {
|
||||
id: thumbnailElement
|
||||
visible: mimeType.match("image") || mimeType.match("video")
|
||||
source: visible ? "image://thumbnailsProvider/" + root.uniqueIdentifier : ""
|
||||
|
||||
property bool rounded: true
|
||||
property bool adapt: true
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
layer.enabled: rounded
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: thumbnailElement.width
|
||||
height: thumbnailElement.height
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: thumbnailElement.adapt ? thumbnailElement.width : Math.min(thumbnailElement.width, thumbnailElement.height)
|
||||
height: thumbnailElement.adapt ? thumbnailElement.height : width
|
||||
radius: messageBox.radius
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
icon.name: "media-playback-start"
|
||||
visible: root.mimeType.match("video")
|
||||
anchors.horizontalCenter: thumbnailElement.horizontalCenter
|
||||
anchors.verticalCenter: thumbnailElement.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: audioElement
|
||||
visible: root.mimeType.match("audio")
|
||||
anchors.fill: parent
|
||||
radius: messageBox.radius
|
||||
color: "lightgrey"
|
||||
|
||||
ColumnLayout {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Button {
|
||||
id : audioPlayButton
|
||||
icon.name: "media-playback-start"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
text: i18nd("kdeconnect-sms", "Audio clip")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>qml/main.qml</file>
|
||||
<file>qml/ConversationList.qml</file>
|
||||
<file>qml/ConversationDisplay.qml</file>
|
||||
<file>qml/ChatMessage.qml</file>
|
||||
</qresource>
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>qml/main.qml</file>
|
||||
<file>qml/ConversationList.qml</file>
|
||||
<file>qml/ConversationDisplay.qml</file>
|
||||
<file>qml/ChatMessage.qml</file>
|
||||
<file>qml/MessageAttachments.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
44
smsapp/thumbnailsprovider.cpp
Normal file
44
smsapp/thumbnailsprovider.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Copyright (C) 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "thumbnailsprovider.h"
|
||||
|
||||
ThumbnailsProvider::ThumbnailsProvider() : QQuickImageProvider(QQuickImageProvider::Image)
|
||||
{
|
||||
}
|
||||
|
||||
QImage ThumbnailsProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize) {
|
||||
Q_UNUSED(size)
|
||||
Q_UNUSED(requestedSize)
|
||||
|
||||
if (m_thumbnails.contains(id)) {
|
||||
return m_thumbnails.value(id);
|
||||
}
|
||||
|
||||
return QImage();
|
||||
}
|
||||
|
||||
void ThumbnailsProvider::addImage(const QString& id, const QImage& image) {
|
||||
m_thumbnails.insert(id, image);
|
||||
}
|
||||
|
||||
void ThumbnailsProvider::clear() {
|
||||
m_thumbnails.clear();
|
||||
}
|
41
smsapp/thumbnailsprovider.h
Normal file
41
smsapp/thumbnailsprovider.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Copyright (C) 2020 Aniket Kumar <anikketkumar786@gmail.com>
|
||||
*
|
||||
* 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef THUMBNAILSPROVIDER_H
|
||||
#define THUMBNAILSPROVIDER_H
|
||||
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
class ThumbnailsProvider : public QQuickImageProvider
|
||||
{
|
||||
public:
|
||||
ThumbnailsProvider();
|
||||
|
||||
QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override;
|
||||
|
||||
void addImage(const QString& id, const QImage& image);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QHash<QString, QImage> m_thumbnails;
|
||||
};
|
||||
|
||||
#endif // THUMBNAILSPROVIDER_H
|
Loading…
Reference in a new issue