From 9ea334d08f42f3c362e86499dc3c0ed658bb428c Mon Sep 17 00:00:00 2001 From: keshavbhatt Date: Mon, 5 Apr 2021 02:11:25 +0530 Subject: src init --- src/WhatsApp.pro | 87 ++++ src/certificateerrordialog.ui | 133 ++++++ src/common.h | 7 + src/downloadmanagerwidget.cpp | 44 ++ src/downloadmanagerwidget.h | 83 ++++ src/downloadmanagerwidget.ui | 123 +++++ src/downloadwidget.cpp | 108 +++++ src/downloadwidget.h | 88 ++++ src/downloadwidget.ui | 80 ++++ src/elidedlabel.cpp | 49 ++ src/elidedlabel.h | 49 ++ src/icons.qrc | 147 ++++++ src/icons/account-pin-circle-line.png | Bin 0 -> 3204 bytes src/icons/anticlockwise-fill.png | Bin 0 -> 769 bytes src/icons/anticlockwise-line.png | Bin 0 -> 842 bytes src/icons/app/icon-128.png | Bin 0 -> 6064 bytes src/icons/app/icon-16.png | Bin 0 -> 1286 bytes src/icons/app/icon-256.png | Bin 0 -> 12301 bytes src/icons/app/icon-32.png | Bin 0 -> 1777 bytes src/icons/app/icon-512.png | Bin 0 -> 22868 bytes src/icons/app/icon-64.png | Bin 0 -> 3308 bytes src/icons/app/resize.sh | 155 ++++++ src/icons/app/whatsapp-message.svg | 94 ++++ src/icons/app/whatsapp.svg | 81 ++++ src/icons/archive-drawer-line.png | Bin 0 -> 589 bytes src/icons/arrow-down-s-line.png | Bin 0 -> 647 bytes src/icons/arrow-go-back-line.png | Bin 0 -> 996 bytes src/icons/arrow-go-forward-line.png | Bin 0 -> 1040 bytes src/icons/arrow-left-circle-line.png | Bin 0 -> 2101 bytes src/icons/arrow-left-line.png | Bin 0 -> 578 bytes src/icons/arrow-left-s-line.png | Bin 0 -> 513 bytes src/icons/arrow-right-circle-line.png | Bin 0 -> 2119 bytes src/icons/arrow-right-line.png | Bin 0 -> 538 bytes src/icons/arrow-right-s-line.png | Bin 0 -> 500 bytes src/icons/arrow-up-s-line.png | Bin 0 -> 610 bytes src/icons/blur-off-line.png | Bin 0 -> 1348 bytes src/icons/camera-off-line.png | Bin 0 -> 1786 bytes src/icons/categories/art-and-design.png | Bin 0 -> 1413 bytes src/icons/categories/books-and-reference.png | Bin 0 -> 680 bytes src/icons/categories/development.png | Bin 0 -> 1383 bytes src/icons/categories/devices-and-iot.png | Bin 0 -> 790 bytes src/icons/categories/education.png | Bin 0 -> 502 bytes src/icons/categories/entertainment.png | Bin 0 -> 1696 bytes src/icons/categories/featured.png | Bin 0 -> 1565 bytes src/icons/categories/finance.png | Bin 0 -> 893 bytes src/icons/categories/games.png | Bin 0 -> 1085 bytes src/icons/categories/health-and-fitness.png | Bin 0 -> 584 bytes src/icons/categories/music-and-audio.png | Bin 0 -> 1237 bytes src/icons/categories/news-and-weather.png | Bin 0 -> 761 bytes src/icons/categories/personalisation.png | Bin 0 -> 819 bytes src/icons/categories/photo-and-video.png | Bin 0 -> 856 bytes src/icons/categories/productivity.png | Bin 0 -> 1579 bytes src/icons/categories/science.png | Bin 0 -> 1489 bytes src/icons/categories/security.png | Bin 0 -> 906 bytes src/icons/categories/server-and-cloud.png | Bin 0 -> 498 bytes src/icons/categories/social.png | Bin 0 -> 1364 bytes src/icons/categories/utilities.png | Bin 0 -> 684 bytes src/icons/clipboard-line.png | Bin 0 -> 590 bytes src/icons/clockwise-fill.png | Bin 0 -> 768 bytes src/icons/clockwise-line.png | Bin 0 -> 848 bytes src/icons/close-fill.png | Bin 0 -> 732 bytes src/icons/compare-image-line.png | Bin 0 -> 1821 bytes src/icons/crop-line.png | Bin 0 -> 528 bytes src/icons/delete-bin-3-line.png | Bin 0 -> 645 bytes src/icons/delete-bin-5-line.png | Bin 0 -> 679 bytes src/icons/disabled-arrow-left-circle-line.png | Bin 0 -> 2156 bytes src/icons/disabled-arrow-right-circle-line.png | Bin 0 -> 2150 bytes src/icons/download-line.png | Bin 0 -> 945 bytes src/icons/drag-move-fill.png | Bin 0 -> 1064 bytes src/icons/error-warning-line.png | Bin 0 -> 2384 bytes src/icons/eye-line.png | Bin 0 -> 2650 bytes src/icons/facebook-box-line.png | Bin 0 -> 770 bytes src/icons/facebook-line.png | Bin 0 -> 583 bytes src/icons/file-copy-line.png | Bin 0 -> 732 bytes src/icons/file-text-line.png | Bin 0 -> 649 bytes src/icons/file-unknow-line.png | Bin 0 -> 850 bytes src/icons/filter-2-line.png | Bin 0 -> 965 bytes src/icons/focus-3-line.png | Bin 0 -> 2186 bytes src/icons/folder-download-line.png | Bin 0 -> 953 bytes src/icons/folder-open-line.png | Bin 0 -> 1009 bytes src/icons/fullscreen-line.png | Bin 0 -> 425 bytes src/icons/funds-line.png | Bin 0 -> 1629 bytes src/icons/fx-line.png | Bin 0 -> 1174 bytes src/icons/grid-line.png | Bin 0 -> 515 bytes src/icons/home-8-line.png | Bin 0 -> 911 bytes src/icons/icon-512.xcf | Bin 0 -> 410837 bytes src/icons/image-2-line.png | Bin 0 -> 1234 bytes src/icons/information-fill.png | Bin 0 -> 1557 bytes src/icons/information-line.png | Bin 0 -> 2396 bytes src/icons/link-unlink-m.png | Bin 0 -> 2829 bytes src/icons/links-line.png | Bin 0 -> 2656 bytes src/icons/loader-2-fill.png | Bin 0 -> 1343 bytes src/icons/lock-2-fill.png | Bin 0 -> 1074 bytes src/icons/lock-line.png | Bin 0 -> 960 bytes src/icons/lock-unlock-line.png | Bin 0 -> 885 bytes src/icons/magic-line.png | Bin 0 -> 2259 bytes src/icons/mail-add-line.png | Bin 0 -> 1321 bytes src/icons/mail-line.png | Bin 0 -> 892 bytes src/icons/map-pin-line.png | Bin 0 -> 2555 bytes src/icons/movie-2-line.png | Bin 0 -> 2821 bytes src/icons/music-2-line.png | Bin 0 -> 1534 bytes src/icons/others/Histogram.png | Bin 0 -> 291 bytes src/icons/others/Omonitor.png | Bin 0 -> 13176 bytes src/icons/others/greendot.png | Bin 0 -> 7109 bytes src/icons/others/monitor.png | Bin 0 -> 3922 bytes src/icons/others/snapcraft.png | Bin 0 -> 1602 bytes src/icons/others/snapcraft.svg | 59 +++ src/icons/others/tt_tbc_head.png | Bin 0 -> 83727 bytes src/icons/others/wall_placeholder_180.jpg | Bin 0 -> 5155 bytes src/icons/pause-line.png | Bin 0 -> 325 bytes src/icons/paypal-line.png | Bin 0 -> 2582 bytes src/icons/picture-in-picture-line.png | Bin 0 -> 651 bytes src/icons/play-fill.png | Bin 0 -> 415 bytes src/icons/play-line.png | Bin 0 -> 828 bytes src/icons/printer-line.png | Bin 0 -> 754 bytes src/icons/questionnaire-line.png | Bin 0 -> 1145 bytes src/icons/record-circle-line.png | Bin 0 -> 2603 bytes src/icons/refresh-line.png | Bin 0 -> 2000 bytes src/icons/repeat-2-fill.png | Bin 0 -> 823 bytes src/icons/save-line.png | Bin 0 -> 502 bytes src/icons/scissors-cut-line.png | Bin 0 -> 1715 bytes src/icons/screenshot-2-line.png | Bin 0 -> 1185 bytes src/icons/search-2-line.png | Bin 0 -> 2339 bytes src/icons/setting-line.png | Bin 0 -> 1494 bytes src/icons/shape-2-line.png | Bin 0 -> 510 bytes src/icons/shape-line.png | Bin 0 -> 1226 bytes src/icons/share-line.png | Bin 0 -> 2102 bytes src/icons/shopping-cart-line.png | Bin 0 -> 1183 bytes src/icons/sip-line.png | Bin 0 -> 1171 bytes src/icons/split-cells-horizontal.png | Bin 0 -> 626 bytes src/icons/split-cells-vertical.png | Bin 0 -> 610 bytes src/icons/star-line.png | Bin 0 -> 2554 bytes src/icons/stop-line.png | Bin 0 -> 471 bytes src/icons/swap-box-line.png | Bin 0 -> 929 bytes src/icons/terminal-box-line.png | Bin 0 -> 665 bytes src/icons/texture.png | Bin 0 -> 2417 bytes src/icons/tiktok-downloader.png | Bin 0 -> 76834 bytes src/icons/time-line.png | Bin 0 -> 2398 bytes src/icons/translate-2.png | Bin 0 -> 2002 bytes src/icons/twitter-line.png | Bin 0 -> 1518 bytes src/icons/volume-mute-line.png | Bin 0 -> 1249 bytes src/icons/volume-up-line.png | Bin 0 -> 2042 bytes src/icons/white/stop-line.png | Bin 0 -> 437 bytes src/icons/white/white_arrow-left-line.png | Bin 0 -> 538 bytes src/icons/white/white_arrow-right-line.png | Bin 0 -> 504 bytes src/icons/white/white_picture-in-picture-line.png | Bin 0 -> 560 bytes src/icons/white/white_play-fill.png | Bin 0 -> 415 bytes src/icons/white/white_record-circle-line.png | Bin 0 -> 2055 bytes src/icons/white/white_scissors-cut-line.png | Bin 0 -> 1715 bytes src/icons/white/white_shape-2-line.png | Bin 0 -> 468 bytes src/icons/white/white_sip-line.png | Bin 0 -> 999 bytes src/icons/white/white_terminal-box-line.png | Bin 0 -> 601 bytes src/icons/youtube-line.png | Bin 0 -> 1901 bytes src/icons/zoom-in-fill.png | Bin 0 -> 1077 bytes src/icons/zoom-in-line.png | Bin 0 -> 1453 bytes src/icons/zoom-out-fill.png | Bin 0 -> 1005 bytes src/icons/zoom-out-line.png | Bin 0 -> 1421 bytes src/main.cpp | 45 ++ src/mainwindow.cpp | 551 ++++++++++++++++++++++ src/mainwindow.h | 107 +++++ src/notificationpopup.h | 144 ++++++ src/passworddialog.ui | 121 +++++ src/requestinterceptor.h | 41 ++ src/settingswidget.cpp | 189 ++++++++ src/settingswidget.h | 66 +++ src/settingswidget.ui | 354 ++++++++++++++ src/utils.cpp | 162 +++++++ src/utils.h | 85 ++++ src/webenginepage.cpp | 252 ++++++++++ src/webenginepage.h | 49 ++ src/widgets/scrolltext/scrolltext.cpp | 179 +++++++ src/widgets/scrolltext/scrolltext.h | 53 +++ 172 files changed, 3785 insertions(+) create mode 100644 src/WhatsApp.pro create mode 100644 src/certificateerrordialog.ui create mode 100644 src/common.h create mode 100644 src/downloadmanagerwidget.cpp create mode 100644 src/downloadmanagerwidget.h create mode 100644 src/downloadmanagerwidget.ui create mode 100644 src/downloadwidget.cpp create mode 100644 src/downloadwidget.h create mode 100644 src/downloadwidget.ui create mode 100644 src/elidedlabel.cpp create mode 100644 src/elidedlabel.h create mode 100644 src/icons.qrc create mode 100644 src/icons/account-pin-circle-line.png create mode 100644 src/icons/anticlockwise-fill.png create mode 100644 src/icons/anticlockwise-line.png create mode 100644 src/icons/app/icon-128.png create mode 100644 src/icons/app/icon-16.png create mode 100644 src/icons/app/icon-256.png create mode 100644 src/icons/app/icon-32.png create mode 100644 src/icons/app/icon-512.png create mode 100644 src/icons/app/icon-64.png create mode 100755 src/icons/app/resize.sh create mode 100644 src/icons/app/whatsapp-message.svg create mode 100644 src/icons/app/whatsapp.svg create mode 100644 src/icons/archive-drawer-line.png create mode 100644 src/icons/arrow-down-s-line.png create mode 100644 src/icons/arrow-go-back-line.png create mode 100644 src/icons/arrow-go-forward-line.png create mode 100644 src/icons/arrow-left-circle-line.png create mode 100644 src/icons/arrow-left-line.png create mode 100644 src/icons/arrow-left-s-line.png create mode 100644 src/icons/arrow-right-circle-line.png create mode 100644 src/icons/arrow-right-line.png create mode 100644 src/icons/arrow-right-s-line.png create mode 100644 src/icons/arrow-up-s-line.png create mode 100644 src/icons/blur-off-line.png create mode 100644 src/icons/camera-off-line.png create mode 100644 src/icons/categories/art-and-design.png create mode 100644 src/icons/categories/books-and-reference.png create mode 100644 src/icons/categories/development.png create mode 100644 src/icons/categories/devices-and-iot.png create mode 100644 src/icons/categories/education.png create mode 100644 src/icons/categories/entertainment.png create mode 100644 src/icons/categories/featured.png create mode 100644 src/icons/categories/finance.png create mode 100644 src/icons/categories/games.png create mode 100644 src/icons/categories/health-and-fitness.png create mode 100644 src/icons/categories/music-and-audio.png create mode 100644 src/icons/categories/news-and-weather.png create mode 100644 src/icons/categories/personalisation.png create mode 100644 src/icons/categories/photo-and-video.png create mode 100644 src/icons/categories/productivity.png create mode 100644 src/icons/categories/science.png create mode 100644 src/icons/categories/security.png create mode 100644 src/icons/categories/server-and-cloud.png create mode 100644 src/icons/categories/social.png create mode 100644 src/icons/categories/utilities.png create mode 100644 src/icons/clipboard-line.png create mode 100644 src/icons/clockwise-fill.png create mode 100644 src/icons/clockwise-line.png create mode 100644 src/icons/close-fill.png create mode 100644 src/icons/compare-image-line.png create mode 100644 src/icons/crop-line.png create mode 100644 src/icons/delete-bin-3-line.png create mode 100644 src/icons/delete-bin-5-line.png create mode 100644 src/icons/disabled-arrow-left-circle-line.png create mode 100644 src/icons/disabled-arrow-right-circle-line.png create mode 100644 src/icons/download-line.png create mode 100644 src/icons/drag-move-fill.png create mode 100644 src/icons/error-warning-line.png create mode 100644 src/icons/eye-line.png create mode 100644 src/icons/facebook-box-line.png create mode 100644 src/icons/facebook-line.png create mode 100644 src/icons/file-copy-line.png create mode 100644 src/icons/file-text-line.png create mode 100644 src/icons/file-unknow-line.png create mode 100644 src/icons/filter-2-line.png create mode 100644 src/icons/focus-3-line.png create mode 100644 src/icons/folder-download-line.png create mode 100644 src/icons/folder-open-line.png create mode 100644 src/icons/fullscreen-line.png create mode 100644 src/icons/funds-line.png create mode 100644 src/icons/fx-line.png create mode 100644 src/icons/grid-line.png create mode 100644 src/icons/home-8-line.png create mode 100644 src/icons/icon-512.xcf create mode 100644 src/icons/image-2-line.png create mode 100644 src/icons/information-fill.png create mode 100644 src/icons/information-line.png create mode 100644 src/icons/link-unlink-m.png create mode 100644 src/icons/links-line.png create mode 100644 src/icons/loader-2-fill.png create mode 100644 src/icons/lock-2-fill.png create mode 100644 src/icons/lock-line.png create mode 100644 src/icons/lock-unlock-line.png create mode 100644 src/icons/magic-line.png create mode 100644 src/icons/mail-add-line.png create mode 100644 src/icons/mail-line.png create mode 100644 src/icons/map-pin-line.png create mode 100644 src/icons/movie-2-line.png create mode 100644 src/icons/music-2-line.png create mode 100644 src/icons/others/Histogram.png create mode 100644 src/icons/others/Omonitor.png create mode 100644 src/icons/others/greendot.png create mode 100644 src/icons/others/monitor.png create mode 100644 src/icons/others/snapcraft.png create mode 100644 src/icons/others/snapcraft.svg create mode 100644 src/icons/others/tt_tbc_head.png create mode 100644 src/icons/others/wall_placeholder_180.jpg create mode 100644 src/icons/pause-line.png create mode 100644 src/icons/paypal-line.png create mode 100644 src/icons/picture-in-picture-line.png create mode 100644 src/icons/play-fill.png create mode 100644 src/icons/play-line.png create mode 100644 src/icons/printer-line.png create mode 100644 src/icons/questionnaire-line.png create mode 100644 src/icons/record-circle-line.png create mode 100644 src/icons/refresh-line.png create mode 100644 src/icons/repeat-2-fill.png create mode 100644 src/icons/save-line.png create mode 100644 src/icons/scissors-cut-line.png create mode 100644 src/icons/screenshot-2-line.png create mode 100644 src/icons/search-2-line.png create mode 100644 src/icons/setting-line.png create mode 100644 src/icons/shape-2-line.png create mode 100644 src/icons/shape-line.png create mode 100644 src/icons/share-line.png create mode 100644 src/icons/shopping-cart-line.png create mode 100644 src/icons/sip-line.png create mode 100644 src/icons/split-cells-horizontal.png create mode 100644 src/icons/split-cells-vertical.png create mode 100644 src/icons/star-line.png create mode 100644 src/icons/stop-line.png create mode 100644 src/icons/swap-box-line.png create mode 100644 src/icons/terminal-box-line.png create mode 100644 src/icons/texture.png create mode 100644 src/icons/tiktok-downloader.png create mode 100644 src/icons/time-line.png create mode 100644 src/icons/translate-2.png create mode 100644 src/icons/twitter-line.png create mode 100644 src/icons/volume-mute-line.png create mode 100644 src/icons/volume-up-line.png create mode 100644 src/icons/white/stop-line.png create mode 100644 src/icons/white/white_arrow-left-line.png create mode 100644 src/icons/white/white_arrow-right-line.png create mode 100644 src/icons/white/white_picture-in-picture-line.png create mode 100644 src/icons/white/white_play-fill.png create mode 100644 src/icons/white/white_record-circle-line.png create mode 100644 src/icons/white/white_scissors-cut-line.png create mode 100644 src/icons/white/white_shape-2-line.png create mode 100644 src/icons/white/white_sip-line.png create mode 100644 src/icons/white/white_terminal-box-line.png create mode 100644 src/icons/youtube-line.png create mode 100644 src/icons/zoom-in-fill.png create mode 100644 src/icons/zoom-in-line.png create mode 100644 src/icons/zoom-out-fill.png create mode 100644 src/icons/zoom-out-line.png create mode 100644 src/main.cpp create mode 100644 src/mainwindow.cpp create mode 100644 src/mainwindow.h create mode 100644 src/notificationpopup.h create mode 100644 src/passworddialog.ui create mode 100644 src/requestinterceptor.h create mode 100644 src/settingswidget.cpp create mode 100644 src/settingswidget.h create mode 100644 src/settingswidget.ui create mode 100644 src/utils.cpp create mode 100644 src/utils.h create mode 100644 src/webenginepage.cpp create mode 100644 src/webenginepage.h create mode 100644 src/widgets/scrolltext/scrolltext.cpp create mode 100644 src/widgets/scrolltext/scrolltext.h diff --git a/src/WhatsApp.pro b/src/WhatsApp.pro new file mode 100644 index 0000000..95e6b33 --- /dev/null +++ b/src/WhatsApp.pro @@ -0,0 +1,87 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2020-03-26T13:53:21 +# +#------------------------------------------------- + +QT += core widgets webengine webenginewidgets + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + + +TARGET = whatsie +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Refer to the documentation for the +# deprecated API to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# No debug output in release mode +CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 + +# Set program version +VERSION = 1.0 +DEFINES += VERSIONSTR=\\\"$${VERSION}\\\" + +SOURCES += \ + downloadmanagerwidget.cpp \ + downloadwidget.cpp \ + elidedlabel.cpp \ + main.cpp \ + mainwindow.cpp \ + settingswidget.cpp \ + utils.cpp \ + webenginepage.cpp \ + widgets/scrolltext/scrolltext.cpp + +RESOURCES += \ + icons.qrc + +HEADERS += \ + common.h \ + downloadmanagerwidget.h \ + downloadwidget.h \ + elidedlabel.h \ + mainwindow.h \ + notificationpopup.h \ + requestinterceptor.h \ + settingswidget.h \ + utils.h \ + webenginepage.h \ + widgets/scrolltext/scrolltext.h + + +# Default rules for deployment. +isEmpty(PREFIX){ + PREFIX = /usr +} + +BINDIR = $$PREFIX/bin +DATADIR = $$PREFIX/share + +target.path = $$BINDIR + +icon.files = icons/linguist.png +icon.path = $$DATADIR/icons/hicolor/512x512/apps/ + +desktop.files = linguist.desktop +desktop.path = $$DATADIR/applications/ + +INSTALLS += target icon desktop + +FORMS += \ + certificateerrordialog.ui \ + downloadmanagerwidget.ui \ + downloadwidget.ui \ + passworddialog.ui \ + settingswidget.ui + diff --git a/src/certificateerrordialog.ui b/src/certificateerrordialog.ui new file mode 100644 index 0000000..a14a784 --- /dev/null +++ b/src/certificateerrordialog.ui @@ -0,0 +1,133 @@ + + + CertificateErrorDialog + + + + 0 + 0 + 370 + 141 + + + + Dialog + + + + 20 + + + 20 + + + + + Icon + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Error + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + If you wish so, you may continue with an unverified certificate. Accepting an unverified certificate mean you may not be connected with the host you tried to connect to. + +Do you wish to override the security check and continue ? + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 16 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::No|QDialogButtonBox::Yes + + + + + + + + + buttonBox + accepted() + CertificateErrorDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CertificateErrorDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..261ee64 --- /dev/null +++ b/src/common.h @@ -0,0 +1,7 @@ +#ifndef COMMON_H +#define COMMON_H +#include + +QString defaultUserAgentStr = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.4389.114 Safari/537.36"; + +#endif // COMMON_H diff --git a/src/downloadmanagerwidget.cpp b/src/downloadmanagerwidget.cpp new file mode 100644 index 0000000..1a0fa27 --- /dev/null +++ b/src/downloadmanagerwidget.cpp @@ -0,0 +1,44 @@ +#include "downloadmanagerwidget.h" + +#include "downloadwidget.h" + +#include +#include + +DownloadManagerWidget::DownloadManagerWidget(QWidget *parent) + : QWidget(parent) + , m_numDownloads(0) +{ + setupUi(this); +} + +void DownloadManagerWidget::downloadRequested(QWebEngineDownloadItem *download) +{ + //Q_ASSERT(download && download->state() == QWebEngineDownloadItem::DownloadRequested); + + QString path = QFileDialog::getSaveFileName(this, tr("Save as"), download->path(),tr("Any file (*)"),nullptr,QFileDialog::DontUseNativeDialog); + if (path.isEmpty()) + return; + + download->setPath(path); + download->accept(); + add(new DownloadWidget(download)); + + show(); +} + +void DownloadManagerWidget::add(DownloadWidget *downloadWidget) +{ + connect(downloadWidget, &DownloadWidget::removeClicked, this, &DownloadManagerWidget::remove); + m_itemsLayout->insertWidget(0, downloadWidget, 0, Qt::AlignTop); + if (m_numDownloads++ == 0) + m_zeroItemsLabel->hide(); +} + +void DownloadManagerWidget::remove(DownloadWidget *downloadWidget) +{ + m_itemsLayout->removeWidget(downloadWidget); + downloadWidget->deleteLater(); + if (--m_numDownloads == 0) + m_zeroItemsLabel->show(); +} diff --git a/src/downloadmanagerwidget.h b/src/downloadmanagerwidget.h new file mode 100644 index 0000000..cca092b --- /dev/null +++ b/src/downloadmanagerwidget.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOWNLOADMANAGERWIDGET_H +#define DOWNLOADMANAGERWIDGET_H + +#include "ui_downloadmanagerwidget.h" + +#include + +QT_BEGIN_NAMESPACE +class QWebEngineDownloadItem; +QT_END_NAMESPACE + +class DownloadWidget; + +// Displays a list of downloads. +class DownloadManagerWidget final : public QWidget, public Ui::DownloadManagerWidget +{ + Q_OBJECT +public: + explicit DownloadManagerWidget(QWidget *parent = nullptr); + + // Prompts user with a "Save As" dialog. If the user doesn't cancel it, then + // the QWebEngineDownloadItem will be accepted and the DownloadManagerWidget + // will be shown on the screen. + void downloadRequested(QWebEngineDownloadItem *webItem); + +private: + void add(DownloadWidget *downloadWidget); + void remove(DownloadWidget *downloadWidget); + + int m_numDownloads; +}; + +#endif // DOWNLOADMANAGERWIDGET_H diff --git a/src/downloadmanagerwidget.ui b/src/downloadmanagerwidget.ui new file mode 100644 index 0000000..8b815d0 --- /dev/null +++ b/src/downloadmanagerwidget.ui @@ -0,0 +1,123 @@ + + + DownloadManagerWidget + + + + 0 + 0 + 452 + 250 + + + + + 400 + 250 + + + + Downloads + + + + + + + QLayout::SetNoConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 450 + 248 + + + + + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + color: palette(shadow) + + + No downloads + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + diff --git a/src/downloadwidget.cpp b/src/downloadwidget.cpp new file mode 100644 index 0000000..005ea1e --- /dev/null +++ b/src/downloadwidget.cpp @@ -0,0 +1,108 @@ +#include "downloadwidget.h" + +#include +#include +#include + +DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent) + : QFrame(parent) + , m_download(download) + , m_timeAdded(QTime::currentTime()) +{ + setupUi(this); + m_dstName->setText(QFileInfo(m_download->path()).fileName()); + m_srcUrl->setText(m_download->url().toDisplayString()); + + connect(m_cancelButton, &QPushButton::clicked, + [this](bool) { + if (m_download->state() == QWebEngineDownloadItem::DownloadInProgress) + m_download->cancel(); + else + emit removeClicked(this); + }); + + connect(m_download, &QWebEngineDownloadItem::downloadProgress, + this, &DownloadWidget::updateWidget); + + connect(m_download, &QWebEngineDownloadItem::stateChanged, + this, &DownloadWidget::updateWidget); + + updateWidget(); +} + +inline QString DownloadWidget::withUnit(qreal bytes) +{ + if (bytes < (1 << 10)) + return tr("%L1 B").arg(bytes); + else if (bytes < (1 << 20)) + return tr("%L1 KiB").arg(bytes / (1 << 10), 0, 'f', 2); + else if (bytes < (1 << 30)) + return tr("%L1 MiB").arg(bytes / (1 << 20), 0, 'f', 2); + else + return tr("%L1 GiB").arg(bytes / (1 << 30), 0, 'f', 2); +} + +void DownloadWidget::updateWidget() +{ + qreal totalBytes = m_download->totalBytes(); + qreal receivedBytes = m_download->receivedBytes(); + qreal bytesPerSecond = receivedBytes / m_timeAdded.elapsed() * 1000; + + auto state = m_download->state(); + switch (state) { + case QWebEngineDownloadItem::DownloadRequested: + Q_UNREACHABLE(); + break; + case QWebEngineDownloadItem::DownloadInProgress: + if (totalBytes >= 0) { + m_progressBar->setValue(qRound(100 * receivedBytes / totalBytes)); + m_progressBar->setDisabled(false); + m_progressBar->setFormat( + tr("%p% - %1 of %2 downloaded - %3/s") + .arg(withUnit(receivedBytes)) + .arg(withUnit(totalBytes)) + .arg(withUnit(bytesPerSecond))); + } else { + m_progressBar->setValue(0); + m_progressBar->setDisabled(false); + m_progressBar->setFormat( + tr("unknown size - %1 downloaded - %2/s") + .arg(withUnit(receivedBytes)) + .arg(withUnit(bytesPerSecond))); + } + break; + case QWebEngineDownloadItem::DownloadCompleted: + m_progressBar->setValue(100); + m_progressBar->setDisabled(true); + m_progressBar->setFormat( + tr("completed - %1 downloaded - %2/s") + .arg(withUnit(receivedBytes)) + .arg(withUnit(bytesPerSecond))); + break; + case QWebEngineDownloadItem::DownloadCancelled: + m_progressBar->setValue(0); + m_progressBar->setDisabled(true); + m_progressBar->setFormat( + tr("cancelled - %1 downloaded - %2/s") + .arg(withUnit(receivedBytes)) + .arg(withUnit(bytesPerSecond))); + break; + case QWebEngineDownloadItem::DownloadInterrupted: + m_progressBar->setValue(0); + m_progressBar->setDisabled(true); + m_progressBar->setFormat( + tr("interrupted: %1") + .arg(m_download->interruptReasonString())); + break; + } + + if (state == QWebEngineDownloadItem::DownloadInProgress) { + static QIcon cancelIcon(QStringLiteral(":/icons/stop-line.png")); + m_cancelButton->setIcon(cancelIcon); + m_cancelButton->setToolTip(tr("Stop downloading")); + } else { + static QIcon removeIcon(QStringLiteral(":/icons/close-fill.png")); + m_cancelButton->setIcon(removeIcon); + m_cancelButton->setToolTip(tr("Remove from list")); + } +} diff --git a/src/downloadwidget.h b/src/downloadwidget.h new file mode 100644 index 0000000..521d996 --- /dev/null +++ b/src/downloadwidget.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOWNLOADWIDGET_H +#define DOWNLOADWIDGET_H + +#include "ui_downloadwidget.h" +#include "elidedlabel.h" + + +#include +#include + +QT_BEGIN_NAMESPACE +class QWebEngineDownloadItem; +QT_END_NAMESPACE + +// Displays one ongoing or finished download (QWebEngineDownloadItem). +class DownloadWidget final : public QFrame, public Ui::DownloadWidget +{ + Q_OBJECT +public: + // Precondition: The QWebEngineDownloadItem has been accepted. + explicit DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent = nullptr); + +signals: + // This signal is emitted when the user indicates that they want to remove + // this download from the downloads list. + void removeClicked(DownloadWidget *self); + +private slots: + void updateWidget(); + +private: + QString withUnit(qreal bytes); + + QWebEngineDownloadItem *m_download; + QTime m_timeAdded; +}; + +#endif // DOWNLOADWIDGET_H diff --git a/src/downloadwidget.ui b/src/downloadwidget.ui new file mode 100644 index 0000000..d405b8f --- /dev/null +++ b/src/downloadwidget.ui @@ -0,0 +1,80 @@ + + + DownloadWidget + + + + 0 + 0 + 526 + 97 + + + + + + + + QLayout::SetMinAndMaxSize + + + + + + + + TextLabel + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + + 75 + true + + + + TextLabel + + + + + + + + + + 24 + + + + + + + + ElidedLabel + QLabel +
elidedlabel.h
+
+
+ + +
diff --git a/src/elidedlabel.cpp b/src/elidedlabel.cpp new file mode 100644 index 0000000..6c14af4 --- /dev/null +++ b/src/elidedlabel.cpp @@ -0,0 +1,49 @@ +#include "elidedlabel.h" + +#include +#include +#include +#include + +ElidedLabel::ElidedLabel(QWidget* parent, Qt::WindowFlags f) + : QLabel(parent, f), m_elide_mode(Qt::ElideRight) { + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); +} + +ElidedLabel::ElidedLabel(const QString& txt, QWidget* parent, Qt::WindowFlags f) + : QLabel(txt, parent, f), m_elide_mode(Qt::ElideRight) { + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); +} + +ElidedLabel::ElidedLabel(const QString& txt, Qt::TextElideMode elideMode, QWidget* parent, Qt::WindowFlags f) + : QLabel(txt, parent, f), m_elide_mode(elideMode) { + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + +} + +void ElidedLabel::setText(const QString& txt) { + QLabel::setText(txt); + cacheElidedText(geometry().width()); + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); +} + + +void ElidedLabel::cacheElidedText(int w) { + m_cached_elided_text = fontMetrics().elidedText(text(), m_elide_mode, w, (buddy() == nullptr)? 0 : Qt::TextShowMnemonic); +} + +void ElidedLabel::resizeEvent(QResizeEvent* e) { + QLabel::resizeEvent(e); + cacheElidedText(e->size().width()); +} + +void ElidedLabel::paintEvent(QPaintEvent* e) { + if(m_elide_mode == Qt::ElideNone) { + QLabel::paintEvent(e); + } else { + QPainter p(this); + p.drawText(0, 0, geometry().width(), geometry().height(), + QStyle::visualAlignment(text().isRightToLeft()? Qt::RightToLeft : Qt::LeftToRight, alignment()) | ((buddy() == nullptr)? 0 : Qt::TextShowMnemonic), + m_cached_elided_text); + } +} diff --git a/src/elidedlabel.h b/src/elidedlabel.h new file mode 100644 index 0000000..1ce5210 --- /dev/null +++ b/src/elidedlabel.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include +#include + +// A label that elides its text when not enough geometry is available to show all of the text. +// Currently only capable of one-line. +class ElidedLabel : public QLabel { + Q_OBJECT + +private: + Qt::TextElideMode m_elide_mode; + QString m_cached_elided_text; + + +public: + ElidedLabel(QWidget* parent = NULL, Qt::WindowFlags f = 0); + ElidedLabel(const QString& txt, QWidget* parent = NULL, Qt::WindowFlags f = 0); + ElidedLabel(const QString& txt, Qt::TextElideMode elideMode = Qt::ElideRight, QWidget* parent = NULL, Qt::WindowFlags f = 0); + +public: + // Set the elide mode used for displaying text. + inline void setElideMode(Qt::TextElideMode elideMode) { + m_elide_mode = elideMode; + updateGeometry(); + } + + // Get the elide mode currently used to display text. + inline Qt::TextElideMode elideMode() const { + return m_elide_mode; + } + + + +public: // QLabel overrides + void setText(const QString&); // note: not virtual so no polymorphism ... + + +protected: // QLabel overrides + virtual void paintEvent(QPaintEvent*) override; + virtual void resizeEvent(QResizeEvent*) override; + +protected: + // Cache the elided text so as to not recompute it every paint event + void cacheElidedText(int w); + +}; diff --git a/src/icons.qrc b/src/icons.qrc new file mode 100644 index 0000000..5a346e3 --- /dev/null +++ b/src/icons.qrc @@ -0,0 +1,147 @@ + + + icons/texture.png + icons/arrow-left-circle-line.png + icons/refresh-line.png + icons/arrow-right-circle-line.png + icons/disabled-arrow-left-circle-line.png + icons/disabled-arrow-right-circle-line.png + icons/download-line.png + icons/image-2-line.png + icons/setting-line.png + icons/map-pin-line.png + icons/folder-open-line.png + icons/paypal-line.png + icons/links-line.png + icons/star-line.png + icons/folder-download-line.png + icons/lock-2-fill.png + icons/questionnaire-line.png + icons/volume-up-line.png + icons/swap-box-line.png + icons/clipboard-line.png + icons/close-fill.png + icons/archive-drawer-line.png + icons/file-copy-line.png + icons/translate-2.png + icons/magic-line.png + icons/twitter-line.png + icons/mail-add-line.png + icons/file-text-line.png + icons/facebook-box-line.png + icons/stop-line.png + icons/loader-2-fill.png + icons/share-line.png + icons/error-warning-line.png + icons/play-line.png + icons/time-line.png + icons/pause-line.png + icons/focus-3-line.png + icons/arrow-right-s-line.png + icons/arrow-left-s-line.png + icons/drag-move-fill.png + icons/volume-mute-line.png + icons/scissors-cut-line.png + icons/play-fill.png + icons/screenshot-2-line.png + icons/search-2-line.png + icons/youtube-line.png + icons/terminal-box-line.png + icons/sip-line.png + icons/shape-2-line.png + icons/record-circle-line.png + icons/repeat-2-fill.png + icons/camera-off-line.png + icons/link-unlink-m.png + icons/eye-line.png + icons/information-fill.png + icons/information-line.png + icons/delete-bin-5-line.png + icons/delete-bin-3-line.png + icons/movie-2-line.png + icons/music-2-line.png + icons/file-unknow-line.png + icons/arrow-left-line.png + icons/arrow-right-line.png + icons/filter-2-line.png + icons/arrow-up-s-line.png + icons/arrow-down-s-line.png + icons/account-pin-circle-line.png + icons/shopping-cart-line.png + icons/picture-in-picture-line.png + icons/home-8-line.png + icons/white/white_scissors-cut-line.png + icons/white/white_play-fill.png + icons/white/white_terminal-box-line.png + icons/white/white_shape-2-line.png + icons/white/white_sip-line.png + icons/white/white_record-circle-line.png + icons/white/stop-line.png + icons/white/white_arrow-right-line.png + icons/white/white_arrow-left-line.png + icons/white/white_picture-in-picture-line.png + icons/others/monitor.png + icons/others/wall_placeholder_180.jpg + icons/categories/devices-and-iot.png + icons/categories/social.png + icons/categories/server-and-cloud.png + icons/categories/security.png + icons/categories/productivity.png + icons/categories/photo-and-video.png + icons/categories/art-and-design.png + icons/categories/personalisation.png + icons/categories/news-and-weather.png + icons/categories/music-and-audio.png + icons/categories/health-and-fitness.png + icons/categories/games.png + icons/categories/finance.png + icons/categories/featured.png + icons/categories/entertainment.png + icons/categories/education.png + icons/categories/science.png + icons/categories/development.png + icons/categories/books-and-reference.png + icons/categories/utilities.png + icons/others/snapcraft.png + icons/mail-line.png + icons/app/icon-256.png + icons/app/icon-128.png + icons/app/icon-64.png + icons/app/icon-32.png + icons/app/icon-16.png + icons/app/icon-512.png + icons/app/resize.sh + icons/others/greendot.png + icons/anticlockwise-line.png + icons/arrow-go-back-line.png + icons/arrow-go-forward-line.png + icons/clockwise-line.png + icons/crop-line.png + icons/facebook-line.png + icons/printer-line.png + icons/save-line.png + icons/grid-line.png + icons/shape-line.png + icons/compare-image-line.png + icons/fx-line.png + icons/zoom-out-line.png + icons/zoom-out-fill.png + icons/zoom-in-line.png + icons/zoom-in-fill.png + icons/split-cells-vertical.png + icons/split-cells-horizontal.png + icons/fullscreen-line.png + icons/clockwise-fill.png + icons/anticlockwise-fill.png + icons/others/Histogram.png + icons/tiktok-downloader.png + icons/icon-512.xcf + icons/blur-off-line.png + icons/lock-line.png + icons/lock-unlock-line.png + icons/funds-line.png + icons/others/tt_tbc_head.png + icons/app/whatsapp-message.svg + icons/app/whatsapp.svg + + diff --git a/src/icons/account-pin-circle-line.png b/src/icons/account-pin-circle-line.png new file mode 100644 index 0000000..1e70a3d Binary files /dev/null and b/src/icons/account-pin-circle-line.png differ diff --git a/src/icons/anticlockwise-fill.png b/src/icons/anticlockwise-fill.png new file mode 100644 index 0000000..908a15a Binary files /dev/null and b/src/icons/anticlockwise-fill.png differ diff --git a/src/icons/anticlockwise-line.png b/src/icons/anticlockwise-line.png new file mode 100644 index 0000000..8cd98de Binary files /dev/null and b/src/icons/anticlockwise-line.png differ diff --git a/src/icons/app/icon-128.png b/src/icons/app/icon-128.png new file mode 100644 index 0000000..f625123 Binary files /dev/null and b/src/icons/app/icon-128.png differ diff --git a/src/icons/app/icon-16.png b/src/icons/app/icon-16.png new file mode 100644 index 0000000..e3ada9b Binary files /dev/null and b/src/icons/app/icon-16.png differ diff --git a/src/icons/app/icon-256.png b/src/icons/app/icon-256.png new file mode 100644 index 0000000..2e5155d Binary files /dev/null and b/src/icons/app/icon-256.png differ diff --git a/src/icons/app/icon-32.png b/src/icons/app/icon-32.png new file mode 100644 index 0000000..8b47514 Binary files /dev/null and b/src/icons/app/icon-32.png differ diff --git a/src/icons/app/icon-512.png b/src/icons/app/icon-512.png new file mode 100644 index 0000000..7974220 Binary files /dev/null and b/src/icons/app/icon-512.png differ diff --git a/src/icons/app/icon-64.png b/src/icons/app/icon-64.png new file mode 100644 index 0000000..175c8fb Binary files /dev/null and b/src/icons/app/icon-64.png differ diff --git a/src/icons/app/resize.sh b/src/icons/app/resize.sh new file mode 100755 index 0000000..a2fd54b --- /dev/null +++ b/src/icons/app/resize.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +# Edit the settings below: + +# Output sizes - +# Please note the format: each size is wrapped with quotes, width and height are separated with space. +output=("16 16" "32 32" "64 64" "128 128" "256 256" "512 512" ) + +# If you frequently use the same source file (f.e. "~/Desktop/src.jpg"), +# set it in "default_src" +default_src=""; + +# If you frequently use the same destination +# (f.e. "~/Desktop/Some_folder/%.jpg"), set it in "default_dst" +# Destination must include "%", it will be replaced by output size, f.e. "800x600" +default_dst="%.png"; + +# Add signature? +default_sign='n' + +# If you frequently use the same signature file (f.e. "~/Desktop/sig.png"), +# set it in "default_sig" +default_sig=""; + +# Gravity is for cropping left/right edges for different proportions (center, east, west) +default_gravity="center" + +# Output JPG quality: maximum is 100 (recommended) +quality=100 + +# ====== +# Do not edit below. +# ====== +# Welcome to Smashing resizer! +# Written by Vlad Gerasimov from http://www.vladstudio.com +# +# This script takes one "source" image and saves it in different sizes. +# +# Requires: +# * imagemagick - http://www.imagemagick.org/ +# * python - I'm sure your PC already has it! + + + +# Unfortunately, bash is awful at math operations. +# We'll create a simple function that handles math for us. +# Example: $(math 2 * 2) + +function math(){ + echo $(python -c "from __future__ import division; print $@") +} + + + +# To make our script short and nice, here is the "save()" function. +# We'll use it to save each size. + +function save(){ + + # read target width and height from function parameters + local dst_w=${1} + local dst_h=${2} + + # calculate ratio + local ratio=$(math $dst_w/$dst_h); + + # calculate "intermediate" width and height + local inter_w=$(math "int(round($src_h*$ratio))") + local inter_h=${src_h} + + # which size we're saving now + #local size="${dst_w}x${dst_h}" + local size="${dst_w}" + echo "Saving ${size}..." + + #crop intermediate image (with target ratio) + convert ${src} -gravity ${gravity} -crop ${inter_w}x${inter_h}+0+0 +repage temp.psd + + # apply signature + if [ "${sign}" == "y" ]; then + convert temp.psd ${sig} -gravity southeast -geometry ${sig_w}x${sig_h}+24+48 -composite temp.psd + fi + + ## For best quality, I resize image 80%, sharpen 3 times, then repeat. + + # setup resize filter and unsharp parameters (calculated through trial and error) + local arguments="-interpolate bicubic -filter Lagrange" + local unsharp="-unsharp 0.4x0.4+0.4+0.008" + + # scale 80%, sharpen, repeat until less than 150% of target size + local current_w=${dst_w} + + # pardon moi for such ugly while condition! + while [ $(math "${current_w}/${dst_w} > 1.5") = "True" ]; do + current_w=$(math ${current_w}\*0\.80) + current_w=$(math "int(round(${current_w}))") + arguments="${arguments} -resize 80% +repage ${unsharp} ${unsharp} ${unsharp} " + done + + # final resize + arguments="${arguments} -resize ${dst_w}x${dst_h}! +repage ${unsharp} ${unsharp} ${unsharp} -density 72x72 +repage" + + # final convert! resize, sharpen, save + convert temp.psd ${arguments} -quality ${quality} ${dst/\%/${size}} + +} + +# Ask for source image, or use default value +echo "Enter path to source image, or hit Enter to keep default value (${default_src}): " +read src +src=${src:-${default_src}} + +# ask for destination path, or use default value +echo "Enter destination path, or hit Enter to keep default value (${default_dst})." +echo "must include % symbol, it will be replaced by output size, f.e. '800x600'" +read dst +dst=${dst:-${default_dst}} + +# Ask for signature image, or use default value +echo "Apply signature? (hit Enter for 'yes' or type 'n' for 'no') " +read sign +sign=${sign:-${default_sign}} + +# Ask for signature image, or use default value +echo "Enter path to signature image, or hit Enter to keep default value (${default_sig}): " +read sig +sig=${sig:-${default_sig}} + +# ask for gravity, or use default value +echo "Enter gravity for cropping left/right edges (center, east, west), or hit Enter to keep default value (${default_gravity}): " +read gravity +gravity=${gravity:-${default_gravity}} + + +# detect source image width and height +src_w=$(identify -format "%w" "${src}") +src_h=$(identify -format "%h" "${src}") + +# detect signature width and height +if [ "${sign}" == "y" ]; then + sig_w=$(identify -format "%w" "${sig}") + sig_h=$(identify -format "%h" "${sig}") +fi + +# loop throught output sizes and save each size +for i in "${output[@]}" +do + save ${i} +done + +# Delete temporary file +rm temp.psd + +# Done! +echo "Done!" diff --git a/src/icons/app/whatsapp-message.svg b/src/icons/app/whatsapp-message.svg new file mode 100644 index 0000000..7f56fa4 --- /dev/null +++ b/src/icons/app/whatsapp-message.svg @@ -0,0 +1,94 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/icons/app/whatsapp.svg b/src/icons/app/whatsapp.svg new file mode 100644 index 0000000..0b81505 --- /dev/null +++ b/src/icons/app/whatsapp.svg @@ -0,0 +1,81 @@ + +image/svg+xml \ No newline at end of file diff --git a/src/icons/archive-drawer-line.png b/src/icons/archive-drawer-line.png new file mode 100644 index 0000000..c770801 Binary files /dev/null and b/src/icons/archive-drawer-line.png differ diff --git a/src/icons/arrow-down-s-line.png b/src/icons/arrow-down-s-line.png new file mode 100644 index 0000000..ab85daa Binary files /dev/null and b/src/icons/arrow-down-s-line.png differ diff --git a/src/icons/arrow-go-back-line.png b/src/icons/arrow-go-back-line.png new file mode 100644 index 0000000..1081e0a Binary files /dev/null and b/src/icons/arrow-go-back-line.png differ diff --git a/src/icons/arrow-go-forward-line.png b/src/icons/arrow-go-forward-line.png new file mode 100644 index 0000000..ef65a0a Binary files /dev/null and b/src/icons/arrow-go-forward-line.png differ diff --git a/src/icons/arrow-left-circle-line.png b/src/icons/arrow-left-circle-line.png new file mode 100644 index 0000000..4d9d808 Binary files /dev/null and b/src/icons/arrow-left-circle-line.png differ diff --git a/src/icons/arrow-left-line.png b/src/icons/arrow-left-line.png new file mode 100644 index 0000000..411f8d5 Binary files /dev/null and b/src/icons/arrow-left-line.png differ diff --git a/src/icons/arrow-left-s-line.png b/src/icons/arrow-left-s-line.png new file mode 100644 index 0000000..6c34c72 Binary files /dev/null and b/src/icons/arrow-left-s-line.png differ diff --git a/src/icons/arrow-right-circle-line.png b/src/icons/arrow-right-circle-line.png new file mode 100644 index 0000000..a993751 Binary files /dev/null and b/src/icons/arrow-right-circle-line.png differ diff --git a/src/icons/arrow-right-line.png b/src/icons/arrow-right-line.png new file mode 100644 index 0000000..9085577 Binary files /dev/null and b/src/icons/arrow-right-line.png differ diff --git a/src/icons/arrow-right-s-line.png b/src/icons/arrow-right-s-line.png new file mode 100644 index 0000000..6c1aaa5 Binary files /dev/null and b/src/icons/arrow-right-s-line.png differ diff --git a/src/icons/arrow-up-s-line.png b/src/icons/arrow-up-s-line.png new file mode 100644 index 0000000..04b0500 Binary files /dev/null and b/src/icons/arrow-up-s-line.png differ diff --git a/src/icons/blur-off-line.png b/src/icons/blur-off-line.png new file mode 100644 index 0000000..1d20104 Binary files /dev/null and b/src/icons/blur-off-line.png differ diff --git a/src/icons/camera-off-line.png b/src/icons/camera-off-line.png new file mode 100644 index 0000000..f748ce5 Binary files /dev/null and b/src/icons/camera-off-line.png differ diff --git a/src/icons/categories/art-and-design.png b/src/icons/categories/art-and-design.png new file mode 100644 index 0000000..706dcdd Binary files /dev/null and b/src/icons/categories/art-and-design.png differ diff --git a/src/icons/categories/books-and-reference.png b/src/icons/categories/books-and-reference.png new file mode 100644 index 0000000..9684a3c Binary files /dev/null and b/src/icons/categories/books-and-reference.png differ diff --git a/src/icons/categories/development.png b/src/icons/categories/development.png new file mode 100644 index 0000000..b81758b Binary files /dev/null and b/src/icons/categories/development.png differ diff --git a/src/icons/categories/devices-and-iot.png b/src/icons/categories/devices-and-iot.png new file mode 100644 index 0000000..b81ee28 Binary files /dev/null and b/src/icons/categories/devices-and-iot.png differ diff --git a/src/icons/categories/education.png b/src/icons/categories/education.png new file mode 100644 index 0000000..5d474c4 Binary files /dev/null and b/src/icons/categories/education.png differ diff --git a/src/icons/categories/entertainment.png b/src/icons/categories/entertainment.png new file mode 100644 index 0000000..53bf12b Binary files /dev/null and b/src/icons/categories/entertainment.png differ diff --git a/src/icons/categories/featured.png b/src/icons/categories/featured.png new file mode 100644 index 0000000..0bc0e29 Binary files /dev/null and b/src/icons/categories/featured.png differ diff --git a/src/icons/categories/finance.png b/src/icons/categories/finance.png new file mode 100644 index 0000000..c6edb26 Binary files /dev/null and b/src/icons/categories/finance.png differ diff --git a/src/icons/categories/games.png b/src/icons/categories/games.png new file mode 100644 index 0000000..2578a5f Binary files /dev/null and b/src/icons/categories/games.png differ diff --git a/src/icons/categories/health-and-fitness.png b/src/icons/categories/health-and-fitness.png new file mode 100644 index 0000000..bf36890 Binary files /dev/null and b/src/icons/categories/health-and-fitness.png differ diff --git a/src/icons/categories/music-and-audio.png b/src/icons/categories/music-and-audio.png new file mode 100644 index 0000000..a226a08 Binary files /dev/null and b/src/icons/categories/music-and-audio.png differ diff --git a/src/icons/categories/news-and-weather.png b/src/icons/categories/news-and-weather.png new file mode 100644 index 0000000..97b5fe2 Binary files /dev/null and b/src/icons/categories/news-and-weather.png differ diff --git a/src/icons/categories/personalisation.png b/src/icons/categories/personalisation.png new file mode 100644 index 0000000..352226f Binary files /dev/null and b/src/icons/categories/personalisation.png differ diff --git a/src/icons/categories/photo-and-video.png b/src/icons/categories/photo-and-video.png new file mode 100644 index 0000000..554a3cb Binary files /dev/null and b/src/icons/categories/photo-and-video.png differ diff --git a/src/icons/categories/productivity.png b/src/icons/categories/productivity.png new file mode 100644 index 0000000..0bb33f4 Binary files /dev/null and b/src/icons/categories/productivity.png differ diff --git a/src/icons/categories/science.png b/src/icons/categories/science.png new file mode 100644 index 0000000..069e83a Binary files /dev/null and b/src/icons/categories/science.png differ diff --git a/src/icons/categories/security.png b/src/icons/categories/security.png new file mode 100644 index 0000000..22132a5 Binary files /dev/null and b/src/icons/categories/security.png differ diff --git a/src/icons/categories/server-and-cloud.png b/src/icons/categories/server-and-cloud.png new file mode 100644 index 0000000..0a69247 Binary files /dev/null and b/src/icons/categories/server-and-cloud.png differ diff --git a/src/icons/categories/social.png b/src/icons/categories/social.png new file mode 100644 index 0000000..39e5478 Binary files /dev/null and b/src/icons/categories/social.png differ diff --git a/src/icons/categories/utilities.png b/src/icons/categories/utilities.png new file mode 100644 index 0000000..95a642d Binary files /dev/null and b/src/icons/categories/utilities.png differ diff --git a/src/icons/clipboard-line.png b/src/icons/clipboard-line.png new file mode 100644 index 0000000..18ba32d Binary files /dev/null and b/src/icons/clipboard-line.png differ diff --git a/src/icons/clockwise-fill.png b/src/icons/clockwise-fill.png new file mode 100644 index 0000000..75a577d Binary files /dev/null and b/src/icons/clockwise-fill.png differ diff --git a/src/icons/clockwise-line.png b/src/icons/clockwise-line.png new file mode 100644 index 0000000..6bf7aca Binary files /dev/null and b/src/icons/clockwise-line.png differ diff --git a/src/icons/close-fill.png b/src/icons/close-fill.png new file mode 100644 index 0000000..63fbd29 Binary files /dev/null and b/src/icons/close-fill.png differ diff --git a/src/icons/compare-image-line.png b/src/icons/compare-image-line.png new file mode 100644 index 0000000..f080138 Binary files /dev/null and b/src/icons/compare-image-line.png differ diff --git a/src/icons/crop-line.png b/src/icons/crop-line.png new file mode 100644 index 0000000..edf9098 Binary files /dev/null and b/src/icons/crop-line.png differ diff --git a/src/icons/delete-bin-3-line.png b/src/icons/delete-bin-3-line.png new file mode 100644 index 0000000..bf62d84 Binary files /dev/null and b/src/icons/delete-bin-3-line.png differ diff --git a/src/icons/delete-bin-5-line.png b/src/icons/delete-bin-5-line.png new file mode 100644 index 0000000..947a403 Binary files /dev/null and b/src/icons/delete-bin-5-line.png differ diff --git a/src/icons/disabled-arrow-left-circle-line.png b/src/icons/disabled-arrow-left-circle-line.png new file mode 100644 index 0000000..67769ff Binary files /dev/null and b/src/icons/disabled-arrow-left-circle-line.png differ diff --git a/src/icons/disabled-arrow-right-circle-line.png b/src/icons/disabled-arrow-right-circle-line.png new file mode 100644 index 0000000..078e72a Binary files /dev/null and b/src/icons/disabled-arrow-right-circle-line.png differ diff --git a/src/icons/download-line.png b/src/icons/download-line.png new file mode 100644 index 0000000..a8f6cec Binary files /dev/null and b/src/icons/download-line.png differ diff --git a/src/icons/drag-move-fill.png b/src/icons/drag-move-fill.png new file mode 100644 index 0000000..1e8b211 Binary files /dev/null and b/src/icons/drag-move-fill.png differ diff --git a/src/icons/error-warning-line.png b/src/icons/error-warning-line.png new file mode 100644 index 0000000..9c6e522 Binary files /dev/null and b/src/icons/error-warning-line.png differ diff --git a/src/icons/eye-line.png b/src/icons/eye-line.png new file mode 100644 index 0000000..c856fa5 Binary files /dev/null and b/src/icons/eye-line.png differ diff --git a/src/icons/facebook-box-line.png b/src/icons/facebook-box-line.png new file mode 100644 index 0000000..c3c9a35 Binary files /dev/null and b/src/icons/facebook-box-line.png differ diff --git a/src/icons/facebook-line.png b/src/icons/facebook-line.png new file mode 100644 index 0000000..e0a5205 Binary files /dev/null and b/src/icons/facebook-line.png differ diff --git a/src/icons/file-copy-line.png b/src/icons/file-copy-line.png new file mode 100644 index 0000000..f07fbcb Binary files /dev/null and b/src/icons/file-copy-line.png differ diff --git a/src/icons/file-text-line.png b/src/icons/file-text-line.png new file mode 100644 index 0000000..93be6b6 Binary files /dev/null and b/src/icons/file-text-line.png differ diff --git a/src/icons/file-unknow-line.png b/src/icons/file-unknow-line.png new file mode 100644 index 0000000..30ceffc Binary files /dev/null and b/src/icons/file-unknow-line.png differ diff --git a/src/icons/filter-2-line.png b/src/icons/filter-2-line.png new file mode 100644 index 0000000..04b127c Binary files /dev/null and b/src/icons/filter-2-line.png differ diff --git a/src/icons/focus-3-line.png b/src/icons/focus-3-line.png new file mode 100644 index 0000000..acd8380 Binary files /dev/null and b/src/icons/focus-3-line.png differ diff --git a/src/icons/folder-download-line.png b/src/icons/folder-download-line.png new file mode 100644 index 0000000..a971c93 Binary files /dev/null and b/src/icons/folder-download-line.png differ diff --git a/src/icons/folder-open-line.png b/src/icons/folder-open-line.png new file mode 100644 index 0000000..7049366 Binary files /dev/null and b/src/icons/folder-open-line.png differ diff --git a/src/icons/fullscreen-line.png b/src/icons/fullscreen-line.png new file mode 100644 index 0000000..788249d Binary files /dev/null and b/src/icons/fullscreen-line.png differ diff --git a/src/icons/funds-line.png b/src/icons/funds-line.png new file mode 100644 index 0000000..3c38303 Binary files /dev/null and b/src/icons/funds-line.png differ diff --git a/src/icons/fx-line.png b/src/icons/fx-line.png new file mode 100644 index 0000000..e443c06 Binary files /dev/null and b/src/icons/fx-line.png differ diff --git a/src/icons/grid-line.png b/src/icons/grid-line.png new file mode 100644 index 0000000..dae2987 Binary files /dev/null and b/src/icons/grid-line.png differ diff --git a/src/icons/home-8-line.png b/src/icons/home-8-line.png new file mode 100644 index 0000000..5811472 Binary files /dev/null and b/src/icons/home-8-line.png differ diff --git a/src/icons/icon-512.xcf b/src/icons/icon-512.xcf new file mode 100644 index 0000000..b9275f6 Binary files /dev/null and b/src/icons/icon-512.xcf differ diff --git a/src/icons/image-2-line.png b/src/icons/image-2-line.png new file mode 100644 index 0000000..f1c2494 Binary files /dev/null and b/src/icons/image-2-line.png differ diff --git a/src/icons/information-fill.png b/src/icons/information-fill.png new file mode 100644 index 0000000..ddcd05d Binary files /dev/null and b/src/icons/information-fill.png differ diff --git a/src/icons/information-line.png b/src/icons/information-line.png new file mode 100644 index 0000000..8336ada Binary files /dev/null and b/src/icons/information-line.png differ diff --git a/src/icons/link-unlink-m.png b/src/icons/link-unlink-m.png new file mode 100644 index 0000000..9a4c56e Binary files /dev/null and b/src/icons/link-unlink-m.png differ diff --git a/src/icons/links-line.png b/src/icons/links-line.png new file mode 100644 index 0000000..c0e3eaf Binary files /dev/null and b/src/icons/links-line.png differ diff --git a/src/icons/loader-2-fill.png b/src/icons/loader-2-fill.png new file mode 100644 index 0000000..044be77 Binary files /dev/null and b/src/icons/loader-2-fill.png differ diff --git a/src/icons/lock-2-fill.png b/src/icons/lock-2-fill.png new file mode 100644 index 0000000..86b7d7c Binary files /dev/null and b/src/icons/lock-2-fill.png differ diff --git a/src/icons/lock-line.png b/src/icons/lock-line.png new file mode 100644 index 0000000..6370adc Binary files /dev/null and b/src/icons/lock-line.png differ diff --git a/src/icons/lock-unlock-line.png b/src/icons/lock-unlock-line.png new file mode 100644 index 0000000..d2bf8e9 Binary files /dev/null and b/src/icons/lock-unlock-line.png differ diff --git a/src/icons/magic-line.png b/src/icons/magic-line.png new file mode 100644 index 0000000..2422682 Binary files /dev/null and b/src/icons/magic-line.png differ diff --git a/src/icons/mail-add-line.png b/src/icons/mail-add-line.png new file mode 100644 index 0000000..d04eba5 Binary files /dev/null and b/src/icons/mail-add-line.png differ diff --git a/src/icons/mail-line.png b/src/icons/mail-line.png new file mode 100644 index 0000000..c2a13cc Binary files /dev/null and b/src/icons/mail-line.png differ diff --git a/src/icons/map-pin-line.png b/src/icons/map-pin-line.png new file mode 100644 index 0000000..159ca5b Binary files /dev/null and b/src/icons/map-pin-line.png differ diff --git a/src/icons/movie-2-line.png b/src/icons/movie-2-line.png new file mode 100644 index 0000000..dbfdf7f Binary files /dev/null and b/src/icons/movie-2-line.png differ diff --git a/src/icons/music-2-line.png b/src/icons/music-2-line.png new file mode 100644 index 0000000..d2edf8c Binary files /dev/null and b/src/icons/music-2-line.png differ diff --git a/src/icons/others/Histogram.png b/src/icons/others/Histogram.png new file mode 100644 index 0000000..d2bddb3 Binary files /dev/null and b/src/icons/others/Histogram.png differ diff --git a/src/icons/others/Omonitor.png b/src/icons/others/Omonitor.png new file mode 100644 index 0000000..f1c1a64 Binary files /dev/null and b/src/icons/others/Omonitor.png differ diff --git a/src/icons/others/greendot.png b/src/icons/others/greendot.png new file mode 100644 index 0000000..be914c6 Binary files /dev/null and b/src/icons/others/greendot.png differ diff --git a/src/icons/others/monitor.png b/src/icons/others/monitor.png new file mode 100644 index 0000000..7ba4759 Binary files /dev/null and b/src/icons/others/monitor.png differ diff --git a/src/icons/others/snapcraft.png b/src/icons/others/snapcraft.png new file mode 100644 index 0000000..da50180 Binary files /dev/null and b/src/icons/others/snapcraft.png differ diff --git a/src/icons/others/snapcraft.svg b/src/icons/others/snapcraft.svg new file mode 100644 index 0000000..a14c440 --- /dev/null +++ b/src/icons/others/snapcraft.svg @@ -0,0 +1,59 @@ + + diff --git a/src/icons/others/tt_tbc_head.png b/src/icons/others/tt_tbc_head.png new file mode 100644 index 0000000..20cac2c Binary files /dev/null and b/src/icons/others/tt_tbc_head.png differ diff --git a/src/icons/others/wall_placeholder_180.jpg b/src/icons/others/wall_placeholder_180.jpg new file mode 100644 index 0000000..d696b5f Binary files /dev/null and b/src/icons/others/wall_placeholder_180.jpg differ diff --git a/src/icons/pause-line.png b/src/icons/pause-line.png new file mode 100644 index 0000000..4be8f55 Binary files /dev/null and b/src/icons/pause-line.png differ diff --git a/src/icons/paypal-line.png b/src/icons/paypal-line.png new file mode 100644 index 0000000..f6ac01d Binary files /dev/null and b/src/icons/paypal-line.png differ diff --git a/src/icons/picture-in-picture-line.png b/src/icons/picture-in-picture-line.png new file mode 100644 index 0000000..4416bfd Binary files /dev/null and b/src/icons/picture-in-picture-line.png differ diff --git a/src/icons/play-fill.png b/src/icons/play-fill.png new file mode 100644 index 0000000..1ead6ba Binary files /dev/null and b/src/icons/play-fill.png differ diff --git a/src/icons/play-line.png b/src/icons/play-line.png new file mode 100644 index 0000000..9561499 Binary files /dev/null and b/src/icons/play-line.png differ diff --git a/src/icons/printer-line.png b/src/icons/printer-line.png new file mode 100644 index 0000000..fed36d3 Binary files /dev/null and b/src/icons/printer-line.png differ diff --git a/src/icons/questionnaire-line.png b/src/icons/questionnaire-line.png new file mode 100644 index 0000000..9c1fcc6 Binary files /dev/null and b/src/icons/questionnaire-line.png differ diff --git a/src/icons/record-circle-line.png b/src/icons/record-circle-line.png new file mode 100644 index 0000000..ad66257 Binary files /dev/null and b/src/icons/record-circle-line.png differ diff --git a/src/icons/refresh-line.png b/src/icons/refresh-line.png new file mode 100644 index 0000000..c105522 Binary files /dev/null and b/src/icons/refresh-line.png differ diff --git a/src/icons/repeat-2-fill.png b/src/icons/repeat-2-fill.png new file mode 100644 index 0000000..f32602a Binary files /dev/null and b/src/icons/repeat-2-fill.png differ diff --git a/src/icons/save-line.png b/src/icons/save-line.png new file mode 100644 index 0000000..b0206e9 Binary files /dev/null and b/src/icons/save-line.png differ diff --git a/src/icons/scissors-cut-line.png b/src/icons/scissors-cut-line.png new file mode 100644 index 0000000..3ee54d7 Binary files /dev/null and b/src/icons/scissors-cut-line.png differ diff --git a/src/icons/screenshot-2-line.png b/src/icons/screenshot-2-line.png new file mode 100644 index 0000000..567ce04 Binary files /dev/null and b/src/icons/screenshot-2-line.png differ diff --git a/src/icons/search-2-line.png b/src/icons/search-2-line.png new file mode 100644 index 0000000..453acd1 Binary files /dev/null and b/src/icons/search-2-line.png differ diff --git a/src/icons/setting-line.png b/src/icons/setting-line.png new file mode 100644 index 0000000..fcbd74c Binary files /dev/null and b/src/icons/setting-line.png differ diff --git a/src/icons/shape-2-line.png b/src/icons/shape-2-line.png new file mode 100644 index 0000000..a230b14 Binary files /dev/null and b/src/icons/shape-2-line.png differ diff --git a/src/icons/shape-line.png b/src/icons/shape-line.png new file mode 100644 index 0000000..d5944fb Binary files /dev/null and b/src/icons/shape-line.png differ diff --git a/src/icons/share-line.png b/src/icons/share-line.png new file mode 100644 index 0000000..22bf75d Binary files /dev/null and b/src/icons/share-line.png differ diff --git a/src/icons/shopping-cart-line.png b/src/icons/shopping-cart-line.png new file mode 100644 index 0000000..219b634 Binary files /dev/null and b/src/icons/shopping-cart-line.png differ diff --git a/src/icons/sip-line.png b/src/icons/sip-line.png new file mode 100644 index 0000000..16aeb6c Binary files /dev/null and b/src/icons/sip-line.png differ diff --git a/src/icons/split-cells-horizontal.png b/src/icons/split-cells-horizontal.png new file mode 100644 index 0000000..b180049 Binary files /dev/null and b/src/icons/split-cells-horizontal.png differ diff --git a/src/icons/split-cells-vertical.png b/src/icons/split-cells-vertical.png new file mode 100644 index 0000000..c741af8 Binary files /dev/null and b/src/icons/split-cells-vertical.png differ diff --git a/src/icons/star-line.png b/src/icons/star-line.png new file mode 100644 index 0000000..9f9a328 Binary files /dev/null and b/src/icons/star-line.png differ diff --git a/src/icons/stop-line.png b/src/icons/stop-line.png new file mode 100644 index 0000000..2bda682 Binary files /dev/null and b/src/icons/stop-line.png differ diff --git a/src/icons/swap-box-line.png b/src/icons/swap-box-line.png new file mode 100644 index 0000000..0f270b2 Binary files /dev/null and b/src/icons/swap-box-line.png differ diff --git a/src/icons/terminal-box-line.png b/src/icons/terminal-box-line.png new file mode 100644 index 0000000..3e66e7d Binary files /dev/null and b/src/icons/terminal-box-line.png differ diff --git a/src/icons/texture.png b/src/icons/texture.png new file mode 100644 index 0000000..12bae83 Binary files /dev/null and b/src/icons/texture.png differ diff --git a/src/icons/tiktok-downloader.png b/src/icons/tiktok-downloader.png new file mode 100644 index 0000000..7ca80f6 Binary files /dev/null and b/src/icons/tiktok-downloader.png differ diff --git a/src/icons/time-line.png b/src/icons/time-line.png new file mode 100644 index 0000000..590aa72 Binary files /dev/null and b/src/icons/time-line.png differ diff --git a/src/icons/translate-2.png b/src/icons/translate-2.png new file mode 100644 index 0000000..10a2c39 Binary files /dev/null and b/src/icons/translate-2.png differ diff --git a/src/icons/twitter-line.png b/src/icons/twitter-line.png new file mode 100644 index 0000000..4e5dad9 Binary files /dev/null and b/src/icons/twitter-line.png differ diff --git a/src/icons/volume-mute-line.png b/src/icons/volume-mute-line.png new file mode 100644 index 0000000..1877d6c Binary files /dev/null and b/src/icons/volume-mute-line.png differ diff --git a/src/icons/volume-up-line.png b/src/icons/volume-up-line.png new file mode 100644 index 0000000..3473479 Binary files /dev/null and b/src/icons/volume-up-line.png differ diff --git a/src/icons/white/stop-line.png b/src/icons/white/stop-line.png new file mode 100644 index 0000000..2cd918c Binary files /dev/null and b/src/icons/white/stop-line.png differ diff --git a/src/icons/white/white_arrow-left-line.png b/src/icons/white/white_arrow-left-line.png new file mode 100644 index 0000000..1ab063b Binary files /dev/null and b/src/icons/white/white_arrow-left-line.png differ diff --git a/src/icons/white/white_arrow-right-line.png b/src/icons/white/white_arrow-right-line.png new file mode 100644 index 0000000..e203184 Binary files /dev/null and b/src/icons/white/white_arrow-right-line.png differ diff --git a/src/icons/white/white_picture-in-picture-line.png b/src/icons/white/white_picture-in-picture-line.png new file mode 100644 index 0000000..ee4dc9a Binary files /dev/null and b/src/icons/white/white_picture-in-picture-line.png differ diff --git a/src/icons/white/white_play-fill.png b/src/icons/white/white_play-fill.png new file mode 100644 index 0000000..1ead6ba Binary files /dev/null and b/src/icons/white/white_play-fill.png differ diff --git a/src/icons/white/white_record-circle-line.png b/src/icons/white/white_record-circle-line.png new file mode 100644 index 0000000..91b34d5 Binary files /dev/null and b/src/icons/white/white_record-circle-line.png differ diff --git a/src/icons/white/white_scissors-cut-line.png b/src/icons/white/white_scissors-cut-line.png new file mode 100644 index 0000000..3ee54d7 Binary files /dev/null and b/src/icons/white/white_scissors-cut-line.png differ diff --git a/src/icons/white/white_shape-2-line.png b/src/icons/white/white_shape-2-line.png new file mode 100644 index 0000000..6be2c99 Binary files /dev/null and b/src/icons/white/white_shape-2-line.png differ diff --git a/src/icons/white/white_sip-line.png b/src/icons/white/white_sip-line.png new file mode 100644 index 0000000..cefb4e3 Binary files /dev/null and b/src/icons/white/white_sip-line.png differ diff --git a/src/icons/white/white_terminal-box-line.png b/src/icons/white/white_terminal-box-line.png new file mode 100644 index 0000000..f98536f Binary files /dev/null and b/src/icons/white/white_terminal-box-line.png differ diff --git a/src/icons/youtube-line.png b/src/icons/youtube-line.png new file mode 100644 index 0000000..96a7b80 Binary files /dev/null and b/src/icons/youtube-line.png differ diff --git a/src/icons/zoom-in-fill.png b/src/icons/zoom-in-fill.png new file mode 100644 index 0000000..aa40dfd Binary files /dev/null and b/src/icons/zoom-in-fill.png differ diff --git a/src/icons/zoom-in-line.png b/src/icons/zoom-in-line.png new file mode 100644 index 0000000..21c13e1 Binary files /dev/null and b/src/icons/zoom-in-line.png differ diff --git a/src/icons/zoom-out-fill.png b/src/icons/zoom-out-fill.png new file mode 100644 index 0000000..39f173f Binary files /dev/null and b/src/icons/zoom-out-fill.png differ diff --git a/src/icons/zoom-out-line.png b/src/icons/zoom-out-line.png new file mode 100644 index 0000000..8d5168b Binary files /dev/null and b/src/icons/zoom-out-line.png differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..5971c92 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include "common.h" + +extern QString defaultUserAgentStr; + +int main(int argc, char *argv[]) +{ + + //argv[argc++] = "--single-process"; + + QApplication app(argc, argv); + app.setWindowIcon(QIcon(":/icons/app/icon-256.png")); + + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + static const char ENV_VAR_QT_DEVICE_PIXEL_RATIO[] = "QT_DEVICE_PIXEL_RATIO"; + if (!qEnvironmentVariableIsSet(ENV_VAR_QT_DEVICE_PIXEL_RATIO) + && !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR") + && !qEnvironmentVariableIsSet("QT_SCALE_FACTOR") + && !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + } + + QApplication::setApplicationName("WhatSie"); + QApplication::setOrganizationName("org.keshavnrj.ubuntu"); + QApplication::setApplicationVersion(VERSIONSTR); + + QtWebEngine::initialize(); + + QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, true); + QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); + + MainWindow window; + window.show(); + + return app.exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..38ecbe6 --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,551 @@ +#include "mainwindow.h" + + +extern QString defaultUserAgentStr; + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), + notificationsTitleRegExp("^\\([1-9]\\d*\\).*"), + trayIconRead(":/icons/app/whatsapp.svg"), + trayIconUnread(":/icons/app/whatsapp-message.svg") +{ + setWindowTitle(QApplication::applicationName()); + setWindowIcon(QIcon(":/icons/app/icon-256.png")); + setMinimumWidth(800); + setMinimumHeight(600); + readSettings(); + + createActions(); + createStatusBar(); + createTrayIcon(); + createWebEngine(); + + init_settingWidget(); + + lightPalette = qApp->palette(); + updateWindowTheme(); + + // quit application if the download manager window is the only remaining window + m_downloadManagerWidget.setAttribute(Qt::WA_QuitOnClose, false); + + +} + +void MainWindow::updatePageTheme() +{ + QString webPageTheme = "web"; //implies light + QString windowTheme = settings.value("windowTheme","light").toString(); + if(windowTheme == "dark"){ + webPageTheme = "web dark"; + } + if(webEngine && webEngine->page()){ + webEngine->page()->runJavaScript( + "document.querySelector('body').className='"+webPageTheme+"';", + [](const QVariant &result){ + qDebug() << "Value is: " << result.toString() << endl; + } + ); + } +} + +void MainWindow::updateWindowTheme() +{ + if(settings.value("windowTheme","light").toString() == "dark") + { + //TODO make dark palette match whatsapp dark theme + qApp->setStyle(QStyleFactory::create("fusion")); + QPalette palette; + palette.setColor(QPalette::Window,QColor("#131C21")); //whatsapp dark color + palette.setColor(QPalette::WindowText,Qt::white); + palette.setColor(QPalette::Disabled,QPalette::WindowText,QColor(127,127,127)); + palette.setColor(QPalette::Base,QColor(42,42,42)); + palette.setColor(QPalette::AlternateBase,QColor(66,66,66)); + palette.setColor(QPalette::ToolTipBase,Qt::white); + palette.setColor(QPalette::ToolTipText,QColor(53,53,53)); + palette.setColor(QPalette::Text,Qt::white); + palette.setColor(QPalette::Disabled,QPalette::Text,QColor(127,127,127)); + palette.setColor(QPalette::Dark,QColor(35,35,35)); + palette.setColor(QPalette::Shadow,QColor(20,20,20)); + palette.setColor(QPalette::Button,QColor(53,53,53)); + palette.setColor(QPalette::ButtonText,Qt::white); + palette.setColor(QPalette::Disabled,QPalette::ButtonText,QColor(127,127,127)); + palette.setColor(QPalette::BrightText,Qt::red); + palette.setColor(QPalette::Link,QColor("skyblue")); + palette.setColor(QPalette::Highlight,QColor(49,106,150)); + palette.setColor(QPalette::Disabled,QPalette::Highlight,QColor(80,80,80)); + palette.setColor(QPalette::HighlightedText,Qt::white); + palette.setColor(QPalette::Disabled,QPalette::HighlightedText,QColor(127,127,127)); + qApp->setPalette(palette); + this->webEngine->setStyleSheet("QWebEngineView{background:#131C21;}"); //whatsapp dark color + } + else{ + qApp->setPalette(lightPalette); + this->update(); + } +} + +void MainWindow::handleCookieAdded(const QNetworkCookie &cookie) +{ + qDebug() << cookie.toRawForm() << "\n\n\n"; +} + +void MainWindow::readSettings() +{ + restoreGeometry(settings.value("geometry").toByteArray()); + restoreState(settings.value("windowState").toByteArray()); +} + +void MainWindow::init_settingWidget() +{ + if(settingsWidget == nullptr) + { + settingsWidget = new SettingsWidget(this,webEngine->page()->profile()->cachePath() + ,webEngine->page()->profile()->persistentStoragePath()); + settingsWidget->setWindowTitle(QApplication::applicationName()+" | Settings"); + settingsWidget->setWindowFlags(Qt::Dialog); + + connect(settingsWidget,SIGNAL(updateWindowTheme()),this,SLOT(updateWindowTheme())); + connect(settingsWidget,SIGNAL(updatePageTheme()),this,SLOT(updatePageTheme())); + connect(settingsWidget,&SettingsWidget::muteToggled,[=](const bool checked) + { + this->toggleMute(checked); + }); + connect(settingsWidget,&SettingsWidget::userAgentChanged,[=](QString userAgentStr) + { + if(webEngine->page()->profile()->httpUserAgent() != userAgentStr) + { + settings.setValue("useragent",userAgentStr); + this->updateSettingsUserAgentWidget(); + this->askToReloadPage(); + } + }); + connect(settingsWidget,&SettingsWidget::autoPlayMediaToggled,[=](bool checked) + { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + + auto* webSettings = profile->settings(); + webSettings->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture,checked); + + this->webEngine->page()->profile()->settings()->setAttribute( + QWebEngineSettings::PlaybackRequiresUserGesture, + checked); + }); + } +} + +void MainWindow::showSettings() +{ + if(webEngine == nullptr){ + QMessageBox::critical(this,QApplication::applicationName()+"| Error", + "Unable to initialize settings module.\nIs webengine initialized?"); + return; + } + if(!settingsWidget->isVisible()) + { + this->updateSettingsUserAgentWidget(); + settingsWidget->refresh(); + settingsWidget->showNormal(); + } +} + +void MainWindow::updateSettingsUserAgentWidget() +{ + settingsWidget->updateDefaultUAButton(this->webEngine->page()->profile()->httpUserAgent()); +} + +void MainWindow::askToReloadPage() +{ + QMessageBox msgBox; + msgBox.setWindowTitle(QApplication::applicationName()+" | Action required"); + msgBox.setInformativeText("Page needs to be reloaded to continue."); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + this->doAppReload(); +} + +void MainWindow::showAbout() +{ + QDialog *aboutDialog = new QDialog(this,Qt::Dialog); + aboutDialog->setWindowModality(Qt::WindowModal); + QVBoxLayout *layout = new QVBoxLayout; + QLabel *message = new QLabel(aboutDialog); + layout->addWidget(message); + connect(message,&QLabel::linkActivated,[=](const QString linkStr){ + if(linkStr.contains("about_qt")){ + qApp->aboutQt(); + }else{ + QDesktopServices::openUrl(QUrl(linkStr)); + } + }); + aboutDialog->setLayout(layout); + aboutDialog->setAttribute(Qt::WA_DeleteOnClose,true); + aboutDialog->show(); + + QString mes = + "

" + "


" + "

Designed and Developed

" + "

by Keshav Bhatt <keshavnrj@gmail.com>

" + "

Website: https://ktechpit.com

" + "

Runtime: Qt Toolkit

" + "

Version: "+QApplication::applicationVersion()+"

" + "


" + "

More Apps

" + "


"; + + QGraphicsOpacityEffect *eff = new QGraphicsOpacityEffect(this); + message->setGraphicsEffect(eff); + QPropertyAnimation *a = new QPropertyAnimation(eff,"opacity"); + a->setDuration(1000); + a->setStartValue(0); + a->setEndValue(1); + a->setEasingCurve(QEasingCurve::InCurve); + a->start(QPropertyAnimation::DeleteWhenStopped); + message->setText(mes); + message->show(); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + settings.setValue("geometry", saveGeometry()); + settings.setValue("windowState", saveState()); + + if(QSystemTrayIcon::isSystemTrayAvailable() && settings.value("closeButtonActionCombo",0).toInt() == 0){ + this->hide(); + event->ignore(); + notify(QApplication::applicationName(),"Application is minimized to system tray."); + return; + } + event->accept(); + qApp->quit(); + QMainWindow::closeEvent(event); +} + +void MainWindow::notify(QString title,QString message) +{ + if(settings.value("disableNotificationPopups",false).toBool() == true){ + return; + } + auto popup = new NotificationPopup(webEngine); + connect(popup,&NotificationPopup::notification_clicked,[=](){ + if(windowState()==Qt::WindowMinimized || windowState()!=Qt::WindowActive){ + activateWindow(); + raise(); + show(); + } + }); + popup->adjustSize(); + popup->present(title,message,QPixmap(":/icons/app/icon-64.png")); +} + +void MainWindow::createActions() +{ + + minimizeAction = new QAction(tr("Mi&nimize to tray"), this); + connect(minimizeAction, &QAction::triggered, this, &QWidget::hide); + addAction(minimizeAction); + + restoreAction = new QAction(tr("&Restore"), this); + connect(restoreAction, &QAction::triggered, this, &QWidget::showNormal); + addAction(restoreAction); + + reloadAction = new QAction(tr("Re&load"), this); + reloadAction->setShortcut(Qt::Key_F5); + connect(reloadAction, &QAction::triggered, this, &MainWindow::doReload); + addAction(reloadAction); + + settingsAction = new QAction(tr("Settings"), this); + connect(settingsAction, &QAction::triggered, this, &MainWindow::showSettings); + + + aboutAction = new QAction(tr("About"), this); + connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout); + + quitAction = new QAction(tr("&Quit"), this); + quitAction->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key_Q)); + connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit); + addAction(quitAction); +} + +void MainWindow::createStatusBar() +{ + QStatusBar *statusBar = new QStatusBar(this); + setStatusBar(statusBar); + statusBar->hide(); + this->statusBar = statusBar; +} + +void MainWindow::createTrayIcon() +{ + trayIconMenu = new QMenu(this); + trayIconMenu->addAction(minimizeAction); + trayIconMenu->addAction(restoreAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(reloadAction); + trayIconMenu->addAction(settingsAction); + trayIconMenu->addAction(aboutAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); + + trayIcon = new QSystemTrayIcon(trayIconRead, this); + trayIcon->setContextMenu(trayIconMenu); + + trayIcon->show(); + + connect(trayIcon, &QSystemTrayIcon::messageClicked, + this, &MainWindow::messageClicked); + connect(trayIcon, &QSystemTrayIcon::activated, + this, &MainWindow::iconActivated); +} + +void MainWindow::init_globalWebProfile() +{ + + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + auto* webSettings = profile->settings(); + webSettings->setAttribute(QWebEngineSettings::AutoLoadImages, true); + webSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + webSettings->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); + webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + webSettings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); + webSettings->setAttribute(QWebEngineSettings::XSSAuditingEnabled, true); + webSettings->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + webSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, false); + webSettings->setAttribute(QWebEngineSettings::DnsPrefetchEnabled,true); + webSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled ,true); + webSettings->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, false); + webSettings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + //webSettings->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, true); + + // QObject::connect( + // QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested, + // &m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested); + + QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, + true); + +} + +void MainWindow::createWebEngine() +{ + init_globalWebProfile(); + + QSizePolicy widgetSize; + widgetSize.setHorizontalPolicy(QSizePolicy::Expanding); + widgetSize.setVerticalPolicy(QSizePolicy::Expanding); + widgetSize.setHorizontalStretch(1); + widgetSize.setVerticalStretch(1); + + QWebEngineView *webEngine = new QWebEngineView(this); + setCentralWidget(webEngine); + webEngine->setSizePolicy(widgetSize); + webEngine->show(); + + this->webEngine = webEngine; + + + connect(webEngine, &QWebEngineView::titleChanged, + this, &MainWindow::handleWebViewTitleChanged); + connect(webEngine, &QWebEngineView::loadStarted, + this, &MainWindow::handleLoadStarted); + connect(webEngine, &QWebEngineView::loadProgress, + this, &MainWindow::handleLoadProgress); + connect(webEngine, &QWebEngineView::loadFinished, + this, &MainWindow::handleLoadFinished); + connect(webEngine, &QWebEngineView::renderProcessTerminated, + [this](QWebEnginePage::RenderProcessTerminationStatus termStatus, int statusCode) { + QString status; + switch (termStatus) { + case QWebEnginePage::NormalTerminationStatus: + status = tr("Render process normal exit"); + break; + case QWebEnginePage::AbnormalTerminationStatus: + status = tr("Render process abnormal exit"); + break; + case QWebEnginePage::CrashedTerminationStatus: + status = tr("Render process crashed"); + break; + case QWebEnginePage::KilledTerminationStatus: + status = tr("Render process killed"); + break; + } + QMessageBox::StandardButton btn = QMessageBox::question(window(), status, + tr("Render process exited with code: %1\n" + "Do you want to reload the page ?").arg(statusCode)); + if (btn == QMessageBox::Yes) + QTimer::singleShot(0, [this] { this->webEngine->reload(); }); + }); + + QWebEngineCookieStore *browser_cookie_store = webEngine->page()->profile()->cookieStore(); + connect( browser_cookie_store, &QWebEngineCookieStore::cookieAdded, this, &MainWindow::handleCookieAdded ); + + createWebPage(false); +} + +void MainWindow::createWebPage(bool offTheRecord) +{ + if (offTheRecord && !m_otrProfile) { + m_otrProfile.reset(new QWebEngineProfile); + } + + auto profile = offTheRecord ? m_otrProfile.get() : QWebEngineProfile::defaultProfile(); + + profile->setHttpUserAgent(settings.value("useragent",defaultUserAgentStr).toString()); + + auto popup = new NotificationPopup(webEngine); + connect(popup,&NotificationPopup::notification_clicked,[=](){ + if(windowState()==Qt::WindowMinimized || windowState()!=Qt::WindowActive){ + activateWindow(); + raise(); + show(); + } + }); + profile->setNotificationPresenter([=] (std::unique_ptr notification) + { + if(settings.value("disableNotificationPopups",false).toBool() == true){ + return; + } + popup->present(notification); + }); + + QWebEnginePage *page = new WebEnginePage(profile,webEngine); + if(settings.value("windowTheme","light").toString() == "dark"){ + page->setBackgroundColor(QColor("#F0F0F0")); //whatsapp bg color + } + webEngine->setPage(page); + //page should be set parent of profile to prevent + //Release of profile requested but WebEnginePage still not deleted. Expect troubles ! + profile->setParent(page); + //RequestInterceptor *interceptor = new RequestInterceptor(profile); + //profile->setUrlRequestInterceptor(interceptor); + page->setUrl(QUrl("https://web.whatsapp.com/")); + + connect(profile, &QWebEngineProfile::downloadRequested, + &m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested); + + connect(webEngine->page(), SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), + this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest))); +} + +void MainWindow::fullScreenRequested(QWebEngineFullScreenRequest request) +{ + if (request.toggleOn()) + { + webEngine->showFullScreen(); + this->showFullScreen(); + request.accept(); + } else { + webEngine->showNormal(); + this->showNormal(); + request.accept(); + } +} + +void MainWindow::handleWebViewTitleChanged(QString title) +{ + setWindowTitle(title); + + if (notificationsTitleRegExp.exactMatch(title)) + { + trayIcon->setIcon(trayIconUnread); + setWindowIcon(trayIconUnread); + } + else + { + trayIcon->setIcon(trayIconRead); + setWindowIcon(trayIconRead); + } +} + +void MainWindow::handleLoadStarted() +{ + statusBar->show(); +} + +void MainWindow::handleLoadFinished(bool loaded) +{ + if(loaded){ + updatePageTheme(); + } +} + +void MainWindow::handleLoadProgress(int progress) +{ + if (progress >= 100) + { + statusBar->hide(); + } + else + { + statusBar->showMessage("Loading "+QString::number(progress)+"%"); + } +} + +//unused direct method to download file without having entry in download manager +void MainWindow::handleDownloadRequested(QWebEngineDownloadItem *download) +{ + QFileDialog dialog; + dialog.setParent(this); + dialog.setAcceptMode(QFileDialog::AcceptMode::AcceptSave); + dialog.setFileMode(QFileDialog::FileMode::AnyFile); + QString suggestedFileName = QUrl(download->path()).fileName(); + dialog.selectFile(suggestedFileName); + + if (dialog.exec() && dialog.selectedFiles().size() > 0) + { + download->setPath(dialog.selectedFiles().at(0)); + download->accept(); + } +} + +void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) +{ + Q_UNUSED(reason); + if (isVisible()) { + hide(); + } else { + showNormal(); + } +} + +void MainWindow::messageClicked() +{ + if (isVisible()) { + hide(); + } else { + showNormal(); + } +} + +void MainWindow::doAppReload() +{ + if(this->webEngine->page()){ + this->webEngine->page()->disconnect(); + } + createWebPage(false); +} + +void MainWindow::doReload() +{ + this->webEngine->triggerPageAction(QWebEnginePage::ReloadAndBypassCache, false); +} + +void MainWindow::toggleMute(const bool checked) +{ + this->webEngine->page()->setAudioMuted(checked); +} + +// get value of page theme when page is loaded +QString MainWindow::getPageTheme() +{ + static QString theme = "web"; //implies light + if(webEngine && webEngine->page()) + { + webEngine->page()->runJavaScript( + "document.querySelector('body').className;", + [](const QVariant &result){ + theme = result.toString(); + } + ); + } + return theme; +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..367d18a --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,107 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "notificationpopup.h" +#include "requestinterceptor.h" +#include "settingswidget.h" +#include "webenginepage.h" + +#include "downloadmanagerwidget.h" + + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); +public slots: + void updateWindowTheme(); + void updatePageTheme(); +protected: + void closeEvent(QCloseEvent *event) override; + +private: + QPalette lightPalette; + void createActions(); + void createStatusBar(); + void createTrayIcon(); + void createWebEngine(); + + QSettings settings; + + QRegExp notificationsTitleRegExp; + QIcon trayIconRead; + QIcon trayIconUnread; + + QAction *reloadAction; + QAction *minimizeAction; + QAction *restoreAction; + QAction *aboutAction; + QAction *settingsAction; + QAction *quitAction; + + QMenu *trayIconMenu; + QSystemTrayIcon *trayIcon; + + QWebEngineView *webEngine; + QStatusBar *statusBar; + + + SettingsWidget * settingsWidget = nullptr; + + //void reload(); + + DownloadManagerWidget m_downloadManagerWidget; + QScopedPointer m_otrProfile; + + +private slots: + + void readSettings(); + void handleWebViewTitleChanged(QString title); + void handleLoadStarted(); + void handleLoadProgress(int progress); + void handleDownloadRequested(QWebEngineDownloadItem *download); + void iconActivated(QSystemTrayIcon::ActivationReason reason); + void messageClicked(); + void doReload(); + void showAbout(); + void notify(QString title, QString message); + void showSettings(); + void handleCookieAdded(const QNetworkCookie &cookie); + void handleLoadFinished(bool loaded); + + QString getPageTheme(); + void toggleMute(const bool checked); + void doAppReload(); + void askToReloadPage(); + void updateSettingsUserAgentWidget(); + void fullScreenRequested(QWebEngineFullScreenRequest request); + + void createWebPage(bool offTheRecord =false); + void init_settingWidget(); + void init_globalWebProfile(); +}; + +#endif // MAINWINDOW_H diff --git a/src/notificationpopup.h b/src/notificationpopup.h new file mode 100644 index 0000000..2246129 --- /dev/null +++ b/src/notificationpopup.h @@ -0,0 +1,144 @@ +#ifndef NOTIFICATIONPOPUP_H +#define NOTIFICATIONPOPUP_H + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "widgets/scrolltext/scrolltext.h" + +#include + +class NotificationPopup : public QWidget +{ + Q_OBJECT + + QLabel m_icon, m_title; ScrollText m_message; + std::unique_ptr notification; + +public: + NotificationPopup(QWidget *parent) : QWidget(parent) + { + setWindowFlags(Qt::ToolTip); + auto rootLayout = new QHBoxLayout(this); + + rootLayout->addWidget(&m_icon); + + auto bodyLayout = new QVBoxLayout; + rootLayout->addLayout(bodyLayout); + + auto titleLayout = new QHBoxLayout; + bodyLayout->addLayout(titleLayout); + + titleLayout->addWidget(&m_title); + titleLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); + + auto close = new QPushButton(tr("Close")); + titleLayout->addWidget(close); + connect(close, &QPushButton::clicked, this, &NotificationPopup::onClosed); + + bodyLayout->addWidget(&m_message); + adjustSize(); + } + + void present(QString title,QString message,const QPixmap image) + { + m_title.setText("" + title + ""); + m_message.setText(message); + m_icon.setPixmap(image.scaledToHeight(m_icon.height(),Qt::SmoothTransformation)); + + this->adjustSize(); + qApp->processEvents(); + + int x = QApplication::desktop()->geometry().width()-(this->width()+10); + int y = 40; + + + QTimer::singleShot(10000,this,[=](){ + onClosed(); + }); + + QPropertyAnimation *a = new QPropertyAnimation(this,"pos"); + a->setDuration(200); + a->setStartValue(QApplication::desktop()->mapToGlobal(QPoint(x+this->width(),y))); + a->setEndValue(QApplication::desktop()->mapToGlobal(QPoint(x,y))); + a->setEasingCurve(QEasingCurve::Linear); + a->start(QPropertyAnimation::DeleteWhenStopped); + + this->show(); + + } + + void present(std::unique_ptr &newNotification) + { + if (notification) { + notification->close(); + notification.reset(); + } + + notification.swap(newNotification); + + m_title.setText("" + notification->title() + ""); + m_message.setText(notification->message()); + m_icon.setPixmap(QPixmap::fromImage(notification->icon()).scaledToHeight(m_icon.height())); + + //show(); + notification->show(); + + connect(notification.get(), &QWebEngineNotification::closed, this, &NotificationPopup::onClosed); + QTimer::singleShot(10000, notification.get(), [&] () { onClosed(); }); + + this->adjustSize(); + qApp->processEvents(); + + int x = QApplication::desktop()->geometry().width()-(this->width()+10); + int y = 40; + + QPropertyAnimation *a = new QPropertyAnimation(this,"pos"); + a->setDuration(200); + a->setStartValue(QApplication::desktop()->mapToGlobal(QPoint(x+this->width(),y))); + a->setEndValue(QApplication::desktop()->mapToGlobal(QPoint(x,y))); + a->setEasingCurve(QEasingCurve::Linear); + a->start(QPropertyAnimation::DeleteWhenStopped); + this->show(); + } + +protected slots: + void onClosed() + { + hide(); + if(notification){ + notification->close(); + notification.reset(); + }else{ + this->deleteLater(); + } + } + +protected: + void mouseReleaseEvent(QMouseEvent *event) override + { + QWidget::mouseReleaseEvent(event); + if (event->button() == Qt::LeftButton) { + qDebug()<<"noti clicked"; + emit notification_clicked(); + if(notification ) + notification->click(); + onClosed(); + } + } +signals: + void notification_clicked(); +}; + +#endif // NOTIFICATIONPOPUP_H diff --git a/src/passworddialog.ui b/src/passworddialog.ui new file mode 100644 index 0000000..7f9bf99 --- /dev/null +++ b/src/passworddialog.ui @@ -0,0 +1,121 @@ + + + PasswordDialog + + + + 0 + 0 + 399 + 148 + + + + Authentication Required + + + + + + Icon + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Info + + + true + + + + + + + Username: + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + userLabel + m_userNameLineEdit + passwordLabel + m_passwordLineEdit + buttonBox + m_iconLabel + m_infoLabel + + + + + buttonBox + accepted() + PasswordDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PasswordDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/requestinterceptor.h b/src/requestinterceptor.h new file mode 100644 index 0000000..95f2d48 --- /dev/null +++ b/src/requestinterceptor.h @@ -0,0 +1,41 @@ +#ifndef REQUESTINTERCEPTOR_H +#define REQUESTINTERCEPTOR_H +#include +#include +#include +#include +#include +#include +#include +#include + +class RequestInterceptor : public QWebEngineUrlRequestInterceptor +{ + Q_OBJECT + +signals: + void blocked(QString adUrl); +private: + QSettings m_settings; + +public: + RequestInterceptor(QObject *parent = nullptr) : QWebEngineUrlRequestInterceptor(parent) + { + } + + void interceptRequest(QWebEngineUrlRequestInfo &info) + { + QString reqUrlStr = info.requestUrl().toString(); + +// if(reqUrlStr.contains("mms-type=video")|| reqUrlStr.contains("stream/video?key")){ +// if(m_settings.value("disableVideos",false).toBool()){ +// info.block(true); +// qDebug()<<"INTERCEPTOR: Blocked video - "< + +extern QString defaultUserAgentStr; + +SettingsWidget::SettingsWidget(QWidget *parent, QString engineCachePath, QString enginePersistentStoragePath) : + QWidget(parent), + ui(new Ui::SettingsWidget) +{ + ui->setupUi(this); + + ui->disableVideosCheckBox->hide();//impl later + + this->engineCachePath = engineCachePath; + this->enginePersistentStoragePath = enginePersistentStoragePath; + + ui->closeButtonActionComboBox->setCurrentIndex(settings.value("closeButtonActionCombo",0).toInt()); + ui->notificationCheckBox->setChecked(settings.value("disableNotificationPopups",false).toBool()); + ui->muteAudioCheckBox->setChecked(settings.value("muteAudio",false).toBool()); + ui->autoPlayMediaCheckBox->setChecked(settings.value("autoPlayMedia",false).toBool()); + ui->themeComboBox->setCurrentText(utils::toCamelCase(settings.value("windowTheme","light").toString())); + ui->userAgentLineEdit->setText(settings.value("useragent",defaultUserAgentStr).toString()); + + applyThemeQuirks(); + + ui->setUserAgent->setEnabled(false); +} + +SettingsWidget::~SettingsWidget() +{ + delete ui; +} + +void SettingsWidget::refresh() +{ + ui->cacheSize->setText(utils::refreshCacheSize(cachePath())); + ui->cookieSize->setText(utils::refreshCacheSize(persistentStoragePath())); +} + +void SettingsWidget::updateDefaultUAButton(const QString engineUA) +{ + bool isDefault = QString::compare(engineUA,defaultUserAgentStr,Qt::CaseInsensitive) == 0; + ui->defaultUserAgentButton->setEnabled(!isDefault); + + if(ui->userAgentLineEdit->text().trimmed().isEmpty()){ + ui->userAgentLineEdit->setText(engineUA); + } +} + + +QString SettingsWidget::cachePath() +{ + return engineCachePath; +} + +QString SettingsWidget::persistentStoragePath() +{ + return enginePersistentStoragePath; +} + +void SettingsWidget::on_deleteCache_clicked() +{ + QMessageBox msgBox; + msgBox.setText("This will delete app cache! Application cache makes application load faster."); + msgBox.setIconPixmap(QPixmap(":/icons/information-line.png").scaled(42,42,Qt::KeepAspectRatio,Qt::SmoothTransformation)); + + msgBox.setInformativeText("Delete Application cache ?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + switch (ret) { + case QMessageBox::Yes:{ + utils::delete_cache(this->cachePath()); + refresh(); + break; + } + case QMessageBox::No: + break; + } +} + +void SettingsWidget::on_deletePersistentData_clicked() +{ + QMessageBox msgBox; + msgBox.setText("This will delete app Persistent Data ! Persistent data includes persistent cookies, HTML5 local storage, and visited links."); + msgBox.setIconPixmap(QPixmap(":/icons/information-line.png").scaled(42,42,Qt::KeepAspectRatio,Qt::SmoothTransformation)); + msgBox.setInformativeText("Delete Application Cookies ?"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + switch (ret) { + case QMessageBox::Yes:{ + utils::delete_cache(this->persistentStoragePath()); + refresh(); + break; + } + case QMessageBox::No: + break; + } +} + +void SettingsWidget::on_notificationCheckBox_toggled(bool checked) +{ + settings.setValue("disableNotificationPopups",checked); +} + +void SettingsWidget::on_themeComboBox_currentTextChanged(const QString &arg1) +{ + applyThemeQuirks(); + settings.setValue("windowTheme",QString(arg1).toLower()); + emit updateWindowTheme(); + emit updatePageTheme(); +} + + +void SettingsWidget::applyThemeQuirks() +{ + //little quirks + if(QString::compare(ui->themeComboBox->currentText(),"dark",Qt::CaseInsensitive)==0) + { + ui->label_7->setStyleSheet("color:#c2c5d1;padding: 0px 8px 0px 8px;background:transparent;"); + }else{ + ui->label_7->setStyleSheet("color:#1e1f21;padding: 0px 8px 0px 8px;background:transparent;"); + } +} + + +void SettingsWidget::on_muteAudioCheckBox_toggled(bool checked) +{ + settings.setValue("muteAudio",checked); + emit muteToggled(checked); +} + +void SettingsWidget::on_autoPlayMediaCheckBox_toggled(bool checked) +{ + settings.setValue("autoPlayMedia",checked); + emit autoPlayMediaToggled(checked); +} + +void SettingsWidget::on_defaultUserAgentButton_clicked() +{ + ui->userAgentLineEdit->setText(defaultUserAgentStr); + emit userAgentChanged(ui->userAgentLineEdit->text()); +} + +void SettingsWidget::on_userAgentLineEdit_textChanged(const QString &arg1) +{ + bool isDefault = QString::compare(arg1.trimmed(),defaultUserAgentStr,Qt::CaseInsensitive) == 0; + bool isPrevious= QString::compare(arg1.trimmed(),settings.value("useragent",defaultUserAgentStr).toString(),Qt::CaseInsensitive) == 0; + + if(isDefault == false && arg1.trimmed().isEmpty()==false) + { + ui->defaultUserAgentButton->setEnabled(false); + ui->setUserAgent->setEnabled(false); + } + if(isPrevious == false && arg1.trimmed().isEmpty() == false) + { + ui->setUserAgent->setEnabled(true); + ui->defaultUserAgentButton->setEnabled(true); + } + if(isPrevious){ + ui->defaultUserAgentButton->setEnabled(true); + ui->setUserAgent->setEnabled(false); + } +} + +void SettingsWidget::on_setUserAgent_clicked() +{ + if(ui->userAgentLineEdit->text().trimmed().isEmpty()){ + QMessageBox::information(this,QApplication::applicationName()+"| Error", + "Cannot set an empty UserAgent String."); + return; + } + emit userAgentChanged(ui->userAgentLineEdit->text()); +} + + + +void SettingsWidget::on_disableVideosCheckBox_toggled(bool checked) +{ + settings.setValue("disableVideos",checked); +} + +void SettingsWidget::on_closeButtonActionComboBox_currentIndexChanged(int index) +{ + settings.setValue("closeButtonActionCombo",index); +} diff --git a/src/settingswidget.h b/src/settingswidget.h new file mode 100644 index 0000000..a21a410 --- /dev/null +++ b/src/settingswidget.h @@ -0,0 +1,66 @@ +#ifndef SETTINGSWIDGET_H +#define SETTINGSWIDGET_H + +#include +#include +#include "utils.h" + + + +namespace Ui { +class SettingsWidget; +} + +class SettingsWidget : public QWidget +{ + Q_OBJECT + +signals: + void updateWindowTheme(); + void updatePageTheme(); + void muteToggled(const bool checked); + void autoPlayMediaToggled(const bool checked); + void userAgentChanged(QString userAgentStr); + +public: + explicit SettingsWidget(QWidget *parent = nullptr,QString engineCachePath = "", + QString enginePersistentStoragePath = ""); + ~SettingsWidget(); + +public slots: + void refresh(); + void updateDefaultUAButton(const QString engineUA); +private slots: + QString cachePath(); + QString persistentStoragePath(); + + void on_deleteCache_clicked(); + + void on_deletePersistentData_clicked(); + + void on_notificationCheckBox_toggled(bool checked); + + void on_themeComboBox_currentTextChanged(const QString &arg1); + + void applyThemeQuirks(); + void on_muteAudioCheckBox_toggled(bool checked); + + void on_defaultUserAgentButton_clicked(); + + void on_userAgentLineEdit_textChanged(const QString &arg1); + + void on_setUserAgent_clicked(); + + void on_autoPlayMediaCheckBox_toggled(bool checked); + + void on_disableVideosCheckBox_toggled(bool checked); + + void on_closeButtonActionComboBox_currentIndexChanged(int index); + +private: + Ui::SettingsWidget *ui; + QString engineCachePath,enginePersistentStoragePath; + QSettings settings; +}; + +#endif // SETTINGSWIDGET_H diff --git a/src/settingswidget.ui b/src/settingswidget.ui new file mode 100644 index 0000000..7318e5c --- /dev/null +++ b/src/settingswidget.ui @@ -0,0 +1,354 @@ + + + SettingsWidget + + + + 0 + 0 + 539 + 447 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + background-color: qlineargradient(spread:reflect, x1:0, y1:1, x2:1, y2:1, stop:0 rgba(63, 129, 216, 255), stop:0.328358 rgba(63, 129, 216, 111), stop:0.61194 rgba(63, 129, 216, 48), stop:0.895522 rgba(63, 129, 216, 15)); + + + + + + + background:transparent; +padding: 8px 0px 8px 8px; + + + + + + :/icons/app/icon-64.png + + + + + + + + 0 + 0 + + + + + 16 + + + + QLabel{ +padding: 0px 8px 0px 8px; +background:transparent; +} + + + Application Settings + + + Qt::PlainText + + + + + + + + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + General settings + + + + + + + + Default close button action + + + + + + + + Minimize to tray + + + + + Quit Application + + + + + + + + + + + + Theme + + + + + + + + Dark + + + + + Light + + + + + + + + + + + + User Agent + + + + + + + + + + Set + + + + :/icons/categories/utilities.png:/icons/categories/utilities.png + + + + + + + Default + + + + :/icons/refresh-line.png:/icons/refresh-line.png + + + + + + + + + + + Disable Notifications PopUp + + + + + + + Mute Audio + + + + + + + Disable Auto Playback of Media + + + + + + + Disable loading videos + + + + + + + + + + + + Application Storage and Other Settings + + + + + + + + Clear + + + + :/icons/delete-bin-3-line.png:/icons/delete-bin-3-line.png + + + + + + + Application Cache + + + + + + + - + + + Qt::AlignCenter + + + + + + + + 10 + false + + + + Property + + + + + + + + 10 + false + + + + Option + + + Qt::AlignCenter + + + + + + + + 10 + false + + + + Size + + + Qt::AlignCenter + + + + + + + <html><head/><body><p>Persistent data includes persistent cookies, HTML5 local storage, and visited links.</p></body></html> + + + Persistent data + + + + + + + - + + + Qt::AlignCenter + + + + + + + Clear + + + + :/icons/delete-bin-3-line.png:/icons/delete-bin-3-line.png + + + + + + + + + + + + + + + + + + diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..543b837 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,162 @@ +#include "utils.h" +#include +#include + +utils::utils(QObject *parent) : QObject(parent) +{ + setParent(parent); +} + +utils::~utils() +{ + this->deleteLater(); +} + +//calculate dir size +quint64 utils::dir_size(const QString & directory) +{ + quint64 sizex = 0; + QFileInfo str_info(directory); + if (str_info.isDir()) + { + QDir dir(directory); + QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot); + for (int i = 0; i < list.size(); ++i) + { + QFileInfo fileInfo = list.at(i); + if(fileInfo.isDir()) + { + sizex += dir_size(fileInfo.absoluteFilePath()); + } + else{ + sizex += fileInfo.size(); + } + } + } + return sizex; +} + +//get the size of cache folder in human readble format +QString utils::refreshCacheSize(const QString cache_dir) +{ + qint64 cache_size = dir_size(cache_dir); + QString cache_unit; + if(cache_size > 1024*1024*1024) + { + cache_size = cache_size/(1024*1024*1024); + cache_unit = " GB"; + } + if(cache_size > 1024*1024) + { + cache_size = cache_size/(1024*1024); + cache_unit = " MB"; + } + else if(cache_size > 1024) + { + cache_size = cache_size/(1024); + cache_unit = " kB"; + } + else + { + cache_unit = " B"; + } + return QString::number(cache_size) + cache_unit; +} + +bool utils::delete_cache(const QString cache_dir) +{ + bool deleted = QDir(cache_dir).removeRecursively(); + QDir(cache_dir).mkpath(cache_dir); + return deleted; +} + +//returns string with first letter capitalized +QString utils::toCamelCase(const QString& s) +{ + QStringList parts = s.split(' ', QString::SkipEmptyParts); + for (int i = 0; i < parts.size(); ++i) + parts[i].replace(0, 1, parts[i][0].toUpper()); + return parts.join(" "); +} + +QString utils::generateRandomId(int length){ + + QString str = QUuid::createUuid().toString(); + str.remove(QRegularExpression("{|}|-")); + if(str.length()length){ + while(str.length() != length){ + str = str.remove(str.length()-1,1); + } + } + return str; +} + +QString utils::genRand(int length) +{ + QDateTime cd = QDateTime::currentDateTime(); + const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"+QString::number(cd.currentMSecsSinceEpoch()).remove(QRegExp("[^a-zA-Z\\d\\s]"))); + + const int randomStringLength = length; + QString randomString; + qsrand(cd.toTime_t()); + for(int i=0; i") + .replace("<","<") + .replace("'","'"); +} + diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..9d2520f --- /dev/null +++ b/src/utils.h @@ -0,0 +1,85 @@ +#ifndef UTILS_H +#define UTILS_H + +#include +#include +#include +#include +#include +#include +#include + +class utils : public QObject +{ + Q_OBJECT + +public: + utils(QObject* parent=0); + virtual ~utils(); +public slots: + static QString refreshCacheSize(const QString cache_dir); + static bool delete_cache(const QString cache_dir); + static QString toCamelCase(const QString &s); + static QString generateRandomId(int length); + static QString genRand(int length); + static QString convertSectoDay(qint64 secs); + static QString returnPath(QString pathname); + + static QString EncodeXML ( const QString& encodeMe ){ + + QString temp; + int length = encodeMe.size(); + for (int index = 0; index < length; index++) + { + QChar character(encodeMe.at(index)); + + switch (character.unicode()) + { + case '&': + temp += "&"; break; + + case '\'': + temp += "'"; break; + + case '"': + temp += """; break; + + case '<': + temp += "<"; break; + + case '>': + temp += ">"; break; + + default: + temp += character; + break; + } + } + + return temp; + } + + static QString DecodeXML ( const QString& decodeMe ) { + + QString temp(decodeMe); + + temp.replace("&", "&"); + temp.replace("'", "'"); + temp.replace(""", "\""); + temp.replace("<", "<"); + temp.replace(">", ">"); + + return temp; + } + + static QString htmlToPlainText(QString str); + +private slots: + //use refreshCacheSize + static quint64 dir_size(const QString &directory); + + + +}; + +#endif // UTILS_H diff --git a/src/webenginepage.cpp b/src/webenginepage.cpp new file mode 100644 index 0000000..4478d6d --- /dev/null +++ b/src/webenginepage.cpp @@ -0,0 +1,252 @@ +#include "webenginepage.h" + +#include +#include + + +WebEnginePage::WebEnginePage(QWebEngineProfile *profile, QObject *parent) + : QWebEnginePage(profile, parent) +{ + // Connect signals and slots + connect(this, &QWebEnginePage::featurePermissionRequested, + this, &WebEnginePage::handleFeaturePermissionRequested); + connect(this, &QWebEnginePage::loadFinished, + this, &WebEnginePage::handleLoadFinished); + profile->setHttpUserAgent(profile->httpUserAgent().replace("QtWebEngine/5.13.0","")); + connect(this, &QWebEnginePage::authenticationRequired, this, &WebEnginePage::handleAuthenticationRequired); + connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebEnginePage::handleFeaturePermissionRequested); + connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, &WebEnginePage::handleProxyAuthenticationRequired); + connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, &WebEnginePage::handleRegisterProtocolHandlerRequested); + +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + connect(this, &QWebEnginePage::selectClientCertificate, this, &WebEnginePage::handleSelectClientCertificate); +#endif +} + +bool WebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) +{ + qDebug() << "Navigation request: [" + url.toDisplayString() + "] " + type; + + if (QWebEnginePage::NavigationType::NavigationTypeLinkClicked == type) + { + QDesktopServices::openUrl(url); + return false; + } + + return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); +} + +QWebEnginePage *WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) +{ + Q_UNUSED(type); + return new WebEnginePage(this->profile()); +} + + +inline QString questionForFeature(QWebEnginePage::Feature feature) +{ + switch (feature) { + case QWebEnginePage::Geolocation: + return WebEnginePage::tr("Allow %1 to access your location information?"); + case QWebEnginePage::MediaAudioCapture: + return WebEnginePage::tr("Allow %1 to access your microphone?"); + case QWebEnginePage::MediaVideoCapture: + return WebEnginePage::tr("Allow %1 to access your webcam?"); + case QWebEnginePage::MediaAudioVideoCapture: + return WebEnginePage::tr("Allow %1 to access your microphone and webcam?"); + case QWebEnginePage::MouseLock: + return WebEnginePage::tr("Allow %1 to lock your mouse cursor?"); + case QWebEnginePage::DesktopVideoCapture: + return WebEnginePage::tr("Allow %1 to capture video of your desktop?"); + case QWebEnginePage::DesktopAudioVideoCapture: + return WebEnginePage::tr("Allow %1 to capture audio and video of your desktop?"); + case QWebEnginePage::Notifications: + return WebEnginePage::tr("Allow %1 to show notification on your desktop?"); + } + return QString(); +} + +void WebEnginePage::handleFeaturePermissionRequested(const QUrl &securityOrigin, Feature feature) +{ + QString title = tr("Permission Request"); + QString question = questionForFeature(feature).arg(securityOrigin.host()); + if (!question.isEmpty() && QMessageBox::question(view()->window(), title, question) == QMessageBox::Yes) + setFeaturePermission(securityOrigin, feature, PermissionGrantedByUser); + else + setFeaturePermission(securityOrigin, feature, PermissionDeniedByUser); +} + +void WebEnginePage::handleLoadFinished(bool ok) +{ + Q_UNUSED(ok); + setFeaturePermission( + QUrl("https://web.whatsapp.com/"), + QWebEnginePage::Feature::Notifications, + QWebEnginePage::PermissionPolicy::PermissionGrantedByUser + ); + setFeaturePermission( + QUrl("https://web.whatsapp.com/"), + QWebEnginePage::Feature::MediaAudioCapture, + QWebEnginePage::PermissionPolicy::PermissionGrantedByUser + ); + setFeaturePermission( + QUrl("https://web.whatsapp.com/"), + QWebEnginePage::Feature::MediaVideoCapture, + QWebEnginePage::PermissionPolicy::PermissionGrantedByUser + ); + setFeaturePermission( + QUrl("https://web.whatsapp.com/"), + QWebEnginePage::Feature::MediaAudioVideoCapture, + QWebEnginePage::PermissionPolicy::PermissionGrantedByUser + ); +} + +void WebEnginePage::fullScreenRequestedByPage(QWebEngineFullScreenRequest request) +{ + qDebug()<<"Fullscreen"; + request.accept(); +} + +QStringList WebEnginePage::chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) +{ + qDebug()<setFileMode(dialogMode); + dialog->setOption(QFileDialog::DontUseNativeDialog,true); + + QStringList mimeFilters = acceptedMimeTypes; + + if(acceptedMimeTypes.contains("image/*")){ + foreach(QByteArray mime,QImageReader::supportedImageFormats()){ + mimeFilters.append("image/"+mime); + } + } + + dialog->setMimeTypeFilters(mimeFilters); + + QStringList selectedFiles; + if(dialog->exec()) { + selectedFiles = dialog->selectedFiles(); + } + + return selectedFiles; +} + +bool WebEnginePage::certificateError(const QWebEngineCertificateError &error) +{ + QWidget *mainWindow = view()->window(); + if (error.isOverridable()) { + QDialog dialog(mainWindow); + dialog.setModal(true); + dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); + Ui::CertificateErrorDialog certificateDialog; + certificateDialog.setupUi(&dialog); + certificateDialog.m_iconLabel->setText(QString()); + QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, mainWindow)); + certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32)); + certificateDialog.m_errorLabel->setText(error.errorDescription()); + dialog.setWindowTitle(tr("Certificate Error")); + return dialog.exec() == QDialog::Accepted; + } + + QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription()); + return false; +} + +void WebEnginePage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth) +{ + QWidget *mainWindow = view()->window(); + QDialog dialog(mainWindow); + dialog.setModal(true); + dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); + + Ui::PasswordDialog passwordDialog; + passwordDialog.setupUi(&dialog); + + passwordDialog.m_iconLabel->setText(QString()); + QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mainWindow)); + passwordDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32)); + + QString introMessage(tr("Enter username and password for \"%1\" at %2") + .arg(auth->realm()).arg(requestUrl.toString().toHtmlEscaped())); + passwordDialog.m_infoLabel->setText(introMessage); + passwordDialog.m_infoLabel->setWordWrap(true); + + if (dialog.exec() == QDialog::Accepted) { + auth->setUser(passwordDialog.m_userNameLineEdit->text()); + auth->setPassword(passwordDialog.m_passwordLineEdit->text()); + } else { + // Set authenticator null if dialog is cancelled + *auth = QAuthenticator(); + } +} + +void WebEnginePage::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *auth, const QString &proxyHost) +{ + QWidget *mainWindow = view()->window(); + QDialog dialog(mainWindow); + dialog.setModal(true); + dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint); + + Ui::PasswordDialog passwordDialog; + passwordDialog.setupUi(&dialog); + + passwordDialog.m_iconLabel->setText(QString()); + QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mainWindow)); + passwordDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32)); + + QString introMessage = tr("Connect to proxy \"%1\" using:"); + introMessage = introMessage.arg(proxyHost.toHtmlEscaped()); + passwordDialog.m_infoLabel->setText(introMessage); + passwordDialog.m_infoLabel->setWordWrap(true); + + if (dialog.exec() == QDialog::Accepted) { + auth->setUser(passwordDialog.m_userNameLineEdit->text()); + auth->setPassword(passwordDialog.m_passwordLineEdit->text()); + } else { + // Set authenticator null if dialog is cancelled + *auth = QAuthenticator(); + } +} + +//! [registerProtocolHandlerRequested] +void WebEnginePage::handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request) +{ + auto answer = QMessageBox::question( + view()->window(), + tr("Permission Request"), + tr("Allow %1 to open all %2 links?") + .arg(request.origin().host()) + .arg(request.scheme())); + if (answer == QMessageBox::Yes) + request.accept(); + else + request.reject(); +} +//! [registerProtocolHandlerRequested] + +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) +void WebEnginePage::handleSelectClientCertificate(QWebEngineClientCertificateSelection selection) +{ + // Just select one. + selection.select(selection.certificates().at(0)); + + qDebug() << __FUNCTION__; + for(QSslCertificate cert : selection.certificates()) { + qDebug() << cert; + selection.select(cert); // select the first available cert + break; + } + qDebug() << selection.host(); +} +#endif + + diff --git a/src/webenginepage.h b/src/webenginepage.h new file mode 100644 index 0000000..7ec1a69 --- /dev/null +++ b/src/webenginepage.h @@ -0,0 +1,49 @@ +#ifndef WEBENGINEPAGE_H +#define WEBENGINEPAGE_H + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ui_certificateerrordialog.h" +#include "ui_passworddialog.h" + +class WebEnginePage : public QWebEnginePage +{ + Q_OBJECT +public: + WebEnginePage(QWebEngineProfile *profile, QObject *parent = nullptr); + +protected: + bool acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override; + QWebEnginePage* createWindow(QWebEnginePage::WebWindowType type) override; + bool certificateError(const QWebEngineCertificateError &error) override; + QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes); + +public slots: + void handleFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature); + void handleLoadFinished(bool ok); + +private slots: + void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth); + void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost); + void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); +#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + void handleSelectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection); +#endif + void fullScreenRequestedByPage(QWebEngineFullScreenRequest request); +}; + +#endif // WEBENGINEPAGE_H diff --git a/src/widgets/scrolltext/scrolltext.cpp b/src/widgets/scrolltext/scrolltext.cpp new file mode 100644 index 0000000..00696af --- /dev/null +++ b/src/widgets/scrolltext/scrolltext.cpp @@ -0,0 +1,179 @@ +#include "scrolltext.h" +#include +#include + +ScrollText::ScrollText(QWidget *parent) : + QWidget(parent), scrollPos(0) +{ + + staticText.setTextFormat(Qt::PlainText); + + setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); + + setMinimumHeight(fontMetrics().height()+10); + setMaximumHeight(this->minimumHeight()+6); + + leftMargin = 0; //height() / 3; + + setSeparator(" "); + + connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); + timer.setInterval(50); +} + +QString ScrollText::text() const +{ + return _text; +} + +void ScrollText::setText(QString text) +{ + _text = text; + updateText(); + update(); +} + +QString ScrollText::separator() const +{ + return _separator; +} + +void ScrollText::setSeparator(QString separator) +{ + _separator = separator; + updateText(); + update(); +} + +void ScrollText::setLeftMargin(int pixels) +{ + leftMargin = pixels; + update(); +} + +void ScrollText::pause() +{ + if(scrollEnabled){ + timer.stop(); + } +} + +void ScrollText::resume() +{ + if(scrollEnabled){ + timer.start(); + scrolledOnce = false; + } +} + +void ScrollText::updateText() +{ + scrolledOnce = false; + timer.stop(); + + singleTextWidth = fontMetrics().horizontalAdvance(_text); +// scrollEnabled = true; + scrollEnabled = (singleTextWidth > width() - leftMargin); + + if(scrollEnabled) + { + scrollPos = -64; + staticText.setText(_text + _separator); + timer.start(); + } + else{ + staticText.setText(_text); + } + staticText.prepare(QTransform(), font()); + //wholeTextSize = QSize(fontMetrics().width(staticText.text()), fontMetrics().height()); + wholeTextSize = QSize(fontMetrics().horizontalAdvance(staticText.text()), fontMetrics().height()); + +} + +void ScrollText::paintEvent(QPaintEvent*) +{ + QPainter p(this); + + if(scrollEnabled) + { + buffer.fill(qRgba(0, 0, 0, 0)); + QPainter pb(&buffer); + pb.setPen(p.pen()); + pb.setFont(p.font()); + + int x = qMin(-scrollPos, 0) + leftMargin; + while(x < width()) + { + pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2) + QPoint(2, 2), staticText); + x += wholeTextSize.width(); + } + + //Apply Alpha Channel + pb.setCompositionMode(QPainter::CompositionMode_DestinationIn); + pb.setClipRect(width() - 15, 0, 15, height()); + pb.drawImage(0, 0, alphaChannel); + pb.setClipRect(0, 0, 15, height()); + //initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive + if(scrollPos < 0) + pb.setOpacity((qreal)(qMax(-8, scrollPos) + 8) / 8.0); + pb.drawImage(0, 0, alphaChannel); + p.drawImage(0, 0, buffer); + } + else + { + p.drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, text()); +// p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); + } +} + +void ScrollText::resizeEvent(QResizeEvent*) +{ + //When the widget is resized, we need to update the alpha channel. + + alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied); + buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); + + //Create Alpha Channel: + if(width() > 64) + { + //create first scanline + QRgb* scanline1 = (QRgb*)alphaChannel.scanLine(0); + for(int x = 1; x < 16; ++x) + scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); + for(int x = 15; x < width() - 15; ++x) + scanline1[x] = qRgb(0, 0, 0); + //copy scanline to the other ones + for(int y = 1; y < height(); ++y) + memcpy(alphaChannel.scanLine(y), (uchar*)scanline1, width() * 4); + } + else + alphaChannel.fill(qRgb(0, 0, 0)); + + + //Update scrolling state + bool newScrollEnabled = (singleTextWidth > width() - leftMargin); + if(newScrollEnabled != scrollEnabled) + updateText(); +} + +void ScrollText::timer_timeout() +{ + scrollPos = (scrollPos + 2) + % wholeTextSize.width(); + pauseAfterOneRotation(scrollPos); + update(); +} + +void ScrollText::pauseAfterOneRotation(int scrollPos) +{ + if(scrolledOnce == false && scrollPos+2==wholeTextSize.width()){ + scrolledOnce = true; + } + if(scrolledOnce){ + pause(); + } +} + + + + diff --git a/src/widgets/scrolltext/scrolltext.h b/src/widgets/scrolltext/scrolltext.h new file mode 100644 index 0000000..a660615 --- /dev/null +++ b/src/widgets/scrolltext/scrolltext.h @@ -0,0 +1,53 @@ +#ifndef SCROLLTEXT_H +#define SCROLLTEXT_H + +#include +#include +#include + + +class ScrollText : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QString separator READ separator WRITE setSeparator) + +public: + explicit ScrollText(QWidget *parent = 0); + +public slots: + QString text() const; + void setText(QString text); + + QString separator() const; + void setSeparator(QString separator); + void setLeftMargin(int pixels); + void pause(); + void resume(); + + +protected: + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + +private: + void updateText(); + QString _text; + QString _separator; + QStaticText staticText; + int singleTextWidth; + QSize wholeTextSize; + int leftMargin; + bool scrollEnabled; + int scrollPos; + QImage alphaChannel; + QImage buffer; + QTimer timer; + bool scrolledOnce = false; + +private slots: + virtual void timer_timeout(); + void pauseAfterOneRotation(int scrollPos); +}; + +#endif // SCROLLTEXT_H -- cgit v1.2.3