Adding support to send attachments to the remote device.
This commit is contained in:
parent
60a1adf229
commit
706fc314fb
14 changed files with 343 additions and 122 deletions
|
@ -53,6 +53,7 @@ int main(int argc, char** argv)
|
|||
parser.addOption(QCommandLineOption(QStringLiteral("lock"), i18n("Lock the specified device")));
|
||||
parser.addOption(QCommandLineOption(QStringLiteral("send-sms"), i18n("Sends an SMS. Requires destination"), i18n("message")));
|
||||
parser.addOption(QCommandLineOption(QStringLiteral("destination"), i18n("Phone number to send the message"), i18n("phone number")));
|
||||
parser.addOption(QCommandLineOption(QStringLiteral("attachment"), i18n("File urls to send attachments with the message"), i18n("file urls")));
|
||||
parser.addOption(QCommandLineOption(QStringList(QStringLiteral("device")) << QStringLiteral("d"), i18n("Device ID"), QStringLiteral("dev")));
|
||||
parser.addOption(QCommandLineOption(QStringList(QStringLiteral("name")) << QStringLiteral("n"), i18n("Device Name"), QStringLiteral("name")));
|
||||
parser.addOption(QCommandLineOption(QStringLiteral("encryption-info"), i18n("Get encryption info about said device")));
|
||||
|
@ -258,9 +259,11 @@ int main(int argc, char** argv)
|
|||
addresses << QVariant::fromValue(address);
|
||||
}
|
||||
|
||||
const QStringList urlList = parser.value(QStringLiteral("attachment")).split(QRegularExpression(QStringLiteral("\\s+")));
|
||||
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"), QStringLiteral("/modules/kdeconnect/devices/") + device + QStringLiteral("/sms"), QStringLiteral("org.kde.kdeconnect.device.sms"), QStringLiteral("sendSms"));
|
||||
const QString text = parser.value(QStringLiteral("send-sms"));
|
||||
msg.setArguments(QVariantList() << QVariant::fromValue(addresses) << text);
|
||||
msg.setArguments(QVariantList() << QVariant::fromValue(addresses) << text << QVariant(urlList));
|
||||
blockOnReply(DBusHelper::sessionBus().asyncCall(msg));
|
||||
} else {
|
||||
QTextStream(stderr) << i18n("error: should specify the SMS's recipient by passing --destination <phone number>");
|
||||
|
|
|
@ -72,6 +72,15 @@ ConversationAddress::ConversationAddress(QString address)
|
|||
: m_address(address)
|
||||
{}
|
||||
|
||||
bool ConversationMessage::isOutgoing() const
|
||||
{
|
||||
return type() == MessageTypeSent
|
||||
|| type() == MessageTypeOutbox
|
||||
|| type() == MessageTypeDraft
|
||||
|| type() == MessageTypeFailed
|
||||
|| type() == MessageTypeQueued;
|
||||
}
|
||||
|
||||
Attachment::Attachment(qint64 partID, QString mimeType, QString base64EncodedFile, QString uniqueIdentifier)
|
||||
: m_partID(partID)
|
||||
, m_mimeType(mimeType)
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
bool isMultitarget() const { return (eventField() & ConversationMessage::EventMultiTarget); }
|
||||
|
||||
bool isIncoming() const { return type() == MessageTypeInbox; }
|
||||
bool isOutgoing() const { return type() == MessageTypeSent; }
|
||||
bool isOutgoing() const;
|
||||
bool containsAttachment() const { return !attachments().isEmpty(); }
|
||||
|
||||
/**
|
||||
|
|
|
@ -177,7 +177,7 @@ void ConversationsDbusInterface::updateConversation(const qint64& conversationID
|
|||
waitingForMessagesLock.unlock();
|
||||
}
|
||||
|
||||
void ConversationsDbusInterface::replyToConversation(const qint64& conversationID, const QString& message)
|
||||
void ConversationsDbusInterface::replyToConversation(const qint64& conversationID, const QString& message, const QVariantList& attachmentUrls)
|
||||
{
|
||||
const auto messagesList = m_conversations[conversationID];
|
||||
if (messagesList.isEmpty()) {
|
||||
|
@ -192,11 +192,11 @@ void ConversationsDbusInterface::replyToConversation(const qint64& conversationI
|
|||
addresses << QVariant::fromValue(address);
|
||||
}
|
||||
|
||||
m_smsInterface.sendSms(addresses, message, messagesList.first().subID());
|
||||
m_smsInterface.sendSms(addresses, message, attachmentUrls, messagesList.first().subID());
|
||||
}
|
||||
|
||||
void ConversationsDbusInterface::sendWithoutConversation(const QVariantList& addresses, const QString& message) {
|
||||
m_smsInterface.sendSms(addresses, message);
|
||||
void ConversationsDbusInterface::sendWithoutConversation(const QVariantList& addresses, const QString& message, const QVariantList& attachmentUrls) {
|
||||
m_smsInterface.sendSms(addresses, message, attachmentUrls);
|
||||
}
|
||||
|
||||
void ConversationsDbusInterface::requestAllConversationThreads()
|
||||
|
|
|
@ -77,12 +77,12 @@ public Q_SLOTS:
|
|||
/**
|
||||
* Send a new message to this conversation
|
||||
*/
|
||||
void replyToConversation(const qint64& conversationID, const QString& message);
|
||||
void replyToConversation(const qint64& conversationID, const QString& message, const QVariantList& attachmentUrls);
|
||||
|
||||
/**
|
||||
* Send a new message to the contact having no previous coversation with
|
||||
*/
|
||||
void sendWithoutConversation(const QVariantList& addressList, const QString& message);
|
||||
void sendWithoutConversation(const QVariantList& addressList, const QString& message, const QVariantList& attachmentUrls);
|
||||
|
||||
/**
|
||||
* Send the request to the Telephony plugin to update the list of conversation threads
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#include <QDebug>
|
||||
#include <QDBusConnection>
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMimeDatabase>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include <core/device.h>
|
||||
#include <core/daemon.h>
|
||||
|
@ -27,6 +31,7 @@ SmsPlugin::SmsPlugin(QObject* parent, const QVariantList& args)
|
|||
, m_telepathyInterface(QStringLiteral("org.freedesktop.Telepathy.ConnectionManager.kdeconnect"), QStringLiteral("/kdeconnect"))
|
||||
, m_conversationInterface(new ConversationsDbusInterface(this))
|
||||
{
|
||||
m_codec = QTextCodec::codecForName(CODEC_NAME);
|
||||
}
|
||||
|
||||
SmsPlugin::~SmsPlugin()
|
||||
|
@ -47,7 +52,7 @@ bool SmsPlugin::receivePacket(const NetworkPacket& np)
|
|||
return true;
|
||||
}
|
||||
|
||||
void SmsPlugin::sendSms(const QVariantList& addresses, const QString& messageBody, const qint64 subID)
|
||||
void SmsPlugin::sendSms(const QVariantList& addresses, const QString& textMessage, const QVariantList& attachmentUrls, const qint64 subID)
|
||||
{
|
||||
QVariantList addressMapList;
|
||||
for (const QVariant& address : addresses) {
|
||||
|
@ -56,13 +61,35 @@ void SmsPlugin::sendSms(const QVariantList& addresses, const QString& messageBod
|
|||
}
|
||||
|
||||
QVariantMap packetMap({
|
||||
{QStringLiteral("sendSms"), true},
|
||||
{QStringLiteral("addresses"), addressMapList},
|
||||
{QStringLiteral("messageBody"), messageBody}
|
||||
{QStringLiteral("version"), 2},
|
||||
{QStringLiteral("addresses"), addressMapList}
|
||||
});
|
||||
|
||||
// If there is any text message add it to the network packet
|
||||
if (textMessage != QStringLiteral("")) {
|
||||
packetMap[QStringLiteral("textMessage")] = textMessage;
|
||||
}
|
||||
|
||||
if (subID != -1) {
|
||||
packetMap[QStringLiteral("subID")] = subID;
|
||||
}
|
||||
|
||||
QVariantList attachmentMapList;
|
||||
for (const QVariant& attachmentUrl : attachmentUrls) {
|
||||
const Attachment attachment = createAttachmentFromUrl(attachmentUrl.toString());
|
||||
QVariantMap attachmentMap({
|
||||
{QStringLiteral("fileName"), attachment.uniqueIdentifier()},
|
||||
{QStringLiteral("base64EncodedFile"), attachment.base64EncodedFile()},
|
||||
{QStringLiteral("mimeType"), attachment.mimeType()}
|
||||
});
|
||||
attachmentMapList.append(attachmentMap);
|
||||
}
|
||||
|
||||
// If there is any attachment add it to the network packet
|
||||
if (!attachmentMapList.isEmpty()) {
|
||||
packetMap[QStringLiteral("attachments")] = attachmentMapList;
|
||||
}
|
||||
|
||||
NetworkPacket np(PACKET_TYPE_SMS_REQUEST, packetMap);
|
||||
qCDebug(KDECONNECT_PLUGIN_SMS) << "Dispatching SMS send request to remote";
|
||||
sendPacket(np);
|
||||
|
@ -185,6 +212,30 @@ void SmsPlugin::getAttachment(const qint64& partID, const QString& uniqueIdentif
|
|||
}
|
||||
}
|
||||
|
||||
Attachment SmsPlugin::createAttachmentFromUrl(const QString& url)
|
||||
{
|
||||
QFile file(url);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
if (!file.exists()) {
|
||||
return Attachment();
|
||||
}
|
||||
|
||||
QFileInfo fileInfo(file);
|
||||
QString fileName(fileInfo.fileName());
|
||||
|
||||
QByteArray byteArray = file.readAll().toBase64();
|
||||
file.close();
|
||||
|
||||
QString base64EncodedFile = m_codec->toUnicode(byteArray);
|
||||
|
||||
QMimeDatabase mimeDatabase;
|
||||
QString mimeType = mimeDatabase.mimeTypeForFile(url).name();
|
||||
|
||||
Attachment attachment(-1, mimeType, base64EncodedFile, fileName);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
|
||||
QString SmsPlugin::dbusPath() const
|
||||
{
|
||||
|
|
|
@ -75,15 +75,21 @@
|
|||
/**
|
||||
* Packet sent to request a message be sent
|
||||
*
|
||||
* This will almost certainly need to be replaced or augmented to support MMS,
|
||||
* but be sure the Android side remains compatible with old desktop apps!
|
||||
*
|
||||
* The body should look like so:
|
||||
* { "sendSms": true,
|
||||
* { "version": 2,
|
||||
* "addresses": <List of Addresses>
|
||||
* "messageBody": "Hi mom!",
|
||||
* "textMessage": "Hi mom!",
|
||||
* "attachments": <List of Attached files>
|
||||
* "sub_id": "3859358340534"
|
||||
* }
|
||||
*
|
||||
* An AttachmentContainer object looks like:
|
||||
* {
|
||||
* "fileName": <String> // Name of the file
|
||||
* "base64EncodedFile": <String> // Base64 encoded file
|
||||
* "mimeType": <String> // File type (eg: image/jpg, video/mp4 etc.)
|
||||
* }
|
||||
*
|
||||
*/
|
||||
#define PACKET_TYPE_SMS_REQUEST QStringLiteral("kdeconnect.sms.request")
|
||||
|
||||
|
@ -123,6 +129,10 @@
|
|||
|
||||
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SMS)
|
||||
|
||||
#define CODEC_NAME "CP1251"
|
||||
|
||||
class QTextCodec;
|
||||
|
||||
class Q_DECL_EXPORT SmsPlugin
|
||||
: public KdeConnectPlugin
|
||||
{
|
||||
|
@ -139,7 +149,7 @@ public:
|
|||
QString dbusPath() const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void sendSms(const QVariantList& addresses, const QString& messageBody, const qint64 subID = -1);
|
||||
Q_SCRIPTABLE void sendSms(const QVariantList& addresses, const QString& textMessage, const QVariantList& attachmentUrls, const qint64 subID = -1);
|
||||
|
||||
/**
|
||||
* Send a request to the remote for all of its conversations
|
||||
|
@ -183,8 +193,14 @@ private:
|
|||
*/
|
||||
bool handleSmsAttachmentFile(const NetworkPacket& np);
|
||||
|
||||
/**
|
||||
* Encode a local file so it can be sent to the remote device as part of an MMS message.
|
||||
*/
|
||||
Attachment createAttachmentFromUrl(const QString& url);
|
||||
|
||||
QDBusInterface m_telepathyInterface;
|
||||
ConversationsDbusInterface* m_conversationInterface;
|
||||
QTextCodec *m_codec;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,13 +86,18 @@ void ConversationModel::setAddressList(const QList<ConversationAddress>& address
|
|||
m_addressList = addressList;
|
||||
}
|
||||
|
||||
void ConversationModel::sendReplyToConversation(const QString& message)
|
||||
bool ConversationModel::sendReplyToConversation(const QString& textMessage, QList<QUrl> attachmentUrls)
|
||||
{
|
||||
//qCDebug(KDECONNECT_SMS_CONVERSATION_MODEL) << "Trying to send" << message << "to conversation with ID" << m_threadId;
|
||||
m_conversationsInterface->replyToConversation(m_threadId, message);
|
||||
QVariantList fileUrls;
|
||||
for (const auto& url : attachmentUrls) {
|
||||
fileUrls << QVariant::fromValue(url.toLocalFile());
|
||||
}
|
||||
|
||||
void ConversationModel::startNewConversation(const QString& message, const QList<ConversationAddress>& addressList)
|
||||
m_conversationsInterface->replyToConversation(m_threadId, textMessage, fileUrls);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConversationModel::startNewConversation(const QString& textMessage, const QList<ConversationAddress>& addressList, QList<QUrl> attachmentUrls)
|
||||
{
|
||||
QVariantList addresses;
|
||||
|
||||
|
@ -100,7 +105,13 @@ void ConversationModel::startNewConversation(const QString& message, const QList
|
|||
addresses << QVariant::fromValue(address);
|
||||
}
|
||||
|
||||
m_conversationsInterface->sendWithoutConversation(addresses, message);
|
||||
QVariantList fileUrls;
|
||||
for (const auto& url : attachmentUrls) {
|
||||
fileUrls << QVariant::fromValue(url.toLocalFile());
|
||||
}
|
||||
|
||||
m_conversationsInterface->sendWithoutConversation(addresses, textMessage, fileUrls);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConversationModel::requestMoreMessages(const quint32& howMany)
|
||||
|
|
|
@ -48,8 +48,8 @@ public:
|
|||
QList<ConversationAddress> addressList() const { return m_addressList; }
|
||||
void setAddressList(const QList<ConversationAddress>& addressList);
|
||||
|
||||
Q_INVOKABLE void sendReplyToConversation(const QString& message);
|
||||
Q_INVOKABLE void startNewConversation(const QString& message, const QList<ConversationAddress>& addressList);
|
||||
Q_INVOKABLE bool sendReplyToConversation(const QString& textMessage, QList<QUrl> attachmentUrls);
|
||||
Q_INVOKABLE bool startNewConversation(const QString& textMessage, const QList<ConversationAddress>& addressList, QList<QUrl> attachmentUrls);
|
||||
Q_INVOKABLE void requestMoreMessages(const quint32& howMany = 10);
|
||||
|
||||
Q_INVOKABLE QString getCharCountInfo(const QString& message) const;
|
||||
|
|
|
@ -168,102 +168,8 @@ Kirigami.ScrollablePage
|
|||
}
|
||||
}
|
||||
|
||||
footer: Controls.Pane {
|
||||
id: sendingArea
|
||||
enabled: page.deviceConnected
|
||||
layer.enabled: sendingArea.enabled
|
||||
layer.effect: DropShadow {
|
||||
verticalOffset: 1
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
samples: 20
|
||||
spread: 0.3
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
padding: 0
|
||||
wheelEnabled: true
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.viewBackgroundColor
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.ScrollView {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: page.height > 300 ? page.height / 3 : 2 * page.height / 3
|
||||
contentWidth: page.width - sendButtonArea.width
|
||||
clip: true
|
||||
Controls.ScrollBar.horizontal.policy: Controls.ScrollBar.AlwaysOff
|
||||
|
||||
Controls.TextArea {
|
||||
anchors.fill: parent
|
||||
id: messageField
|
||||
placeholderText: i18nd("kdeconnect-sms", "Compose message")
|
||||
wrapMode: TextEdit.Wrap
|
||||
topPadding: Kirigami.Units.gridUnit * 0.5
|
||||
bottomPadding: topPadding
|
||||
selectByMouse: true
|
||||
topInset: height * 2 // This removes background (frame) of the TextArea. Setting `background: Item {}` would cause segfault.
|
||||
Keys.onReturnPressed: {
|
||||
if (event.key === Qt.Key_Return) {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
messageField.append("")
|
||||
} else {
|
||||
sendButton.onClicked()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: sendButtonArea
|
||||
|
||||
Controls.ToolButton {
|
||||
id: sendButton
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
padding: 0
|
||||
Kirigami.Icon {
|
||||
source: "document-send"
|
||||
enabled: sendButton.enabled
|
||||
isMask: true
|
||||
smooth: true
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.gridUnit * 1.5
|
||||
height: width
|
||||
}
|
||||
onClicked: {
|
||||
// don't send empty messages
|
||||
if (!messageField.text.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// disable the button to prevent sending
|
||||
// the same message several times
|
||||
sendButton.enabled = false
|
||||
|
||||
// send the message
|
||||
if (page.conversationId == page.invalidId) {
|
||||
conversationModel.startNewConversation(messageField.text, addresses)
|
||||
} else {
|
||||
conversationModel.sendReplyToConversation(messageField.text)
|
||||
}
|
||||
messageField.text = ""
|
||||
|
||||
// re-enable the button
|
||||
sendButton.enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: "charCount"
|
||||
text: conversationModel.getCharCountInfo(messageField.text)
|
||||
visible: text.length > 0
|
||||
Layout.minimumWidth: Math.max(Layout.minimumWidth, width) // Make this label only grow, never shrink
|
||||
}
|
||||
}
|
||||
}
|
||||
footer: SendingArea {
|
||||
width: parent.width
|
||||
addresses: page.addresses
|
||||
}
|
||||
}
|
||||
|
|
208
smsapp/qml/SendingArea.qml
Normal file
208
smsapp/qml/SendingArea.qml
Normal file
|
@ -0,0 +1,208 @@
|
|||
/**
|
||||
* 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.1
|
||||
import QtQuick.Controls 2.2 as Controls
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.kirigami 2.4 as Kirigami
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Dialogs 1.1
|
||||
import org.kde.kdeconnect.sms 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
property var addresses
|
||||
property var selectedFileUrls: []
|
||||
readonly property int maxMessageSize: 600000
|
||||
|
||||
MessageDialog {
|
||||
id: messageDialog
|
||||
title: i18nd("kdeconnect-sms", "Failed to send")
|
||||
text: i18nd("kdeconnect-sms", "Max message size limit exceeded.")
|
||||
|
||||
onAccepted: {
|
||||
messageDialog.close()
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
folder: shortcuts.home
|
||||
selectMultiple: true
|
||||
|
||||
onAccepted: {
|
||||
root.selectedFileUrls = fileDialog.fileUrls
|
||||
fileDialog.close()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Pane {
|
||||
id: sendingArea
|
||||
enabled: page.deviceConnected
|
||||
layer.enabled: sendingArea.enabled
|
||||
layer.effect: DropShadow {
|
||||
verticalOffset: 1
|
||||
color: Kirigami.Theme.disabledTextColor
|
||||
samples: 20
|
||||
spread: 0.3
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
padding: 0
|
||||
wheelEnabled: true
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.viewBackgroundColor
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Controls.ScrollView {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: page.height > 300 ? page.height / 3 : 2 * page.height / 3
|
||||
contentWidth: page.width - sendButtonArea.width
|
||||
clip: true
|
||||
Controls.ScrollBar.horizontal.policy: Controls.ScrollBar.AlwaysOff
|
||||
|
||||
Controls.TextArea {
|
||||
anchors.fill: parent
|
||||
id: messageField
|
||||
placeholderText: i18nd("kdeconnect-sms", "Compose message")
|
||||
wrapMode: TextEdit.Wrap
|
||||
topPadding: Kirigami.Units.gridUnit * 0.5
|
||||
bottomPadding: topPadding
|
||||
selectByMouse: true
|
||||
topInset: height * 2 // This removes background (frame) of the TextArea. Setting `background: Item {}` would cause segfault.
|
||||
Keys.onReturnPressed: {
|
||||
if (event.key === Qt.Key_Return) {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
messageField.append("")
|
||||
} else {
|
||||
sendButton.onClicked()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: sendButtonArea
|
||||
|
||||
RowLayout {
|
||||
Controls.ToolButton {
|
||||
id: sendButton
|
||||
enabled: messageField.text.length || selectedFileUrls.length
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
padding: 0
|
||||
Kirigami.Icon {
|
||||
source: "document-send"
|
||||
enabled: sendButton.enabled
|
||||
isMask: true
|
||||
smooth: true
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.gridUnit * 1.5
|
||||
height: width
|
||||
}
|
||||
|
||||
property bool messageSent: false
|
||||
|
||||
onClicked: {
|
||||
// disable the button to prevent sending
|
||||
// the same message several times
|
||||
sendButton.enabled = false
|
||||
|
||||
if (SmsHelper.totalMessageSize(selectedFileUrls, messageField.text) > maxMessageSize) {
|
||||
messageDialog.visible = true
|
||||
} else if (page.conversationId === page.invalidId) {
|
||||
messageSent = conversationModel.startNewConversation(messageField.text, addresses, selectedFileUrls)
|
||||
} else {
|
||||
messageSent = conversationModel.sendReplyToConversation(messageField.text, selectedFileUrls)
|
||||
}
|
||||
|
||||
if (messageSent) {
|
||||
messageField.text = ""
|
||||
selectedFileUrls = []
|
||||
sendButton.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.ToolButton {
|
||||
id: attachFilesButton
|
||||
enabled: true
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
padding: 0
|
||||
Text {
|
||||
id: attachedFilesCount
|
||||
text: selectedFileUrls.length
|
||||
color: "red"
|
||||
visible: selectedFileUrls.length > 0
|
||||
}
|
||||
Kirigami.Icon {
|
||||
source: "insert-image"
|
||||
isMask: true
|
||||
smooth: true
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.gridUnit * 1.5
|
||||
height: width
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
fileDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
Controls.ToolButton {
|
||||
id: clearAttachmentButton
|
||||
visible: selectedFileUrls.length > 0
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
||||
padding: 0
|
||||
Kirigami.Icon {
|
||||
id: cancelIcon
|
||||
source: "edit-clear"
|
||||
isMask: true
|
||||
smooth: true
|
||||
anchors.centerIn: parent
|
||||
width: Kirigami.Units.gridUnit * 1.5
|
||||
height: width
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
selectedFileUrls = []
|
||||
if (messageField.text == "") {
|
||||
sendButton.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: "charCount"
|
||||
text: conversationModel.getCharCountInfo(messageField.text)
|
||||
visible: text.length > 0
|
||||
Layout.minimumWidth: Math.max(Layout.minimumWidth, width) // Make this label only grow, never shrink
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
<file>qml/ChatMessage.qml</file>
|
||||
<file>qml/MessageAttachments.qml</file>
|
||||
<file>qml/AttachmentViewer.qml</file>
|
||||
<file>qml/SendingArea.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QStandardPaths>
|
||||
#include <QHash>
|
||||
#include <QtDebug>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <KPeople/PersonData>
|
||||
#include <KPeople/PersonsModel>
|
||||
|
@ -442,3 +443,13 @@ bool SmsHelper::isInGsmAlphabetExtension(const QChar& ch)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
quint64 SmsHelper::totalMessageSize(const QList<QUrl>& urls, const QString& text) {
|
||||
quint64 totalSize = text.size();
|
||||
for (QUrl url : urls) {
|
||||
QFileInfo fileInfo(url.toLocalFile());
|
||||
totalSize += fileInfo.size();
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,11 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE static bool isAddressValid(const QString& address);
|
||||
|
||||
/**
|
||||
* Return the total size of the message
|
||||
*/
|
||||
Q_INVOKABLE static quint64 totalMessageSize(const QList<QUrl>& urls, const QString& text);
|
||||
|
||||
private:
|
||||
static bool isInGsmAlphabet(const QChar& ch);
|
||||
static bool isInGsmAlphabetExtension(const QChar& ch);
|
||||
|
|
Loading…
Reference in a new issue