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
|
||||
)
|
||||
|
||||
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
|
||||
if( CMAKE_C_COMPILER_ID MATCHES "MSVC" AND CMAKE_VS_PLATFORM_NAME MATCHES "Win64|x64" )
|
||||
set( IS_64BIT ON )
|
||||
|
@ -12,6 +12,7 @@ cmake_args=(
|
||||
-G "${AUDACITY_CMAKE_GENERATOR}"
|
||||
-D audacity_use_pch=no
|
||||
-D audacity_has_networking=yes
|
||||
-D audacity_has_updates_check=yes
|
||||
-D CMAKE_BUILD_TYPE="${AUDACITY_BUILD_TYPE}"
|
||||
-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 "widgets/FileConfig.h"
|
||||
#include "widgets/FileHistory.h"
|
||||
#include "update/UpdateManager.h"
|
||||
|
||||
#ifdef HAS_NETWORKING
|
||||
#include "NetworkManager.h"
|
||||
@ -1489,6 +1490,10 @@ bool AudacityApp::InitPart2()
|
||||
SplashDialog::DoHelpWelcome(*project);
|
||||
}
|
||||
|
||||
#if defined(HAVE_UPDATES_CHECK)
|
||||
mUpdateManager = std::make_unique<UpdateManager>(*project);
|
||||
#endif
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
FFmpegStartup();
|
||||
#endif
|
||||
|
@ -33,6 +33,7 @@ class Importer;
|
||||
class CommandHandler;
|
||||
class AppCommandEvent;
|
||||
class AudacityProject;
|
||||
class UpdateManager;
|
||||
|
||||
class AudacityApp final : public wxApp {
|
||||
public:
|
||||
@ -113,6 +114,10 @@ class AudacityApp final : public wxApp {
|
||||
std::unique_ptr<wxSocketServer> mIPCServ;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_UPDATES_CHECK)
|
||||
std::unique_ptr<UpdateManager> mUpdateManager;
|
||||
#endif
|
||||
|
||||
public:
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
@ -982,6 +982,19 @@ list( APPEND SOURCES
|
||||
xml/XMLWriter.h
|
||||
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
|
||||
)
|
||||
|
||||
@ -1038,6 +1051,9 @@ list( APPEND DEFINES
|
||||
__STDC_CONSTANT_MACROS
|
||||
STRICT
|
||||
>
|
||||
$<$<BOOL:${USE_UPDATE_CHECK}>:
|
||||
HAVE_UPDATES_CHECK
|
||||
>
|
||||
)
|
||||
|
||||
# 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