Search for emojis with :<keyword>
This commit is contained in:
parent
3410903afb
commit
a78f60f974
9 changed files with 271 additions and 2 deletions
BIN
db/emojis.db
Normal file
BIN
db/emojis.db
Normal file
Binary file not shown.
|
@ -16,7 +16,7 @@ CONFIG += sailfishapp sailfishapp_i18n
|
||||||
|
|
||||||
PKGCONFIG += nemonotifications-qt5 ngf-qt5
|
PKGCONFIG += nemonotifications-qt5 ngf-qt5
|
||||||
|
|
||||||
QT += core dbus
|
QT += core dbus sql
|
||||||
|
|
||||||
SOURCES += src/harbour-fernschreiber.cpp \
|
SOURCES += src/harbour-fernschreiber.cpp \
|
||||||
src/appsettings.cpp \
|
src/appsettings.cpp \
|
||||||
|
@ -24,6 +24,7 @@ SOURCES += src/harbour-fernschreiber.cpp \
|
||||||
src/chatmodel.cpp \
|
src/chatmodel.cpp \
|
||||||
src/dbusadaptor.cpp \
|
src/dbusadaptor.cpp \
|
||||||
src/dbusinterface.cpp \
|
src/dbusinterface.cpp \
|
||||||
|
src/emojisearchworker.cpp \
|
||||||
src/fernschreiberutils.cpp \
|
src/fernschreiberutils.cpp \
|
||||||
src/notificationmanager.cpp \
|
src/notificationmanager.cpp \
|
||||||
src/processlauncher.cpp \
|
src/processlauncher.cpp \
|
||||||
|
@ -102,8 +103,11 @@ ICONPATH = /usr/share/icons/hicolor
|
||||||
fernschreiber.desktop.path = /usr/share/applications/
|
fernschreiber.desktop.path = /usr/share/applications/
|
||||||
fernschreiber.desktop.files = harbour-fernschreiber.desktop
|
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 \
|
INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
|
||||||
fernschreiber.desktop gui images
|
fernschreiber.desktop gui images database
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/appsettings.h \
|
src/appsettings.h \
|
||||||
|
@ -111,6 +115,7 @@ HEADERS += \
|
||||||
src/chatmodel.h \
|
src/chatmodel.h \
|
||||||
src/dbusadaptor.h \
|
src/dbusadaptor.h \
|
||||||
src/dbusinterface.h \
|
src/dbusinterface.h \
|
||||||
|
src/emojisearchworker.h \
|
||||||
src/fernschreiberutils.h \
|
src/fernschreiberutils.h \
|
||||||
src/notificationmanager.h \
|
src/notificationmanager.h \
|
||||||
src/processlauncher.h \
|
src/processlauncher.h \
|
||||||
|
|
|
@ -43,6 +43,7 @@ Page {
|
||||||
property variant chatPartnerInformation;
|
property variant chatPartnerInformation;
|
||||||
property variant chatGroupInformation;
|
property variant chatGroupInformation;
|
||||||
property int chatOnlineMemberCount: 0;
|
property int chatOnlineMemberCount: 0;
|
||||||
|
property variant emojiProposals;
|
||||||
|
|
||||||
function updateChatPartnerStatusText() {
|
function updateChatPartnerStatusText() {
|
||||||
if (chatPartnerInformation.status['@type'] === "userStatusEmpty" ) {
|
if (chatPartnerInformation.status['@type'] === "userStatusEmpty" ) {
|
||||||
|
@ -176,6 +177,44 @@ Page {
|
||||||
controlSendButton();
|
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: {
|
Component.onCompleted: {
|
||||||
initializePage();
|
initializePage();
|
||||||
}
|
}
|
||||||
|
@ -227,6 +266,9 @@ Page {
|
||||||
uploadingProgressBar.maximumValue = fileInformation.size;
|
uploadingProgressBar.maximumValue = fileInformation.size;
|
||||||
uploadingProgressBar.value = fileInformation.remote.uploaded_size;
|
uploadingProgressBar.value = fileInformation.remote.uploaded_size;
|
||||||
}
|
}
|
||||||
|
onEmojiSearchSuccessful: {
|
||||||
|
chatPage.emojiProposals = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
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 {
|
Timer {
|
||||||
id: chatContactTimeUpdater
|
id: chatContactTimeUpdater
|
||||||
interval: 60000
|
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 {
|
Text {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
|
@ -1199,6 +1313,7 @@ Page {
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
controlSendButton();
|
controlSendButton();
|
||||||
|
textReplacementTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ BuildRequires: pkgconfig(Qt5Core)
|
||||||
BuildRequires: pkgconfig(Qt5Qml)
|
BuildRequires: pkgconfig(Qt5Qml)
|
||||||
BuildRequires: pkgconfig(Qt5Quick)
|
BuildRequires: pkgconfig(Qt5Quick)
|
||||||
BuildRequires: pkgconfig(Qt5DBus)
|
BuildRequires: pkgconfig(Qt5DBus)
|
||||||
|
BuildRequires: pkgconfig(Qt5Sql)
|
||||||
BuildRequires: pkgconfig(nemonotifications-qt5)
|
BuildRequires: pkgconfig(nemonotifications-qt5)
|
||||||
BuildRequires: pkgconfig(ngf-qt5)
|
BuildRequires: pkgconfig(ngf-qt5)
|
||||||
BuildRequires: desktop-file-utils
|
BuildRequires: desktop-file-utils
|
||||||
|
|
|
@ -24,6 +24,7 @@ PkgConfigBR:
|
||||||
- Qt5Qml
|
- Qt5Qml
|
||||||
- Qt5Quick
|
- Qt5Quick
|
||||||
- Qt5DBus
|
- Qt5DBus
|
||||||
|
- Qt5Sql
|
||||||
- nemonotifications-qt5
|
- nemonotifications-qt5
|
||||||
- ngf-qt5
|
- ngf-qt5
|
||||||
|
|
||||||
|
|
69
src/emojisearchworker.cpp
Normal file
69
src/emojisearchworker.cpp
Normal 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
52
src/emojisearchworker.h
Normal 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
|
|
@ -93,6 +93,8 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent)
|
||||||
connect(this->tdLibReceiver, SIGNAL(stickerSets(QVariantList)), this, SLOT(handleStickerSets(QVariantList)));
|
connect(this->tdLibReceiver, SIGNAL(stickerSets(QVariantList)), this, SLOT(handleStickerSets(QVariantList)));
|
||||||
connect(this->tdLibReceiver, SIGNAL(stickerSet(QVariantMap)), this, SLOT(handleStickerSet(QVariantMap)));
|
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->tdLibReceiver->start();
|
||||||
|
|
||||||
this->setLogVerbosityLevel();
|
this->setLogVerbosityLevel();
|
||||||
|
@ -467,6 +469,16 @@ void TDLibWrapper::getStickerSet(const QString &setId)
|
||||||
this->sendRequest(requestObject);
|
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()
|
QVariantMap TDLibWrapper::getUserInformation()
|
||||||
{
|
{
|
||||||
return this->userInformation;
|
return this->userInformation;
|
||||||
|
@ -828,6 +840,12 @@ void TDLibWrapper::handleStickerSet(const QVariantMap &stickerSet)
|
||||||
emit stickerSetReceived(stickerSet);
|
emit stickerSetReceived(stickerSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TDLibWrapper::handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList)
|
||||||
|
{
|
||||||
|
LOG("Emoji search completed" << queryString);
|
||||||
|
emit emojiSearchSuccessful(resultList);
|
||||||
|
}
|
||||||
|
|
||||||
void TDLibWrapper::setInitialParameters()
|
void TDLibWrapper::setInitialParameters()
|
||||||
{
|
{
|
||||||
LOG("Sending initial parameters to TD Lib");
|
LOG("Sending initial parameters to TD Lib");
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "tdlibreceiver.h"
|
#include "tdlibreceiver.h"
|
||||||
#include "dbusadaptor.h"
|
#include "dbusadaptor.h"
|
||||||
#include "dbusinterface.h"
|
#include "dbusinterface.h"
|
||||||
|
#include "emojisearchworker.h"
|
||||||
|
|
||||||
class TDLibWrapper : public QObject
|
class TDLibWrapper : public QObject
|
||||||
{
|
{
|
||||||
|
@ -129,6 +130,9 @@ public:
|
||||||
Q_INVOKABLE void getInstalledStickerSets();
|
Q_INVOKABLE void getInstalledStickerSets();
|
||||||
Q_INVOKABLE void getStickerSet(const QString &setId);
|
Q_INVOKABLE void getStickerSet(const QString &setId);
|
||||||
|
|
||||||
|
// Others (candidates for extraction ;))
|
||||||
|
Q_INVOKABLE void searchEmoji(const QString &queryString);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const Group* getGroup(qlonglong groupId) const;
|
const Group* getGroup(qlonglong groupId) const;
|
||||||
static ChatMemberStatus chatMemberStatusFromString(const QString &status);
|
static ChatMemberStatus chatMemberStatusFromString(const QString &status);
|
||||||
|
@ -169,6 +173,7 @@ signals:
|
||||||
void installedStickerSetsUpdated(const QVariantList &stickerSetIds);
|
void installedStickerSetsUpdated(const QVariantList &stickerSetIds);
|
||||||
void stickerSetsReceived(const QVariantList &stickerSets);
|
void stickerSetsReceived(const QVariantList &stickerSets);
|
||||||
void stickerSetReceived(const QVariantMap &stickerSet);
|
void stickerSetReceived(const QVariantMap &stickerSet);
|
||||||
|
void emojiSearchSuccessful(const QVariantList &result);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void handleVersionDetected(const QString &version);
|
void handleVersionDetected(const QString &version);
|
||||||
|
@ -204,6 +209,7 @@ public slots:
|
||||||
void handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds);
|
void handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds);
|
||||||
void handleStickerSets(const QVariantList &stickerSets);
|
void handleStickerSets(const QVariantList &stickerSets);
|
||||||
void handleStickerSet(const QVariantMap &stickerSet);
|
void handleStickerSet(const QVariantMap &stickerSet);
|
||||||
|
void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setInitialParameters();
|
void setInitialParameters();
|
||||||
|
@ -228,6 +234,8 @@ private:
|
||||||
QVariantMap unreadChatInformation;
|
QVariantMap unreadChatInformation;
|
||||||
QHash<qlonglong,Group*> basicGroups;
|
QHash<qlonglong,Group*> basicGroups;
|
||||||
QHash<qlonglong,Group*> superGroups;
|
QHash<qlonglong,Group*> superGroups;
|
||||||
|
EmojiSearchWorker emojiSearchWorker;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TDLIBWRAPPER_H
|
#endif // TDLIBWRAPPER_H
|
||||||
|
|
Loading…
Reference in a new issue