mirror of
https://github.com/huderlem/porymap.git
synced 2026-08-23 00:56:47 -05:00
Merge pull request #590 from GriffinRichards/update-promoter
Add update promoter
This commit is contained in:
@@ -8,9 +8,14 @@
|
||||
#include <QSize>
|
||||
#include <QKeySequence>
|
||||
#include <QMultiMap>
|
||||
#include <QDateTime>
|
||||
#include <QUrl>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#include "events.h"
|
||||
|
||||
static const QVersionNumber porymapVersion = QVersionNumber::fromString(PORYMAP_VERSION);
|
||||
|
||||
// In both versions the default new map border is a generic tree
|
||||
#define DEFAULT_BORDER_RSE (QList<uint16_t>{0x1D4, 0x1D5, 0x1DC, 0x1DD})
|
||||
#define DEFAULT_BORDER_FRLG (QList<uint16_t>{0x14, 0x15, 0x1C, 0x1D})
|
||||
@@ -74,6 +79,10 @@ public:
|
||||
this->paletteEditorBitDepth = 24;
|
||||
this->projectSettingsTab = 0;
|
||||
this->warpBehaviorWarningDisabled = false;
|
||||
this->checkForUpdates = true;
|
||||
this->lastUpdateCheckTime = QDateTime();
|
||||
this->lastUpdateCheckVersion = porymapVersion;
|
||||
this->rateLimitTimes.clear();
|
||||
}
|
||||
void addRecentProject(QString project);
|
||||
void setRecentProjects(QStringList projects);
|
||||
@@ -105,6 +114,10 @@ public:
|
||||
void setPaletteEditorBitDepth(int bitDepth);
|
||||
void setProjectSettingsTab(int tab);
|
||||
void setWarpBehaviorWarningDisabled(bool disabled);
|
||||
void setCheckForUpdates(bool enabled);
|
||||
void setLastUpdateCheckTime(QDateTime time);
|
||||
void setLastUpdateCheckVersion(QVersionNumber version);
|
||||
void setRateLimitTimes(QMap<QUrl, QDateTime> map);
|
||||
QString getRecentProject();
|
||||
QStringList getRecentProjects();
|
||||
bool getReopenOnLaunch();
|
||||
@@ -135,6 +148,10 @@ public:
|
||||
int getPaletteEditorBitDepth();
|
||||
int getProjectSettingsTab();
|
||||
bool getWarpBehaviorWarningDisabled();
|
||||
bool getCheckForUpdates();
|
||||
QDateTime getLastUpdateCheckTime();
|
||||
QVersionNumber getLastUpdateCheckVersion();
|
||||
QMap<QUrl, QDateTime> getRateLimitTimes();
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
@@ -183,6 +200,10 @@ private:
|
||||
int paletteEditorBitDepth;
|
||||
int projectSettingsTab;
|
||||
bool warpBehaviorWarningDisabled;
|
||||
bool checkForUpdates;
|
||||
QDateTime lastUpdateCheckTime;
|
||||
QVersionNumber lastUpdateCheckVersion;
|
||||
QMap<QUrl, QDateTime> rateLimitTimes;
|
||||
};
|
||||
|
||||
extern PorymapConfig porymapConfig;
|
||||
|
||||
87
include/core/network.h
Normal file
87
include/core/network.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
/*
|
||||
The two classes defined here provide a simplified interface for Qt's network classes QNetworkAccessManager and QNetworkReply.
|
||||
|
||||
With the Qt classes, the workflow for a GET is roughly: generate a QNetworkRequest, give this request to QNetworkAccessManager::get,
|
||||
connect the returned object to QNetworkReply::finished, and in the slot of that connection handle the various HTTP headers and attributes,
|
||||
then manage errors or process the webpage's body.
|
||||
|
||||
These classes handle generating the QNetworkRequest with a given URL and manage the HTTP headers in the reply. They will automatically
|
||||
respect rate limits and return cached data if the webpage hasn't changed since previous requests. Instead of interacting with a QNetworkReply,
|
||||
callers interact with a simplified NetworkReplyData.
|
||||
Example that logs Porymap's description on GitHub:
|
||||
|
||||
NetworkAccessManager * manager = new NetworkAccessManager(this);
|
||||
NetworkReplyData * reply = manager->get("https://api.github.com/repos/huderlem/porymap");
|
||||
connect(reply, &NetworkReplyData::finished, [reply] () {
|
||||
if (!reply->errorString().isEmpty()) {
|
||||
logError(QString("Failed to read description: %1").arg(reply->errorString()));
|
||||
} else {
|
||||
auto webpage = QJsonDocument::fromJson(reply->body());
|
||||
logInfo(QString("Porymap: %1").arg(webpage["description"].toString()));
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
*/
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QDateTime>
|
||||
|
||||
class NetworkReplyData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QUrl url() const { return m_url; }
|
||||
QUrl nextUrl() const { return m_nextUrl; }
|
||||
QByteArray body() const { return m_body; }
|
||||
QString errorString() const { return m_error; }
|
||||
QDateTime retryAfter() const { return m_retryAfter; }
|
||||
bool isFinished() const { return m_finished; }
|
||||
|
||||
friend class NetworkAccessManager;
|
||||
|
||||
private:
|
||||
QUrl m_url;
|
||||
QUrl m_nextUrl;
|
||||
QByteArray m_body;
|
||||
QString m_error;
|
||||
QDateTime m_retryAfter;
|
||||
bool m_finished;
|
||||
|
||||
void finish() {
|
||||
m_finished = true;
|
||||
emit finished();
|
||||
};
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
};
|
||||
|
||||
class NetworkAccessManager : public QNetworkAccessManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NetworkAccessManager(QObject * parent = nullptr);
|
||||
~NetworkAccessManager();
|
||||
NetworkReplyData * get(const QString &url);
|
||||
NetworkReplyData * get(const QUrl &url);
|
||||
|
||||
private:
|
||||
// For a more complex cache we could implement a QAbstractCache for the manager
|
||||
struct CacheEntry {
|
||||
QString eTag;
|
||||
QByteArray data;
|
||||
};
|
||||
QMap<QUrl, CacheEntry*> cache;
|
||||
QMap<QUrl, QDateTime> rateLimitTimes;
|
||||
void processReply(QNetworkReply * reply, NetworkReplyData * data);
|
||||
const QNetworkRequest getRequest(const QUrl &url);
|
||||
};
|
||||
|
||||
#endif // NETWORK_H
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "preferenceeditor.h"
|
||||
#include "projectsettingseditor.h"
|
||||
#include "customscriptseditor.h"
|
||||
#include "updatepromoter.h"
|
||||
|
||||
|
||||
|
||||
@@ -288,6 +289,7 @@ private slots:
|
||||
void on_spinBox_SelectedCollision_valueChanged(int collision);
|
||||
void on_actionRegion_Map_Editor_triggered();
|
||||
void on_actionPreferences_triggered();
|
||||
void on_actionCheck_for_Updates_triggered();
|
||||
void togglePreferenceSpecificUi();
|
||||
void on_actionProject_Settings_triggered();
|
||||
void on_actionCustom_Scripts_triggered();
|
||||
@@ -307,6 +309,8 @@ private:
|
||||
QPointer<PreferenceEditor> preferenceEditor = nullptr;
|
||||
QPointer<ProjectSettingsEditor> projectSettingsEditor = nullptr;
|
||||
QPointer<CustomScriptsEditor> customScriptsEditor = nullptr;
|
||||
QPointer<UpdatePromoter> updatePromoter = nullptr;
|
||||
QPointer<NetworkAccessManager> networkAccessManager = nullptr;
|
||||
FilterChildrenProxyModel *mapListProxyModel;
|
||||
QStandardItemModel *mapListModel;
|
||||
QList<QStandardItem*> *mapGroupItemsList;
|
||||
@@ -397,6 +401,8 @@ private:
|
||||
QObjectList shortcutableObjects() const;
|
||||
void addCustomHeaderValue(QString key, QJsonValue value, bool isNew = false);
|
||||
int insertTilesetLabel(QStringList * list, QString label);
|
||||
|
||||
void checkForUpdates(bool requestedByUser);
|
||||
};
|
||||
|
||||
enum MapListUserRoles {
|
||||
|
||||
@@ -52,7 +52,6 @@ public:
|
||||
static QJSValue fromBlock(Block block);
|
||||
static QJSValue fromTile(Tile tile);
|
||||
static Tile toTile(QJSValue obj);
|
||||
static QJSValue version(QList<int> versionNums);
|
||||
static QJSValue dimensions(int width, int height);
|
||||
static QJSValue position(int x, int y);
|
||||
static const QImage * getImage(const QString &filepath, bool useCache);
|
||||
|
||||
@@ -14,7 +14,6 @@ class AboutPorymap : public QMainWindow
|
||||
public:
|
||||
explicit AboutPorymap(QWidget *parent = nullptr);
|
||||
~AboutPorymap();
|
||||
QList<int> getVersionNumbers();
|
||||
private:
|
||||
Ui::AboutPorymap *ui;
|
||||
};
|
||||
|
||||
50
include/ui/updatepromoter.h
Normal file
50
include/ui/updatepromoter.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef UPDATEPROMOTER_H
|
||||
#define UPDATEPROMOTER_H
|
||||
|
||||
#include "network.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPushButton>
|
||||
#include <QVersionNumber>
|
||||
|
||||
namespace Ui {
|
||||
class UpdatePromoter;
|
||||
}
|
||||
|
||||
class UpdatePromoter : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdatePromoter(QWidget *parent, NetworkAccessManager *manager);
|
||||
~UpdatePromoter() {};
|
||||
|
||||
void checkForUpdates();
|
||||
void updatePreferences();
|
||||
|
||||
private:
|
||||
Ui::UpdatePromoter *ui;
|
||||
NetworkAccessManager *const manager;
|
||||
QPushButton * button_Downloads;
|
||||
QPushButton * button_Retry;
|
||||
|
||||
QString changelog;
|
||||
QUrl downloadUrl;
|
||||
QVersionNumber newVersion;
|
||||
bool foundReleases;
|
||||
|
||||
QSet<QUrl> visitedUrls; // Prevent infinite redirection
|
||||
|
||||
void resetDialog();
|
||||
void get(const QUrl &url);
|
||||
void processWebpage(const QJsonDocument &data, const QUrl &nextUrl);
|
||||
void error(const QString &err, const QDateTime time = QDateTime());
|
||||
|
||||
private slots:
|
||||
void dialogButtonClicked(QAbstractButton *button);
|
||||
|
||||
signals:
|
||||
void changedPreferences();
|
||||
};
|
||||
|
||||
#endif // UPDATEPROMOTER_H
|
||||
Reference in New Issue
Block a user