Update to a new version notification

This commit is contained in:
Yuriy Puchkov
2020-12-09 18:12:37 +02:00
parent 4884609461
commit 784da1a652
10 changed files with 329 additions and 6 deletions

View File

@@ -30,8 +30,14 @@
#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMenu>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSystemTrayIcon>
#ifdef Q_OS_WIN
@@ -49,10 +55,12 @@
Controller::Controller()
: m_captureWindow(nullptr)
, m_history(nullptr)
, m_trayIconMenu(nullptr)
, m_networkCheckUpdates(nullptr)
, m_showCheckAppUpdateStatus(false)
{
m_history = nullptr;
m_trayIconMenu = nullptr;
m_appLatestVersion = QStringLiteral(APP_VERSION).replace("v", "");
qApp->setQuitOnLastWindowClosed(false);
// set default shortcusts if not set yet
@@ -84,6 +92,7 @@ Controller::Controller()
QScreen* currentScreen = QGuiApplication::screenAt(QCursor::pos());
currentScreen->grabWindow(QApplication::desktop()->winId(), 0, 0, 1, 1);
#endif
getLatestAvailableVersion();
}
Controller::~Controller()
@@ -106,6 +115,58 @@ void Controller::enableExports()
this, &Controller::captureFailed, this, &Controller::handleCaptureFailed);
}
void Controller::getLatestAvailableVersion()
{
// This features is required for MacOS and Windows user and for Linux users
// who installed Flameshot not from the repository.
m_networkCheckUpdates = new QNetworkAccessManager();
m_networkCheckUpdates = new QNetworkAccessManager(this);
QNetworkRequest requestCheckUpdates(QUrl(FLAMESHOT_APP_VERSION_URL));
connect(m_networkCheckUpdates,
&QNetworkAccessManager::finished,
this,
&Controller::handleReplyCheckUpdates);
m_networkCheckUpdates->get(requestCheckUpdates);
}
void Controller::handleReplyCheckUpdates(QNetworkReply* reply)
{
if (reply->error() == QNetworkReply::NoError) {
QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
QJsonObject json = response.object();
m_appLatestVersion = json["tag_name"].toString().replace("v", "");
if (m_appLatestVersion.compare(
QStringLiteral(APP_VERSION).replace("v", "")) < 0) {
// Next commented lines are for debugging
// if (m_appLatestVersion.compare(
// QStringLiteral("v0.8.5.4").replace("v", "")) > 0) {
m_appLatestUrl = json["html_url"].toString();
QString newVersion =
tr("New version %1 is available").arg(m_appLatestVersion);
m_appUpdates->setText(newVersion);
if (m_showCheckAppUpdateStatus) {
sendTrayNotification(newVersion, "Flameshot", 5);
QDesktopServices::openUrl(QUrl(m_appLatestUrl));
}
} else if (m_showCheckAppUpdateStatus) {
sendTrayNotification(
tr("You have the latest version"), "Flameshot", 5);
}
}
// nothing to do on fails, is not critical for checking for updates
m_showCheckAppUpdateStatus = false;
}
void Controller::appUpdates()
{
if (m_appLatestUrl.isEmpty()) {
m_showCheckAppUpdateStatus = true;
getLatestAvailableVersion();
} else {
QDesktopServices::openUrl(QUrl(m_appLatestUrl));
}
}
void Controller::requestCapture(const CaptureRequest& request)
{
uint id = request.id();
@@ -170,13 +231,18 @@ void Controller::startVisualCapture(const uint id,
#elif (defined(Q_OS_MAC) || defined(Q_OS_MAC64) || defined(Q_OS_MACOS) || \
defined(Q_OS_MACX))
// In "Emulate fullscreen mode"
// m_captureWindow->show();
m_captureWindow->showFullScreen();
m_captureWindow->activateWindow();
m_captureWindow->raise();
#else
m_captureWindow->showFullScreen();
#endif
if (!m_appLatestUrl.isEmpty() &&
0 != m_appLatestVersion.compare(
ConfigHandler().ignoreUpdateToVersion())) {
m_captureWindow->showAppUpdateNotification(m_appLatestVersion,
m_appLatestUrl);
}
} else {
emit captureFailed(id);
}
@@ -262,6 +328,10 @@ void Controller::enableTrayIcon()
configAction, &QAction::triggered, this, &Controller::openConfigWindow);
QAction* infoAction = new QAction(tr("&About"), this);
connect(infoAction, &QAction::triggered, this, &Controller::openInfoWindow);
m_appUpdates = new QAction(tr("Check for updates"), this);
connect(m_appUpdates, &QAction::triggered, this, &Controller::appUpdates);
QAction* quitAction = new QAction(tr("&Quit"), this);
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
@@ -277,6 +347,8 @@ void Controller::enableTrayIcon()
m_trayIconMenu->addAction(recentAction);
m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(configAction);
m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(m_appUpdates);
m_trayIconMenu->addAction(infoAction);
m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(quitAction);

View File

@@ -17,6 +17,9 @@
#pragma once
#define FLAMESHOT_APP_VERSION_URL \
"https://api.github.com/repos/namecheap/flameshot/releases/latest"
#include "src/core/capturerequest.h"
#include <QMap>
#include <QMenu>
@@ -32,6 +35,8 @@ class InfoWindow;
class QSystemTrayIcon;
class CaptureLauncher;
class HistoryWidget;
class QNetworkAccessManager;
class QNetworkReply;
using lambda = std::function<void(void)>;
class Controller : public QObject
@@ -57,6 +62,7 @@ public slots:
void openConfigWindow();
void openInfoWindow();
void appUpdates();
void openLauncherWindow();
void enableTrayIcon();
void disableTrayIcon();
@@ -78,13 +84,22 @@ private slots:
void handleCaptureTaken(uint id, QPixmap p);
void handleCaptureFailed(uint id);
void handleReplyCheckUpdates(QNetworkReply* reply);
private:
Controller();
void getLatestAvailableVersion();
// replace QTimer::singleShot introduced in Qt 5.4
// the actual target Qt version is 5.3
void doLater(int msec, QObject* receiver, lambda func);
// class members
QAction* m_appUpdates;
QString m_appLatestUrl;
QString m_appLatestVersion;
bool m_showCheckAppUpdateStatus;
QMap<uint, CaptureRequest> m_requestMap;
QPointer<CaptureWidget> m_captureWindow;
QPointer<InfoWindow> m_infoWindow;
@@ -94,4 +109,6 @@ private:
HistoryWidget* m_history;
QMenu* m_trayIconMenu;
QNetworkAccessManager* m_networkCheckUpdates;
};

View File

@@ -1,4 +1,5 @@
#include "imgs3settings.h"
#include "src/core/controller.h"
#include "src/tools/storage/imgstorages.h"
#include "src/utils/confighandler.h"
#include <QByteArray>

View File

@@ -236,6 +236,16 @@ void ConfigHandler::setShowSidePanelButton(const bool showSidePanelButton)
showSidePanelButton);
}
void ConfigHandler::setIgnoreUpdateToVersion(const QString& text)
{
m_settings.setValue(QStringLiteral("ignoreUpdateToVersion"), text);
}
QString ConfigHandler::ignoreUpdateToVersion()
{
return m_settings.value(QStringLiteral("ignoreUpdateToVersion")).toString();
}
bool ConfigHandler::desktopNotificationValue()
{
bool res = true;

View File

@@ -97,6 +97,9 @@ public:
void setDefaults();
void setAllTheButtons();
void setIgnoreUpdateToVersion(const QString& text);
QString ignoreUpdateToVersion();
QVector<QStringList> shortcuts();
void setShortcutsDefault();
bool setShortcut(const QString&, const QString&);

View File

@@ -12,6 +12,7 @@ target_sources(
notificationwidget.h
orientablepushbutton.h
historywidget.h
updatenotificationwidget.h
)
target_sources(
@@ -24,4 +25,5 @@ target_sources(
notificationwidget.cpp
orientablepushbutton.cpp
historywidget.cpp
updatenotificationwidget.cpp
)

View File

@@ -24,7 +24,6 @@
// <http://www.gnu.org/licenses/old-licenses/library.txt>
#include "capturewidget.h"
#include "src/core/controller.h"
#include "src/tools/storage/storagemanager.h"
#include "src/tools/toolfactory.h"
#include "src/utils/colorutils.h"
@@ -37,6 +36,7 @@
#include "src/widgets/capture/notifierbox.h"
#include "src/widgets/orientablepushbutton.h"
#include "src/widgets/panel/sidepanelwidget.h"
#include "src/widgets/updatenotificationwidget.h"
#include <QApplication>
#include <QDateTime>
#include <QDesktopWidget>
@@ -68,8 +68,9 @@ CaptureWidget::CaptureWidget(const uint id,
, m_toolWidget(nullptr)
, m_mouseOverHandle(SelectionWidget::NO_SIDE)
, m_id(id)
, m_lastMouseWheel(0)
, m_updateNotificationWidget(nullptr)
{
m_lastMouseWheel = 0;
// Base config of the widget
m_eventFilter = new HoverEventFilter(this);
connect(m_eventFilter,
@@ -294,7 +295,19 @@ void CaptureWidget::paintEvent(QPaintEvent*)
painter.setClipRect(rect());
if (m_showInitialMsg) {
#if (defined(Q_OS_MAC) || defined(Q_OS_MAC64) || defined(Q_OS_MACOS) || \
defined(Q_OS_MACX))
QRect helpRect;
QScreen* currentScreen = QGuiApplication::screenAt(QCursor::pos());
if (currentScreen) {
helpRect = currentScreen->geometry();
} else {
helpRect = QGuiApplication::primaryScreen()->geometry();
}
#else
QRect helpRect = QGuiApplication::primaryScreen()->geometry();
#endif
helpRect.moveTo(mapFromGlobal(helpRect.topLeft()));
QString helpTxt =
@@ -764,6 +777,19 @@ void CaptureWidget::initPanel()
m_panel->pushWidget(new QUndoView(&m_undoStack, this));
}
void CaptureWidget::showAppUpdateNotification(const QString& appLatestVersion,
const QString& appLatestUrl)
{
if (nullptr == m_updateNotificationWidget) {
m_updateNotificationWidget =
new UpdateNotificationWidget(this, appLatestVersion, appLatestUrl);
}
m_updateNotificationWidget->move(
(width() - m_updateNotificationWidget->width()) / 2, 0);
makeChild(m_updateNotificationWidget);
m_updateNotificationWidget->show();
}
void CaptureWidget::initSelection()
{
m_selection = new SelectionWidget(m_uiColor, this);

View File

@@ -44,6 +44,7 @@ class QNetworkReply;
class ColorPicker;
class NotifierBox;
class HoverEventFilter;
class UpdateNotificationWidget;
class CaptureWidget : public QWidget
{
@@ -58,6 +59,8 @@ public:
void updateButtons();
QPixmap pixmap();
void showAppUpdateNotification(const QString& appLatestVersion,
const QString& appLatestUrl);
public slots:
void deleteToolwidgetOrClose();
@@ -145,6 +148,7 @@ private:
QRect extendedRect(QRect* r) const;
private:
UpdateNotificationWidget* m_updateNotificationWidget;
quint64 m_lastMouseWheel;
QUndoStack m_undoStack;
QPointer<CaptureToolButton> m_sizeIndButton;

View File

@@ -0,0 +1,141 @@
//
// Created by yuriypuchkov on 09.12.2020.
//
#include "updatenotificationwidget.h"
#include "src/utils/confighandler.h"
#include <QDesktopServices>
#include <QLabel>
#include <QPropertyAnimation>
#include <QPushButton>
#include <QScrollArea>
#include <QTimer>
#include <QVBoxLayout>
#include <QWheelEvent>
UpdateNotificationWidget::UpdateNotificationWidget(
QWidget* parent,
const QString& appLatestVersion,
const QString& appLatestUrl)
: QWidget(parent)
, m_appLatestVersion(appLatestVersion)
, m_appLatestUrl(appLatestUrl)
, m_layout(nullptr)
{
setMinimumSize(400, 100);
initInternalPanel();
setAttribute(Qt::WA_TransparentForMouseEvents);
setCursor(Qt::ArrowCursor);
m_showAnimation = new QPropertyAnimation(m_internalPanel, "geometry", this);
m_showAnimation->setEasingCurve(QEasingCurve::InOutQuad);
m_showAnimation->setDuration(300);
m_hideAnimation = new QPropertyAnimation(m_internalPanel, "geometry", this);
m_hideAnimation->setEasingCurve(QEasingCurve::InOutQuad);
m_hideAnimation->setDuration(300);
connect(m_hideAnimation,
&QPropertyAnimation::finished,
m_internalPanel,
&QWidget::hide);
setAppLatestVersion(appLatestVersion);
}
void UpdateNotificationWidget::show()
{
setAttribute(Qt::WA_TransparentForMouseEvents, false);
m_showAnimation->setStartValue(QRect(0, -height(), width(), height()));
m_showAnimation->setEndValue(QRect(0, 0, width(), height()));
m_internalPanel->show();
m_showAnimation->start();
QWidget::show();
}
void UpdateNotificationWidget::hide()
{
setAttribute(Qt::WA_TransparentForMouseEvents);
m_hideAnimation->setStartValue(QRect(0, 0, width(), height()));
m_hideAnimation->setEndValue(QRect(0, -height(), 0, height()));
m_hideAnimation->start();
m_internalPanel->hide();
QWidget::hide();
}
void UpdateNotificationWidget::setAppLatestVersion(const QString& latestVersion)
{
m_appLatestVersion = latestVersion;
QString newVersion =
tr("New Flameshot version %1 is available").arg(latestVersion);
m_notification->setText(newVersion);
}
void UpdateNotificationWidget::laterButton()
{
hide();
}
void UpdateNotificationWidget::ignoreButton()
{
ConfigHandler().setIgnoreUpdateToVersion(m_appLatestVersion);
hide();
}
void UpdateNotificationWidget::updateButton()
{
QDesktopServices::openUrl(m_appLatestUrl);
hide();
}
void UpdateNotificationWidget::initInternalPanel()
{
m_internalPanel = new QScrollArea(this);
m_internalPanel->setAttribute(Qt::WA_NoMousePropagation);
QWidget* widget = new QWidget();
m_internalPanel->setWidget(widget);
m_internalPanel->setWidgetResizable(true);
QColor bgColor = palette().window().color();
bgColor.setAlphaF(0.0);
m_internalPanel->setStyleSheet(
QStringLiteral("QScrollArea {background-color: %1}").arg(bgColor.name()));
m_internalPanel->hide();
//
m_layout = new QVBoxLayout();
widget->setLayout(m_layout);
// caption
m_notification = new QLabel(m_appLatestVersion, this);
m_layout->addWidget(m_notification);
// buttons layout
QHBoxLayout* buttonsLayout = new QHBoxLayout();
QSpacerItem* bottonsSpacer = new QSpacerItem(1, 1, QSizePolicy::Expanding);
buttonsLayout->addSpacerItem(bottonsSpacer);
m_layout->addLayout(buttonsLayout);
// ignore
QPushButton* ignoreBtn = new QPushButton(tr("Ignore"), this);
buttonsLayout->addWidget(ignoreBtn);
connect(ignoreBtn,
&QPushButton::clicked,
this,
&UpdateNotificationWidget::ignoreButton);
// later
QPushButton* laterBtn = new QPushButton(tr("Later"), this);
buttonsLayout->addWidget(laterBtn);
connect(laterBtn,
&QPushButton::clicked,
this,
&UpdateNotificationWidget::laterButton);
// update
QPushButton* updateBtn = new QPushButton(tr("Update"), this);
buttonsLayout->addWidget(updateBtn);
connect(updateBtn,
&QPushButton::clicked,
this,
&UpdateNotificationWidget::updateButton);
}

View File

@@ -0,0 +1,47 @@
//
// Created by yuriypuchkov on 09.12.2020.
//
#ifndef FLAMESHOT_UPDATENOTIFICATIONWIDGET_H
#define FLAMESHOT_UPDATENOTIFICATIONWIDGET_H
#include <QPointer>
#include <QWidget>
class QVBoxLayout;
class QPropertyAnimation;
class QScrollArea;
class QPushButton;
class QLabel;
class UpdateNotificationWidget : public QWidget
{
Q_OBJECT
public:
explicit UpdateNotificationWidget(QWidget* parent,
const QString& appLatestVersion,
const QString& appLatestUrl);
void setAppLatestVersion(const QString& latestVersion);
void hide();
void show();
public slots:
void ignoreButton();
void laterButton();
void updateButton();
private:
void initInternalPanel();
// class members
QString m_appLatestVersion;
QString m_appLatestUrl;
QVBoxLayout* m_layout;
QLabel* m_notification;
QScrollArea* m_internalPanel;
QPropertyAnimation* m_showAnimation;
QPropertyAnimation* m_hideAnimation;
};
#endif // FLAMESHOT_UPDATENOTIFICATIONWIDGET_H