diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c5889d9..f296913 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources(${PROJECT_NAME} PRIVATE "Components/AboutDialog.cpp" "Components/ABToggleComponent.cpp" + "Components/DonationSelector.cpp" "Components/EarlySection.cpp" "Components/HeaderSection.cpp" "Components/InfoButtonComponent.cpp" diff --git a/Source/Components/AboutDialog.cpp b/Source/Components/AboutDialog.cpp index f372343..8d9fa4d 100644 --- a/Source/Components/AboutDialog.cpp +++ b/Source/Components/AboutDialog.cpp @@ -19,6 +19,7 @@ #include "AboutDialog.h" #include "Config.h" +#include "DonationSelector.h" #include AboutDialog::AboutDialog() @@ -29,16 +30,34 @@ AboutDialog::AboutDialog() logo = juce::Drawable::createFromImageData(BinaryData::logo_svg, BinaryData::logo_svgSize); - const juce::String pluginInfoText = juce::String("ElephantDSP.com Room Reverb is free software distributed under the GNU General Public License version 3. For more information, contact options, and the source code, visit www.ElephantDSP.com\n\n") + - "Version: " + juce::String(PROJECT_VERSION) + "\n" + - "Format: " + juce::String(juce::AudioProcessor::getWrapperTypeDescription(pluginHostType.getPluginLoadedAs())) + "\n" + - "Host: " + juce::String(pluginHostType.getHostDescription()) + "\n" + - "OS: " + juce::SystemStats::getOperatingSystemName(); + const juce::String pluginInfoText = juce::String("Room Reverb is free software distributed under the GNU General Public License version 3. For more information, contact options, and the source code, visit www.ElephantDSP.com\n\n") + + "If you like this audio plugin, please consider donating a few spare coins. Thank you very much! :)"; pluginInfo.setText(pluginInfoText, juce::dontSendNotification); pluginInfo.setFont(juce::Font(22.0f)); pluginInfo.setJustificationType(juce::Justification::centred); addAndMakeVisible(pluginInfo); +#if JUCE_IOS + donateCTA = std::make_unique(); +#else + donateCTA = std::make_unique(); + juce::HyperlinkButton* donateButton = static_cast(donateCTA.get()); + donateButton->setButtonText("Donate with PayPal"); + donateButton->setFont(juce::Font(22.0f, juce::Font::underlined), false, juce::Justification::centred); + donateButton->setURL(juce::URL("https://www.paypal.com/donate/?hosted_button_id=Z3RSDGUEPVY52")); + donateButton->setTooltip(""); +#endif + addAndMakeVisible(donateCTA.get()); + + const juce::String versionInfoText = "Version: " + juce::String(PROJECT_VERSION) + "\n" + + "Format: " + juce::String(juce::AudioProcessor::getWrapperTypeDescription(pluginHostType.getPluginLoadedAs())) + "\n" + + "Host: " + juce::String(pluginHostType.getHostDescription()) + "\n" + + "OS: " + juce::SystemStats::getOperatingSystemName(); + versionInfo.setText(versionInfoText, juce::dontSendNotification); + versionInfo.setFont(juce::Font(18.0f)); + versionInfo.setJustificationType(juce::Justification::centred); + addAndMakeVisible(versionInfo); + if (pluginHostType.getPluginLoadedAs() == juce::AudioProcessor::wrapperType_VST3) vstLogo = juce::Drawable::createFromImageData(BinaryData::VST_Compatible_Logo_Steinberg_with_TM_negative_svg, BinaryData::VST_Compatible_Logo_Steinberg_with_TM_negative_svgSize); @@ -66,15 +85,22 @@ void AboutDialog::resized() { auto area = getLocalBounds().reduced(2); - const int titleBarHeight = 35; + // header + const int titleBarHeight = 40; auto titleBar = area.removeFromTop(titleBarHeight); closeButton.setBounds(titleBar.removeFromRight(titleBarHeight).reduced(10)); - if (logo != nullptr) logoBounds = area.removeFromTop(40).reduced(5).toFloat(); + // footer + auto footer = area.removeFromBottom(150); if (vstLogo != nullptr) - vstLogoBounds = area.removeFromBottom(150).reduced(5).toFloat(); - - pluginInfo.setBounds(area); + { + vstLogoBounds = footer.removeFromRight(footer.getWidth() / 2).reduced(10).toFloat(); + } + versionInfo.setBounds(footer.reduced(10)); + + // content + pluginInfo.setBounds(area.removeFromTop(180)); + donateCTA->setBounds(area.removeFromTop(50).withSizeKeepingCentre(350, 50)); } diff --git a/Source/Components/AboutDialog.h b/Source/Components/AboutDialog.h index 3965dac..0e21a62 100644 --- a/Source/Components/AboutDialog.h +++ b/Source/Components/AboutDialog.h @@ -35,6 +35,8 @@ class AboutDialog : public juce::Component std::unique_ptr logo; juce::Rectangle logoBounds; juce::Label pluginInfo; + std::unique_ptr donateCTA; + juce::Label versionInfo; std::unique_ptr vstLogo; juce::Rectangle vstLogoBounds; diff --git a/Source/Components/DonationSelector.cpp b/Source/Components/DonationSelector.cpp new file mode 100644 index 0000000..2a5dcae --- /dev/null +++ b/Source/Components/DonationSelector.cpp @@ -0,0 +1,79 @@ +/** + * ElephantDSP.com Room Reverb + * + * Copyright (C) 2023 Christian Voigt + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "DonationSelector.h" + +DonationSelector::DonationSelector() +{ + setText("Donate via in-app purchase"); + getRootMenu()->addItem("In-app purchase is unavailable!", false, false, {}); + setJustificationType(juce::Justification::centred); + + if (!juce::InAppPurchases::getInstance()->isInAppPurchasesSupported()) + { + jassertfalse; // In-app purchases are only supported on iOS + return; + } + + donationProducts = juce::Array({DonationProduct{"donation05", "Retrieving price..."}, + DonationProduct{"donation10", "Retrieving price..."}, + DonationProduct{"donation20", "Retrieving price..."}, + DonationProduct{"donation50", "Retrieving price..."}}); + + juce::InAppPurchases::getInstance()->addListener(this); + + juce::StringArray identifiers; + for (const auto& donationProduct : donationProducts) + identifiers.add(donationProduct.identifier); + juce::InAppPurchases::getInstance()->getProductsInformation(identifiers); +} + +DonationSelector::~DonationSelector() +{ + juce::InAppPurchases::getInstance()->removeListener(this); +} + +void DonationSelector::productsInfoReturned(const juce::Array& products) +{ + if (products.isEmpty()) + return; + + // remove "unavailable" entry + getRootMenu()->clear(); + + for (auto& donationProduct : donationProducts) + { + for (int i = 0; i < products.size(); ++i) + { + if (donationProduct.identifier == products[i].identifier) + { + donationProduct.purchasePrice = products[i].price; + getRootMenu()->addItem(donationProduct.purchasePrice, [=] + { purchase(donationProduct.identifier); }); + break; + } + } + } +} + +void DonationSelector::purchase(const juce::String& identifier) +{ + juce::InAppPurchases::getInstance()->purchaseProduct(identifier); + setText("Donate via in-app purchase"); +} diff --git a/Source/Components/DonationSelector.h b/Source/Components/DonationSelector.h new file mode 100644 index 0000000..91b6024 --- /dev/null +++ b/Source/Components/DonationSelector.h @@ -0,0 +1,45 @@ +/** + * ElephantDSP.com Room Reverb + * + * Copyright (C) 2023 Christian Voigt + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +class DonationSelector : public juce::ComboBox, + private juce::InAppPurchases::Listener +{ +public: + struct DonationProduct + { + juce::String identifier; + juce::String purchasePrice; + }; + + DonationSelector(); + ~DonationSelector() override; + +private: + void productsInfoReturned(const juce::Array& products) override; + void purchase(const juce::String& identifier); + + juce::Array donationProducts; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DonationSelector) +}; diff --git a/Source/LookAndFeel/CustomLookAndFeel.cpp b/Source/LookAndFeel/CustomLookAndFeel.cpp index 0926b65..6dbf148 100644 --- a/Source/LookAndFeel/CustomLookAndFeel.cpp +++ b/Source/LookAndFeel/CustomLookAndFeel.cpp @@ -48,6 +48,8 @@ CustomLookAndFeel::CustomLookAndFeel() setColour(juce::ResizableWindow::ColourIds::backgroundColourId, juce::Colour(0xff5e5e5e)); setColour(juce::DocumentWindow::textColourId, juce::Colours::white); + setColour(juce::HyperlinkButton::textColourId, juce::Colour(0xffdc0000)); + setColour(juce::TextButton::buttonColourId, juce::Colour(0xff303030)); setColour(juce::TextButton::buttonOnColourId, juce::Colour(0xff5e5e5e));