Support open-with from external sources (e.g. web links)

This commit is contained in:
Sebastian Wolf 2020-11-08 21:13:04 +01:00
parent 5127b8ae02
commit 89e0576adc
21 changed files with 212 additions and 8 deletions

View file

@ -33,5 +33,8 @@ ApplicationWindow
onPleaseOpenMessage: { onPleaseOpenMessage: {
appWindow.activate(); appWindow.activate();
} }
onPleaseOpenUrl: {
appWindow.activate();
}
} }
} }

View file

@ -310,21 +310,28 @@ function enhanceMessageText(formattedText) {
} }
function handleLink(link) { function handleLink(link) {
var tMePrefix = tdLibWrapper.getOptionString("t_me_url");
if (link.indexOf("user://") === 0) { if (link.indexOf("user://") === 0) {
var userInformation = tdLibWrapper.getUserInformationByName(link.substring(8)); var userInformation = tdLibWrapper.getUserInformationByName(link.substring(8));
tdLibWrapper.createPrivateChat(userInformation.id); tdLibWrapper.createPrivateChat(userInformation.id);
} else if (link.indexOf("userId://") === 0) { } else if (link.indexOf("userId://") === 0) {
tdLibWrapper.createPrivateChat(link.substring(9)); tdLibWrapper.createPrivateChat(link.substring(9));
} else if (link.indexOf("tg://") === 0) {
console.log("Special TG link: " + link);
if (link.indexOf("tg://join?invite=") === 0) {
tdLibWrapper.joinChatByInviteLink(tMePrefix + "joinchat/" + link.substring(17));
} else if (link.indexOf("tg://resolve?domain=") === 0) {
tdLibWrapper.searchPublicChat(link.substring(20));
}
} else { } else {
var tMePrefix = tdLibWrapper.getOptionString("t_me_url");
if (link.indexOf(tMePrefix) === 0) { if (link.indexOf(tMePrefix) === 0) {
if (link.indexOf("joinchat") !== -1) { if (link.indexOf("joinchat") !== -1) {
console.log("Joining Chatto: " + link); console.log("Joining Chat: " + link);
tdLibWrapper.joinChatByInviteLink(link); tdLibWrapper.joinChatByInviteLink(link);
// Do the necessary stuff to open the chat if successful // Do the necessary stuff to open the chat if successful
// Fail with nice error message if it doesn't work // Fail with nice error message if it doesn't work
} else { } else {
console.log("SUCH! " + link.substring(tMePrefix.length)); console.log("Search public chat: " + link.substring(tMePrefix.length));
tdLibWrapper.searchPublicChat(link.substring(tMePrefix.length)); tdLibWrapper.searchPublicChat(link.substring(tMePrefix.length));
// Check responses for updateBasicGroup or updateSupergroup // Check responses for updateBasicGroup or updateSupergroup
// Fire createBasicGroupChat or createSupergroupChat // Fire createBasicGroupChat or createSupergroupChat

View file

@ -50,6 +50,10 @@ Page {
pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : tdLibWrapper.getChat(chatId) }, PageStackAction.Immediate) pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : tdLibWrapper.getChat(chatId) }, PageStackAction.Immediate)
} }
} }
onPleaseOpenUrl: {
console.log("[OverviewPage] Opening URL requested: " + url);
Functions.handleLink(url);
}
} }
Timer { Timer {

View file

@ -52,6 +52,16 @@ Page {
} }
} }
TextSwitch {
checked: appSettings.useOpenWith
text: qsTr("Open-with menu integration")
description: qsTr("Integrate Fernschreiber into open-with menu of Sailfish OS")
automaticCheck: false
onClicked: {
appSettings.useOpenWith = !checked
}
}
ComboBox { ComboBox {
id: feedbackComboBox id: feedbackComboBox
label: qsTr("Notification feedback") label: qsTr("Notification feedback")

View file

@ -22,6 +22,7 @@
namespace { namespace {
const QString KEY_SEND_BY_ENTER("sendByEnter"); const QString KEY_SEND_BY_ENTER("sendByEnter");
const QString KEY_USE_OPEN_WITH("useOpenWith");
const QString KEY_SHOW_STICKERS_AS_IMAGES("showStickersAsImages"); const QString KEY_SHOW_STICKERS_AS_IMAGES("showStickersAsImages");
const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback"); const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback");
} }
@ -44,6 +45,20 @@ void AppSettings::setSendByEnter(bool sendByEnter)
} }
} }
bool AppSettings::getUseOpenWith() const
{
return settings.value(KEY_USE_OPEN_WITH, true).toBool();
}
void AppSettings::setUseOpenWith(bool useOpenWith)
{
if (getUseOpenWith() != useOpenWith) {
LOG(KEY_USE_OPEN_WITH << useOpenWith);
settings.setValue(KEY_USE_OPEN_WITH, useOpenWith);
emit useOpenWithChanged();
}
}
bool AppSettings::showStickersAsImages() const bool AppSettings::showStickersAsImages() const
{ {
return settings.value(KEY_SHOW_STICKERS_AS_IMAGES, true).toBool(); return settings.value(KEY_SHOW_STICKERS_AS_IMAGES, true).toBool();

View file

@ -24,6 +24,7 @@
class AppSettings : public QObject { class AppSettings : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool sendByEnter READ getSendByEnter WRITE setSendByEnter NOTIFY sendByEnterChanged) Q_PROPERTY(bool sendByEnter READ getSendByEnter WRITE setSendByEnter NOTIFY sendByEnterChanged)
Q_PROPERTY(bool useOpenWith READ getUseOpenWith WRITE setUseOpenWith NOTIFY useOpenWithChanged)
Q_PROPERTY(bool showStickersAsImages READ showStickersAsImages WRITE setShowStickersAsImages NOTIFY showStickersAsImagesChanged) Q_PROPERTY(bool showStickersAsImages READ showStickersAsImages WRITE setShowStickersAsImages NOTIFY showStickersAsImagesChanged)
Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged) Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged)
@ -41,6 +42,9 @@ public:
bool getSendByEnter() const; bool getSendByEnter() const;
void setSendByEnter(bool sendByEnter); void setSendByEnter(bool sendByEnter);
bool getUseOpenWith() const;
void setUseOpenWith(bool useOpenWith);
bool showStickersAsImages() const; bool showStickersAsImages() const;
void setShowStickersAsImages(bool showAsImages); void setShowStickersAsImages(bool showAsImages);
@ -49,6 +53,7 @@ public:
signals: signals:
void sendByEnterChanged(); void sendByEnterChanged();
void useOpenWithChanged();
void showStickersAsImagesChanged(); void showStickersAsImagesChanged();
void notificationFeedbackChanged(); void notificationFeedbackChanged();

View file

@ -31,3 +31,11 @@ void DBusAdaptor::openMessage(const QString &chatId, const QString &messageId)
qDebug() << "[DBusAdaptor] Open Message " << chatId << messageId; qDebug() << "[DBusAdaptor] Open Message " << chatId << messageId;
emit pleaseOpenMessage(chatId, messageId); emit pleaseOpenMessage(chatId, messageId);
} }
void DBusAdaptor::openUrl(const QStringList &arguments)
{
qDebug() << "[DBusAdaptor] Open Url" << arguments;
if (arguments.length() >= 1) {
emit pleaseOpenUrl(arguments.first());
}
}

View file

@ -33,9 +33,11 @@ public:
signals: signals:
void pleaseOpenMessage(const QString &chatId, const QString &messageId); void pleaseOpenMessage(const QString &chatId, const QString &messageId);
void pleaseOpenUrl(const QString &url);
public slots: public slots:
void openMessage(const QString &chatId, const QString &messageId); void openMessage(const QString &chatId, const QString &messageId);
void openUrl(const QStringList &arguments);
}; };

View file

@ -53,7 +53,7 @@ int main(int argc, char *argv[])
context->setContextProperty("appSettings", appSettings); context->setContextProperty("appSettings", appSettings);
qmlRegisterUncreatableType<AppSettings>(uri, 1, 0, "AppSettings", QString()); qmlRegisterUncreatableType<AppSettings>(uri, 1, 0, "AppSettings", QString());
TDLibWrapper *tdLibWrapper = new TDLibWrapper(view.data()); TDLibWrapper *tdLibWrapper = new TDLibWrapper(appSettings, view.data());
context->setContextProperty("tdLibWrapper", tdLibWrapper); context->setContextProperty("tdLibWrapper", tdLibWrapper);
qmlRegisterUncreatableType<TDLibWrapper>(uri, 1, 0, "TelegramAPI", QString()); qmlRegisterUncreatableType<TDLibWrapper>(uri, 1, 0, "TelegramAPI", QString());

View file

@ -47,9 +47,10 @@ namespace {
const QString _EXTRA("@extra"); const QString _EXTRA("@extra");
} }
TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) TDLibWrapper::TDLibWrapper(AppSettings *appSettings, QObject *parent) : QObject(parent)
{ {
LOG("Initializing TD Lib..."); LOG("Initializing TD Lib...");
this->appSettings = appSettings;
this->tdLibClient = td_json_client_create(); this->tdLibClient = td_json_client_create();
this->tdLibReceiver = new TDLibReceiver(this->tdLibClient, this); this->tdLibReceiver = new TDLibReceiver(this->tdLibClient, this);
@ -60,7 +61,11 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent)
} }
this->dbusInterface = new DBusInterface(this); this->dbusInterface = new DBusInterface(this);
this->initializeOpenWith(); if (this->appSettings->getUseOpenWith()) {
this->initializeOpenWith();
} else {
this->removeOpenWith();
}
connect(this->tdLibReceiver, SIGNAL(versionDetected(QString)), this, SLOT(handleVersionDetected(QString))); connect(this->tdLibReceiver, SIGNAL(versionDetected(QString)), this, SLOT(handleVersionDetected(QString)));
connect(this->tdLibReceiver, SIGNAL(authorizationStateChanged(QString, QVariantMap)), this, SLOT(handleAuthorizationStateChanged(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(authorizationStateChanged(QString, QVariantMap)), this, SLOT(handleAuthorizationStateChanged(QString, QVariantMap)));
@ -110,6 +115,8 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent)
connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList))); connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
connect(this->appSettings, SIGNAL(useOpenWithChanged()), this, SLOT(handleOpenWithChanged()));
this->tdLibReceiver->start(); this->tdLibReceiver->start();
this->setLogVerbosityLevel(); this->setLogVerbosityLevel();
@ -737,6 +744,15 @@ void TDLibWrapper::joinChatByInviteLink(const QString &inviteLink)
this->sendRequest(requestObject); this->sendRequest(requestObject);
} }
void TDLibWrapper::getDeepLinkInfo(const QString &link)
{
LOG("Resolving TG deep link" << link);
QVariantMap requestObject;
requestObject.insert(_TYPE, "getDeepLinkInfo");
requestObject.insert("link", link);
this->sendRequest(requestObject);
}
void TDLibWrapper::searchEmoji(const QString &queryString) void TDLibWrapper::searchEmoji(const QString &queryString)
{ {
LOG("Searching emoji" << queryString); LOG("Searching emoji" << queryString);
@ -1059,6 +1075,15 @@ void TDLibWrapper::handleEmojiSearchCompleted(const QString &queryString, const
emit emojiSearchSuccessful(resultList); emit emojiSearchSuccessful(resultList);
} }
void TDLibWrapper::handleOpenWithChanged()
{
if (this->appSettings->getUseOpenWith()) {
this->initializeOpenWith();
} else {
this->removeOpenWith();
}
}
void TDLibWrapper::setInitialParameters() void TDLibWrapper::setInitialParameters()
{ {
LOG("Sending initial parameters to TD Lib"); LOG("Sending initial parameters to TD Lib");
@ -1105,6 +1130,39 @@ void TDLibWrapper::initializeOpenWith()
{ {
LOG("Initialize open-with"); LOG("Initialize open-with");
qDebug() << "Checking standard open URL file...";
QString openUrlFilePath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/open-url.desktop";
if (QFile::exists(openUrlFilePath)) {
qDebug() << "Standard open URL file exists, good!";
} else {
qDebug() << "Copying standard open URL file to " << openUrlFilePath;
QFile::copy("/usr/share/applications/open-url.desktop", openUrlFilePath);
QProcess::startDetached("update-desktop-database " + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
}
QString desktopFilePath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/harbour-fernschreiber-open-url.desktop";
QFile desktopFile(desktopFilePath);
if (!desktopFile.exists()) {
qDebug() << "Creating Open-With file at " << desktopFile.fileName();
if (desktopFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream fileOut(&desktopFile);
fileOut.setCodec("UTF-8");
fileOut << QString("[Desktop Entry]").toUtf8() << "\n";
fileOut << QString("Type=Application").toUtf8() << "\n";
fileOut << QString("Name=Fernschreiber").toUtf8() << "\n";
fileOut << QString("Icon=harbour-fernschreiber").toUtf8() << "\n";
fileOut << QString("NotShowIn=X-MeeGo;").toUtf8() << "\n";
fileOut << QString("MimeType=text/html;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/tg;").toUtf8() << "\n";
fileOut << QString("X-Maemo-Service=de.ygriega.fernschreiber").toUtf8() << "\n";
fileOut << QString("X-Maemo-Object-Path=/de/ygriega/fernschreiber").toUtf8() << "\n";
fileOut << QString("X-Maemo-Method=de.ygriega.fernschreiber.openUrl").toUtf8() << "\n";
fileOut << QString("Hidden=true;").toUtf8() << "\n";
fileOut.flush();
desktopFile.close();
QProcess::startDetached("update-desktop-database " + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
}
}
QString dbusPathName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/dbus-1/services"; QString dbusPathName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/dbus-1/services";
QDir dbusPath(dbusPathName); QDir dbusPath(dbusPathName);
if (!dbusPath.exists()) { if (!dbusPath.exists()) {
@ -1127,6 +1185,13 @@ void TDLibWrapper::initializeOpenWith()
} }
} }
void TDLibWrapper::removeOpenWith()
{
LOG("Remove open-with");
QFile::remove(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/harbour-fernschreiber-open-url.desktop");
QProcess::startDetached("update-desktop-database " + QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
}
const TDLibWrapper::Group *TDLibWrapper::updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups) const TDLibWrapper::Group *TDLibWrapper::updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups)
{ {
Group* group = groups->value(groupId); Group* group = groups->value(groupId);

View file

@ -25,12 +25,13 @@
#include "dbusadaptor.h" #include "dbusadaptor.h"
#include "dbusinterface.h" #include "dbusinterface.h"
#include "emojisearchworker.h" #include "emojisearchworker.h"
#include "appsettings.h"
class TDLibWrapper : public QObject class TDLibWrapper : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit TDLibWrapper(QObject *parent = nullptr); explicit TDLibWrapper(AppSettings *appSettings, QObject *parent = nullptr);
~TDLibWrapper(); ~TDLibWrapper();
enum AuthorizationState { enum AuthorizationState {
@ -153,9 +154,12 @@ public:
Q_INVOKABLE void getPollVoters(const QString &chatId, const qlonglong &messageId, const int &optionId, const int &limit, const int &offset, const QString &extra); Q_INVOKABLE void getPollVoters(const QString &chatId, const qlonglong &messageId, const int &optionId, const int &limit, const int &offset, const QString &extra);
Q_INVOKABLE void searchPublicChat(const QString &userName); Q_INVOKABLE void searchPublicChat(const QString &userName);
Q_INVOKABLE void joinChatByInviteLink(const QString &inviteLink); Q_INVOKABLE void joinChatByInviteLink(const QString &inviteLink);
Q_INVOKABLE void getDeepLinkInfo(const QString &link);
// Others (candidates for extraction ;)) // Others (candidates for extraction ;))
Q_INVOKABLE void searchEmoji(const QString &queryString); Q_INVOKABLE void searchEmoji(const QString &queryString);
Q_INVOKABLE void initializeOpenWith();
Q_INVOKABLE void removeOpenWith();
public: public:
const Group* getGroup(qlonglong groupId) const; const Group* getGroup(qlonglong groupId) const;
@ -228,16 +232,17 @@ public slots:
void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation);
void handleStickerSets(const QVariantList &stickerSets); void handleStickerSets(const QVariantList &stickerSets);
void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList); void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList);
void handleOpenWithChanged();
private: private:
void setInitialParameters(); void setInitialParameters();
void setEncryptionKey(); void setEncryptionKey();
void setLogVerbosityLevel(); void setLogVerbosityLevel();
void initializeOpenWith();
const Group *updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups); const Group *updateGroup(qlonglong groupId, const QVariantMap &groupInfo, QHash<qlonglong,Group*> *groups);
private: private:
void *tdLibClient; void *tdLibClient;
AppSettings *appSettings;
TDLibReceiver *tdLibReceiver; TDLibReceiver *tdLibReceiver;
DBusInterface *dbusInterface; DBusInterface *dbusInterface;
QString version; QString version;

View file

@ -1062,6 +1062,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Nicht-grafische Rückmeldungen (Klänge, Vibration) bei Hinweisen nutzen</translation> <translation>Nicht-grafische Rückmeldungen (Klänge, Vibration) bei Hinweisen nutzen</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation>Integration im Öffnen-Mit-Menü</translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation>Fernschreiber ins Öffnen-Mit-Menü von Sailfish OS integrieren</translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1056,6 +1056,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Usa comentarios no gráficos (sonido, vibración) para las notificaciones</translation> <translation>Usa comentarios no gráficos (sonido, vibración) para las notificaciones</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1063,6 +1063,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Käytä ei-graafista palautetta (ääni, värinä) ilmoituksille</translation> <translation>Käytä ei-graafista palautetta (ääni, värinä) ilmoituksille</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1056,6 +1056,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1062,6 +1062,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Usa feedback non visuale come suoni e/o vibrazione per le notifiche</translation> <translation>Usa feedback non visuale come suoni e/o vibrazione per le notifiche</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1068,6 +1068,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1068,6 +1068,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Сопровождать уведомления звуками и вибрацией.</translation> <translation>Сопровождать уведомления звуками и вибрацией.</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1062,6 +1062,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>Använd icke-grafisk återkoppling (ljud, vibration) för avisering</translation> <translation>Använd icke-grafisk återkoppling (ljud, vibration) för avisering</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1056,6 +1056,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation>使</translation> <translation>使</translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>

View file

@ -1056,6 +1056,14 @@
<source>Use non-graphical feedback (sound, vibration) for notifications</source> <source>Use non-graphical feedback (sound, vibration) for notifications</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Open-with menu integration</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Integrate Fernschreiber into open-with menu of Sailfish OS</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>StickerPicker</name> <name>StickerPicker</name>