Update to a new version notification
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
141
src/widgets/updatenotificationwidget.cpp
Normal file
141
src/widgets/updatenotificationwidget.cpp
Normal 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);
|
||||
}
|
||||
47
src/widgets/updatenotificationwidget.h
Normal file
47
src/widgets/updatenotificationwidget.h
Normal 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
|
||||
Reference in New Issue
Block a user