Search for emojis with :<keyword>

This commit is contained in:
Sebastian J. Wolf 2020-10-18 18:57:01 +02:00
parent 3410903afb
commit a78f60f974
9 changed files with 271 additions and 2 deletions

BIN
db/emojis.db Normal file

Binary file not shown.

View file

@ -16,7 +16,7 @@ CONFIG += sailfishapp sailfishapp_i18n
PKGCONFIG += nemonotifications-qt5 ngf-qt5
QT += core dbus
QT += core dbus sql
SOURCES += src/harbour-fernschreiber.cpp \
src/appsettings.cpp \
@ -24,6 +24,7 @@ SOURCES += src/harbour-fernschreiber.cpp \
src/chatmodel.cpp \
src/dbusadaptor.cpp \
src/dbusinterface.cpp \
src/emojisearchworker.cpp \
src/fernschreiberutils.cpp \
src/notificationmanager.cpp \
src/processlauncher.cpp \
@ -102,8 +103,11 @@ ICONPATH = /usr/share/icons/hicolor
fernschreiber.desktop.path = /usr/share/applications/
fernschreiber.desktop.files = harbour-fernschreiber.desktop
database.files = db
database.path = /usr/share/$${TARGET}
INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
fernschreiber.desktop gui images
fernschreiber.desktop gui images database
HEADERS += \
src/appsettings.h \
@ -111,6 +115,7 @@ HEADERS += \
src/chatmodel.h \
src/dbusadaptor.h \
src/dbusinterface.h \
src/emojisearchworker.h \
src/fernschreiberutils.h \
src/notificationmanager.h \
src/processlauncher.h \

View file

@ -43,6 +43,7 @@ Page {
property variant chatPartnerInformation;
property variant chatGroupInformation;
property int chatOnlineMemberCount: 0;
property variant emojiProposals;
function updateChatPartnerStatusText() {
if (chatPartnerInformation.status['@type'] === "userStatusEmpty" ) {
@ -176,6 +177,44 @@ Page {
controlSendButton();
}
function getWordBoundaries(text, cursorPosition) {
var wordBoundaries = { beginIndex : 0, endIndex : text.length};
var currentIndex = 0;
for (currentIndex = (cursorPosition - 1); currentIndex > 0; currentIndex--) {
if (text.charAt(currentIndex) === ' ') {
wordBoundaries.beginIndex = currentIndex + 1;
break;
}
}
for (currentIndex = cursorPosition; currentIndex < text.length; currentIndex++) {
if (text.charAt(currentIndex) === ' ') {
wordBoundaries.endIndex = currentIndex;
break;
}
}
return wordBoundaries;
}
function handleMessageTextReplacement(text, cursorPosition) {
var wordBoundaries = getWordBoundaries(text, cursorPosition);
var currentWord = text.substring(wordBoundaries.beginIndex, wordBoundaries.endIndex);
if (currentWord.length > 1 && currentWord.charAt(0) === ':') {
tdLibWrapper.searchEmoji(currentWord.substring(1));
} else {
chatPage.emojiProposals = null;
}
}
function replaceMessageText(text, cursorPosition, newText) {
var wordBoundaries = getWordBoundaries(text, cursorPosition);
var newCompleteText = text.substring(0, wordBoundaries.beginIndex) + newText + " " + text.substring(wordBoundaries.endIndex);
var newIndex = wordBoundaries.beginIndex + newText.length + 1;
newMessageTextField.text = newCompleteText;
newMessageTextField.cursorPosition = newIndex;
lostFocusTimer.start();
}
Component.onCompleted: {
initializePage();
}
@ -227,6 +266,9 @@ Page {
uploadingProgressBar.maximumValue = fileInformation.size;
uploadingProgressBar.value = fileInformation.remote.uploaded_size;
}
onEmojiSearchSuccessful: {
chatPage.emojiProposals = result;
}
}
Connections {
@ -269,6 +311,26 @@ Page {
}
}
Timer {
id: lostFocusTimer
interval: 200
running: false
repeat: false
onTriggered: {
newMessageTextField.forceActiveFocus();
}
}
Timer {
id: textReplacementTimer
interval: 600
running: false
repeat: false
onTriggered: {
handleMessageTextReplacement(newMessageTextField.text, newMessageTextField.cursorPosition);
}
}
Timer {
id: chatContactTimeUpdater
interval: 60000
@ -1151,6 +1213,58 @@ Page {
}
Column {
id: emojiColumn
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
visible: emojiProposals ? ( emojiProposals.length > 0 ? true : false ) : false
opacity: emojiProposals ? ( emojiProposals.length > 0 ? 1 : 0 ) : 0
Behavior on opacity { NumberAnimation {} }
spacing: Theme.paddingMedium
Flickable {
width: parent.width
height: emojiResultRow.height + Theme.paddingSmall
anchors.horizontalCenter: parent.horizontalCenter
contentWidth: emojiResultRow.width
clip: true
Row {
id: emojiResultRow
spacing: Theme.paddingMedium
Repeater {
model: emojiProposals
Item {
height: singleEmojiRow.height
width: singleEmojiRow.width
Row {
id: singleEmojiRow
spacing: Theme.paddingSmall
Image {
id: emojiPicture
source: "../js/emoji/" + modelData.file_name
width: Theme.fontSizeLarge
height: Theme.fontSizeLarge
}
}
MouseArea {
anchors.fill: parent
onClicked: {
replaceMessageText(newMessageTextField.text, newMessageTextField.cursorPosition, modelData.emoji);
emojiProposals = null;
}
}
}
}
}
}
}
Text {
width: parent.width
@ -1199,6 +1313,7 @@ Page {
onTextChanged: {
controlSendButton();
textReplacementTimer.restart();
}
}

View file

@ -24,6 +24,7 @@ BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Qml)
BuildRequires: pkgconfig(Qt5Quick)
BuildRequires: pkgconfig(Qt5DBus)
BuildRequires: pkgconfig(Qt5Sql)
BuildRequires: pkgconfig(nemonotifications-qt5)
BuildRequires: pkgconfig(ngf-qt5)
BuildRequires: desktop-file-utils

View file

@ -24,6 +24,7 @@ PkgConfigBR:
- Qt5Qml
- Qt5Quick
- Qt5DBus
- Qt5Sql
- nemonotifications-qt5
- ngf-qt5

69
src/emojisearchworker.cpp Normal file
View file

@ -0,0 +1,69 @@
/*
Copyright (C) 2020 Sebastian J. Wolf
This file is part of Fernschreiber.
Fernschreiber 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 3 of the License, or
(at your option) any later version.
Fernschreiber 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 Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
#include "emojisearchworker.h"
#define LOG(x) qDebug() << "[EmojiSearchWorker]" << x
EmojiSearchWorker::~EmojiSearchWorker()
{
LOG("Destroying myself...");
database.close();
}
EmojiSearchWorker::EmojiSearchWorker(QObject *parent) : QThread(parent)
{
LOG("Initializing Emoji database");
QSqlDatabase::removeDatabase("emojis");
database = QSqlDatabase::addDatabase("QSQLITE", "emojis");
database.setDatabaseName("/usr/share/harbour-fernschreiber/db/emojis.db");
}
void EmojiSearchWorker::setParameters(const QString &queryString)
{
this->queryString = queryString;
}
void EmojiSearchWorker::performSearch()
{
LOG("Performing emoji search" << this->queryString);
QVariantList resultList;
if (database.open()) {
QSqlQuery query(database);
query.prepare("select * from emojis where description match (:queryString) limit 25");
query.bindValue(":queryString", queryString + "*");
query.exec();
while (query.next()) {
if (isInterruptionRequested()) {
break;
}
QVariantMap foundEmoji;
foundEmoji.insert("file_name", query.value(0).toString());
foundEmoji.insert("emoji", query.value(1).toString());
foundEmoji.insert("emoji_version", query.value(2).toString());
foundEmoji.insert("description", query.value(3).toString());
resultList.append(foundEmoji);
}
database.close();
} else {
LOG("Unable to perform a query on database" << database.lastError().databaseText());
}
emit searchCompleted(queryString, resultList);
}

52
src/emojisearchworker.h Normal file
View file

@ -0,0 +1,52 @@
/*
Copyright (C) 2020 Sebastian J. Wolf
This file is part of Fernschreiber.
Fernschreiber 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 3 of the License, or
(at your option) any later version.
Fernschreiber 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 Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EMOJISEARCHWORKER_H
#define EMOJISEARCHWORKER_H
#include <QThread>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariantList>
#include <QDebug>
class EmojiSearchWorker : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
performSearch();
}
public:
~EmojiSearchWorker() override;
explicit EmojiSearchWorker(QObject *parent = nullptr);
void setParameters(const QString &queryString);
signals:
void searchCompleted(const QString &queryString, const QVariantList &resultList);
public slots:
private:
QSqlDatabase database;
QString queryString;
void performSearch();
};
#endif // EMOJISEARCHWORKER_H

View file

@ -93,6 +93,8 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent)
connect(this->tdLibReceiver, SIGNAL(stickerSets(QVariantList)), this, SLOT(handleStickerSets(QVariantList)));
connect(this->tdLibReceiver, SIGNAL(stickerSet(QVariantMap)), this, SLOT(handleStickerSet(QVariantMap)));
connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
this->tdLibReceiver->start();
this->setLogVerbosityLevel();
@ -467,6 +469,16 @@ void TDLibWrapper::getStickerSet(const QString &setId)
this->sendRequest(requestObject);
}
void TDLibWrapper::searchEmoji(const QString &queryString)
{
LOG("Searching emoji" << queryString);
while (this->emojiSearchWorker.isRunning()) {
this->emojiSearchWorker.requestInterruption();
}
this->emojiSearchWorker.setParameters(queryString);
this->emojiSearchWorker.start();
}
QVariantMap TDLibWrapper::getUserInformation()
{
return this->userInformation;
@ -828,6 +840,12 @@ void TDLibWrapper::handleStickerSet(const QVariantMap &stickerSet)
emit stickerSetReceived(stickerSet);
}
void TDLibWrapper::handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList)
{
LOG("Emoji search completed" << queryString);
emit emojiSearchSuccessful(resultList);
}
void TDLibWrapper::setInitialParameters()
{
LOG("Sending initial parameters to TD Lib");

View file

@ -24,6 +24,7 @@
#include "tdlibreceiver.h"
#include "dbusadaptor.h"
#include "dbusinterface.h"
#include "emojisearchworker.h"
class TDLibWrapper : public QObject
{
@ -129,6 +130,9 @@ public:
Q_INVOKABLE void getInstalledStickerSets();
Q_INVOKABLE void getStickerSet(const QString &setId);
// Others (candidates for extraction ;))
Q_INVOKABLE void searchEmoji(const QString &queryString);
public:
const Group* getGroup(qlonglong groupId) const;
static ChatMemberStatus chatMemberStatusFromString(const QString &status);
@ -169,6 +173,7 @@ signals:
void installedStickerSetsUpdated(const QVariantList &stickerSetIds);
void stickerSetsReceived(const QVariantList &stickerSets);
void stickerSetReceived(const QVariantMap &stickerSet);
void emojiSearchSuccessful(const QVariantList &result);
public slots:
void handleVersionDetected(const QString &version);
@ -204,6 +209,7 @@ public slots:
void handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds);
void handleStickerSets(const QVariantList &stickerSets);
void handleStickerSet(const QVariantMap &stickerSet);
void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList);
private:
void setInitialParameters();
@ -228,6 +234,8 @@ private:
QVariantMap unreadChatInformation;
QHash<qlonglong,Group*> basicGroups;
QHash<qlonglong,Group*> superGroups;
EmojiSearchWorker emojiSearchWorker;
};
#endif // TDLIBWRAPPER_H