| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2017 - ROLI Ltd.
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 5 End-User License
 -    Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
 -    27th April 2017).
 - 
 -    End User License Agreement: www.juce.com/juce-5-licence
 -    Privacy Policy: www.juce.com/juce-5-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - #include "../JuceLibraryCode/JuceHeader.h"
 - #include "VoicePurchases.h"
 - 
 - //==============================================================================
 - class InAppPurchaseApplication  : public JUCEApplication,
 -                                   private AsyncUpdater
 - {
 - public:
 -     //==============================================================================
 -     InAppPurchaseApplication()   : voicePurchases (*this) {}
 - 
 -     //==============================================================================
 -     const String getApplicationName() override       { return ProjectInfo::projectName; }
 -     const String getApplicationVersion() override    { return ProjectInfo::versionString; }
 -     bool moreThanOneInstanceAllowed() override       { return false; }
 - 
 -     //==============================================================================
 -     void initialise (const String&) override
 -     {
 -         Desktop::getInstance().getDefaultLookAndFeel().setUsingNativeAlertWindows (true);
 - 
 -         dm.addAudioCallback (&player);
 -         dm.initialiseWithDefaultDevices (0, 2);
 - 
 -         mainWindow = new MainWindow;
 -     }
 - 
 -     void shutdown() override
 -     {
 -         mainWindow = nullptr;
 -         dm.closeAudioDevice();
 -         dm.removeAudioCallback (&player);
 -     }
 - 
 -     static InAppPurchaseApplication* getInstance()
 -     {
 -         return static_cast<InAppPurchaseApplication*> (JUCEApplication::getInstance());
 -     }
 - 
 -     //==============================================================================
 -     SoundPlayer& getPlayer()
 -     {
 -         return player;
 -     }
 - 
 -     VoicePurchases& getPurchases()
 -     {
 -         return voicePurchases;
 -     }
 - 
 -     //==============================================================================
 -     class MainContentComponent : public Component, private Button::Listener
 -     {
 -     public:
 -         MainContentComponent()
 -         {
 -             setOpaque (true);
 - 
 -             phraseListBox.setRowHeight (33);
 -             phraseListBox.selectRow (0);
 -             phraseListBox.updateContent();
 - 
 -             voiceListBox.setRowHeight (66);
 -             voiceListBox.selectRow (0);
 -             voiceListBox.updateContent();
 -             voiceListBox.getViewport()->setScrollOnDragEnabled (true);
 - 
 -             addAndMakeVisible (phraseLabel);
 -             addAndMakeVisible (phraseListBox);
 -             addAndMakeVisible (playStopButton);
 -             addAndMakeVisible (voiceLabel);
 -             addAndMakeVisible (voiceListBox);
 - 
 -             playStopButton.addListener (this);
 - 
 -            #if JUCE_ANDROID || JUCE_IOS
 -             auto screenBounds = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
 -             setSize (screenBounds.getWidth(), screenBounds.getHeight());
 -            #else
 -             setSize (800, 600);
 -            #endif
 -         }
 - 
 -         void updateDisplay()
 -         {
 -             voiceListBox.updateContent();
 -             voiceListBox.repaint();
 -         }
 - 
 -     private:
 -         //==============================================================================
 -         class PhraseModel : public ListBoxModel
 -         {
 -         public:
 -             PhraseModel() {}
 - 
 -             int getNumRows() override    { return phrases.size(); }
 - 
 -             void paintListBoxItem (int row, Graphics& g, int w, int h, bool isSelected) override
 -             {
 -                 Rectangle<int> r (0, 0, w, h);
 - 
 -                 auto& lf = Desktop::getInstance().getDefaultLookAndFeel();
 -                 g.setColour (lf.findColour (isSelected ? TextEditor::highlightColourId : ListBox::backgroundColourId));
 -                 g.fillRect (r);
 - 
 -                 g.setColour (lf.findColour (ListBox::textColourId));
 - 
 -                 g.setFont (18);
 - 
 -                 String phrase = (isPositiveAndBelow (row, phrases.size()) ? phrases[row] : String{});
 -                 g.drawText (phrase, 10, 0, w, h, Justification::centredLeft);
 -             }
 - 
 -         private:
 -             static StringArray phrases;
 - 
 -             JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PhraseModel)
 -         };
 - 
 -         //==============================================================================
 -         class VoiceModel : public ListBoxModel
 -         {
 -         public:
 -             //==============================================================================
 -             class VoiceRow : public Component, private Button::Listener, private Timer
 -             {
 -             public:
 -                 VoiceRow ()    : voices (getInstance()->getPurchases().getVoiceNames())
 -                 {
 -                     addAndMakeVisible (nameLabel);
 -                     addAndMakeVisible (purchaseButton);
 -                     addAndMakeVisible (priceLabel);
 - 
 -                     purchaseButton.addListener (this);
 - 
 -                     setSize (600, 33);
 -                 }
 - 
 -                 void paint (Graphics& g) override
 -                 {
 -                     auto r = getLocalBounds().reduced (4);
 -                     {
 -                         auto voiceIconBounds = r.removeFromLeft (r.getHeight());
 -                         g.setColour (Colours::black);
 -                         g.drawRect (voiceIconBounds);
 - 
 -                         voiceIconBounds.reduce (1, 1);
 -                         g.setColour (hasBeenPurchased ? Colours::white : Colours::grey);
 -                         g.fillRect (voiceIconBounds);
 - 
 -                         g.drawImage (avatar, voiceIconBounds.toFloat());
 - 
 -                         if (! hasBeenPurchased)
 -                         {
 -                             g.setColour (Colours::white.withAlpha (0.8f));
 -                             g.fillRect (voiceIconBounds);
 - 
 -                             if (purchaseInProgress)
 -                                 getLookAndFeel().drawSpinningWaitAnimation (g, Colours::darkgrey,
 -                                                                             voiceIconBounds.getX(), voiceIconBounds.getY(),
 -                                                                             voiceIconBounds.getWidth(), voiceIconBounds.getHeight());
 -                         }
 -                     }
 -                 }
 - 
 -                 void resized() override
 -                 {
 -                     auto r = getLocalBounds().reduced (4 + 8, 4);
 -                     auto h = r.getHeight();
 -                     auto w = static_cast<int> (h * 1.5);
 - 
 -                     r.removeFromLeft (h);
 -                     purchaseButton.setBounds (r.removeFromRight (w).withSizeKeepingCentre (w, h / 2));
 - 
 -                     nameLabel.setBounds (r.removeFromTop (18));
 -                     priceLabel.setBounds (r.removeFromTop (18));
 -                 }
 - 
 -                 void update (int rowNumber, bool rowIsSelected)
 -                 {
 -                     isSelected  = rowIsSelected;
 -                     rowSelected = rowNumber;
 - 
 -                     if (isPositiveAndBelow (rowNumber, voices.size()))
 -                     {
 -                         auto imageResourceName = voices[rowNumber] + "_png";
 - 
 -                         nameLabel.setText (voices[rowNumber], NotificationType::dontSendNotification);
 - 
 -                         auto purchase = getInstance()->getPurchases().getPurchase (rowNumber);
 -                         hasBeenPurchased = purchase.isPurchased;
 -                         purchaseInProgress = purchase.purchaseInProgress;
 - 
 -                         if (purchaseInProgress)
 -                             startTimer (1000 / 50);
 -                         else
 -                             stopTimer();
 - 
 -                         nameLabel.setFont (Font (16).withStyle (Font::bold | (hasBeenPurchased ? 0 : Font::italic)));
 -                         nameLabel.setColour (Label::textColourId, hasBeenPurchased ? Colours::white : Colours::grey);
 - 
 -                         priceLabel.setFont (Font (10).withStyle (purchase.priceIsKnown ? 0 : Font::italic));
 -                         priceLabel.setColour (Label::textColourId, hasBeenPurchased ? Colours::white : Colours::grey);
 -                         priceLabel.setText (purchase.purchasePrice, NotificationType::dontSendNotification);
 - 
 -                         if (rowNumber == 0)
 -                         {
 -                             purchaseButton.setButtonText ("Internal");
 -                             purchaseButton.setEnabled (false);
 -                         }
 -                         else
 -                         {
 -                             purchaseButton.setButtonText (hasBeenPurchased ? "Purchased" : "Purchase");
 -                             purchaseButton.setEnabled (! hasBeenPurchased && purchase.priceIsKnown);
 -                         }
 - 
 -                         setInterceptsMouseClicks (! hasBeenPurchased, ! hasBeenPurchased);
 - 
 -                         int rawSize;
 -                         if (auto* rawData = BinaryData::getNamedResource (imageResourceName.toRawUTF8(), rawSize))
 -                         {
 -                             MemoryInputStream imageData (rawData, static_cast<size_t> (rawSize), false);
 -                             avatar = PNGImageFormat().decodeImage (imageData);
 -                         }
 -                     }
 -                 }
 -             private:
 -                 //==============================================================================
 -                 void buttonClicked (Button*) override
 -                 {
 -                     if (rowSelected >= 0)
 -                     {
 -                         if (! hasBeenPurchased)
 -                         {
 -                             getInstance()->getPurchases().purchaseVoice (rowSelected);
 -                             purchaseInProgress = true;
 -                             startTimer (1000 / 50);
 -                         }
 -                     }
 -                 }
 - 
 -                 void timerCallback() override   { repaint(); }
 - 
 -                 //==============================================================================
 -                 bool isSelected = false, hasBeenPurchased = false, purchaseInProgress = false;
 -                 int rowSelected = -1;
 -                 Image avatar;
 - 
 -                 StringArray voices;
 - 
 -                 Label nameLabel, priceLabel;
 -                 TextButton purchaseButton {"Purchase"};
 - 
 -                 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VoiceRow)
 -             };
 - 
 -             //==============================================================================
 -             VoiceModel() : voiceProducts (getInstance()->getPurchases().getVoiceNames()) {}
 - 
 -             int getNumRows() override    { return voiceProducts.size(); }
 - 
 -             Component* refreshComponentForRow (int row, bool selected, Component* existing) override
 -             {
 -                 if (isPositiveAndBelow (row, voiceProducts.size()))
 -                 {
 -                     if (existing == nullptr)
 -                         existing = new VoiceRow;
 - 
 -                     if (auto* voiceRow = dynamic_cast<VoiceRow*> (existing))
 -                         voiceRow->update (row, selected);
 - 
 -                     return existing;
 -                 }
 - 
 -                 return nullptr;
 -             }
 - 
 -             void paintListBoxItem (int, Graphics& g, int w, int h, bool isSelected) override
 -             {
 -                 auto r = Rectangle<int> (0, 0, w, h).reduced (4);
 - 
 -                 auto& lf = Desktop::getInstance().getDefaultLookAndFeel();
 -                 g.setColour (lf.findColour (isSelected ? TextEditor::highlightColourId : ListBox::backgroundColourId));
 -                 g.fillRect (r);
 -             }
 - 
 -         private:
 -             StringArray voiceProducts;
 -             JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VoiceModel)
 -         };
 - 
 -         //==============================================================================
 -         void resized() override
 -         {
 -             auto r = getLocalBounds().reduced (20);
 - 
 -             {
 -                 auto phraseArea = r.removeFromTop (r.getHeight() / 2);
 - 
 -                 phraseLabel.setBounds (phraseArea.removeFromTop (36).reduced (0, 10));
 -                 playStopButton.setBounds (phraseArea.removeFromBottom (50).reduced (0, 10));
 -                 phraseListBox.setBounds (phraseArea);
 -             }
 - 
 -             {
 -                 auto voiceArea = r;
 - 
 -                 voiceLabel.setBounds (voiceArea.removeFromTop (36).reduced (0, 10));
 -                 voiceListBox.setBounds (voiceArea);
 -             }
 -         }
 - 
 -         void paint (Graphics& g) override
 -         {
 -             g.fillAll (Desktop::getInstance().getDefaultLookAndFeel()
 -                           .findColour (ResizableWindow::backgroundColourId));
 -         }
 - 
 -         //==============================================================================
 -         void buttonClicked (Button*) override
 -         {
 -             MemoryOutputStream resourceName;
 - 
 -             auto idx = voiceListBox.getSelectedRow();
 -             if (isPositiveAndBelow (idx, soundNames.size()))
 -             {
 -                 resourceName << soundNames[idx] << phraseListBox.getSelectedRow() << "_ogg";
 -                 int numBytes;
 - 
 -                 if (auto* data = BinaryData::getNamedResource (resourceName.toString().toRawUTF8(), numBytes))
 -                     getInstance()->getPlayer().play (data, static_cast<size_t> (numBytes));
 -             }
 -         }
 - 
 -         //==============================================================================
 -         StringArray soundNames = getInstance()->getPurchases().getVoiceNames();
 - 
 -         PhraseModel phraseModel;
 -         Label phraseLabel {"phraseLabel", NEEDS_TRANS ("Phrases:")};
 -         ListBox phraseListBox { "phraseListBox", &phraseModel };
 -         TextButton playStopButton {"Play"};
 - 
 -         VoiceModel voiceModel;
 -         Label voiceLabel {"voiceLabel", NEEDS_TRANS ("Voices:")};
 -         ListBox voiceListBox { "voiceListBox", &voiceModel };
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
 -     };
 - 
 -     //==============================================================================
 -     class MainWindow    : public DocumentWindow
 -     {
 -     public:
 -         MainWindow ()  : DocumentWindow (ProjectInfo::projectName,
 -                                          Desktop::getInstance().getDefaultLookAndFeel()
 -                                                                .findColour (ResizableWindow::backgroundColourId),
 -                                          DocumentWindow::allButtons)
 -         {
 -             setUsingNativeTitleBar (true);
 -             setContentOwned (new MainContentComponent(), true);
 - 
 -            #if JUCE_ANDROID || JUCE_IOS
 -             setFullScreen (true);
 -            #else
 -             centreWithSize (getWidth(), getHeight());
 -            #endif
 - 
 -             setVisible (true);
 -         }
 - 
 -         void closeButtonPressed() override
 -         {
 -             JUCEApplication::getInstance()->systemRequestedQuit();
 -         }
 - 
 -     private:
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
 -     };
 - 
 - private:
 -     //==============================================================================
 -     void handleAsyncUpdate() override
 -     {
 -         if (auto* contentComponent = dynamic_cast<MainContentComponent*> (mainWindow->getContentComponent()))
 -             contentComponent->updateDisplay();
 -     }
 - 
 -     //==============================================================================
 -     VoicePurchases voicePurchases;
 -     AudioDeviceManager dm;
 -     SoundPlayer player;
 -     ScopedPointer<MainWindow> mainWindow;
 -     ScopedPointer<AlertWindow> alertWindow;
 - };
 - 
 - StringArray InAppPurchaseApplication::MainContentComponent::PhraseModel::phrases {{"I love JUCE!", "The five dimensions of touch", "Make it fast!"}};
 - 
 - //==============================================================================
 - // This macro generates the main() routine that launches the app.
 - START_JUCE_APPLICATION (InAppPurchaseApplication)
 
 
  |