From faa613d6711e4c995895f19859bc5a51b24d6e17 Mon Sep 17 00:00:00 2001
From: zty199 <46324746+zty199@users.noreply.github.com>
Date: Mon, 19 Dec 2022 02:26:07 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20ISSUE=20#I62BVT=20=E6=B7=BB=E5=8A=A0?=
 =?UTF-8?q?=E7=BD=91=E9=A1=B5=E9=80=9A=E7=9F=A5=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

WebEngineView 中添加 WebEngineView::present(std::unique_ptr<QWebEngineNotification> &newNotification) 函数,通过 DNotifySender 转发系统通知

Log: 添加网页通知功能,通知图片缓存在 /tmp 下;使用 DLogManager 生成日志;修复强制使用 DTK 平台插件异常问题
---
 spark-webapp-runtime/application.cpp          | 33 +++++++++++++
 spark-webapp-runtime/application.h            | 14 ++++++
 spark-webapp-runtime/globaldefine.h           |  4 +-
 spark-webapp-runtime/main.cpp                 |  5 +-
 spark-webapp-runtime/mainwindow.cpp           | 43 +++++++++++++++++
 spark-webapp-runtime/mainwindow.h             |  6 +++
 spark-webapp-runtime/spark-webapp-runtime.pro |  2 +-
 .../spark-webapp-runtime_zh_CN.ts             | 47 ++++++++++---------
 spark-webapp-runtime/webenginepage.cpp        |  7 +++
 spark-webapp-runtime/webengineview.cpp        | 42 +++++++++++++++++
 spark-webapp-runtime/webengineview.h          |  2 +
 11 files changed, 179 insertions(+), 26 deletions(-)

diff --git a/spark-webapp-runtime/application.cpp b/spark-webapp-runtime/application.cpp
index 9ac7b4d..63b9dc9 100644
--- a/spark-webapp-runtime/application.cpp
+++ b/spark-webapp-runtime/application.cpp
@@ -4,9 +4,15 @@
 #include <DPlatformWindowHandle>
 #include <DAboutDialog>
 
+#include <QStandardPaths>
+
+#include <unistd.h>
+
 Application::Application(int &argc, char **argv)
     : DApplication(argc, argv)
 {
+    saveLaunchParams(argc, argv);
+
     loadTranslator();
 
     setAttribute(Qt::AA_UseHighDpiPixmaps);
@@ -35,6 +41,33 @@ void Application::handleAboutAction()
     DApplication::handleAboutAction();
 }
 
+QStringList Application::launchParams() const
+{
+    return m_argv;
+}
+
+void Application::setMainWindow(MainWindow *window)
+{
+    m_mainWindow = window;
+}
+
+MainWindow *Application::mainWindow()
+{
+    return m_mainWindow;
+}
+
+void Application::saveLaunchParams(int &argc, char **argv)
+{
+    m_argc = argc;
+
+    m_argv.clear();
+    for (int i = 0; i < m_argc; i++) {
+        m_argv.append(argv[i]);
+    }
+
+    qDebug() << Q_FUNC_INFO << m_argc << m_argv;
+}
+
 void Application::initAboutDialog()
 {
     // Customized DAboutDialog
diff --git a/spark-webapp-runtime/application.h b/spark-webapp-runtime/application.h
index 30f7597..805699a 100644
--- a/spark-webapp-runtime/application.h
+++ b/spark-webapp-runtime/application.h
@@ -1,6 +1,8 @@
 #ifndef APPLICATION_H
 #define APPLICATION_H
 
+#include "mainwindow.h"
+
 #include <DApplication>
 
 DWIDGET_USE_NAMESPACE
@@ -13,7 +15,13 @@ public:
     Application(int &argc, char **argv);
     void handleAboutAction() override;
 
+    QStringList launchParams() const;
+
+    void setMainWindow(MainWindow *window);
+    MainWindow *mainWindow();
+
 private:
+    void saveLaunchParams(int &argc, char **argv);
     void initAboutDialog();
 
 signals:
@@ -21,6 +29,12 @@ signals:
 
 public slots:
     void slotMainWindowClose();
+
+private:
+    MainWindow *m_mainWindow = nullptr;
+
+    int m_argc;
+    QStringList m_argv;
 };
 
 #endif // APPLICATION_H
diff --git a/spark-webapp-runtime/globaldefine.h b/spark-webapp-runtime/globaldefine.h
index 90198e2..af86626 100644
--- a/spark-webapp-runtime/globaldefine.h
+++ b/spark-webapp-runtime/globaldefine.h
@@ -4,7 +4,7 @@
 #include <QObject>
 
 #define DEFAULT_TITLE QObject::tr("SparkWebAppRuntime")
-#define APPLICATION_NAME QString("SparkWebAppRuntime")
+#define APPLICATION_NAME QString("spark-webapp-runtime")
 #define ORGANIZATION_NAME QString("spark-union")
 #define DEFAULT_URL QString("qrc:/help/help.html")
 #define DEFAULT_WIDTH (1024)
@@ -18,6 +18,6 @@
 #define DEFAULT_PORT 0
 #define DEFAULT_GPU 1
 
-#define CURRENT_VER QString("1.6.6")
+#define CURRENT_VER QString("1.7.0")
 
 #endif // GLOBALDEFINE_H
diff --git a/spark-webapp-runtime/main.cpp b/spark-webapp-runtime/main.cpp
index 8f9ca87..e1496a8 100644
--- a/spark-webapp-runtime/main.cpp
+++ b/spark-webapp-runtime/main.cpp
@@ -44,8 +44,8 @@ int main(int argc, char *argv[])
     int fakeArgc = argc + 2;
     QVector<char *> fakeArgv(fakeArgc);
     fakeArgv[0] = argv[0];
-    fakeArgv[1] = QString("-platformtheme").toUtf8().data();
-    fakeArgv[2] = QString("deepin").toUtf8().data();
+    fakeArgv[1] = const_cast<char *>("-platformtheme");
+    fakeArgv[2] = const_cast<char *>("deepin");
     for (int i = 1; i < argc; i++) {
         fakeArgv[i + 2] = argv[i];
     }
@@ -347,6 +347,7 @@ int main(int argc, char *argv[])
 #endif
 
     MainWindow w(szTitle, szUrl, width, height, tray, fullScreen, fixSize, hideButtons);
+    a.setMainWindow(&w);
     QObject::connect(&a, &Application::newInstanceStarted, &w, &MainWindow::slotNewInstanceStarted);
     QObject::connect(&w, &MainWindow::sigClose, &a, &Application::slotMainWindowClose);
 
diff --git a/spark-webapp-runtime/mainwindow.cpp b/spark-webapp-runtime/mainwindow.cpp
index e9795f7..446013f 100644
--- a/spark-webapp-runtime/mainwindow.cpp
+++ b/spark-webapp-runtime/mainwindow.cpp
@@ -3,6 +3,7 @@
 #include "webengineview.h"
 #include "webenginepage.h"
 
+#include <DLog>
 #include <DWidgetUtil>
 #include <DTitlebar>
 #include <DMessageManager>
@@ -15,6 +16,10 @@
 #include <QDir>
 #include <QStandardPaths>
 
+#include <unistd.h>
+
+DCORE_USE_NAMESPACE
+
 MainWindow::MainWindow(QString szTitle,
                        QString szUrl,
                        int nWidth,
@@ -56,6 +61,9 @@ MainWindow::MainWindow(QString szTitle,
     , btnCancel(new DPushButton(QObject::tr("Cancel"), downloadProgressWidget))
     , isCanceled(false)
 {
+    initTmpDir();
+    initLog();
+
     initUI();
     initTrayIcon();
     initConnections();
@@ -90,6 +98,18 @@ void MainWindow::setDescription(const QString &desc)
     }
 }
 
+QString MainWindow::title() const
+{
+    return m_title;
+}
+
+QString MainWindow::tmpDir() const
+{
+    QString orgName = qobject_cast<DApplication *>(qApp)->organizationName();
+    QString appName = qobject_cast<DApplication *>(qApp)->applicationName();
+    return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + orgName + "/" + appName + "/" + m_title + "/" + QString::number(getuid());
+}
+
 void MainWindow::keyPressEvent(QKeyEvent *event)
 {
     if (!m_fixSize->isChecked()) // 固定窗口大小时禁止全屏
@@ -127,6 +147,29 @@ void MainWindow::closeEvent(QCloseEvent *event)
     DMainWindow::closeEvent(event);
 }
 
+void MainWindow::initLog()
+{
+    if (!QDir(tmpDir()).exists()) {
+        return;
+    }
+
+    DLogManager::setlogFilePath(tmpDir() + "/" + "log");
+    DLogManager::registerFileAppender();
+    DLogManager::registerConsoleAppender();
+}
+
+void MainWindow::initTmpDir()
+{
+    QDir dir(tmpDir());
+    dir.removeRecursively();
+    dir.mkpath(dir.path());
+    if (!dir.exists()) {
+        qCritical() << Q_FUNC_INFO << dir.path() << "not exists";
+        return;
+    }
+    qDebug() << Q_FUNC_INFO << dir.path() << "created";
+}
+
 void MainWindow::initUI()
 {
     // 初始化 MainWindow
diff --git a/spark-webapp-runtime/mainwindow.h b/spark-webapp-runtime/mainwindow.h
index 2840d2d..d875b77 100644
--- a/spark-webapp-runtime/mainwindow.h
+++ b/spark-webapp-runtime/mainwindow.h
@@ -36,12 +36,18 @@ public:
     void setIcon(QString szIconPath);
     void setDescription(const QString &desc);
 
+    QString title() const;
+    QString tmpDir() const;
+
 protected:
     void keyPressEvent(QKeyEvent *event);
     void resizeEvent(QResizeEvent *event);
     void closeEvent(QCloseEvent *event);
 
 private:
+    void initLog();
+    void initTmpDir();
+
     void initUI();
     void initTitleBar();
     void initDownloadProgressBar();
diff --git a/spark-webapp-runtime/spark-webapp-runtime.pro b/spark-webapp-runtime/spark-webapp-runtime.pro
index e8d78c3..0f3d749 100644
--- a/spark-webapp-runtime/spark-webapp-runtime.pro
+++ b/spark-webapp-runtime/spark-webapp-runtime.pro
@@ -1,4 +1,4 @@
-QT += core gui webenginewidgets svg concurrent
+QT += core gui webenginewidgets svg concurrent dbus
 
 greaterThan(QT_MAJOR_VERSION, 5): QT += widgets
 
diff --git a/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts b/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
index c436c27..dd1df84 100644
--- a/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
+++ b/spark-webapp-runtime/translations/spark-webapp-runtime_zh_CN.ts
@@ -4,12 +4,12 @@
 <context>
     <name>DAboutDialog</name>
     <message>
-        <location filename="../application.cpp" line="49"/>
+        <location filename="../application.cpp" line="82"/>
         <source>Version: %1</source>
         <translation>版本:%1</translation>
     </message>
     <message>
-        <location filename="../application.cpp" line="65"/>
+        <location filename="../application.cpp" line="98"/>
         <source>%1 is released under %2</source>
         <translation>%1遵循%2协议发布</translation>
     </message>
@@ -17,7 +17,7 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../application.cpp" line="57"/>
+        <location filename="../application.cpp" line="90"/>
         <location filename="../main.cpp" line="186"/>
         <source>Presented By Spark developers # HadesStudio</source>
         <translation>由 星火开发者联盟 @ 花心胡萝卜 提供</translation>
@@ -113,95 +113,100 @@
         <translation>星火网页应用运行环境</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="42"/>
+        <location filename="../mainwindow.cpp" line="47"/>
         <source>Full Screen</source>
         <translation>全屏显示</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="43"/>
+        <location filename="../mainwindow.cpp" line="48"/>
         <source>Fix Size</source>
         <translation>固定大小</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="44"/>
+        <location filename="../mainwindow.cpp" line="49"/>
         <source>Hide Buttons</source>
         <translation>隐藏按钮</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="45"/>
+        <location filename="../mainwindow.cpp" line="50"/>
         <source>Clear Cache</source>
         <translation>清理缓存</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="47"/>
+        <location filename="../mainwindow.cpp" line="52"/>
         <source>Show MainWindow</source>
         <translation>显示主界面</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="54"/>
+        <location filename="../mainwindow.cpp" line="59"/>
         <source>Pause</source>
         <translation>暂停</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="55"/>
+        <location filename="../mainwindow.cpp" line="60"/>
         <source>Resume</source>
         <translation>继续</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="56"/>
+        <location filename="../mainwindow.cpp" line="61"/>
         <source>Cancel</source>
         <translation>取消</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="338"/>
+        <location filename="../mainwindow.cpp" line="381"/>
         <source>Save As</source>
         <translation>另存为</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="402"/>
+        <location filename="../mainwindow.cpp" line="445"/>
         <source>%1Start downloading %2</source>
         <translation>%1开始下载 %2</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="413"/>
+        <location filename="../mainwindow.cpp" line="456"/>
         <source>%1Wait for previous download to complete!</source>
         <translation>%1请等待上一个下载任务完成!</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="435"/>
+        <location filename="../mainwindow.cpp" line="478"/>
         <source>Open</source>
         <translation>打开</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="439"/>
+        <location filename="../mainwindow.cpp" line="482"/>
         <source>download finished.</source>
         <translation>下载完成。</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="439"/>
+        <location filename="../mainwindow.cpp" line="482"/>
         <source>Show in file manager?</source>
         <translation>是否在文件管理器中显示?</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="477"/>
+        <location filename="../mainwindow.cpp" line="520"/>
         <source>%1Download canceled!</source>
         <translation>%1下载取消!</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="482"/>
+        <location filename="../mainwindow.cpp" line="525"/>
         <source>%1Load error occurred!</source>
         <translation>%1加载存在错误!</translation>
     </message>
+    <message>
+        <location filename="../webengineview.cpp" line="79"/>
+        <source>View</source>
+        <translation>查看</translation>
+    </message>
 </context>
 <context>
     <name>TitleBarMenu</name>
     <message>
-        <location filename="../mainwindow.cpp" line="48"/>
+        <location filename="../mainwindow.cpp" line="53"/>
         <source>About</source>
         <translation>关于</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="49"/>
+        <location filename="../mainwindow.cpp" line="54"/>
         <source>Exit</source>
         <translation>退出</translation>
     </message>
diff --git a/spark-webapp-runtime/webenginepage.cpp b/spark-webapp-runtime/webenginepage.cpp
index 756758e..ae66356 100644
--- a/spark-webapp-runtime/webenginepage.cpp
+++ b/spark-webapp-runtime/webenginepage.cpp
@@ -5,6 +5,13 @@
 WebEnginePage::WebEnginePage(QObject *parent)
     : QWebEnginePage(parent)
 {
+    connect(this, &QWebEnginePage::featurePermissionRequested, [&](const QUrl &origin, QWebEnginePage::Feature feature) {
+        if (feature != QWebEnginePage::Notifications) {
+            return;
+        }
+
+        setFeaturePermission(origin, feature, QWebEnginePage::PermissionGrantedByUser);
+    });
 }
 
 WebEnginePage::~WebEnginePage()
diff --git a/spark-webapp-runtime/webengineview.cpp b/spark-webapp-runtime/webengineview.cpp
index 6fa3ed8..b402ed5 100644
--- a/spark-webapp-runtime/webengineview.cpp
+++ b/spark-webapp-runtime/webengineview.cpp
@@ -1,13 +1,17 @@
 #include "webengineview.h"
 //#include "webengineurlrequestinterceptor.h"
+#include "application.h"
 
 #include <DGuiApplicationHelper>
+#include <DNotifySender>
 
 #include <QWebEngineSettings>
 #include <QWebEngineProfile>
 #include <QLocale>
+#include <QFileInfo>
 
 DGUI_USE_NAMESPACE
+DCORE_USE_NAMESPACE
 
 WebEngineView::WebEngineView(QWidget *parent)
     : QWebEngineView(parent)
@@ -17,6 +21,9 @@ WebEngineView::WebEngineView(QWidget *parent)
         //        page()->setUrlRequestInterceptor(interceptor);
         //        page()->settings()->setAttribute(QWebEngineSettings::WebAttribute::LocalContentCanAccessRemoteUrls, true);
         page()->profile()->setHttpAcceptLanguage(QLocale::system().name());
+        page()->profile()->setNotificationPresenter([&](std::unique_ptr<QWebEngineNotification> notification) {
+            WebEngineView::present(notification);
+        });
     });
 }
 
@@ -51,3 +58,38 @@ void WebEngineView::handleChromiumFlags()
 
     qDebug() << Q_FUNC_INFO << "QTWEBENGINE_CHROMIUM_FLAGS=" + qgetenv("QTWEBENGINE_CHROMIUM_FLAGS");
 }
+
+void WebEngineView::present(std::unique_ptr<QWebEngineNotification> &newNotification)
+{
+    qDebug() << Q_FUNC_INFO << "New notification received:" << newNotification->title() << newNotification->message();
+
+    QImage image = newNotification->icon();
+    QString tmpDir = qobject_cast<Application *>(qApp)->mainWindow()->tmpDir();
+    QString appIcon = tmpDir + "/" + "icon.png";
+    if (QFileInfo::exists(appIcon)) {
+        QFile::remove(appIcon);
+    }
+    image.save(appIcon, "PNG");
+
+    QString summary = newNotification->title();
+    QString appName = qobject_cast<Application *>(qApp)->mainWindow()->title();
+    QString appBody = newNotification->message();
+    quint32 replaceId = 0;
+    int timeOut = 3000;
+    QStringList actions = QStringList() << "view" << QObject::tr("View");
+
+    QString launchCmd = qobject_cast<Application *>(qApp)->launchParams().join(",");
+    qDebug() << launchCmd;
+    QVariantMap hints;
+    hints.insert("x-deepin-action-view", launchCmd);
+
+    DUtil::DNotifySender(summary)
+        .appName(appName)
+        .appIcon(appIcon)
+        .appBody(appBody)
+        .replaceId(replaceId)
+        .timeOut(timeOut)
+        .actions(actions)
+        .hints(hints)
+        .call();
+}
diff --git a/spark-webapp-runtime/webengineview.h b/spark-webapp-runtime/webengineview.h
index b688fd6..bd075ff 100644
--- a/spark-webapp-runtime/webengineview.h
+++ b/spark-webapp-runtime/webengineview.h
@@ -2,6 +2,7 @@
 #define WEBENGINEVIEW_H
 
 #include <QWebEngineView>
+#include <QWebEngineNotification>
 
 // class WebEngineUrlRequestInterceptor;
 class WebEngineView : public QWebEngineView
@@ -12,6 +13,7 @@ public:
     explicit WebEngineView(QWidget *parent = nullptr);
 
     static void handleChromiumFlags();
+    static void present(std::unique_ptr<QWebEngineNotification> &newNotification);
 
 private:
     //    WebEngineUrlRequestInterceptor *interceptor = nullptr;