AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

commit 07f07589865992ced56c7322658fbe5f7a20a510
parent 14c63c416367535e63a70d24a0adca23a712b4f8
Author: jatinchowdhury18 <jatinchowdhury18@gmail.com>
Date:   Sun, 23 Aug 2020 11:27:03 -0700

Add simple auto-update checking (#74)

* Add simple auto-update checking

* Update changelog

Co-authored-by: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Diffstat:
MCHANGELOG.md | 1+
MPlugin/CHOWTapeModel.jucer | 3+++
APlugin/Source/GUI/AutoUpdating.cpp | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/AutoUpdating.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
MPlugin/Source/PluginProcessor.cpp | 15+++++++++++++--
MPlugin/Source/PluginProcessor.h | 4++++
6 files changed, 243 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -6,6 +6,7 @@ this file. - Updated delay lines in wow/flutter processing to use 3-point Lagrange interpolation. - Change Newton-Raphson solver to use 4 or 8 iterations, in unrolled loop. +- Added simple behavior to automatically check for updates. - Improved loss filter sliders. - Fixed tooltip name sometimes not appearing. - Fixed save/load bug for VST3 in Ableton. diff --git a/Plugin/CHOWTapeModel.jucer b/Plugin/CHOWTapeModel.jucer @@ -19,6 +19,9 @@ <FILE id="bQP3yl" name="RobotoCondensed-Regular.ttf" compile="0" resource="1" file="Source/GUI/Assets/RobotoCondensed-Regular.ttf"/> </GROUP> + <FILE id="XNEbSl" name="AutoUpdating.cpp" compile="1" resource="0" + file="Source/GUI/AutoUpdating.cpp"/> + <FILE id="u8IfBD" name="AutoUpdating.h" compile="0" resource="0" file="Source/GUI/AutoUpdating.h"/> <FILE id="rOj90C" name="InfoComp.cpp" compile="1" resource="0" file="Source/GUI/InfoComp.cpp"/> <FILE id="FxvDV3" name="InfoComp.h" compile="0" resource="0" file="Source/GUI/InfoComp.h"/> <FILE id="IgOtsG" name="MyLNF.cpp" compile="1" resource="0" file="Source/GUI/MyLNF.cpp"/> diff --git a/Plugin/Source/GUI/AutoUpdating.cpp b/Plugin/Source/GUI/AutoUpdating.cpp @@ -0,0 +1,167 @@ +#include "AutoUpdating.h" + +namespace +{ + const String updateFilePath = "ChowdhuryDSP/ChowTape/UpdateManage.txt"; + const String currentVersion = "v" + String (JucePlugin_VersionString); + const String versionURL = "https://api.github.com/repos/jatinchowdhury18/AnalogTapeModel/releases/latest"; + const String updateURL = "https://github.com/jatinchowdhury18/AnalogTapeModel/releases/latest"; + const Colour backgroundColour = Colour (0xFF31323A).withAlpha (0.9f); +} + +AutoUpdater::AutoUpdater() +{ + auto setupButton = [=] (TextButton& button) + { + addAndMakeVisible (button); + button.setColour (TextButton::buttonColourId, backgroundColour); + button.setColour (TextButton::textColourOffId, Colour (0xFFEAA92C)); + button.setColour (ComboBox::outlineColourId, Colours::transparentBlack); + button.setOpaque (false); + button.setMouseCursor (MouseCursor::PointingHandCursor); + button.setLookAndFeel (&ubLNF); + }; + + setupButton (yesButton); + setupButton (noButton); + + yesButton.onClick = std::bind (&AutoUpdater::yesButtonPressed, this); + noButton.onClick = std::bind (&AutoUpdater::noButtonPressed, this); +} + +AutoUpdater::~AutoUpdater() +{ + yesButton.setLookAndFeel (nullptr); + noButton.setLookAndFeel (nullptr); +} + +void AutoUpdater::yesButtonPressed() +{ + // open update link + URL updateLink (updateURL); + updateLink.launchInDefaultBrowser(); + + // reset update check file + setVisible (false); + editUpdateCheckFile (newVersion, true); +} + +void AutoUpdater::noButtonPressed() +{ + // reset update check file + setVisible (false); + editUpdateCheckFile (newVersion, false); +} + +void AutoUpdater::paint (Graphics& g) +{ + g.fillAll (backgroundColour); + + g.setColour (Colours::white); + g.setFont (Font (36.0f)); + + String updatePrompt = String ("Version " + newVersion.removeCharacters ("v") + " of CHOW Tape is available. Would you like to download?"); + + const auto promptWidth = getWidth() * 2 / 3; + const auto promptX = getWidth() / 6; + const auto promptHeight = 50; + const auto promptY = getHeight() / 2 - promptHeight; + + g.drawFittedText (updatePrompt, promptX, promptY, promptWidth, promptHeight, Justification::centred, 2); +} + +void AutoUpdater::resized() +{ + const auto y = getHeight() / 2 + 10; + const auto width = 90; + const auto pad = 5; + const auto height = 40; + + yesButton.setBounds (getWidth() / 2 - width - pad, y, width, height); + noButton.setBounds (getWidth() / 2 + pad, y, width, height); +} + +bool AutoUpdater::runAutoUpdateCheck() +{ + auto updateFile = getUpdateCheckFile(); + String latestVersion = getLatestVersion(); + + if (latestVersion.isEmpty()) // unable to get latest version + return false; + + if (latestVersion == currentVersion) // you're up to date! + return false; + + String updateVersion = getUpdateFileVersion (updateFile); + bool lastYesNo = getUpdateFileYesNo (updateFile); + + // you've already said you don't want to update to this version + if ((updateVersion == latestVersion) && (lastYesNo == false)) + return false; + + newVersion = latestVersion; + return true; +} + +File AutoUpdater::getUpdateCheckFile() +{ + File updateCheckFile = File::getSpecialLocation (File::userApplicationDataDirectory); + updateCheckFile = updateCheckFile.getChildFile (updateFilePath); + + if (! updateCheckFile.existsAsFile()) + { + updateCheckFile.create(); + updateCheckFile.appendText (currentVersion + "\n"); + updateCheckFile.appendText ("YES\n"); + } + + return updateCheckFile; +} + +String AutoUpdater::getLatestVersion() +{ + URL latestVersionURL (versionURL); + std::unique_ptr<InputStream> inStream (latestVersionURL.createInputStream (false, nullptr, nullptr, {}, 5000)); + + if (inStream == nullptr) + return {}; + + auto content = inStream->readEntireStreamAsString(); + auto latestReleaseDetails = JSON::parse (content); + + auto* json = latestReleaseDetails.getDynamicObject(); + + if (json == nullptr) + return {}; + + return json->getProperty ("tag_name").toString(); +} + +String AutoUpdater::getUpdateFileVersion (const File& updateFile) +{ + StringArray lines; + updateFile.readLines (lines); + + return lines[0]; +} + +bool AutoUpdater::getUpdateFileYesNo (const File& updateFile) +{ + StringArray lines; + updateFile.readLines (lines); + + return lines[1] == "YES"; +} + +void AutoUpdater::editUpdateCheckFile (String version, bool wantsUpdate) +{ + auto updateFile = getUpdateCheckFile(); + updateFile.deleteFile(); + updateFile.create(); + updateFile.appendText (version + "\n"); + + if (wantsUpdate) + updateFile.appendText ("YES\n"); + else + updateFile.appendText ("NO\n"); +} diff --git a/Plugin/Source/GUI/AutoUpdating.h b/Plugin/Source/GUI/AutoUpdating.h @@ -0,0 +1,55 @@ +#ifndef AUTOUPDATING_H_INCLUDED +#define AUTOUPDATING_H_INCLUDED + +#include <JuceHeader.h> +#include "MyLNF.h" + +struct UpdateButtonLNF : public MyLNF +{ + UpdateButtonLNF() {} + + Font getTextButtonFont (TextButton&, int /*buttonHeight*/) override + { + return Font (30.0f).boldened(); + } + + void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, bool, bool) override + { + LookAndFeel_V4::drawButtonBackground (g, button, backgroundColour, false, false); + } + +private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UpdateButtonLNF) +}; + +class AutoUpdater : public Component +{ +public: + AutoUpdater(); + ~AutoUpdater(); + + void paint (Graphics& g) override; + void resized() override; + + bool runAutoUpdateCheck(); + void noButtonPressed(); + void yesButtonPressed(); + +private: + File getUpdateCheckFile(); + String getLatestVersion(); + String getUpdateFileVersion (const File& updateFile); + bool getUpdateFileYesNo (const File& updateFile); + void editUpdateCheckFile (String version, bool wantsUpdate); + + String newVersion = String (JucePlugin_VersionString); + + TextButton yesButton { "Yes" }; + TextButton noButton { "No" }; + UpdateButtonLNF ubLNF; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AutoUpdater) +}; + + +#endif // AUTOUPDATING_H_INCLUDED diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp @@ -12,7 +12,6 @@ #include "GUI/InfoComp.h" #include "GUI/TitleComp.h" #include "GUI/TooltipComp.h" -#include "GUI/MyLNF.h" //============================================================================== ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() @@ -38,6 +37,8 @@ ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor() scope = magicState.createAndAddObject<foleys::MagicOscilloscope> ("scope"); LookAndFeel::setDefaultLookAndFeel (&myLNF); + + needsUpdate = updater.runAutoUpdateCheck(); } ChowtapeModelAudioProcessor::~ChowtapeModelAudioProcessor() @@ -273,7 +274,17 @@ AudioProcessorEditor* ChowtapeModelAudioProcessor::createEditor() return new foleys::MagicPluginEditor (magicState, BinaryData::preset_save_gui_xml, BinaryData::preset_save_gui_xmlSize, std::move (builder)); #else - return new foleys::MagicPluginEditor (magicState, BinaryData::gui_xml, BinaryData::gui_xmlSize, std::move (builder)); + auto* editor = new foleys::MagicPluginEditor (magicState, BinaryData::gui_xml, BinaryData::gui_xmlSize, std::move (builder)); + + if (needsUpdate) + { + needsUpdate = false; + + editor->addAndMakeVisible (updater); + updater.setBounds (0, 0, editor->getWidth(), editor->getHeight()); + } + + return editor; #endif } diff --git a/Plugin/Source/PluginProcessor.h b/Plugin/Source/PluginProcessor.h @@ -21,6 +21,7 @@ #include "Processors/Timing_Effects/DelayProcessor.h" #include "Presets/PresetManager.h" #include "GUI/MyLNF.h" +#include "GUI/AutoUpdating.h" //============================================================================== /** @@ -92,6 +93,9 @@ private: PresetManager presetManager; MyLNF myLNF; + AutoUpdater updater; + bool needsUpdate = false; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChowtapeModelAudioProcessor) };