mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 15:49:36 +02:00
Merge with master and resolve CI configure script conflict.
This commit is contained in:
parent
07187ad789
commit
0ab6aefe11
@ -191,6 +191,14 @@ cmake_dependent_option(
|
|||||||
Off
|
Off
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cmake_dependent_option(
|
||||||
|
${_OPT}has_updates_check
|
||||||
|
"Has a builtin support for checking of updates"
|
||||||
|
On
|
||||||
|
"${_OPT}has_networking"
|
||||||
|
Off
|
||||||
|
)
|
||||||
|
|
||||||
# Determine 32-bit or 64-bit target
|
# Determine 32-bit or 64-bit target
|
||||||
if( CMAKE_C_COMPILER_ID MATCHES "MSVC" AND CMAKE_VS_PLATFORM_NAME MATCHES "Win64|x64" )
|
if( CMAKE_C_COMPILER_ID MATCHES "MSVC" AND CMAKE_VS_PLATFORM_NAME MATCHES "Win64|x64" )
|
||||||
set( IS_64BIT ON )
|
set( IS_64BIT ON )
|
||||||
|
@ -12,6 +12,7 @@ cmake_args=(
|
|||||||
-G "${AUDACITY_CMAKE_GENERATOR}"
|
-G "${AUDACITY_CMAKE_GENERATOR}"
|
||||||
-D audacity_use_pch=no
|
-D audacity_use_pch=no
|
||||||
-D audacity_has_networking=yes
|
-D audacity_has_networking=yes
|
||||||
|
-D audacity_has_updates_check=yes
|
||||||
-D CMAKE_BUILD_TYPE="${AUDACITY_BUILD_TYPE}"
|
-D CMAKE_BUILD_TYPE="${AUDACITY_BUILD_TYPE}"
|
||||||
-D CMAKE_INSTALL_PREFIX="${AUDACITY_INSTALL_PREFIX}"
|
-D CMAKE_INSTALL_PREFIX="${AUDACITY_INSTALL_PREFIX}"
|
||||||
)
|
)
|
||||||
|
@ -111,6 +111,7 @@ It handles initialization and termination by subclassing wxApp.
|
|||||||
#include "tracks/ui/Scrubbing.h"
|
#include "tracks/ui/Scrubbing.h"
|
||||||
#include "widgets/FileConfig.h"
|
#include "widgets/FileConfig.h"
|
||||||
#include "widgets/FileHistory.h"
|
#include "widgets/FileHistory.h"
|
||||||
|
#include "update/UpdateManager.h"
|
||||||
|
|
||||||
#ifdef HAS_NETWORKING
|
#ifdef HAS_NETWORKING
|
||||||
#include "NetworkManager.h"
|
#include "NetworkManager.h"
|
||||||
@ -1489,6 +1490,10 @@ bool AudacityApp::InitPart2()
|
|||||||
SplashDialog::DoHelpWelcome(*project);
|
SplashDialog::DoHelpWelcome(*project);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_UPDATES_CHECK)
|
||||||
|
mUpdateManager = std::make_unique<UpdateManager>(*project);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FFMPEG
|
#ifdef USE_FFMPEG
|
||||||
FFmpegStartup();
|
FFmpegStartup();
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,6 +33,7 @@ class Importer;
|
|||||||
class CommandHandler;
|
class CommandHandler;
|
||||||
class AppCommandEvent;
|
class AppCommandEvent;
|
||||||
class AudacityProject;
|
class AudacityProject;
|
||||||
|
class UpdateManager;
|
||||||
|
|
||||||
class AudacityApp final : public wxApp {
|
class AudacityApp final : public wxApp {
|
||||||
public:
|
public:
|
||||||
@ -113,6 +114,10 @@ class AudacityApp final : public wxApp {
|
|||||||
std::unique_ptr<wxSocketServer> mIPCServ;
|
std::unique_ptr<wxSocketServer> mIPCServ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_UPDATES_CHECK)
|
||||||
|
std::unique_ptr<UpdateManager> mUpdateManager;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
@ -982,6 +982,19 @@ list( APPEND SOURCES
|
|||||||
xml/XMLWriter.h
|
xml/XMLWriter.h
|
||||||
xml/audacityproject.dtd
|
xml/audacityproject.dtd
|
||||||
|
|
||||||
|
# Update version
|
||||||
|
$<$<BOOL:${${_OPT}has_updates_check}>:
|
||||||
|
update/VersionId.h
|
||||||
|
update/VersionId.cpp
|
||||||
|
update/VersionPatch.h
|
||||||
|
update/UpdateDataParser.h
|
||||||
|
update/UpdateDataParser.cpp
|
||||||
|
update/UpdateManager.h
|
||||||
|
update/UpdateManager.cpp
|
||||||
|
update/UpdatePopupDialog.h
|
||||||
|
update/UpdatePopupDialog.cpp
|
||||||
|
>
|
||||||
|
|
||||||
Experimental.cmake
|
Experimental.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1038,6 +1051,9 @@ list( APPEND DEFINES
|
|||||||
__STDC_CONSTANT_MACROS
|
__STDC_CONSTANT_MACROS
|
||||||
STRICT
|
STRICT
|
||||||
>
|
>
|
||||||
|
$<$<BOOL:${USE_UPDATE_CHECK}>:
|
||||||
|
HAVE_UPDATES_CHECK
|
||||||
|
>
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we have cmake 3.16 or higher, we can use precompiled headers, but
|
# If we have cmake 3.16 or higher, we can use precompiled headers, but
|
||||||
|
152
src/update/UpdateDataParser.cpp
Normal file
152
src/update/UpdateDataParser.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdateDataParser.cpp
|
||||||
|
@brief Declare a class that parse update server data format.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "UpdateDataParser.h"
|
||||||
|
|
||||||
|
#include "xml/XMLFileReader.h"
|
||||||
|
|
||||||
|
UpdateDataParser::UpdateDataParser()
|
||||||
|
{}
|
||||||
|
|
||||||
|
UpdateDataParser::~UpdateDataParser()
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool UpdateDataParser::Parse(const VersionPatch::UpdateDataFormat& updateData, VersionPatch* versionPatch)
|
||||||
|
{
|
||||||
|
XMLFileReader xmlReader;
|
||||||
|
|
||||||
|
mVersionPatch = versionPatch;
|
||||||
|
auto ok = xmlReader.ParseString(this, updateData);
|
||||||
|
mVersionPatch = nullptr;
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxArrayString UpdateDataParser::splitChangelogSentences(const wxString& changelogContent)
|
||||||
|
{
|
||||||
|
wxArrayString changelogSentenceList;
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
std::string s(changelogContent.ToStdString());
|
||||||
|
std::string token;
|
||||||
|
const std::string delimiter(". ");
|
||||||
|
|
||||||
|
while ((pos = s.find(delimiter)) != std::string::npos)
|
||||||
|
{
|
||||||
|
token = s.substr(0, pos + 1);
|
||||||
|
changelogSentenceList.Add(token);
|
||||||
|
|
||||||
|
s.erase(0, pos + delimiter.length());
|
||||||
|
}
|
||||||
|
changelogSentenceList.Add(s);
|
||||||
|
|
||||||
|
return changelogSentenceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateDataParser::HandleXMLTag(const wxChar* tag, const wxChar** attrs)
|
||||||
|
{
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kDescriptionTag]) == 0)
|
||||||
|
{
|
||||||
|
mXmlParsingState = XmlParsedTags::kDescriptionTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWindowsTag]) == 0)
|
||||||
|
{
|
||||||
|
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_WINDOWS)
|
||||||
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kMacosTag]) == 0)
|
||||||
|
{
|
||||||
|
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_MAC)
|
||||||
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinuxTag]) == 0)
|
||||||
|
{
|
||||||
|
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_UNIX_LINUX)
|
||||||
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kVersionTag]) == 0)
|
||||||
|
{
|
||||||
|
if (mXmlParsingState == XmlParsedTags::kOsTag)
|
||||||
|
mXmlParsingState = XmlParsedTags::kVersionTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinkTag]) == 0)
|
||||||
|
{
|
||||||
|
if (mXmlParsingState == XmlParsedTags::kOsTag)
|
||||||
|
mXmlParsingState = XmlParsedTags::kLinkTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& xmlTag : mXmlTagNames)
|
||||||
|
{
|
||||||
|
if (wxStrcmp(tag, xmlTag.second) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDataParser::HandleXMLEndTag(const wxChar* tag)
|
||||||
|
{
|
||||||
|
if (mXmlParsingState == XmlParsedTags::kDescriptionTag ||
|
||||||
|
mXmlParsingState == XmlParsedTags::kLinkTag)
|
||||||
|
mXmlParsingState = XmlParsedTags::kNotUsedTag;
|
||||||
|
|
||||||
|
if (mXmlParsingState == XmlParsedTags::kVersionTag)
|
||||||
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDataParser::HandleXMLContent(const wxString& content)
|
||||||
|
{
|
||||||
|
if (mVersionPatch == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxString trimedContent(content);
|
||||||
|
|
||||||
|
switch (mXmlParsingState)
|
||||||
|
{
|
||||||
|
case XmlParsedTags::kDescriptionTag:
|
||||||
|
trimedContent.Trim(true).Trim(false);
|
||||||
|
mVersionPatch->changelog = splitChangelogSentences(trimedContent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XmlParsedTags::kVersionTag:
|
||||||
|
trimedContent.Trim(true).Trim(false);
|
||||||
|
mVersionPatch->version = VersionId::ParseFromString(trimedContent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XmlParsedTags::kLinkTag:
|
||||||
|
trimedContent.Trim(true).Trim(false);
|
||||||
|
mVersionPatch->download = trimedContent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLTagHandler* UpdateDataParser::HandleXMLChild(const wxChar* tag)
|
||||||
|
{
|
||||||
|
for (auto& xmlTag : mXmlTagNames)
|
||||||
|
{
|
||||||
|
if (wxStrcmp(tag, xmlTag.second) == 0)
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
66
src/update/UpdateDataParser.h
Normal file
66
src/update/UpdateDataParser.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdateDataParser.h
|
||||||
|
@brief Declare a class that parse update server data format.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VersionPatch.h"
|
||||||
|
|
||||||
|
#include "xml/XMLTagHandler.h"
|
||||||
|
|
||||||
|
#include <wx/arrstr.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
/// A class that parse update server data format.
|
||||||
|
class UpdateDataParser final : public XMLTagHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UpdateDataParser();
|
||||||
|
~UpdateDataParser();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parsing from update data format to VersionPatch fields.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateData">Input data.</param>
|
||||||
|
/// <param name="versionPatch">Parsed output data.</param>
|
||||||
|
/// <returns>True if success.</returns>
|
||||||
|
bool Parse(const VersionPatch::UpdateDataFormat& updateData, VersionPatch* versionPatch);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class XmlParsedTags : int {
|
||||||
|
kNotUsedTag,
|
||||||
|
kUpdateTag,
|
||||||
|
kDescriptionTag,
|
||||||
|
kOsTag,
|
||||||
|
kWindowsTag,
|
||||||
|
kMacosTag,
|
||||||
|
kLinuxTag,
|
||||||
|
kVersionTag,
|
||||||
|
kLinkTag
|
||||||
|
};
|
||||||
|
XmlParsedTags mXmlParsingState{ XmlParsedTags::kNotUsedTag };
|
||||||
|
|
||||||
|
std::map<XmlParsedTags, wxString> mXmlTagNames{
|
||||||
|
{ XmlParsedTags::kUpdateTag, wxT("Updates") },
|
||||||
|
{ XmlParsedTags::kDescriptionTag, wxT("Description") },
|
||||||
|
{ XmlParsedTags::kOsTag, wxT("OS") },
|
||||||
|
{ XmlParsedTags::kWindowsTag, wxT("Windows") },
|
||||||
|
{ XmlParsedTags::kMacosTag, wxT("Macos") },
|
||||||
|
{ XmlParsedTags::kLinuxTag, wxT("Linux") },
|
||||||
|
{ XmlParsedTags::kVersionTag, wxT("Version") },
|
||||||
|
{ XmlParsedTags::kLinkTag, wxT("Link") },
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HandleXMLTag(const wxChar* tag, const wxChar** attrs) override;
|
||||||
|
void HandleXMLEndTag(const wxChar* tag) override;
|
||||||
|
void HandleXMLContent(const wxString& content) override;
|
||||||
|
XMLTagHandler* HandleXMLChild(const wxChar* tag) override;
|
||||||
|
|
||||||
|
wxArrayString splitChangelogSentences(const wxString& changelogContent);
|
||||||
|
|
||||||
|
VersionPatch* mVersionPatch{ nullptr };
|
||||||
|
};
|
150
src/update/UpdateManager.cpp
Normal file
150
src/update/UpdateManager.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdateManager.cpp
|
||||||
|
@brief Declare a class that managing of updates.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "UpdateManager.h"
|
||||||
|
#include "UpdatePopupDialog.h"
|
||||||
|
|
||||||
|
#include "NetworkManager.h"
|
||||||
|
#include "IResponse.h"
|
||||||
|
#include "Request.h"
|
||||||
|
|
||||||
|
#include "widgets/AudacityMessageBox.h"
|
||||||
|
|
||||||
|
#include <wx/platinfo.h>
|
||||||
|
#include <wx/utils.h>
|
||||||
|
|
||||||
|
static const char* prefsUpdatePopupDialogShown = "/Update/UpdatePopupDialogShown";
|
||||||
|
static const char* prefsUpdateScheduledTime = "/Update/UpdateScheduledTime";
|
||||||
|
|
||||||
|
enum { ID_TIMER = wxID_HIGHEST + 1 };
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(UpdateManager, wxEvtHandler)
|
||||||
|
EVT_TIMER(ID_TIMER, UpdateManager::OnTimer)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
UpdateManager::UpdateManager(AudacityProject& project)
|
||||||
|
: mTrackingInterval(
|
||||||
|
std::chrono::milliseconds(std::chrono::hours(12)).count())
|
||||||
|
{
|
||||||
|
mParent = (wxWindow*)(&GetProjectFrame(project));
|
||||||
|
wxASSERT(mParent);
|
||||||
|
|
||||||
|
mTimer.SetOwner(this, ID_TIMER);
|
||||||
|
mTimer.StartOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateManager::~UpdateManager()
|
||||||
|
{
|
||||||
|
mTimer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::enableTracking(bool enable)
|
||||||
|
{
|
||||||
|
gPrefs->Write(prefsUpdatePopupDialogShown, enable);
|
||||||
|
gPrefs->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateManager::isTrackingEnabled()
|
||||||
|
{
|
||||||
|
return gPrefs->ReadBool(prefsUpdatePopupDialogShown, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionPatch UpdateManager::getVersionPatch() const
|
||||||
|
{
|
||||||
|
return mVersionPatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::getUpdates()
|
||||||
|
{
|
||||||
|
audacity::network_manager::Request request("https://updates.audacityteam.org/feed/latest.xml");
|
||||||
|
auto response = audacity::network_manager::NetworkManager::GetInstance().doGet(request);
|
||||||
|
|
||||||
|
response->setRequestFinishedCallback([response, this](audacity::network_manager::IResponse*) {
|
||||||
|
|
||||||
|
if (response->getError() != audacity::network_manager::NetworkError::NoError)
|
||||||
|
{
|
||||||
|
AudacityMessageBox(
|
||||||
|
XO("Unable to connect to Audacity update server."),
|
||||||
|
XO("Error checking for update"),
|
||||||
|
wxOK | wxCENTRE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mUpdateDataParser.Parse(response->readAll<VersionPatch::UpdateDataFormat>(), &mVersionPatch))
|
||||||
|
{
|
||||||
|
AudacityMessageBox(
|
||||||
|
XO("Update data was corrupted."),
|
||||||
|
XO("Error checking for update"),
|
||||||
|
wxOK | wxCENTRE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVersionPatch.version > CurrentBuildVersion())
|
||||||
|
{
|
||||||
|
mParent->CallAfter([this] {
|
||||||
|
UpdatePopupDialog dlg(mParent, this);
|
||||||
|
const int code = dlg.ShowModal();
|
||||||
|
|
||||||
|
if (code == wxID_YES)
|
||||||
|
{
|
||||||
|
if (!wxLaunchDefaultBrowser(mVersionPatch.download))
|
||||||
|
{
|
||||||
|
AudacityMessageBox(
|
||||||
|
XO("Can't open the Audacity download link."),
|
||||||
|
XO("Error downloading update"),
|
||||||
|
wxOK | wxCENTRE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::OnTimer(wxTimerEvent& WXUNUSED(event))
|
||||||
|
{
|
||||||
|
if (isTrackingEnabled() && isTimeToUpdate())
|
||||||
|
getUpdates();
|
||||||
|
|
||||||
|
mTimer.StartOnce(mTrackingInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateManager::isTimeToUpdate()
|
||||||
|
{
|
||||||
|
long long nextTrackingTime = std::stoll(
|
||||||
|
gPrefs->Read(prefsUpdateScheduledTime, "0").ToStdString());
|
||||||
|
|
||||||
|
// Get current time in milliseconds
|
||||||
|
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::system_clock::now());
|
||||||
|
|
||||||
|
auto currentTimeInMillisec = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
now_ms.time_since_epoch()).count();
|
||||||
|
|
||||||
|
// If next update time 0 or less then current time -> show update dialog,
|
||||||
|
// else this condition allow us to avoid from duplicating update notifications.
|
||||||
|
if (nextTrackingTime < currentTimeInMillisec)
|
||||||
|
{
|
||||||
|
nextTrackingTime = currentTimeInMillisec + mTrackingInterval;
|
||||||
|
|
||||||
|
gPrefs->Write(prefsUpdateScheduledTime,
|
||||||
|
wxString(std::to_string(nextTrackingTime)));
|
||||||
|
gPrefs->Flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
57
src/update/UpdateManager.h
Normal file
57
src/update/UpdateManager.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdateManager.h
|
||||||
|
@brief Declare a class that managing of updates.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VersionId.h"
|
||||||
|
#include "VersionPatch.h"
|
||||||
|
#include "UpdateDataParser.h"
|
||||||
|
|
||||||
|
#include "Project.h"
|
||||||
|
#include "Prefs.h"
|
||||||
|
|
||||||
|
#include <wx/string.h>
|
||||||
|
#include <wx/event.h>
|
||||||
|
#include <wx/timer.h>
|
||||||
|
|
||||||
|
/// A class that managing of updates.
|
||||||
|
/**
|
||||||
|
Opt-in request and show update dialog by the scheduled time.
|
||||||
|
Have a built-in check that allows avoiding multiplying update notifications
|
||||||
|
when multiple Audacity windows are shown.
|
||||||
|
*/
|
||||||
|
class UpdateManager final : public wxEvtHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UpdateManager(AudacityProject& project);
|
||||||
|
~UpdateManager();
|
||||||
|
|
||||||
|
void getUpdates();
|
||||||
|
|
||||||
|
void enableTracking(bool enable);
|
||||||
|
bool isTrackingEnabled();
|
||||||
|
|
||||||
|
VersionPatch getVersionPatch() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UpdateDataParser mUpdateDataParser;
|
||||||
|
VersionPatch mVersionPatch;
|
||||||
|
|
||||||
|
wxWindow* mParent;
|
||||||
|
|
||||||
|
wxTimer mTimer;
|
||||||
|
const int mTrackingInterval;
|
||||||
|
|
||||||
|
void OnTimer(wxTimerEvent& event);
|
||||||
|
|
||||||
|
/// Scheduling update time for avoiding multiplying update notifications.
|
||||||
|
bool isTimeToUpdate();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
};
|
136
src/update/UpdatePopupDialog.cpp
Normal file
136
src/update/UpdatePopupDialog.cpp
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdatePopupDialog.cpp
|
||||||
|
@brief Define a dialog for notifying users about new version available.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "update/UpdatePopupDialog.h"
|
||||||
|
|
||||||
|
#include "ShuttleGui.h"
|
||||||
|
#include "widgets/HelpSystem.h"
|
||||||
|
|
||||||
|
#include <wx/debug.h>
|
||||||
|
#include <wx/sstream.h>
|
||||||
|
#include <wx/txtstrm.h>
|
||||||
|
|
||||||
|
enum { DontShowID = wxID_HIGHEST + 1 };
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE (UpdatePopupDialog, wxDialogWrapper)
|
||||||
|
EVT_BUTTON (wxID_YES, UpdatePopupDialog::OnUpdate)
|
||||||
|
EVT_BUTTON (wxID_NO, UpdatePopupDialog::OnSkip)
|
||||||
|
EVT_CHECKBOX (DontShowID, UpdatePopupDialog::OnDontShow)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
IMPLEMENT_CLASS (UpdatePopupDialog, wxDialogWrapper)
|
||||||
|
|
||||||
|
UpdatePopupDialog::UpdatePopupDialog (wxWindow* parent, UpdateManager* updateManager)
|
||||||
|
: wxDialogWrapper (parent, -1, XO ("Update Audacity"),
|
||||||
|
wxDefaultPosition, wxDefaultSize,
|
||||||
|
wxCAPTION),
|
||||||
|
mUpdateManager (updateManager)
|
||||||
|
{
|
||||||
|
wxASSERT(mUpdateManager);
|
||||||
|
|
||||||
|
ShuttleGui S (this, eIsCreating);
|
||||||
|
S.SetBorder (5);
|
||||||
|
S.StartVerticalLay (wxEXPAND, 1);
|
||||||
|
{
|
||||||
|
S.AddWindow (AddHtmlContent (S.GetParent()));
|
||||||
|
|
||||||
|
S.StartHorizontalLay (wxEXPAND, 0);
|
||||||
|
{
|
||||||
|
S.SetBorder (5);
|
||||||
|
|
||||||
|
S.Id (DontShowID).AddCheckBox (
|
||||||
|
XO ("Don't show this again at start up"), !mUpdateManager->isTrackingEnabled());
|
||||||
|
|
||||||
|
S.Prop(1).AddSpace(1, 0, 1);
|
||||||
|
|
||||||
|
S.Id (wxID_NO).AddButton (XO ("Skip"));
|
||||||
|
S.Id (wxID_YES).AddButton (XO ("Install update"));
|
||||||
|
|
||||||
|
S.SetBorder (5);
|
||||||
|
}
|
||||||
|
S.EndHorizontalLay();
|
||||||
|
}
|
||||||
|
S.EndVerticalLay();
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
Center();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdatePopupDialog::~UpdatePopupDialog()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdatePopupDialog::OnUpdate (wxCommandEvent&)
|
||||||
|
{
|
||||||
|
EndModal (wxID_YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdatePopupDialog::OnSkip (wxCommandEvent&)
|
||||||
|
{
|
||||||
|
EndModal (wxID_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdatePopupDialog::OnDontShow (wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
mUpdateManager->enableTracking(!event.IsChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlWindow* UpdatePopupDialog::AddHtmlContent (wxWindow* parent)
|
||||||
|
{
|
||||||
|
wxStringOutputStream o;
|
||||||
|
wxTextOutputStream informationStr (o);
|
||||||
|
|
||||||
|
static const auto title = XO("Audacity %s is available!")
|
||||||
|
.Format(mUpdateManager->getVersionPatch().version.getString());
|
||||||
|
|
||||||
|
informationStr
|
||||||
|
<< wxT("<html><body><h3>")
|
||||||
|
<< title.Translation()
|
||||||
|
<< wxT("</h3><h5>")
|
||||||
|
<< XO("Changelog")
|
||||||
|
<< wxT("</h5><p>");
|
||||||
|
|
||||||
|
informationStr << wxT("<ul>");
|
||||||
|
for (auto& logLine : mUpdateManager->getVersionPatch().changelog)
|
||||||
|
{
|
||||||
|
informationStr << wxT("<li>");
|
||||||
|
// We won't to translate downloaded text.
|
||||||
|
informationStr << logLine;
|
||||||
|
informationStr << wxT("</li>");
|
||||||
|
}
|
||||||
|
informationStr << wxT("</ul></p>");
|
||||||
|
|
||||||
|
informationStr << wxT("<p>");
|
||||||
|
informationStr << XO("<a href = \"https://github.com/audacity/audacity/releases\">Read more on GitHub</a>");
|
||||||
|
informationStr << wxT("</p>");
|
||||||
|
|
||||||
|
informationStr << wxT("</body></html>");
|
||||||
|
|
||||||
|
HtmlWindow* html = safenew LinkingHtmlWindow (parent, -1,
|
||||||
|
wxDefaultPosition,
|
||||||
|
wxSize (500, -1),
|
||||||
|
wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER);
|
||||||
|
|
||||||
|
html->SetBorders (20);
|
||||||
|
html->SetPage (o.GetString());
|
||||||
|
|
||||||
|
wxHtmlContainerCell* cell = html->GetInternalRepresentation();
|
||||||
|
|
||||||
|
cell->Layout (500);
|
||||||
|
|
||||||
|
const wxSize size = wxSize (500, cell->GetHeight());
|
||||||
|
|
||||||
|
html->SetMinSize (size);
|
||||||
|
html->SetMaxSize (size);
|
||||||
|
html->SetSize (size);
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
46
src/update/UpdatePopupDialog.h
Normal file
46
src/update/UpdatePopupDialog.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file UpdatePopupDialog.h
|
||||||
|
@brief Define a dialog for notifying users about new version available.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "widgets/wxPanelWrapper.h"
|
||||||
|
#include "wx/string.h"
|
||||||
|
|
||||||
|
#include "Project.h"
|
||||||
|
|
||||||
|
#include "update/UpdateManager.h"
|
||||||
|
|
||||||
|
class HtmlWindow;
|
||||||
|
class wxWindow;
|
||||||
|
class AudacityProject;
|
||||||
|
class UpdateManager;
|
||||||
|
|
||||||
|
/// Show dialog window with update information for the user.
|
||||||
|
/**
|
||||||
|
Support user action behaviors as skip, download a new version,
|
||||||
|
and a checkbox that does not allow tracking version again.
|
||||||
|
*/
|
||||||
|
class UpdatePopupDialog final : public wxDialogWrapper
|
||||||
|
{
|
||||||
|
DECLARE_DYNAMIC_CLASS (AboutDialog)
|
||||||
|
public:
|
||||||
|
explicit UpdatePopupDialog (wxWindow* parent, UpdateManager *updateManager);
|
||||||
|
virtual ~UpdatePopupDialog();
|
||||||
|
|
||||||
|
void OnUpdate (wxCommandEvent& event);
|
||||||
|
void OnSkip (wxCommandEvent& event);
|
||||||
|
void OnDontShow (wxCommandEvent& event);
|
||||||
|
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
|
private:
|
||||||
|
HtmlWindow* AddHtmlContent (wxWindow* parent);
|
||||||
|
|
||||||
|
UpdateManager* const mUpdateManager;
|
||||||
|
};
|
85
src/update/VersionId.cpp
Normal file
85
src/update/VersionId.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file VersionId.h
|
||||||
|
@brief Declare a class with version number manipulation.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
#include "VersionId.h"
|
||||||
|
|
||||||
|
VersionId::VersionId(int version, int release, int revision)
|
||||||
|
: mVersion(version),
|
||||||
|
mRelease(release),
|
||||||
|
mRevision(revision)
|
||||||
|
{}
|
||||||
|
|
||||||
|
wxString VersionId::MakeString(int version, int release, int revision)
|
||||||
|
{
|
||||||
|
return std::to_string(version)
|
||||||
|
+ "." + std::to_string(release)
|
||||||
|
+ "." + std::to_string(revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionId VersionId::ParseFromString(wxString& versionString)
|
||||||
|
{
|
||||||
|
auto versionStringParts = wxSplit(versionString, '.');
|
||||||
|
|
||||||
|
// If we have corrupted version string,
|
||||||
|
// then return the zero version number, that not allow us to update.
|
||||||
|
if (versionStringParts.size() != 3)
|
||||||
|
return VersionId{};
|
||||||
|
|
||||||
|
for (auto& v : versionStringParts)
|
||||||
|
{
|
||||||
|
if (v.empty() || !v.IsNumber())
|
||||||
|
return VersionId{};
|
||||||
|
}
|
||||||
|
|
||||||
|
return VersionId(
|
||||||
|
std::stoi(versionStringParts[0].ToStdString()),
|
||||||
|
std::stoi(versionStringParts[1].ToStdString()),
|
||||||
|
std::stoi(versionStringParts[2].ToStdString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString VersionId::getString() const
|
||||||
|
{
|
||||||
|
return MakeString(mVersion, mRelease, mRevision);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionId::operator== (const VersionId& other)
|
||||||
|
{
|
||||||
|
return mVersion == other.mVersion &&
|
||||||
|
mRelease == other.mRelease &&
|
||||||
|
mRevision == other.mRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionId::operator!= (const VersionId& other)
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionId::operator< (const VersionId& other)
|
||||||
|
{
|
||||||
|
if (mVersion < other.mVersion)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mRelease < other.mRelease &&
|
||||||
|
mVersion == other.mVersion)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mRevision < other.mRevision &&
|
||||||
|
mVersion == other.mVersion &&
|
||||||
|
mRelease == other.mRelease)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionId::operator> (const VersionId& other)
|
||||||
|
{
|
||||||
|
if (*this == other) return false;
|
||||||
|
|
||||||
|
return !(*this < other);
|
||||||
|
}
|
49
src/update/VersionId.h
Normal file
49
src/update/VersionId.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file VersionId.h
|
||||||
|
@brief Declare a class with version number manipulation.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wx/arrstr.h>
|
||||||
|
|
||||||
|
/// A class, that support base manipulation with version number.
|
||||||
|
/**
|
||||||
|
By default initialized by zero version number (Version = 0, Release = 0, Revision = 0),
|
||||||
|
that not allow us to update.
|
||||||
|
*/
|
||||||
|
class VersionId final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Creates an zero version object.
|
||||||
|
VersionId() = default;
|
||||||
|
VersionId(int version, int release, int revision);
|
||||||
|
|
||||||
|
/// Creates version string like "1.2.3" by parameters.
|
||||||
|
static wxString MakeString(int version, int release, int revision);
|
||||||
|
/// Parse and return version object from version string like "1.2.3".
|
||||||
|
static VersionId ParseFromString(wxString& versionString);
|
||||||
|
|
||||||
|
/// Make string with version by MakeString() from instance values.
|
||||||
|
wxString getString() const;
|
||||||
|
|
||||||
|
bool operator== (const VersionId& other);
|
||||||
|
bool operator!= (const VersionId& other);
|
||||||
|
|
||||||
|
bool operator< (const VersionId& other);
|
||||||
|
bool operator> (const VersionId& other);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mVersion{ 0 };
|
||||||
|
int mRelease{ 0 };
|
||||||
|
int mRevision{ 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Return version (VersionId) object with current Audacity build version.
|
||||||
|
static inline VersionId CurrentBuildVersion()
|
||||||
|
{
|
||||||
|
return VersionId{ AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION };
|
||||||
|
}
|
23
src/update/VersionPatch.h
Normal file
23
src/update/VersionPatch.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*!********************************************************************
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
@file VersionPatch.h
|
||||||
|
@brief Declare a structure that describes patch fields.
|
||||||
|
|
||||||
|
Anton Gerasimov
|
||||||
|
**********************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VersionId.h"
|
||||||
|
|
||||||
|
/// A structure that describes patch fields.
|
||||||
|
struct VersionPatch final
|
||||||
|
{
|
||||||
|
using UpdateDataFormat = std::string;
|
||||||
|
|
||||||
|
VersionPatch() = default;
|
||||||
|
|
||||||
|
VersionId version;
|
||||||
|
wxArrayString changelog;
|
||||||
|
wxString download;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user