diff --git a/smsapp/conversationlistmodel.cpp b/smsapp/conversationlistmodel.cpp index 84c5fa452..2780706f1 100644 --- a/smsapp/conversationlistmodel.cpp +++ b/smsapp/conversationlistmodel.cpp @@ -263,3 +263,32 @@ void ConversationListModel::displayContacts() { } } } + +bool ConversationListModel::isPhoneNumberValid(const QString& number) { + return SmsHelper::isPhoneNumberValid(number); +} + +QString ConversationListModel::getDisplayNameForAddress(const QString &address) { + const auto item = getConversationForAddress(address); + if (!item) { + return QString(); + } + return item->data(Qt::DisplayRole).toString(); +} + +void ConversationListModel::createConversationForAddress(const QString& address) { + QStandardItem* item = new QStandardItem(); + item->setText(address); + + QList addresses; + addresses.append(ConversationAddress(address)); + item->setData(QVariant::fromValue(addresses), AddressesRole); + + QString displayBody = i18n("%1", address); + item->setData(displayBody, Qt::ToolTipRole); + item->setData(false, MultitargetRole); + item->setData(qint64(INVALID_THREAD_ID), ConversationIdRole); + item->setData(qint64(INVALID_DATE), DateRole); + item->setData(address, SenderRole); + appendRow(item); +} diff --git a/smsapp/conversationlistmodel.h b/smsapp/conversationlistmodel.h index 9575174a5..124b35fb9 100644 --- a/smsapp/conversationlistmodel.h +++ b/smsapp/conversationlistmodel.h @@ -57,6 +57,22 @@ public: Q_SCRIPTABLE void refresh(); + /** + * This method gets name of conversations or contact if it find any matching address + * Needed for checking if the converstion already or contact already exist or no before adding an arbbitrary contact + */ + Q_INVOKABLE QString getDisplayNameForAddress(const QString& address); + + /* This method creates conversation with an arbitrary address */ + Q_INVOKABLE void createConversationForAddress(const QString& address); + + /** + * This method ensurse whether the phone number format is valid or not + * TODO: This is here because I don't know how to make the QML call the smshelper directly + * but that is what should be happening! + */ + Q_INVOKABLE bool isPhoneNumberValid(const QString& number); + public Q_SLOTS: void handleCreatedConversation(const QDBusVariant& msg); void handleConversationUpdated(const QDBusVariant& msg); diff --git a/smsapp/qml/ConversationList.qml b/smsapp/qml/ConversationList.qml index 69c938b3e..bd50e3247 100644 --- a/smsapp/qml/ConversationList.qml +++ b/smsapp/qml/ConversationList.qml @@ -125,6 +125,7 @@ Kirigami.ScrollablePage readonly property bool deviceConnected: devicesCombo.enabled readonly property QtObject device: devicesCombo.currentIndex >= 0 ? devicesModel.data(devicesModel.index(devicesCombo.currentIndex, 0), DevicesModel.DeviceRole) : null readonly property alias lastDeviceId: conversationListModel.deviceId + property string displayName Component { id: chatView @@ -147,6 +148,7 @@ Kirigami.ScrollablePage } } + header: TextField { /** * Used as the filter of the list of messages @@ -154,6 +156,7 @@ Kirigami.ScrollablePage id: filter placeholderText: i18nd("kdeconnect-sms", "Filter...") width: parent.width + height: addButton.height z: 10 onTextChanged: { if (filter.text != "") { @@ -164,6 +167,15 @@ Kirigami.ScrollablePage view.model.setFilterFixedString(filter.text) view.currentIndex = 0 + + if (conversationListModel.isPhoneNumberValid(filter.text)) { + addButton.visible = true + addButton.focus = true + } else { + addButton.visible = false + addButton.focus = false + filter.width = view.width + } } onAccepted: { view.currentItem.startChat() @@ -181,10 +193,39 @@ Kirigami.ScrollablePage onActivated: filter.forceActiveFocus() } } + headerPositioning: ListView.OverlayHeader Keys.forwardTo: [headerItem] + Button { + id: addButton + text: i18nd("kdeconnect-sms", "Add") + anchors.right: parent.right + height: view.headerItem.height + visible: false + + onClicked: { + // We have to disable the filter temporarily in order to avoid getting key inputs accidently while processing the request + view.headerItem.enabled = false + // If the address entered by the user already exists, fetch the name of the contact otherwise it will return empty string + displayName = conversationListModel.getDisplayNameForAddress(view.headerItem.text) + if (displayName != "") { + view.headerItem.text = displayName + } else { + conversationListModel.createConversationForAddress(view.headerItem.text) + } + + view.headerItem.enabled = true + addButton.visible = false + view.headerItem.width = view.width + } + Keys.onReturnPressed: { + event.clicked = true + addButton.onClicked() + } + } + delegate: Kirigami.AbstractListItem { id: listItem diff --git a/smsapp/smshelper.cpp b/smsapp/smshelper.cpp index 39996d2a2..84242f4fd 100644 --- a/smsapp/smshelper.cpp +++ b/smsapp/smshelper.cpp @@ -127,6 +127,13 @@ QString SmsHelper::canonicalizePhoneNumber(const QString& phoneNumber) return toReturn; } +bool SmsHelper::isPhoneNumberValid(const QString& phoneNumber) +{ + // This regular expression matches a wide range of international Phone number formats, minimum of 3 digits and maximum upto 15 digits + QRegularExpression validNumberPattern(QStringLiteral("^((\\+?(\\d{2}))\\s?)?((\\d{2})|(\\((\\d{2})\\))\\s?)?(\\d{3,15})(\\-(\\d{3,15}))?$")); + return validNumberPattern.match(phoneNumber).hasMatch(); +} + class PersonsCache : public QObject { public: PersonsCache() { diff --git a/smsapp/smshelper.h b/smsapp/smshelper.h index 16c2d6b21..9d2ecbed4 100644 --- a/smsapp/smshelper.h +++ b/smsapp/smshelper.h @@ -117,7 +117,12 @@ public: static bool isInGsmAlphabet(const QChar& ch); static bool isInGsmAlphabetExtension(const QChar& ch); - + + /** + * Used to validate arbitrary phone number entered by the user + */ + static bool isPhoneNumberValid(const QString& phoneNumber); + private: SmsHelper(){}; ~SmsHelper(){};