@@ -342,12 +342,43 @@ OverlayController::OverlayController( bool desktopMode,
|
|||||||
{
|
{
|
||||||
m_enableDebug = value.toBool();
|
m_enableDebug = value.toBool();
|
||||||
}
|
}
|
||||||
|
value
|
||||||
|
= appSettings()->value( "disableVersionCheck", m_disableVersionCheck );
|
||||||
|
if ( value.isValid() && !value.isNull() )
|
||||||
|
{
|
||||||
|
m_disableVersionCheck = value.toBool();
|
||||||
|
}
|
||||||
value = appSettings()->value( "debugState", m_debugState );
|
value = appSettings()->value( "debugState", m_debugState );
|
||||||
if ( value.isValid() && !value.isNull() )
|
if ( value.isValid() && !value.isNull() )
|
||||||
{
|
{
|
||||||
m_debugState = value.toInt();
|
m_debugState = value.toInt();
|
||||||
}
|
}
|
||||||
appSettings()->endGroup();
|
appSettings()->endGroup();
|
||||||
|
|
||||||
|
// Grab local version number
|
||||||
|
QStringList verNumericalString
|
||||||
|
= QString( application_strings::applicationVersionString ).split( "-" );
|
||||||
|
QStringList verMajorMinorPatchString = verNumericalString[0].split( "." );
|
||||||
|
m_localVersionMajor = verMajorMinorPatchString[0].toInt();
|
||||||
|
m_localVersionMinor = verMajorMinorPatchString[1].toInt();
|
||||||
|
m_localVersionPatch = verMajorMinorPatchString[2].toInt();
|
||||||
|
|
||||||
|
// Init network manager
|
||||||
|
connect( netManager,
|
||||||
|
SIGNAL( finished( QNetworkReply* ) ),
|
||||||
|
this,
|
||||||
|
SLOT( OnNetworkReply( QNetworkReply* ) ) );
|
||||||
|
|
||||||
|
if ( !m_disableVersionCheck )
|
||||||
|
{
|
||||||
|
QNetworkRequest netRequest;
|
||||||
|
netRequest.setUrl( QUrl( application_strings::versionCheckUrl ) );
|
||||||
|
netManager->get( netRequest );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG( INFO ) << "Version Check: Feature disabled. Not checking version.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayController::~OverlayController()
|
OverlayController::~OverlayController()
|
||||||
@@ -808,6 +839,67 @@ void OverlayController::setEnableDebug( bool value, bool notify )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OverlayController::disableVersionCheck() const
|
||||||
|
{
|
||||||
|
return m_disableVersionCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::setDisableVersionCheck( bool value, bool notify )
|
||||||
|
{
|
||||||
|
if ( m_disableVersionCheck == value )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_disableVersionCheck = value;
|
||||||
|
if ( !m_disableVersionCheck )
|
||||||
|
{
|
||||||
|
QNetworkRequest netRequest;
|
||||||
|
netRequest.setUrl( QUrl( application_strings::versionCheckUrl ) );
|
||||||
|
netManager->get( netRequest );
|
||||||
|
}
|
||||||
|
appSettings()->beginGroup( "applicationSettings" );
|
||||||
|
appSettings()->setValue( "disableVersionCheck", m_disableVersionCheck );
|
||||||
|
appSettings()->endGroup();
|
||||||
|
appSettings()->sync();
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
emit disableVersionCheckChanged( m_disableVersionCheck );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayController::newVersionDetected() const
|
||||||
|
{
|
||||||
|
return m_newVersionDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::setNewVersionDetected( bool value, bool notify )
|
||||||
|
{
|
||||||
|
if ( m_newVersionDetected == value )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_newVersionDetected = value;
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
emit newVersionDetectedChanged( m_newVersionDetected );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OverlayController::versionCheckText() const
|
||||||
|
{
|
||||||
|
return m_versionCheckText;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::setVersionCheckText( QString value, bool notify )
|
||||||
|
{
|
||||||
|
m_versionCheckText = value;
|
||||||
|
LOG( INFO ) << "m_versionCheckText = " << m_versionCheckText;
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
emit versionCheckTextChanged( m_versionCheckText );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int OverlayController::debugState() const
|
int OverlayController::debugState() const
|
||||||
{
|
{
|
||||||
return m_debugState;
|
return m_debugState;
|
||||||
@@ -1493,4 +1585,82 @@ void OverlayController::cancelAlarm01Sound()
|
|||||||
m_alarm01SoundEffect.stop();
|
m_alarm01SoundEffect.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OverlayController::OnNetworkReply( QNetworkReply* reply )
|
||||||
|
{
|
||||||
|
if ( reply->error() == QNetworkReply::NoError )
|
||||||
|
{
|
||||||
|
QByteArray replyByteData = reply->readAll();
|
||||||
|
LOG( INFO ) << "Version Check: Recieved Data: " << replyByteData;
|
||||||
|
QJsonParseError parseError;
|
||||||
|
m_remoteVersionJsonDocument
|
||||||
|
= QJsonDocument::fromJson( replyByteData, &parseError );
|
||||||
|
if ( parseError.error == QJsonParseError::NoError )
|
||||||
|
{
|
||||||
|
m_remoteVersionJsonObject = m_remoteVersionJsonDocument.object();
|
||||||
|
m_remoteVersionMajor
|
||||||
|
= m_remoteVersionJsonObject.value( "major" ).toInt();
|
||||||
|
m_remoteVersionMinor
|
||||||
|
= m_remoteVersionJsonObject.value( "minor" ).toInt();
|
||||||
|
m_remoteVersionPatch
|
||||||
|
= m_remoteVersionJsonObject.value( "patch" ).toInt();
|
||||||
|
m_updateMessage
|
||||||
|
= m_remoteVersionJsonObject.value( "updateMessage" ).toString();
|
||||||
|
m_optionalMessage
|
||||||
|
= m_remoteVersionJsonObject.value( "optionalMessage" )
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
// this is a little convoluted to ensure if our local version is
|
||||||
|
// somehow higher than remote, it doesn't detect an update from just
|
||||||
|
// higher remote "minor" or "patch" values.
|
||||||
|
if ( ( m_remoteVersionMajor > m_localVersionMajor )
|
||||||
|
|| ( m_remoteVersionMajor == m_localVersionMajor
|
||||||
|
&& m_remoteVersionMinor > m_localVersionMinor )
|
||||||
|
|| ( m_remoteVersionMajor == m_localVersionMajor
|
||||||
|
&& m_remoteVersionMinor == m_localVersionMinor
|
||||||
|
&& m_remoteVersionPatch > m_localVersionPatch ) )
|
||||||
|
{
|
||||||
|
setNewVersionDetected( true );
|
||||||
|
if ( m_updateMessage.length() > 0 )
|
||||||
|
{
|
||||||
|
setVersionCheckText( m_updateMessage );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setVersionCheckText(
|
||||||
|
"Newer version ("
|
||||||
|
+ QString::number( m_remoteVersionMajor ) + "."
|
||||||
|
+ QString::number( m_remoteVersionMinor ) + "."
|
||||||
|
+ QString::number( m_remoteVersionPatch )
|
||||||
|
+ ") available." );
|
||||||
|
}
|
||||||
|
LOG( INFO )
|
||||||
|
<< "Version Check: Newer version (" << m_remoteVersionMajor
|
||||||
|
<< "." << m_remoteVersionMinor << "."
|
||||||
|
<< m_remoteVersionPatch << ") available.";
|
||||||
|
}
|
||||||
|
else if ( m_optionalMessage.length() > 0 )
|
||||||
|
{
|
||||||
|
setNewVersionDetected( false );
|
||||||
|
LOG( INFO )
|
||||||
|
<< "Version Check: Installed version is latest release.";
|
||||||
|
setVersionCheckText( m_optionalMessage );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG( ERROR )
|
||||||
|
<< "Version Check: Error parsing json. QJsonParseError = "
|
||||||
|
<< parseError.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG( ERROR ) << "Version Check: Error connecting to network. "
|
||||||
|
"QNetworkReply::NetworkError = "
|
||||||
|
<< reply->error();
|
||||||
|
}
|
||||||
|
reply->request().~QNetworkRequest();
|
||||||
|
reply->~QNetworkReply();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advsettings
|
} // namespace advsettings
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <QQuickRenderControl>
|
#include <QQuickRenderControl>
|
||||||
#include <QSoundEffect>
|
#include <QSoundEffect>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkRequest>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <easylogging++.h>
|
#include <easylogging++.h>
|
||||||
|
|
||||||
@@ -47,6 +50,9 @@ constexpr auto applicationOrganizationName = "AdvancedSettings-Team";
|
|||||||
constexpr auto applicationName = "OpenVRAdvancedSettings";
|
constexpr auto applicationName = "OpenVRAdvancedSettings";
|
||||||
constexpr const char* applicationKey = "OVRAS-Team.AdvancedSettings";
|
constexpr const char* applicationKey = "OVRAS-Team.AdvancedSettings";
|
||||||
constexpr const char* applicationDisplayName = "Advanced Settings";
|
constexpr const char* applicationDisplayName = "Advanced Settings";
|
||||||
|
constexpr const char* versionCheckUrl
|
||||||
|
= "https://raw.githubusercontent.com/OpenVR-Advanced-Settings/"
|
||||||
|
"OpenVR-AdvancedSettings/master/ver/versioncheck.json";
|
||||||
|
|
||||||
constexpr const char* applicationVersionString = APPLICATION_VERSION;
|
constexpr const char* applicationVersionString = APPLICATION_VERSION;
|
||||||
|
|
||||||
@@ -84,6 +90,12 @@ class OverlayController : public QObject
|
|||||||
NOTIFY vsyncDisabledChanged )
|
NOTIFY vsyncDisabledChanged )
|
||||||
Q_PROPERTY( bool enableDebug READ enableDebug WRITE setEnableDebug NOTIFY
|
Q_PROPERTY( bool enableDebug READ enableDebug WRITE setEnableDebug NOTIFY
|
||||||
enableDebugChanged )
|
enableDebugChanged )
|
||||||
|
Q_PROPERTY( bool disableVersionCheck READ disableVersionCheck WRITE
|
||||||
|
setDisableVersionCheck NOTIFY disableVersionCheckChanged )
|
||||||
|
Q_PROPERTY( bool newVersionDetected READ newVersionDetected WRITE
|
||||||
|
setNewVersionDetected NOTIFY newVersionDetectedChanged )
|
||||||
|
Q_PROPERTY( QString versionCheckText READ versionCheckText WRITE
|
||||||
|
setVersionCheckText NOTIFY versionCheckTextChanged )
|
||||||
Q_PROPERTY( int customTickRateMs READ customTickRateMs WRITE
|
Q_PROPERTY( int customTickRateMs READ customTickRateMs WRITE
|
||||||
setCustomTickRateMs NOTIFY customTickRateMsChanged )
|
setCustomTickRateMs NOTIFY customTickRateMsChanged )
|
||||||
Q_PROPERTY( int debugState READ debugState WRITE setDebugState NOTIFY
|
Q_PROPERTY( int debugState READ debugState WRITE setDebugState NOTIFY
|
||||||
@@ -113,8 +125,19 @@ private:
|
|||||||
bool m_crashRecoveryDisabled = false;
|
bool m_crashRecoveryDisabled = false;
|
||||||
bool m_vsyncDisabled = false;
|
bool m_vsyncDisabled = false;
|
||||||
bool m_enableDebug = false;
|
bool m_enableDebug = false;
|
||||||
|
bool m_disableVersionCheck = false;
|
||||||
|
bool m_newVersionDetected = false;
|
||||||
int m_customTickRateMs = 20;
|
int m_customTickRateMs = 20;
|
||||||
int m_debugState = 0;
|
int m_debugState = 0;
|
||||||
|
int m_remoteVersionMajor = -1;
|
||||||
|
int m_remoteVersionMinor = -1;
|
||||||
|
int m_remoteVersionPatch = -1;
|
||||||
|
int m_localVersionMajor = -1;
|
||||||
|
int m_localVersionMinor = -1;
|
||||||
|
int m_localVersionPatch = -1;
|
||||||
|
QString m_updateMessage = "";
|
||||||
|
QString m_optionalMessage = "";
|
||||||
|
QString m_versionCheckText = "";
|
||||||
|
|
||||||
QUrl m_runtimePathUrl;
|
QUrl m_runtimePathUrl;
|
||||||
|
|
||||||
@@ -131,6 +154,10 @@ private:
|
|||||||
|
|
||||||
input::SteamIVRInput m_actions;
|
input::SteamIVRInput m_actions;
|
||||||
|
|
||||||
|
QNetworkAccessManager* netManager = new QNetworkAccessManager( this );
|
||||||
|
QJsonDocument m_remoteVersionJsonDocument = QJsonDocument();
|
||||||
|
QJsonObject m_remoteVersionJsonObject;
|
||||||
|
|
||||||
public: // I know it's an ugly hack to make them public to enable external
|
public: // I know it's an ugly hack to make them public to enable external
|
||||||
// access, but I am too lazy to implement getters.
|
// access, but I am too lazy to implement getters.
|
||||||
SteamVRTabController m_steamVRTabController;
|
SteamVRTabController m_steamVRTabController;
|
||||||
@@ -218,7 +245,10 @@ public:
|
|||||||
|
|
||||||
bool crashRecoveryDisabled() const;
|
bool crashRecoveryDisabled() const;
|
||||||
bool enableDebug() const;
|
bool enableDebug() const;
|
||||||
|
bool disableVersionCheck() const;
|
||||||
|
bool newVersionDetected() const;
|
||||||
bool vsyncDisabled() const;
|
bool vsyncDisabled() const;
|
||||||
|
QString versionCheckText() const;
|
||||||
int customTickRateMs() const;
|
int customTickRateMs() const;
|
||||||
int debugState() const;
|
int debugState() const;
|
||||||
|
|
||||||
@@ -226,6 +256,7 @@ public slots:
|
|||||||
void renderOverlay();
|
void renderOverlay();
|
||||||
void OnRenderRequest();
|
void OnRenderRequest();
|
||||||
void OnTimeoutPumpEvents();
|
void OnTimeoutPumpEvents();
|
||||||
|
void OnNetworkReply( QNetworkReply* reply );
|
||||||
|
|
||||||
void showKeyboard( QString existingText, unsigned long userValue = 0 );
|
void showKeyboard( QString existingText, unsigned long userValue = 0 );
|
||||||
|
|
||||||
@@ -237,6 +268,9 @@ public slots:
|
|||||||
|
|
||||||
void setCrashRecoveryDisabled( bool value, bool notify = true );
|
void setCrashRecoveryDisabled( bool value, bool notify = true );
|
||||||
void setEnableDebug( bool value, bool notify = true );
|
void setEnableDebug( bool value, bool notify = true );
|
||||||
|
void setDisableVersionCheck( bool value, bool notify = true );
|
||||||
|
void setNewVersionDetected( bool value, bool notify = true );
|
||||||
|
void setVersionCheckText( QString value, bool notify = true );
|
||||||
void setVsyncDisabled( bool value, bool notify = true );
|
void setVsyncDisabled( bool value, bool notify = true );
|
||||||
void setCustomTickRateMs( int value, bool notify = true );
|
void setCustomTickRateMs( int value, bool notify = true );
|
||||||
void setDebugState( int value, bool notify = true );
|
void setDebugState( int value, bool notify = true );
|
||||||
@@ -245,6 +279,9 @@ signals:
|
|||||||
void keyBoardInputSignal( QString input, unsigned long userValue = 0 );
|
void keyBoardInputSignal( QString input, unsigned long userValue = 0 );
|
||||||
void crashRecoveryDisabledChanged( bool value );
|
void crashRecoveryDisabledChanged( bool value );
|
||||||
void enableDebugChanged( bool value );
|
void enableDebugChanged( bool value );
|
||||||
|
void disableVersionCheckChanged( bool value );
|
||||||
|
void newVersionDetectedChanged( bool value );
|
||||||
|
void versionCheckTextChanged( QString value );
|
||||||
void vsyncDisabledChanged( bool value );
|
void vsyncDisabledChanged( bool value );
|
||||||
void customTickRateMsChanged( int value );
|
void customTickRateMsChanged( int value );
|
||||||
void debugStateChanged( int value );
|
void debugStateChanged( int value );
|
||||||
|
|||||||
@@ -404,13 +404,38 @@ MyStackViewPage {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
MyText {
|
RowLayout {
|
||||||
id: summaryVersionText
|
|
||||||
text: "v0.0.0"
|
Rectangle {
|
||||||
font.pointSize: 16
|
id: summaryVersionCheckTextRect
|
||||||
Layout.fillWidth: true
|
visible: true
|
||||||
horizontalAlignment: Text.AlignRight
|
color: "#1b2939"
|
||||||
|
MyText {
|
||||||
|
id: summaryVersionCheckText
|
||||||
|
text: ""
|
||||||
|
color: "#fffec8"
|
||||||
|
font.pointSize: 22
|
||||||
|
minimumPointSize: 11
|
||||||
|
fontSizeMode: Text.Fit
|
||||||
|
leftPadding: 8
|
||||||
|
rightPadding: 8
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
height: 40
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MyText {
|
||||||
|
id: summaryVersionText
|
||||||
|
text: "v0.0.0"
|
||||||
|
font.pointSize: 16
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,6 +446,13 @@ MyStackViewPage {
|
|||||||
reloadVideoProfiles()
|
reloadVideoProfiles()
|
||||||
|
|
||||||
summaryVersionText.text = applicationVersion
|
summaryVersionText.text = applicationVersion
|
||||||
|
summaryVersionCheckText.text = OverlayController.versionCheckText
|
||||||
|
if (OverlayController.newVersionDetected)
|
||||||
|
{
|
||||||
|
summaryVersionCheckTextRect.color = "#ff0000"
|
||||||
|
} else {
|
||||||
|
summaryVersionCheckTextRect.color = "#1b2939"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (MoveCenterTabController.trackingUniverse === 0) {
|
if (MoveCenterTabController.trackingUniverse === 0) {
|
||||||
@@ -439,6 +471,36 @@ MyStackViewPage {
|
|||||||
summaryPttToggle.checked = AudioTabController.pttEnabled
|
summaryPttToggle.checked = AudioTabController.pttEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: OverlayController
|
||||||
|
onNewVersionDetectedChanged: {
|
||||||
|
if (OverlayController.newVersionDetected)
|
||||||
|
{
|
||||||
|
summaryVersionCheckTextRect.color = "#ff0000"
|
||||||
|
} else {
|
||||||
|
summaryVersionCheckTextRect.color = "#1b2939"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onVersionCheckTextChanged: {
|
||||||
|
summaryVersionCheckText.text = OverlayController.versionCheckText
|
||||||
|
}
|
||||||
|
onDisableVersionCheckChanged: {
|
||||||
|
if (OverlayController.disableVersionCheck)
|
||||||
|
{
|
||||||
|
summaryVersionCheckText.visible = false
|
||||||
|
summaryVersionCheckTextRect.color = "#1b2939"
|
||||||
|
} else {
|
||||||
|
summaryVersionCheckText.visible = true
|
||||||
|
if (OverlayController.newVersionDetected)
|
||||||
|
{
|
||||||
|
summaryVersionCheckTextRect.color = "#ff0000"
|
||||||
|
} else {
|
||||||
|
summaryVersionCheckTextRect.color = "#1b2939"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ChaperoneTabController
|
target: ChaperoneTabController
|
||||||
onChaperoneProfilesUpdated: {
|
onChaperoneProfilesUpdated: {
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ MyStackViewPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MyToggleButton {
|
||||||
|
id: disableVersionCheckToggle
|
||||||
|
text: "Disable Notification of Newer Version Availability"
|
||||||
|
onCheckedChanged: {
|
||||||
|
OverlayController.setDisableVersionCheck(checked, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
@@ -200,6 +208,7 @@ MyStackViewPage {
|
|||||||
customTickRateMsLabel.visible = vsyncDisabledToggle.checked
|
customTickRateMsLabel.visible = vsyncDisabledToggle.checked
|
||||||
debugStateRow.visible = OverlayController.enableDebug
|
debugStateRow.visible = OverlayController.enableDebug
|
||||||
debugStateText.text = OverlayController.debugState
|
debugStateText.text = OverlayController.debugState
|
||||||
|
disableVersionCheckToggle.checked = OverlayController.disableVersionCheck
|
||||||
|
|
||||||
seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
|
seatedOldExternalWarning.visible = MoveCenterTabController.allowExternalEdits && MoveCenterTabController.oldStyleMotion && MoveCenterTabController.enableSeatedMotion
|
||||||
}
|
}
|
||||||
@@ -253,6 +262,9 @@ MyStackViewPage {
|
|||||||
onDebugStateChanged: {
|
onDebugStateChanged: {
|
||||||
debugStateText.text = OverlayController.debugState
|
debugStateText.text = OverlayController.debugState
|
||||||
}
|
}
|
||||||
|
onDisableVersionCheckChanged: {
|
||||||
|
disableVersionCheckToggle.checked = OverlayController.disableVersionCheck
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{ "major": 4, "minor": 0, "patch": 0, "updateMessage": "", "optionalMessage": "" }
|
||||||
Reference in New Issue
Block a user