From 51c24d386f65a270ef25652a43341aa02e40b72d Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Mon, 21 Feb 2022 16:04:39 +0300
Subject: [PATCH 1/6] [sailfish-browser] Add useragents.json with a list of
predefined user agent overrides. Contributes to JB#31240
For Chrome, Firefox, Safari and Edge two versions are defined: the latest
and functionally close to gecko esr78. Each version contains user agents
for desktop and mobile modes.
---
data/useragents.json | 68 ++++++++++++++++++++++++++++++++++++++++++++
sailfish-browser.pro | 4 ++-
2 files changed, 71 insertions(+), 1 deletion(-)
create mode 100644 data/useragents.json
diff --git a/data/useragents.json b/data/useragents.json
new file mode 100644
index 00000000000..11403c89351
--- /dev/null
+++ b/data/useragents.json
@@ -0,0 +1,68 @@
+[
+ {
+ "key": "chlast",
+ "name": "Google Chrome 96",
+ "mobileUA": "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36",
+ "desktopUA": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
+ },
+ {
+ "key": "ch",
+ "name": "Google Chrome 91",
+ "mobileUA": "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Mobile Safari/537.36",
+ "desktopUA": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"
+ },
+ {
+ "key": "fflast",
+ "name": "Mozilla Firefox 96",
+ "mobileUA": "Mozilla/5.0 (Android 8.1.0; Mobile; rv:96.0) Gecko/96.0 Firefox/96.0",
+ "desktopUA": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0"
+ },
+ {
+ "key": "ff",
+ "name": "Mozilla Firefox 78",
+ "mobileUA": "Mozilla/5.0 (Android 8.1.0; Mobile; rv:78.0) Gecko/78.0 Firefox/78.0",
+ "desktopUA": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
+ },
+ {
+ "key": "sflast",
+ "name": "Apple Safari 15",
+ "mobileUA": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
+ "desktopUA": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_0_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15"
+ },
+ {
+ "key": "sf",
+ "name": "Apple Safari 14",
+ "mobileUA": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1",
+ "desktopUA": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15"
+ },
+ {
+ "key": "edgelast",
+ "name": "Microsoft Edge 97",
+ "mobileUA": "Mozilla/5.0 (Linux; Android 10; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Mobile Safari/537.36 Edg/97.0.1072.69",
+ "desktopUA": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 Edg/97.0.1072.69"
+ },
+ {
+ "key": "edge",
+ "name": "Microsoft Edge 91",
+ "mobileUA": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Mobile Safari/537.36 Edg/91.0.864.71",
+ "desktopUA": "Mozilla/5.0 (X11; Linux x86_32) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.37"
+ },
+ {
+ "key": "ie11",
+ "name": "Microsoft Internet Explorer 11",
+ "mobileUA": "Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko",
+ "desktopUA": "Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko"
+ },
+ {
+ "key": "ie8",
+ "name": "Microsoft Internet Explorer 8",
+ "mobileUA": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)",
+ "desktopUA": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)"
+ },
+ {
+ "key": "ie6",
+ "name": "Microsoft Internet Explorer 6",
+ "mobileUA": "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",
+ "desktopUA": "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"
+ }
+]
diff --git a/sailfish-browser.pro b/sailfish-browser.pro
index 37e726a084a..ef9b550ea27 100644
--- a/sailfish-browser.pro
+++ b/sailfish-browser.pro
@@ -21,7 +21,9 @@ oneshots.files = oneshot.d/browser-cleanup-startup-cache \
oneshots.path = /usr/lib/oneshot.d
data.files = data/prefs.js \
- data/ua-update.json.in
+ data/ua-update.json.in \
+ data/useragents.json
+
data.path = /usr/share/sailfish-browser/data
INSTALLS += desktop dbus_service chrome_scripts oneshots data
From 9876768ebfb3a4f1593bfb587b38b91276bb3c64 Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Thu, 17 Feb 2022 21:15:52 +0300
Subject: [PATCH 2/6] [sailfish-browser] Add a table and interfaces to store
user agent overrides in the database. Contributes to JB#31240
---
apps/storage/dbmanager.cpp | 25 +++++++++++++++++++
apps/storage/dbmanager.h | 5 ++++
apps/storage/dbworker.cpp | 50 ++++++++++++++++++++++++++++++++++++++
apps/storage/dbworker.h | 5 ++++
4 files changed, 85 insertions(+)
diff --git a/apps/storage/dbmanager.cpp b/apps/storage/dbmanager.cpp
index 3cb6a21c53c..768da04229c 100644
--- a/apps/storage/dbmanager.cpp
+++ b/apps/storage/dbmanager.cpp
@@ -187,3 +187,28 @@ void DBManager::deleteSetting(const QString &name)
Q_ARG(QString, name));
}
}
+
+void DBManager::setUserAgentOverride(const QString &host, const bool isKey, const QString &userAgent)
+{
+ QMetaObject::invokeMethod(worker, "setUserAgentOverride", Qt::QueuedConnection,
+ Q_ARG(QString, host), Q_ARG(bool, isKey), Q_ARG(QString, userAgent));
+}
+
+void DBManager::unsetUserAgentOverride(const QString &host)
+{
+ QMetaObject::invokeMethod(worker, "unsetUserAgentOverride", Qt::QueuedConnection,
+ Q_ARG(QString, host));
+}
+
+void DBManager::clearUserAgentOverrides()
+{
+ QMetaObject::invokeMethod(worker, "clearUserAgentOverrides", Qt::QueuedConnection);
+}
+
+QVariantMap DBManager::getUserAgentOverrides() const
+{
+ QVariantMap userAgentOverrides;
+ QMetaObject::invokeMethod(worker, "getUserAgentOverrides", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QVariantMap, userAgentOverrides));
+ return userAgentOverrides;
+}
diff --git a/apps/storage/dbmanager.h b/apps/storage/dbmanager.h
index 087e898844e..9a476c5c9c1 100644
--- a/apps/storage/dbmanager.h
+++ b/apps/storage/dbmanager.h
@@ -50,6 +50,11 @@ class DBManager : public QObject
QString getSetting(const QString &name);
void deleteSetting(const QString &name);
+ void setUserAgentOverride(const QString &host, const bool isKey, const QString &userAgent);
+ void unsetUserAgentOverride(const QString &host);
+ void clearUserAgentOverrides();
+ QVariantMap getUserAgentOverrides() const;
+
int getMaxTabId();
signals:
diff --git a/apps/storage/dbworker.cpp b/apps/storage/dbworker.cpp
index 5acb75b630d..921a44bf3ed 100644
--- a/apps/storage/dbworker.cpp
+++ b/apps/storage/dbworker.cpp
@@ -67,6 +67,13 @@ static const char * const create_table_settings =
"value TEXT\n"
");\n";
+static const char * const create_table_user_agent_overrides =
+ "CREATE TABLE user_agent_overrides (\n"
+ " host TEXT NOT NULL UNIQUE PRIMARY KEY,\n"
+ " is_key INTEGER NOT NULL CHECK(is_key IN (0,1)),\n"
+ " user_agent TEXT\n"
+ ") WITHOUT ROWID\n";
+
static const char * const set_user_version =
"PRAGMA user_version=" STR(DB_USER_VERSION) ";\n";
@@ -76,6 +83,7 @@ static const char *db_schema[] = {
create_table_link,
create_table_browser_history,
create_table_settings,
+ create_table_user_agent_overrides,
set_user_version
};
static int db_schema_count = sizeof(db_schema) / sizeof(*db_schema);
@@ -813,3 +821,45 @@ void DBWorker::deleteSetting(const QString &name)
query.bindValue(0, name);
execute(query);
}
+
+void DBWorker::setUserAgentOverride(const QString &host, const bool isKey, const QString &userAgent)
+{
+ QSqlQuery query = prepare("INSERT INTO user_agent_overrides "
+ "(host, is_key, user_agent) "
+ "VALUES (?, ?, ?) "
+ "ON CONFLICT(host) DO UPDATE SET "
+ "is_key=excluded.is_key, "
+ "user_agent=excluded.user_agent;");
+
+ query.bindValue(0, host);
+ query.bindValue(1, isKey);
+ query.bindValue(2, userAgent);
+ execute(query);
+}
+
+void DBWorker::unsetUserAgentOverride(const QString &host)
+{
+ QSqlQuery query = prepare("DELETE FROM user_agent_overrides WHERE host = ?");
+ query.bindValue(0, host);
+ execute(query);
+}
+
+void DBWorker::clearUserAgentOverrides()
+{
+ QSqlQuery query = prepare("DELETE FROM user_agent_overrides");
+ execute(query);
+}
+
+QVariantMap DBWorker::getUserAgentOverrides()
+{
+ QSqlQuery query = prepare("SELECT host, is_key, user_agent FROM user_agent_overrides;");
+ QVariantMap userAgentOverrides;
+ if (execute(query)) {
+ while (query.next()) {
+ userAgentOverrides.insert(query.value(0).toString(),
+ QVariantList({query.value(1).toBool(),
+ query.value(2).toString()}));
+ }
+ }
+ return userAgentOverrides;
+}
diff --git a/apps/storage/dbworker.h b/apps/storage/dbworker.h
index 3afa37d5e75..05acc174ce7 100644
--- a/apps/storage/dbworker.h
+++ b/apps/storage/dbworker.h
@@ -59,6 +59,11 @@ public slots:
SettingsMap getSettings();
void deleteSetting(const QString &name);
+ void setUserAgentOverride(const QString &host, const bool isKey, const QString &userAgent);
+ void unsetUserAgentOverride(const QString &host);
+ void clearUserAgentOverrides();
+ QVariantMap getUserAgentOverrides();
+
signals:
void tabsAvailable(QList tabs);
void thumbPathChanged(int tabId, const QString &path);
From a12fa8453e0f933fd6ccd0c964642619c80e55c4 Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Mon, 21 Feb 2022 16:07:24 +0300
Subject: [PATCH 3/6] [sailfish-browser] Add user agent override management
models. Contributes to JB#31240
---
apps/browser/main.cpp | 4 +
apps/core/browser.cpp | 3 +
apps/core/core.pri | 6 +
apps/core/useragentfiltermodel.cpp | 60 +++++++++
apps/core/useragentfiltermodel.h | 38 ++++++
apps/core/useragentmanager.cpp | 141 +++++++++++++++++++++
apps/core/useragentmanager.h | 41 +++++++
apps/core/useragentmodel.cpp | 189 +++++++++++++++++++++++++++++
apps/core/useragentmodel.h | 81 +++++++++++++
9 files changed, 563 insertions(+)
create mode 100644 apps/core/useragentfiltermodel.cpp
create mode 100644 apps/core/useragentfiltermodel.h
create mode 100644 apps/core/useragentmanager.cpp
create mode 100644 apps/core/useragentmanager.h
create mode 100644 apps/core/useragentmodel.cpp
create mode 100644 apps/core/useragentmodel.h
diff --git a/apps/browser/main.cpp b/apps/browser/main.cpp
index 8cab91427a2..2d8ba7dd1de 100644
--- a/apps/browser/main.cpp
+++ b/apps/browser/main.cpp
@@ -40,6 +40,8 @@
#include "secureaction.h"
#include "faviconmanager.h"
#include "bookmarkmanager.h"
+#include "useragentmodel.h"
+#include "useragentfiltermodel.h"
#ifdef HAS_BOOSTER
#include
@@ -153,6 +155,8 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
qmlRegisterType(uri, 1, 0, "LoginModel");
qmlRegisterType(uri, 1, 0, "LoginFilterModel");
qmlRegisterSingletonType(uri, 1, 0, "BookmarkManager", bookmarkmanager_factory);
+ qmlRegisterType(uri, 1, 0, "UserAgentModel");
+ qmlRegisterType(uri, 1, 0, "UserAgentFilterModel");
}
qmlRegisterSingletonType(uri, 1, 0, "FaviconManager", faviconmanager_factory);
qmlRegisterUncreatableType(uri, 1, 0, "DownloadStatus", "");
diff --git a/apps/core/browser.cpp b/apps/core/browser.cpp
index 083918b01d2..9d1691b54c2 100644
--- a/apps/core/browser.cpp
+++ b/apps/core/browser.cpp
@@ -14,6 +14,7 @@
#include "browser_p.h"
#include "declarativewebutils.h"
#include "downloadmanager.h"
+#include "useragentmanager.h"
#include "settingmanager.h"
#include "browserapp.h"
@@ -83,10 +84,12 @@ Browser::Browser(QQuickView *view, QObject *parent)
DeclarativeWebUtils *utils = DeclarativeWebUtils::instance();
DownloadManager *downloadManager = DownloadManager::instance();
+ UserAgentManager *userAgentManager = UserAgentManager::instance();
d->view->rootContext()->setContextProperty("WebUtils", utils);
d->view->rootContext()->setContextProperty("Settings", SettingManager::instance());
d->view->rootContext()->setContextProperty("DownloadManager", downloadManager);
+ d->view->rootContext()->setContextProperty("UserAgentManager", userAgentManager);
QString mainQml = BrowserApp::captivePortal() ? "captiveportal.qml" : "browser.qml";
diff --git a/apps/core/core.pri b/apps/core/core.pri
index 9f6e7d35d8a..19525752077 100644
--- a/apps/core/core.pri
+++ b/apps/core/core.pri
@@ -20,6 +20,9 @@ SOURCES += \
$$PWD/logging.cpp \
$$PWD/secureaction.cpp \
$$PWD/settingmanager.cpp \
+ $$PWD/useragentmanager.cpp \
+ $$PWD/useragentmodel.cpp \
+ $$PWD/useragentfiltermodel.cpp \
$$PWD/webpagequeue.cpp \
$$PWD/webpages.cpp
@@ -40,5 +43,8 @@ HEADERS += \
$$PWD/logging.h \
$$PWD/secureaction.h \
$$PWD/settingmanager.h \
+ $$PWD/useragentmanager.h \
+ $$PWD/useragentmodel.h \
+ $$PWD/useragentfiltermodel.h \
$$PWD/webpagequeue.h \
$$PWD/webpages.h
diff --git a/apps/core/useragentfiltermodel.cpp b/apps/core/useragentfiltermodel.cpp
new file mode 100644
index 00000000000..e088e31703f
--- /dev/null
+++ b/apps/core/useragentfiltermodel.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "useragentfiltermodel.h"
+#include "useragentmodel.h"
+
+UserAgentFilterModel::UserAgentFilterModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+ setDynamicSortFilter(true);
+}
+
+int UserAgentFilterModel::getIndex(int currentIndex)
+{
+ QModelIndex proxyIndex = index(currentIndex, 0);
+ QModelIndex sourceIndex = mapToSource(proxyIndex);
+ return sourceIndex.row();
+}
+
+bool UserAgentFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+
+ if (sourceModel()->data(index, UserAgentModel::HostRole).toString().trimmed().contains(m_search, Qt::CaseInsensitive)) {
+ return true;
+ }
+ return false;
+}
+
+void UserAgentFilterModel::setSourceModel(QAbstractItemModel *sourceModel)
+{
+ if (sourceModel) {
+ beginResetModel();
+ QSortFilterProxyModel::setSourceModel(sourceModel);
+ endResetModel();
+ }
+}
+
+QString UserAgentFilterModel::search() const
+{
+ return m_search;
+}
+
+void UserAgentFilterModel::setSearch(const QString &search)
+{
+ if (m_search == search) {
+ return;
+ }
+
+ m_search = search;
+ invalidateFilter();
+ emit searchChanged(m_search);
+}
diff --git a/apps/core/useragentfiltermodel.h b/apps/core/useragentfiltermodel.h
new file mode 100644
index 00000000000..2dd551e9281
--- /dev/null
+++ b/apps/core/useragentfiltermodel.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef USERAGENTFILTERMODEL_H
+#define USERAGENTFILTERMODEL_H
+
+#include
+
+class UserAgentFilterModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QString search READ search WRITE setSearch NOTIFY searchChanged)
+public:
+ UserAgentFilterModel(QObject *parent = nullptr);
+
+ Q_INVOKABLE int getIndex(int currentIndex);
+
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+ void setSourceModel(QAbstractItemModel *sourceModel) override;
+
+ QString search() const;
+ void setSearch(const QString &search);
+
+signals:
+ void searchChanged(QString search);
+
+private:
+ QString m_search;
+};
+
+#endif // USERAGENTFILTERMODEL_H
diff --git a/apps/core/useragentmanager.cpp b/apps/core/useragentmanager.cpp
new file mode 100644
index 00000000000..a0c0c087f69
--- /dev/null
+++ b/apps/core/useragentmanager.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "useragentmanager.h"
+#include
+#include
+#include
+#include
+#include
+#include "qmozcontext.h"
+#include "dbmanager.h"
+#include "declarativewebcontainer.h"
+#include "faviconmanager.h"
+
+const auto USER_AGENTS_CONFIG = QStringLiteral("/usr/share/sailfish-browser/data/useragents.json");
+
+static UserAgentManager *gSingleton = nullptr;
+
+UserAgentManager::UserAgentManager(QObject *parent)
+ : QObject(parent)
+{
+ initialize();
+}
+
+UserAgentManager::~UserAgentManager()
+{
+ gSingleton = nullptr;
+}
+
+void UserAgentManager::initialize()
+{
+ QScopedPointer file(new QFile(USER_AGENTS_CONFIG));
+
+ if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return;
+ }
+
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(file->readAll(), &error);
+
+ if (doc.isNull()) {
+ return;
+ }
+
+ if (!doc.isArray()) {
+ return;
+ }
+
+ QJsonArray array = doc.array();
+
+ m_browserList.clear();
+ for (const QJsonValue &value : array) {
+ if (value.isObject()) {
+ QJsonObject obj = value.toObject();
+ QVariantMap val;
+ val["key"] = obj.value("key").toString();
+ val["name"] = obj.value("name").toString();
+ m_browserList.push_back(val);
+ }
+ }
+
+ QVariant conf = doc.toVariant();
+ QVariantMap overrides = getUserAgentOverrides();
+
+ QMozContext *mozContext = QMozContext::instance();
+ if (mozContext->isInitialized()) {
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentlistchanged"), conf);
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentoverrideschanged"), overrides);
+ } else {
+ QObject *context = new QObject(this);
+ connect(mozContext, &QMozContext::initialized, context, [conf, overrides, context]() {
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentlistchanged"), conf);
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentoverrideschanged"), overrides);
+ context->deleteLater();
+ });
+ }
+}
+
+QVariantMap UserAgentManager::getUserAgentOverrides() const
+{
+ return DBManager::instance()->getUserAgentOverrides();
+}
+
+void UserAgentManager::setUserAgentOverride(const QString &host, const QString &userAgent, const bool isKey)
+{
+ DBManager::instance()->setUserAgentOverride(host, isKey, userAgent);
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentoverrideschanged"),
+ QVariantMap{
+ std::pair(
+ host,
+ QVariantList{isKey, userAgent}
+ )
+ });
+
+ DeclarativeWebContainer *webContainer = DeclarativeWebContainer::instance();
+ if (webContainer->webPage() && QUrl(webContainer->url()).host() == host) {
+ FaviconManager::instance()->grabIcon("userAgents", webContainer->webPage(), QSize(64, 64));
+ }
+}
+
+void UserAgentManager::unsetUserAgentOverride(const QString &host) {
+ DBManager::instance()->unsetUserAgentOverride(host);
+ qWarning() << "#### UserAgentManager::setUserAgentOverride";
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentoverrideschanged"),
+ QVariantMap{
+ std::pair(
+ host,
+ QVariantList{true, ""}
+ )
+ });
+ FaviconManager::instance()->remove("userAgents", "https://" + host);
+ FaviconManager::instance()->remove("userAgents", "http://" + host);
+}
+
+void UserAgentManager::clearUserAgentOverrides()
+{
+ qWarning() << "UserAgentManager::clearUserAgentOverrides";
+ DBManager::instance()->clearUserAgentOverrides();
+ SailfishOS::WebEngine::instance()->notifyObservers(QLatin1String("useragentoverrideschanged"),
+ QVariantMap{});
+}
+
+QVariantList UserAgentManager::getBrowserList() const
+{
+ return m_browserList;
+}
+
+UserAgentManager *UserAgentManager::instance()
+{
+ if (!gSingleton) {
+ gSingleton = new UserAgentManager();
+ }
+ return gSingleton;
+}
diff --git a/apps/core/useragentmanager.h b/apps/core/useragentmanager.h
new file mode 100644
index 00000000000..a38d0cf8d99
--- /dev/null
+++ b/apps/core/useragentmanager.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef USERAGENTMANAGER_H
+#define USERAGENTMANAGER_H
+
+#include
+#include
+#include
+#include
+
+class UserAgentManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ static UserAgentManager *instance();
+ QVariantMap getUserAgentOverrides() const;
+ void setUserAgentOverride(const QString &host, const QString &userAgent, const bool isKey);
+ void unsetUserAgentOverride(const QString &host);
+ Q_INVOKABLE void clearUserAgentOverrides();
+
+public slots:
+ QVariantList getBrowserList() const;
+
+private:
+ explicit UserAgentManager(QObject *parent = nullptr);
+ ~UserAgentManager();
+
+ void initialize();
+ QVariantList m_browserList;
+};
+
+#endif
diff --git a/apps/core/useragentmodel.cpp b/apps/core/useragentmodel.cpp
new file mode 100644
index 00000000000..e7bc26847fa
--- /dev/null
+++ b/apps/core/useragentmodel.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "useragentmodel.h"
+#include "useragentmanager.h"
+#include "faviconmanager.h"
+
+UserAgent::UserAgent(const QString &host, const bool isKey, const QString &userAgent)
+ : m_host(host)
+ , m_isKey(isKey)
+ , m_userAgent(userAgent)
+{
+}
+
+QString UserAgent::host() const
+{
+ return m_host;
+}
+
+bool UserAgent::isKey() const
+{
+ return m_isKey;
+}
+
+void UserAgent::setIsKey(bool isKey)
+{
+ m_isKey = isKey;
+}
+
+QString UserAgent::userAgent() const
+{
+ return m_userAgent;
+}
+
+void UserAgent::setUserAgent(const QString &userAgent)
+{
+ m_userAgent = userAgent;
+}
+
+UserAgentModel::UserAgentModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ QVariantMap overrides = UserAgentManager::instance()->getUserAgentOverrides();
+
+ beginResetModel();
+ for (QVariantMap::const_iterator it = overrides.begin(); it != overrides.end(); ++it) {
+ m_userAgentList.append(UserAgent(it.key(), it.value().toList().at(0).toBool(), it.value().toList().at(1).toString()));
+ m_index.insert(it.key(), m_userAgentList.size() - 1);
+ }
+ endResetModel();
+}
+
+int UserAgentModel::findHostIndex(const QString &host) const
+{
+ QHash::const_iterator it = m_index.find(host);
+ return (it != m_index.end()) ? it.value() : -1;
+}
+
+QVariantMap UserAgentModel::currentHostUserAgent() const
+{
+ int id = findHostIndex(m_currentHost);
+ return (id >= 0) ? QVariantMap{{"isKey", m_userAgentList[id].isKey()},
+ {"userAgent", m_userAgentList[id].userAgent()}} :
+ QVariantMap{{"isKey", true},
+ {"userAgent", ""}};
+}
+
+void UserAgentModel::setUserAgentOverride(const QString &host, const QString &userAgent, const bool isKey)
+{
+ UserAgentManager::instance()->setUserAgentOverride(host, userAgent, isKey);
+
+ int id = findHostIndex(host);
+ if (id >= 0) {
+ UserAgent &ua = m_userAgentList[id];
+
+ QVector roles;
+ if (ua.isKey() != isKey) {
+ roles << IsKeyRole;
+ ua.setIsKey(isKey);
+ }
+ if (ua.userAgent() != userAgent) {
+ roles << UserAgentRole;
+ ua.setUserAgent(userAgent);
+ }
+ if (roles.count() > 0) {
+ emit dataChanged(index(id), index(id), roles);
+ if (host == m_currentHost) {
+ emit currentHostUserAgentChanged();
+ }
+ }
+ } else {
+ int count = m_userAgentList.count();
+ beginInsertRows(QModelIndex(), count, count);
+ m_userAgentList.append(UserAgent{host, isKey, userAgent});
+ m_index.insert(host, m_userAgentList.size() - 1);
+ endInsertRows();
+
+ emit countChanged();
+
+ if (host == m_currentHost) {
+ emit currentHostUserAgentChanged();
+ }
+ }
+}
+
+void UserAgentModel::unsetUserAgentOverride(const QString &host)
+{
+ UserAgentManager::instance()->unsetUserAgentOverride(host);
+
+ int id = findHostIndex(host);
+ if (id >= 0) {
+ beginRemoveRows(QModelIndex(), id, id);
+ m_userAgentList.removeAt(id);
+ endRemoveRows();
+
+ m_index.clear();
+ for (int i = 0; i < m_userAgentList.size(); ++i) {
+ m_index.insert(m_userAgentList[i].host(), i);
+ }
+
+ emit countChanged();
+
+ if (host == m_currentHost) {
+ emit currentHostUserAgentChanged();
+ }
+ }
+}
+
+QVariant UserAgentModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() < 0 || index.row() >= m_userAgentList.count())
+ return QVariant();
+
+ const UserAgent &ua = m_userAgentList.at(index.row());
+
+ switch (role) {
+ case HostRole:
+ return ua.host();
+ case IsKeyRole:
+ return ua.isKey();
+ case UserAgentRole:
+ return ua.userAgent();
+ case FavIconRole: {
+ QString favIcon = FaviconManager::instance()->get("userAgents", "https://" + ua.host());
+ if (favIcon.isEmpty()) favIcon = FaviconManager::instance()->get("userAgents", "http://" + ua.host());
+ return favIcon;
+ }
+ default:
+ return QVariant();
+ }
+}
+
+int UserAgentModel::rowCount(const QModelIndex&) const
+{
+ return m_userAgentList.count();
+}
+
+QHash UserAgentModel::roleNames() const
+{
+ QHash roles;
+ roles[HostRole] = "host";
+ roles[IsKeyRole] = "isKey";
+ roles[UserAgentRole] = "userAgent";
+ roles[FavIconRole] = "favicon";
+ return roles;
+}
+
+QString UserAgentModel::currentHost() const
+{
+ return m_currentHost;
+}
+
+void UserAgentModel::setCurrentHost(const QString &host)
+{
+ if (m_currentHost == host) {
+ return;
+ }
+
+ m_currentHost = host;
+ emit currentHostChanged();
+ emit currentHostUserAgentChanged();
+}
diff --git a/apps/core/useragentmodel.h b/apps/core/useragentmodel.h
new file mode 100644
index 00000000000..aabbdebb8f2
--- /dev/null
+++ b/apps/core/useragentmodel.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef USERAGENTMODEL_H
+#define USERAGENTMODEL_H
+
+#include
+#include
+#include
+
+class UserAgent
+{
+public:
+ UserAgent(const QString &host,
+ const bool isKey,
+ const QString &userAgent);
+
+ QString host() const;
+ bool isKey() const;
+ void setIsKey(bool isKey);
+ QString userAgent() const;
+ void setUserAgent(const QString &userAgent);
+
+private:
+ QString m_host;
+ bool m_isKey;
+ QString m_userAgent;
+};
+
+class UserAgentModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
+ Q_PROPERTY(QVariantMap currentHostUserAgent READ currentHostUserAgent NOTIFY currentHostUserAgentChanged FINAL)
+ Q_PROPERTY(QString currentHost READ currentHost WRITE setCurrentHost NOTIFY currentHostChanged)
+
+public:
+ enum Roles {
+ HostRole = Qt::UserRole,
+ IsKeyRole,
+ UserAgentRole,
+ FavIconRole
+ };
+
+ UserAgentModel(QObject *parent = nullptr);
+
+ Q_INVOKABLE void setUserAgentOverride(const QString &host, const QString &userAgent, const bool isKey);
+ Q_INVOKABLE void unsetUserAgentOverride(const QString &host);
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash roleNames() const override;
+
+ QString currentHost() const;
+ void setCurrentHost(const QString &host);
+
+signals:
+ void countChanged();
+ void currentHostUserAgentChanged();
+ void currentHostChanged();
+
+private:
+ QVariantMap currentHostUserAgent() const;
+ int findHostIndex(const QString &host) const;
+
+private:
+ //
+ QHash m_index;
+ QList m_userAgentList;
+ QString m_currentHost;
+};
+
+#endif // USERAGENTMODEL_H
From 2b31b2d54e9485f3bd54f3f1a42cc7d951d82f04 Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Mon, 21 Feb 2022 16:34:00 +0300
Subject: [PATCH 4/6] [sailfish-browser] Provide an option in site info panel
to set user agent override. Contributes to JB#31240
---
apps/browser/qml/pages/SiteUserAgentPage.qml | 104 ++++++++++++++++++
.../qml/pages/components/CertificateInfo.qml | 49 ++++++++-
apps/browser/qml/pages/useragenthelper.js | 30 +++++
apps/core/declarativewebutils.cpp | 5 +
apps/core/declarativewebutils.h | 1 +
5 files changed, 188 insertions(+), 1 deletion(-)
create mode 100644 apps/browser/qml/pages/SiteUserAgentPage.qml
create mode 100755 apps/browser/qml/pages/useragenthelper.js
diff --git a/apps/browser/qml/pages/SiteUserAgentPage.qml b/apps/browser/qml/pages/SiteUserAgentPage.qml
new file mode 100644
index 00000000000..0c11606a53b
--- /dev/null
+++ b/apps/browser/qml/pages/SiteUserAgentPage.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC.
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import QtQuick 2.1
+import Sailfish.Silica 1.0
+import Sailfish.Browser 1.0
+import "useragenthelper.js" as UserAgentHelper
+
+Page {
+ id: page
+
+ property UserAgentModel userAgentModel: UserAgentModel {
+ currentHost: WebUtils.host(webView.url)
+ }
+ property string hostname: userAgentModel.currentHost
+ property bool isKey: userAgentModel.currentHostUserAgent.isKey
+ property string userAgent: userAgentModel.currentHostUserAgent.userAgent
+ property WebPage webPage: null
+
+ SilicaListView {
+ anchors.fill: parent
+ model: UserAgentHelper.model
+
+ header: PageHeader {
+ //% "User agent override"
+ title: qsTrId("sailfish_browser-he-user_agent_override")
+ description: page.hostname
+ }
+
+ delegate: BackgroundItem {
+ id: delegateItem
+
+ onClicked: {
+ if ("custom" in modelData) {
+ pageStack.animatorPush(customUserAgentDialog,
+ {
+ userAgentModel: userAgentModel,
+ userAgent: page.isKey ? "" : page.userAgent,
+ hostname: page.hostname
+ })
+ } else {
+ userAgentModel.setUserAgentOverride(page.hostname, modelData.key, true)
+ pageStack.pop()
+ }
+ }
+
+ Label {
+ width: parent.width
+ leftPadding: Theme.horizontalPageMargin
+ rightPadding: Theme.horizontalPageMargin
+ text: modelData.name + (!page.isKey && "custom" in modelData ? ": " + userAgent : "")
+ elide: Text.ElideRight
+ highlighted: page.isKey ? modelData.key === page.userAgent : "custom" in modelData
+ }
+ }
+
+ VerticalScrollDecorator {}
+ }
+
+ Component {
+ id: customUserAgentDialog
+
+ Dialog {
+ id: dialog
+
+ property UserAgentModel userAgentModel
+ property string userAgent
+ property string hostname
+
+ canAccept: textField.text !== ""
+ onAccepted: {
+ userAgentModel.setUserAgentOverride(hostname, textField.text.trim(), false)
+ }
+
+ DialogHeader {
+ id: header
+ //: Accept button text for adding a home page adress
+ //% "OK"
+ acceptText: qsTrId("sailfish_browser-he-ok")
+ }
+
+ TextField {
+ id: textField
+
+ anchors.top: header.bottom
+ focus: true
+ text: userAgent
+ //% "User agent to use when loading %1."
+ description: qsTrId("sailfish_browser-he-user_agent_for_site").arg(hostname)
+ label: placeholderText
+ inputMethodHints: Qt.ImhNoPredictiveText
+ EnterKey.onClicked: dialog.accept()
+ }
+ }
+ }
+}
+
diff --git a/apps/browser/qml/pages/components/CertificateInfo.qml b/apps/browser/qml/pages/components/CertificateInfo.qml
index a9cee600100..846ace9f58a 100644
--- a/apps/browser/qml/pages/components/CertificateInfo.qml
+++ b/apps/browser/qml/pages/components/CertificateInfo.qml
@@ -13,6 +13,7 @@ import Sailfish.Browser 1.0
import Qt5Mozilla 1.0
import "." as Browser
import Sailfish.WebView.Controls 1.0
+import "../useragenthelper.js" as UserAgentHelper
SilicaFlickable {
id: root
@@ -33,6 +34,10 @@ SilicaFlickable {
})
}
+ function openSiteUseragentSettings() {
+ pageStack.push("../SiteUserAgentPage.qml")
+ }
+
onSecurityChanged: {
// Jump back to the top
contentY = originY
@@ -43,6 +48,11 @@ SilicaFlickable {
host: toolBarRow.url
}
+ UserAgentModel {
+ id: userAgentModel
+ currentHost: WebUtils.host(webView.url)
+ }
+
VerticalScrollDecorator {}
MouseArea {
@@ -116,7 +126,6 @@ SilicaFlickable {
onClicked: showCertDetail()
}
-
Loader {
height: Theme.fontSizeMedium + Theme.iconSizeMedium + Theme.paddingMedium
width: permissionIndicationModel.count === 0 ? implicitWidth : parent.width
@@ -124,6 +133,44 @@ SilicaFlickable {
sourceComponent: permissionIndicationModel.count === 0 ? permissionButtonComponent : permissionComponent
}
+ MouseArea {
+ id: userAgentArea
+
+ width: parent.width
+ height: userAgentColumn.height
+ onClicked: openSiteUseragentSettings()
+
+ Column {
+ id: userAgentColumn
+
+ width: parent.width
+ spacing: Theme.paddingMedium
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Label {
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ x: Theme.horizontalPageMargin
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.Wrap
+ color: Theme.highlightColor
+ //% "Current user agent"
+ text: qsTrId("sailfish_browser-sh-current_user_agent")
+ }
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ horizontalAlignment: Text.AlignHCenter
+ color: Theme.primaryColor
+ font.pixelSize: Theme.fontSizeSmall
+ textFormat: Text.PlainText
+ wrapMode: Text.Wrap
+ text: UserAgentHelper.getUserAgentString(userAgentModel.currentHostUserAgent.userAgent,
+ userAgentModel.currentHostUserAgent.isKey)
+ }
+ }
+ }
+
Component {
id: permissionButtonComponent
diff --git a/apps/browser/qml/pages/useragenthelper.js b/apps/browser/qml/pages/useragenthelper.js
new file mode 100755
index 00000000000..dfc84041da3
--- /dev/null
+++ b/apps/browser/qml/pages/useragenthelper.js
@@ -0,0 +1,30 @@
+var model = [].concat(
+ [{
+ key: "",
+ //: Identifier of the current browser
+ //% "Gecko-based browser (Default)"
+ name: qsTrId("sailfish_browser-la-browser_list_current_browser")
+ }],
+ UserAgentManager.getBrowserList(),
+ [{
+ custom: true,
+ //: A user-defined user agent
+ //% "Custom"
+ name: qsTrId("sailfish_browser-la-browser_list_custom")
+ }]
+ )
+
+function getUserAgentString(userAgent, isKey)
+{
+ if (!isKey) {
+ return userAgent
+ }
+
+ for (var i = 0; i < model.length; i++) {
+ if (i in model && model[i].key === userAgent) {
+ return model[i].name
+ }
+ }
+
+ return model[0].name
+}
diff --git a/apps/core/declarativewebutils.cpp b/apps/core/declarativewebutils.cpp
index 5f13b490708..2799d9b4c5c 100644
--- a/apps/core/declarativewebutils.cpp
+++ b/apps/core/declarativewebutils.cpp
@@ -202,6 +202,11 @@ QString DeclarativeWebUtils::displayableUrl(const QString &fullUrl) const
return !returnUrl.isEmpty() ? returnUrl : fullUrl;
}
+QString DeclarativeWebUtils::host(const QString &fullUrl) const
+{
+ return QUrl(fullUrl).host();
+}
+
QString DeclarativeWebUtils::pageName(const QString &fullUrl) const
{
QUrl url(fullUrl);
diff --git a/apps/core/declarativewebutils.h b/apps/core/declarativewebutils.h
index 8068f0fa9a6..5857944e45a 100644
--- a/apps/core/declarativewebutils.h
+++ b/apps/core/declarativewebutils.h
@@ -36,6 +36,7 @@ class DeclarativeWebUtils : public QObject
Q_INVOKABLE int getLightness(const QColor &color) const;
Q_INVOKABLE QString displayableUrl(const QString &fullUrl) const;
+ Q_INVOKABLE QString host(const QString &fullUrl) const;
Q_INVOKABLE QString pageName(const QString &fullUrl) const;
public slots:
From 44261b4f75d9ce46ab32d97803b3b816756a3652 Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Mon, 21 Feb 2022 16:34:36 +0300
Subject: [PATCH 5/6] [sailfish-browser] Add user agent override management
page. Contributes to JB#31240
---
apps/browser/qml/pages/SettingsPage.qml | 26 +++++
apps/browser/qml/pages/UserAgentPage.qml | 135 +++++++++++++++++++++++
2 files changed, 161 insertions(+)
create mode 100644 apps/browser/qml/pages/UserAgentPage.qml
diff --git a/apps/browser/qml/pages/SettingsPage.qml b/apps/browser/qml/pages/SettingsPage.qml
index b83f2f1098b..a33735d11f0 100644
--- a/apps/browser/qml/pages/SettingsPage.qml
+++ b/apps/browser/qml/pages/SettingsPage.qml
@@ -232,6 +232,32 @@ Page {
onClicked: pageStack.push("PermissionPage.qml")
}
+ BackgroundItem {
+ width: parent.width
+ contentHeight: Theme.itemSizeMedium
+ Row {
+ width: parent.width - 2*Theme.horizontalPageMargin
+ x: Theme.horizontalPageMargin
+ spacing: Theme.paddingMedium
+ anchors.verticalCenter: parent.verticalCenter
+
+ Icon {
+ id: userAgentsIcon
+ source: "image://theme/icon-m-browser-user-agents"
+ width: Theme.iconSizeMedium
+ height: Theme.iconSizeMedium
+ }
+ Label {
+ width: parent.width - parent.spacing - userAgentsIcon.width
+ //: The label for the button for accessing user agent overrides management
+ //% "User agent overrides"
+ text: qsTrId("settings_browser-la-user_agent_overrides")
+ anchors.verticalCenter: userAgentsIcon.verticalCenter
+ }
+ }
+ onClicked: pageStack.push("UserAgentPage.qml")
+ }
+
BackgroundItem {
width: parent.width
contentHeight: Theme.itemSizeMedium
diff --git a/apps/browser/qml/pages/UserAgentPage.qml b/apps/browser/qml/pages/UserAgentPage.qml
new file mode 100644
index 00000000000..5be442b445f
--- /dev/null
+++ b/apps/browser/qml/pages/UserAgentPage.qml
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (c) 2022 Open Mobile Platform LLC.
+**
+****************************************************************************/
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import QtQuick 2.5
+import Sailfish.Silica 1.0
+import Sailfish.Browser 1.0
+import "useragenthelper.js" as UserAgentHelper
+import "components"
+
+Page {
+ UserAgentFilterModel {
+ id: userAgentFilterModel
+ sourceModel: UserAgentModel {
+ id: userAgentModel
+ }
+ }
+
+ SilicaListView {
+ id: view
+
+ anchors.fill: parent
+ model: userAgentFilterModel
+ currentIndex: -1
+ header: Column {
+ width: parent.width
+ PageHeader {
+ //% "User agent overrides"
+ title: qsTrId("sailfish_browser-he-user_agent_overrides")
+ }
+ SearchField {
+ width: parent.width
+ //% "Search"
+ placeholderText: qsTrId("sailfish_browser-ph-usera_gent_override_search")
+ EnterKey.onClicked: focus = false
+ onTextChanged: userAgentFilterModel.search = text
+ inputMethodHints: Qt.ImhPreferLowercase | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
+ visible: userAgentModel.count > 0
+ }
+ }
+
+ delegate: ListItem {
+ id: listItem
+
+ width: parent.width
+ contentHeight: Theme.itemSizeMedium
+ ListView.onAdd: AddAnimation { target: listItem }
+ ListView.onRemove: animateRemoval()
+
+ function remove(host) {
+ remorseDelete(function() {
+ userAgentModel.unsetUserAgentOverride(host)
+ })
+ }
+
+ onClicked: openMenu()
+
+ Row {
+ width: parent.width - 2 * Theme.horizontalPageMargin
+ x: Theme.horizontalPageMargin
+ spacing: Theme.paddingMedium
+ anchors.verticalCenter: parent.verticalCenter
+
+ FavoriteIcon {
+ id: loginsIcon
+
+ anchors.verticalCenter: parent.verticalCenter
+ icon: model.favicon
+ sourceSize.width: Theme.iconSizeMedium
+ sourceSize.height: Theme.iconSizeMedium
+ width: Theme.iconSizeMedium
+ height: Theme.iconSizeMedium
+ }
+
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width - parent.spacing - loginsIcon.width
+ Label {
+ width: parent.width
+ text: Theme.highlightText(model.host,
+ userAgentFilterModel.search,
+ Theme.highlightColor)
+ textFormat: Text.StyledText
+ }
+
+ Label {
+ width: parent.width
+ text: UserAgentHelper.getUserAgentString(model.userAgent, model.isKey)
+ font.pixelSize: Theme.fontSizeExtraSmall
+ elide: Text.ElideRight
+ color: Theme.secondaryColor
+ }
+ }
+ }
+
+ menu: Component {
+ ContextMenu {
+ MenuItem {
+ //% "Edit"
+ text: qsTrId("sailfish_browser-me-user_agent_override_edit")
+ onClicked: {
+ userAgentModel.currentHost = model.host
+ pageStack.animatorPush("SiteUserAgentPage.qml",
+ {
+ userAgentModel: userAgentModel
+ })
+ }
+ }
+ MenuItem {
+ //% "Delete"
+ text: qsTrId("sailfish_browser-me-user_agent_override_delete")
+ onClicked: listItem.remove(host)
+ }
+ }
+ }
+ }
+
+ ViewPlaceholder {
+ //% "Your saved user agent overrides show up here"
+ text: qsTrId("sailfish_browser-la-user_agents_none")
+ enabled: userAgentModel.count === 0
+ }
+
+ VerticalScrollDecorator {
+ parent: view
+ flickable: view
+ }
+ }
+}
From 1e9b5edb5d81a34b067eaca11cb5e221650b2554 Mon Sep 17 00:00:00 2001
From: Pavel Tumakaev
Date: Mon, 21 Feb 2022 16:35:31 +0300
Subject: [PATCH 6/6] [sailfish-browser] Add an option to PrivacySettingsPage
to clear user agent overrides. Contributes to JB#31240
---
apps/browser/qml/pages/PrivacySettingsPage.qml | 10 ++++++++++
.../pages/components/PrivacySettingsConfirmDialog.qml | 11 +++++++++++
2 files changed, 21 insertions(+)
diff --git a/apps/browser/qml/pages/PrivacySettingsPage.qml b/apps/browser/qml/pages/PrivacySettingsPage.qml
index dabaafb59c0..595b181870c 100644
--- a/apps/browser/qml/pages/PrivacySettingsPage.qml
+++ b/apps/browser/qml/pages/PrivacySettingsPage.qml
@@ -123,6 +123,14 @@ Page {
checked: true
}
+ TextSwitch {
+ id: clearUserAgentOverrides
+
+ //% "User аgent overrides"
+ text: qsTrId("settings_browser-la-user_аgent_overrides")
+ checked: true
+ }
+
// Spacer between Button and switches
Item {
width: parent.width
@@ -140,6 +148,7 @@ Page {
|| clearCache.checked
|| clearBookmarks.checked
|| clearSitePermissions.checked
+ || clearUserAgentOverrides.checked
onClicked: {
var page = pageStack.push(Qt.resolvedUrl("components/PrivacySettingsConfirmDialog.qml"), {
@@ -149,6 +158,7 @@ Page {
cacheEnabled: clearCache.checked,
bookmarksEnabled: clearBookmarks.checked,
sitePermissionsEnabled: clearSitePermissions.checked,
+ userAgentOverridesEnabled: clearUserAgentOverrides.checked,
historyPeriod: historyErasingComboBox.currentItem.period,
acceptDestination: previousPage
})
diff --git a/apps/browser/qml/pages/components/PrivacySettingsConfirmDialog.qml b/apps/browser/qml/pages/components/PrivacySettingsConfirmDialog.qml
index 2cfe431cfd0..00f6cf0ef1a 100644
--- a/apps/browser/qml/pages/components/PrivacySettingsConfirmDialog.qml
+++ b/apps/browser/qml/pages/components/PrivacySettingsConfirmDialog.qml
@@ -20,6 +20,7 @@ Dialog {
property alias cacheEnabled: cacheItem.visible
property alias bookmarksEnabled: bookmarksItem.visible
property alias sitePermissionsEnabled: sitePermissionsItem.visible
+ property alias userAgentOverridesEnabled: userAgentOverridesItem.visible
property int historyPeriod
@@ -118,6 +119,13 @@ Dialog {
//% "Site permissions"
text: qsTrId("sailfish_browser-la-site_permissions");
}
+
+ BrowserDataItem {
+ id: userAgentOverridesItem
+
+ //% "User agent overrides"
+ text: qsTrId("sailfish_browser-la-user_agent_overrides");
+ }
}
}
@@ -140,6 +148,9 @@ Dialog {
if (sitePermissionsEnabled) {
Settings.clearSitePermissions()
}
+ if (userAgentOverridesEnabled) {
+ UserAgentManager.clearUserAgentOverrides()
+ }
}
Component.onCompleted: {