Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Network
KDE Connect
Commits
706fc314
Commit
706fc314
authored
Aug 31, 2020
by
Aniket Kumar
🤵
Browse files
Adding support to send attachments to the remote device.
parent
60a1adf2
Pipeline
#32585
passed with stage
in 14 minutes and 44 seconds
Changes
14
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
cli/kdeconnect-cli.cpp
View file @
706fc314
...
...
@@ -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>"
);
...
...
interfaces/conversationmessage.cpp
View file @
706fc314
...
...
@@ -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
)
...
...
interfaces/conversationmessage.h
View file @
706fc314
...
...
@@ -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
();
}
/**
...
...
plugins/sms/conversationsdbusinterface.cpp
View file @
706fc314
...
...
@@ -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
()
...
...
plugins/sms/conversationsdbusinterface.h
View file @
706fc314
...
...
@@ -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
...
...
plugins/sms/smsplugin.cpp
View file @
706fc314
...
...
@@ -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
&
m
essage
Body
,
const
qint64
subID
)
void
SmsPlugin
::
sendSms
(
const
QVariantList
&
addresses
,
const
QString
&
textM
essage
,
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
{
...
...
plugins/sms/smsplugin.h
View file @
706fc314
...
...
@@ -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
&
m
essage
Body
,
const
qint64
subID
=
-
1
);
Q_SCRIPTABLE
void
sendSms
(
const
QVariantList
&
addresses
,
const
QString
&
textM
essage
,
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
smsapp/conversationmodel.cpp
View file @
706fc314
...
...
@@ -86,13 +86,18 @@ void ConversationModel::setAddressList(const QList<ConversationAddress>& address
m_addressList
=
addressList
;
}
void
ConversationModel
::
sendReplyToConversation
(
const
QString
&
m
essage
)
bool
ConversationModel
::
sendReplyToConversation
(
const
QString
&
textM
essage
,
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
());
}
m_conversationsInterface
->
replyToConversation
(
m_threadId
,
textMessage
,
fileUrls
);
return
true
;
}
void
ConversationModel
::
startNewConversation
(
const
QString
&
m
essage
,
const
QList
<
ConversationAddress
>&
addressList
)
bool
ConversationModel
::
startNewConversation
(
const
QString
&
textM
essage
,
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
)
...
...
smsapp/conversationmodel.h
View file @
706fc314
...
...
@@ -48,8 +48,8 @@ public:
QList
<
ConversationAddress
>
addressList
()
const
{
return
m_addressList
;
}
void
setAddressList
(
const
QList
<
ConversationAddress
>&
addressList
);
Q_INVOKABLE
void
sendReplyToConversation
(
const
QString
&
m
essage
);
Q_INVOKABLE
void
startNewConversation
(
const
QString
&
m
essage
,
const
QList
<
ConversationAddress
>&
addressList
);
Q_INVOKABLE
bool
sendReplyToConversation
(
const
QString
&
textM
essage
,
QList
<
QUrl
>
attachmentUrls
);
Q_INVOKABLE
bool
startNewConversation
(
const
QString
&
textM
essage
,
const
QList
<
ConversationAddress
>&
addressList
,
QList
<
QUrl
>
attachmentUrls
);
Q_INVOKABLE
void
requestMoreMessages
(
const
quint32
&
howMany
=
10
);
Q_INVOKABLE
QString
getCharCountInfo
(
const
QString
&
message
)
const
;
...
...
smsapp/qml/ConversationDisplay.qml
View file @
706fc314
...
...
@@ -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
}
}
smsapp/qml/SendingArea.qml
0 → 100644
View file @
706fc314
/**
* 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