feat: ask for permission before update check
This commit is contained in:
parent
4f0e8cb844
commit
b904cba040
13 changed files with 206 additions and 24 deletions
16
.env.example
16
.env.example
|
|
@ -7,28 +7,28 @@
|
|||
#
|
||||
|
||||
# Serial key value to pre-fill the activation dialog
|
||||
# SYNERGY_TEST_SERIAL_KEY="DEADBEEF"
|
||||
# DESKFLOW_TEST_SERIAL_KEY="DEADBEEF"
|
||||
|
||||
# Shows the test menu in the GUI (on by default in debug mode)
|
||||
# SYNERGY_TEST_MENU=true
|
||||
# DESKFLOW_TEST_MENU=true
|
||||
|
||||
# Version checker URL to use (useful for testing)
|
||||
# SYNERGY_VERSION_URL="http://localhost:8787?version=v1"
|
||||
# DESKFLOW_VERSION_URL="https://api.deskflow.org/version?fake=1.100.0"
|
||||
|
||||
# Enable debug logging in the GUI (on by default in debug mode)
|
||||
# SYNERGY_GUI_DEBUG=true
|
||||
# DESKFLOW_GUI_DEBUG=true
|
||||
|
||||
# Enable verbose logging in the GUI (always off by default)
|
||||
# SYNERGY_GUI_VERBOSE=true
|
||||
# DESKFLOW_GUI_VERBOSE=true
|
||||
|
||||
# Reset all settings and delete all data on startup
|
||||
# SYNERGY_RESET_ALL=true
|
||||
# DESKFLOW_RESET_ALL=true
|
||||
|
||||
# Enable the activation dialog (used for testing)
|
||||
# SYNERGY_ENABLE_ACTIVATION=true
|
||||
# DESKFLOW_ENABLE_ACTIVATION=true
|
||||
|
||||
# Show licensed product menu items, etc (used for testing)
|
||||
# SYNERGY_LICENSED_PRODUCT=true
|
||||
# DESKFLOW_LICENSED_PRODUCT=true
|
||||
|
||||
#
|
||||
# Build
|
||||
|
|
|
|||
8
.vscode/tasks.json
vendored
8
.vscode/tasks.json
vendored
|
|
@ -67,9 +67,9 @@
|
|||
{
|
||||
"label": "kill",
|
||||
"type": "shell",
|
||||
"command": "killall synergy; killall synergyc; killall synergys || true",
|
||||
"command": "killall deskflow; killall deskflowc; killall deskflows || true",
|
||||
"windows": {
|
||||
"command": "taskkill /F /IM synergy.exe /IM synergyc.exe /IM synergys.exe; $true"
|
||||
"command": "taskkill /F /IM deskflow.exe /IM deskflowc.exe /IM deskflows.exe; $true"
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
|
|
@ -83,11 +83,11 @@
|
|||
{
|
||||
"label": "gui",
|
||||
"type": "process",
|
||||
"command": "${workspaceFolder}/build/bin/synergy",
|
||||
"command": "${workspaceFolder}/build/bin/deskflow",
|
||||
"dependsOn": ["build", "kill"],
|
||||
"problemMatcher": [],
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/build/bin/synergy.exe"
|
||||
"command": "${workspaceFolder}/build/bin/deskflow.exe"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -570,7 +570,15 @@ void MainWindow::open() {
|
|||
showAndActivate();
|
||||
}
|
||||
|
||||
m_VersionChecker.checkLatest();
|
||||
if (!m_AppConfig.enableUpdateCheck().has_value()) {
|
||||
m_AppConfig.setEnableUpdateCheck(messages::showUpdateCheckOption(this));
|
||||
}
|
||||
|
||||
if (m_AppConfig.enableUpdateCheck().value()) {
|
||||
m_VersionChecker.checkLatest();
|
||||
} else {
|
||||
qDebug("update check disabled");
|
||||
}
|
||||
|
||||
if (m_AppConfig.startedBefore()) {
|
||||
m_CoreProcess.start();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "VersionChecker.h"
|
||||
|
||||
#include "env_vars.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
|
@ -27,17 +29,21 @@
|
|||
|
||||
const char *const kVersion = DESKFLOW_VERSION;
|
||||
|
||||
VersionChecker::VersionChecker(std::shared_ptr<QNetworkAccessManager> network)
|
||||
using namespace deskflow::gui;
|
||||
|
||||
VersionChecker::VersionChecker(
|
||||
std::shared_ptr<QNetworkAccessManagerProxy> network)
|
||||
: m_network(
|
||||
network ? network : std::make_shared<QNetworkAccessManager>(this)) {
|
||||
network ? network : std::make_shared<QNetworkAccessManagerProxy>()) {
|
||||
m_network->init();
|
||||
connect(
|
||||
m_network.get(), SIGNAL(finished(QNetworkReply *)), this,
|
||||
SLOT(replyFinished(QNetworkReply *)));
|
||||
m_network.get(), &QNetworkAccessManagerProxy::finished, this,
|
||||
&VersionChecker::replyFinished);
|
||||
}
|
||||
|
||||
void VersionChecker::checkLatest() const {
|
||||
const QString url =
|
||||
qEnvironmentVariable("DESKFLOW_VERSION_URL", DESKFLOW_VERSION_URL);
|
||||
const QString url = env_vars::versionUrl();
|
||||
qDebug("checking for updates at: %s", qPrintable(url));
|
||||
auto request = QNetworkRequest(url);
|
||||
auto userAgent = QString("Deskflow %1 on %2")
|
||||
.arg(kVersion)
|
||||
|
|
@ -53,7 +59,10 @@ void VersionChecker::replyFinished(QNetworkReply *reply) {
|
|||
auto newestVersion = QString(reply->readAll());
|
||||
if (!newestVersion.isEmpty() &&
|
||||
compareVersions(DESKFLOW_VERSION, newestVersion) > 0) {
|
||||
qDebug("update found: %s", qPrintable(newestVersion));
|
||||
emit updateFound(newestVersion);
|
||||
} else {
|
||||
qDebug("no updates found");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "proxy/QNetworkAccessManagerProxy.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
|
@ -26,13 +28,16 @@ class QNetworkReply;
|
|||
class VersionCheckerTests;
|
||||
|
||||
class VersionChecker : public QObject {
|
||||
using QNetworkAccessManagerProxy =
|
||||
deskflow::gui::proxy::QNetworkAccessManagerProxy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
friend class VersionCheckerTests;
|
||||
|
||||
public:
|
||||
explicit VersionChecker(
|
||||
std::shared_ptr<QNetworkAccessManager> network = nullptr);
|
||||
std::shared_ptr<QNetworkAccessManagerProxy> network = nullptr);
|
||||
void checkLatest() const;
|
||||
public slots:
|
||||
void replyFinished(QNetworkReply *reply);
|
||||
|
|
@ -50,5 +55,5 @@ private:
|
|||
*/
|
||||
static int getStageVersion(QString stage);
|
||||
|
||||
std::shared_ptr<QNetworkAccessManager> m_network;
|
||||
std::shared_ptr<QNetworkAccessManagerProxy> m_network;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ const char *const AppConfig::m_SettingsName[] = {
|
|||
"mainWindowPosition",
|
||||
"showDevThanks",
|
||||
"showCloseReminder",
|
||||
"enableUpdateCheck",
|
||||
};
|
||||
|
||||
AppConfig::AppConfig(
|
||||
|
|
@ -175,6 +176,8 @@ void AppConfig::recallFromCurrentScope() {
|
|||
getFromCurrentScope(kShowDevThanks, m_ShowDevThanks).toBool();
|
||||
m_ShowCloseReminder =
|
||||
getFromCurrentScope(kShowCloseReminder, m_ShowCloseReminder).toBool();
|
||||
m_EnableUpdateCheck = getFromCurrentScope<bool>(
|
||||
kEnableUpdateCheck, [](const QVariant &v) { return v.toBool(); });
|
||||
}
|
||||
|
||||
void AppConfig::recallScreenName() {
|
||||
|
|
@ -231,11 +234,11 @@ void AppConfig::commit() {
|
|||
setInCurrentScope(kInvertConnection, m_InvertConnection);
|
||||
setInCurrentScope(kEnableService, m_EnableService);
|
||||
setInCurrentScope(kCloseToTray, m_CloseToTray);
|
||||
setInCurrentScope(kShowDevThanks, m_ShowDevThanks);
|
||||
setInCurrentScope(kShowCloseReminder, m_ShowCloseReminder);
|
||||
|
||||
setInCurrentScope(kMainWindowSize, m_MainWindowSize);
|
||||
setInCurrentScope(kMainWindowPosition, m_MainWindowPosition);
|
||||
setInCurrentScope(kShowDevThanks, m_ShowDevThanks);
|
||||
setInCurrentScope(kShowCloseReminder, m_ShowCloseReminder);
|
||||
setInCurrentScope(kEnableUpdateCheck, m_EnableUpdateCheck);
|
||||
}
|
||||
|
||||
if (m_TlsChanged) {
|
||||
|
|
@ -535,6 +538,10 @@ bool AppConfig::showDevThanks() const { return m_ShowDevThanks; }
|
|||
|
||||
bool AppConfig::showCloseReminder() const { return m_ShowCloseReminder; }
|
||||
|
||||
std::optional<bool> AppConfig::enableUpdateCheck() const {
|
||||
return m_EnableUpdateCheck;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// End getters
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -661,6 +668,10 @@ void AppConfig::setShowCloseReminder(bool value) {
|
|||
m_ShowCloseReminder = value;
|
||||
}
|
||||
|
||||
void AppConfig::setEnableUpdateCheck(bool value) {
|
||||
m_EnableUpdateCheck = value;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// End setters
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ private:
|
|||
kMainWindowPosition = 40,
|
||||
kShowDevThanks = 41,
|
||||
kShowCloseReminder = 42,
|
||||
kEnableUpdateCheck = 43,
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
@ -180,6 +181,7 @@ public:
|
|||
std::optional<QPoint> mainWindowPosition() const;
|
||||
bool showDevThanks() const;
|
||||
bool showCloseReminder() const;
|
||||
std::optional<bool> enableUpdateCheck() const;
|
||||
|
||||
//
|
||||
// Setters (overrides)
|
||||
|
|
@ -224,6 +226,7 @@ public:
|
|||
void setMainWindowPosition(const QPoint &position);
|
||||
void setShowDevThanks(bool show);
|
||||
void setShowCloseReminder(bool show);
|
||||
void setEnableUpdateCheck(bool value);
|
||||
|
||||
/// @brief Sets the user preference to load from SystemScope.
|
||||
/// @param [in] value
|
||||
|
|
@ -332,6 +335,7 @@ private:
|
|||
bool m_ShowDevThanks = !deskflow::gui::license::isLicensedProduct();
|
||||
bool m_LoadFromSystemScope = false;
|
||||
bool m_ShowCloseReminder = true;
|
||||
std::optional<bool> m_EnableUpdateCheck;
|
||||
|
||||
/**
|
||||
* @brief Flag is set when any TLS is setting is changed, and is reset
|
||||
|
|
|
|||
29
src/lib/gui/env_vars.h
Normal file
29
src/lib/gui/env_vars.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2024 Symless Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file LICENSE that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QtCore>
|
||||
|
||||
namespace deskflow::gui::env_vars {
|
||||
|
||||
inline QString versionUrl() {
|
||||
return qEnvironmentVariable("DESKFLOW_VERSION_URL", DESKFLOW_VERSION_URL);
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui::env_vars
|
||||
|
|
@ -18,8 +18,10 @@
|
|||
#include "messages.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/version.h"
|
||||
#include "constants.h"
|
||||
#include "env_vars.h"
|
||||
#include "gui/license/license_utils.h"
|
||||
#include "styles.h"
|
||||
|
||||
|
|
@ -314,4 +316,19 @@ void showWaylandLibraryError(QWidget *parent) {
|
|||
.arg(kUrlBugReport, kColorSecondary));
|
||||
}
|
||||
|
||||
bool showUpdateCheckOption(QWidget *parent) {
|
||||
QMessageBox message(parent);
|
||||
message.addButton(QObject::tr("Close"), QMessageBox::RejectRole);
|
||||
const auto checkButton = message.addButton(
|
||||
QObject::tr("Check for updates"), QMessageBox::AcceptRole);
|
||||
message.setText(
|
||||
QString("<p>Would you like to check for updates when %1 starts?</p>"
|
||||
"<p>Checking for updates requires an Internet connection.</p>"
|
||||
"<p>URL: <pre>%2</pre></p>")
|
||||
.arg(kAppName, env_vars::versionUrl()));
|
||||
|
||||
message.exec();
|
||||
return message.clickedButton() == checkButton;
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui::messages
|
||||
|
|
|
|||
|
|
@ -56,4 +56,6 @@ void showWaylandExperimental(QWidget *parent);
|
|||
|
||||
void showWaylandLibraryError(QWidget *parent);
|
||||
|
||||
bool showUpdateCheckOption(QWidget *parent);
|
||||
|
||||
} // namespace deskflow::gui::messages
|
||||
|
|
|
|||
37
src/lib/gui/proxy/QNetworkAccessManagerProxy.cpp
Normal file
37
src/lib/gui/proxy/QNetworkAccessManagerProxy.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2024 Symless Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file LICENSE that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "QNetworkAccessManagerProxy.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
namespace deskflow::gui::proxy {
|
||||
|
||||
void QNetworkAccessManagerProxy::init() {
|
||||
m_network = std::make_shared<QNetworkAccessManager>();
|
||||
|
||||
connect(
|
||||
m_network.get(), &QNetworkAccessManager::finished, this,
|
||||
[this](QNetworkReply *reply) { emit finished(reply); });
|
||||
}
|
||||
|
||||
void QNetworkAccessManagerProxy::get(const QNetworkRequest &request) const {
|
||||
m_network->get(request);
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui::proxy
|
||||
39
src/lib/gui/proxy/QNetworkAccessManagerProxy.h
Normal file
39
src/lib/gui/proxy/QNetworkAccessManagerProxy.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2024 Symless Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file LICENSE that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QObject>
|
||||
|
||||
namespace deskflow::gui::proxy {
|
||||
|
||||
class QNetworkAccessManagerProxy : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual void init();
|
||||
virtual void get(const QNetworkRequest &request) const;
|
||||
|
||||
signals:
|
||||
void finished(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
std::shared_ptr<QNetworkAccessManager> m_network;
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui::proxy
|
||||
|
|
@ -16,9 +16,14 @@
|
|||
*/
|
||||
|
||||
#include "gui/VersionChecker.h"
|
||||
#include "shared/gui/TestQtCoreApp.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace deskflow::gui::proxy;
|
||||
using namespace testing;
|
||||
|
||||
class VersionCheckerTests : public ::testing::Test {
|
||||
protected:
|
||||
int compareVersions(const QString &left, const QString &right) {
|
||||
|
|
@ -26,6 +31,22 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
class MockNetworkAccessManager : public QNetworkAccessManagerProxy {
|
||||
public:
|
||||
MOCK_METHOD(void, init, (), (override));
|
||||
MOCK_METHOD(void, get, (const QNetworkRequest &request), (const, override));
|
||||
};
|
||||
|
||||
TEST_F(VersionCheckerTests, checkLatest_callsNetworkGet) {
|
||||
TestQtCoreApp app;
|
||||
const auto network = std::make_shared<NiceMock<MockNetworkAccessManager>>();
|
||||
const VersionChecker checker(network);
|
||||
|
||||
EXPECT_CALL(*network, get(testing::_)).Times(1);
|
||||
|
||||
checker.checkLatest();
|
||||
}
|
||||
|
||||
TEST_F(VersionCheckerTests, compareVersions_major_isValid) {
|
||||
EXPECT_EQ(compareVersions("1.0.0", "2.0.0"), 1);
|
||||
EXPECT_EQ(compareVersions("2.0.0", "1.0.0"), -1);
|
||||
|
|
|
|||
Loading…
Reference in a new issue