📜 ⬆️ ⬇️

We write client for Slack with notifications

Greetings, Habravchane! Slack has released its client for Windows today. But more recently, such a client was not, and the need to receive normal notifications was a necessity. Slack suggested using the Chrome app. This approach had two minuses:
  1. The inability to configure how long the notification will be displayed
  2. If the notification is gone, the user will not know about it.



For example, you left to pour yourself some coffee, and then someone wrote in the chat. You come back to the workplace and ... silence! Nothing happened. You work further, and the person waits and waits for someone to answer him. Disorder! Skype politely notifies you with a pop-up window and brazenly signals in the taskbar that you received a message. Faster read, and then your taskbar and we will flash yellow. Even if you left all day.

Rewind time 1 month ago. Go to the page myawesometeam.slack.com/apps and see the absence of a native client for Windows and Linux, instead there are applications for Chrome. We get upset. We start the application, we understand all the sadness of life.

I began to look for a solution to the problem. The first to come was SlackUI . It is based on CEF (Chromium Embedded Framework). I was almost happy, I started the client and saw the same thing as in the Chrome app. Notifications disappear after 10 seconds, no notifications that something happened while you went for coffee.
')
Well, I started to google and stumbled upon the fact that in Qt WebKit you can write your own plugin, including for notifications. I found the QupZilla project and its plugins for Qt WebKit ( https://github.com/QupZilla/qtwebkit-plugins ). It was what you need!

Step 1. Make a notification plugin for Qt WebKit


In the .pri file, we need to add the header files for the plugin and the Qt header files so that it can pick up our plugin:
HEADERS += $$PWD/qtwebkitplugin.h \ $$[QT_INSTALL_HEADERS]/QtWebKit/qwebkitplatformplugin.h SOURCES += $$PWD/qtwebkitplugin.cpp DEFINES *= QT_STATICPLUGIN 

The code for the plugin itself:
qtwebkitplugin.h
 #include "qwebkitplatformplugin.h" class QtWebKitPlugin : public QObject, public QWebKitPlatformPlugin { Q_OBJECT Q_INTERFACES(QWebKitPlatformPlugin) #if QT_VERSION >= 0x050000 Q_PLUGIN_METADATA(IID "org.qtwebkit.QtWebKit.QtWebKitPlugins") #endif public: explicit QtWebKitPlugin(); bool supportsExtension(Extension ext) const; QObject* createExtension(Extension ext) const; }; 



qtwebkitplugin.cpp
 bool QtWebKitPlugin::supportsExtension(Extension ext) const { return (ext == Notifications); } QObject* QtWebKitPlugin::createExtension(Extension ext) const { switch (ext) { case Notifications: return new NotificationPresenter(); default: return 0; } } #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(qtwebkitplugins, QtWebKitPlugin) #endif #if (QT_VERSION < 0x050000) Q_IMPORT_PLUGIN(qtwebkitplugins) #else Q_IMPORT_PLUGIN(QtWebKitPlugin) #endif 



So far, nothing complicated. NotificationPresenter is a class that will display our notifications, even if the debug console:

notificationpresenter.h
 #include "qwebkitplatformplugin.h" class NotificationPresenter : public QWebNotificationPresenter { public: explicit NotificationPresenter(); void showNotification(const QWebNotificationData* data); }; 


notificationpresenter.cpp
 NotificationPresenter::NotificationPresenter() : QWebNotificationPresenter() { } void NotificationPresenter::showNotification(const QWebNotificationData* data) { qDebug() << "--------------------------"; qDebug() << "Title:"; qDebug() << data->title(); qDebug() << "Message:"; qDebug() << data->message(); qDebug() << "--------------------------"; } 



Step 2. Add QWebView


We connect the .pri file to our project and add a dependency on webkitwidgets to the .pro file:
 ... QT += webkitwidgets include(plugins/qtwebkit/qtwebkit-plugins.pri) ... 


Add to some form of QWebView, after which we need to configure it a bit and subscribe to the featurePermissionRequested event:

Another code?
 void MainWindow::createWebView() { webview->settings()->setAttribute(QWebSettings::JavascriptEnabled, true); webview->settings()->setAttribute(QWebSettings::NotificationsEnabled, true); connect(webView->page(), SIGNAL(featurePermissionRequested(QWebFrame*,QWebPage::Feature)), this, SLOT(featureRequest(QWebFrame*,QWebPage::Feature))); } void MainWindow::featureRequest(QWebFrame *frame, QWebPage::Feature feature) { qDebug() << frame->url(); if (feature == QWebPage::Feature::Notifications) { int result = QMessageBox::question(this, QString("Notification permission"), QString("%1\nasks for notifications persmission. Should I allow?").arg(frame->url().toString()), QMessageBox::StandardButton::Ok, QMessageBox::Cancel); if (result == QMessageBox::StandardButton::Ok) { webView->page()->setFeaturePermission(frame, feature, QWebPage::PermissionPolicy::PermissionGrantedByUser); } } } 



We set a test url with a notification ( for example, this one ) and test the page. A notification should be displayed.

Step 3. Add cookies and cache to disk. Adding Native Fonts


First of all, furious curves fonts. Fix them right away
 webView->settings()->setFontFamily(QWebSettings::StandardFont, "Segoe UI"); webView->settings()->setFontSize(QWebSettings::DefaultFontSize, 16); 


If we now restart the application, we need to repeat the confirmation procedure again, re-enter passwords, etc. So, it's time to save cookies and cache on the disk.
The cache is a bit simpler:
 void MainWindow::setStoragePath() { QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); qDebug() << "Cache path" << path; storagePath = path; webView->page()->settings()->enablePersistentStorage(path); } 

Keeping cookies is more complicated. I just found a ready-made solution from the Qt examples. You can easily find it in Google according to QWebView and CookieJar. An example of CookieJar can be found in the source code of the project.
 void MainWindow::setCookies() { if (!cookieJar) { cookieJar = new CookieJar(this); } webView->page()->networkAccessManager()->setCookieJar(cookieJar); } 

After this, cookies and cache should be saved and no need to enter logins and passwords every time.

Stage 4. We connect additional libraries


For notifications, I decided to use Aseman Qt Tools .
Download, connect to the .pro file
 include(asemantools/asemantools.pri) 


Now in NotificationPresenter of our plug-in you need to drag through some interface to display notifications.
Add to qtwebkit.pri
 INCLUDEPATH += $$top_srcdir HEADERS += $$top_srcdir/mainapplication.h 


Here MainApplication is a successor from QApplication. Add notification display functions:

notificationpresenter.cpp
 void NotificationPresenter::showNotification(const QWebNotificationData* data) { mApp->showNotification(data->title(), data->message()); } 


mainapplication.h
 #include <QApplication> #include "mainwindow.h" #define mApp ((MainApplication*)MainApplication::instance()) class MainApplication : public QApplication { Q_OBJECT public: explicit MainApplication(int &argc, char** argv); void setMainWindow(MainWindow* window); MainWindow* getMainWindow(); void showNotification(QString title, QString message); ~MainApplication(); private: MainWindow *m_window = 0; }; 



mainapplication.cpp
 MainWindow *MainApplication::getMainWindow() { if (!m_window){ m_window = new MainWindow(); } return m_window; } void MainApplication::showNotification(QString title, QString message) { getMainWindow()->showNotification(title, message); } 



Add AsemanNotification to the main program window and make the taskbar blink yellow:
 MainWindow::MainWindow() { // ... notification = new AsemanNativeNotification(this); // ... } void MainWindow::showNotification(QString title, QString message) { notification->sendNotify(title, message, "://images/png/Slack.png", 0, 100000); //   QApplication::alert(this); //   } 

Compile. We start the test page. There should be real notice.

Stage 5. We try to build under Linux


And here we come. In Linux, different DEs and everything will work upside down.
In Unity, the tray icon will appear in the upper left corner of the screen. It looks like this:

In Gnome 3, notifications from AsemanTools were constantly creeping off somewhere outside the screen. I did not find any clear solutions and it became sad and offensive for Linux. Nothing works out of the box, you need eternal dances with a tambourine

Results


As a result, the experience of creating an application based on WebKit, as well as creating plug-ins for Qt.
Result of work:


Link to the resulting project on Github

It is time to put the code in order a little, make coffee and return to the computer, where the yellow Slack icon in the taskbar blinks happily. Push all the changes and wait for the rainbow unicorn to check your project to poke your head at ...

Source: https://habr.com/ru/post/253579/


All Articles