The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
7.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. //==============================================================================
  20. class VoicePurchases : private InAppPurchases::Listener
  21. {
  22. public:
  23. //==============================================================================
  24. struct VoiceProduct
  25. {
  26. const char* identifier;
  27. const char* humanReadable;
  28. bool isPurchased, priceIsKnown, purchaseInProgress;
  29. String purchasePrice;
  30. };
  31. //==============================================================================
  32. VoicePurchases (AsyncUpdater& asyncUpdater)
  33. : guiUpdater (asyncUpdater)
  34. {
  35. voiceProducts = Array<VoiceProduct>(
  36. {VoiceProduct {"robot", "Robot", true, true, false, "Free" },
  37. VoiceProduct {"jules", "Jules", false, false, false, "Retrieving price..." },
  38. VoiceProduct {"fabian", "Fabian", false, false, false, "Retrieving price..." },
  39. VoiceProduct {"ed", "Ed", false, false, false, "Retrieving price..." },
  40. VoiceProduct {"lukasz", "Lukasz", false, false, false, "Retrieving price..." },
  41. VoiceProduct {"jb", "JB", false, false, false, "Retrieving price..." } });
  42. }
  43. ~VoicePurchases()
  44. {
  45. inAppPurchases.removeListener (this);
  46. }
  47. //==============================================================================
  48. VoiceProduct getPurchase (int voiceIndex)
  49. {
  50. if (! havePurchasesBeenRestored)
  51. {
  52. havePurchasesBeenRestored = true;
  53. inAppPurchases.addListener (this);
  54. inAppPurchases.restoreProductsBoughtList (true);
  55. }
  56. return voiceProducts[voiceIndex];
  57. }
  58. void purchaseVoice (int voiceIndex)
  59. {
  60. if (havePricesBeenFetched && isPositiveAndBelow (voiceIndex, voiceProducts.size()))
  61. {
  62. auto& product = voiceProducts.getReference (voiceIndex);
  63. if (! product.isPurchased)
  64. {
  65. product.purchaseInProgress = true;
  66. inAppPurchases.purchaseProduct (product.identifier, false);
  67. }
  68. }
  69. }
  70. StringArray getVoiceNames() const
  71. {
  72. StringArray names;
  73. for (auto& voiceProduct : voiceProducts)
  74. names.add (voiceProduct.humanReadable);
  75. return names;
  76. }
  77. private:
  78. //==============================================================================
  79. void productsInfoReturned (const Array<InAppPurchases::Product>& products) override
  80. {
  81. if (! inAppPurchases.isInAppPurchasesSupported())
  82. {
  83. for (auto idx = 1; idx < voiceProducts.size(); ++idx)
  84. {
  85. auto& voiceProduct = voiceProducts.getReference (idx);
  86. voiceProduct.isPurchased = false;
  87. voiceProduct.priceIsKnown = false;
  88. voiceProduct.purchasePrice = "In-App purcahses unavailable";
  89. }
  90. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  91. "In-app purchase is unavailable!",
  92. "In-App purchases are not available. This either means you are trying "
  93. "to use IAP on a platform that does not support IAP or you haven't setup "
  94. "your app correctly to work with IAP.",
  95. "OK");
  96. }
  97. else
  98. {
  99. for (auto product : products)
  100. {
  101. auto idx = findVoiceIndexFromIdentifier (product.identifier);
  102. if (isPositiveAndBelow (idx, voiceProducts.size()))
  103. {
  104. auto& voiceProduct = voiceProducts.getReference (idx);
  105. voiceProduct.priceIsKnown = true;
  106. voiceProduct.purchasePrice = product.price;
  107. }
  108. }
  109. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  110. "Your credit card will be charged!",
  111. "You are running the sample code for JUCE In-App purchases. "
  112. "Although this is only sample code, it will still CHARGE YOUR CREDIT CARD!",
  113. "Understood!");
  114. }
  115. guiUpdater.triggerAsyncUpdate();
  116. }
  117. void productPurchaseFinished (const PurchaseInfo& info, bool success, const String&) override
  118. {
  119. auto idx = findVoiceIndexFromIdentifier (info.purchase.productId);
  120. if (isPositiveAndBelow (idx, voiceProducts.size()))
  121. {
  122. auto& voiceProduct = voiceProducts.getReference (idx);
  123. voiceProduct.isPurchased = success;
  124. voiceProduct.purchaseInProgress = false;
  125. guiUpdater.triggerAsyncUpdate();
  126. }
  127. }
  128. void purchasesListRestored (const Array<PurchaseInfo>& infos, bool success, const String&) override
  129. {
  130. if (success)
  131. {
  132. for (auto& info : infos)
  133. {
  134. auto idx = findVoiceIndexFromIdentifier (info.purchase.productId);
  135. if (isPositiveAndBelow (idx, voiceProducts.size()))
  136. {
  137. auto& voiceProduct = voiceProducts.getReference (idx);
  138. voiceProduct.isPurchased = true;
  139. }
  140. }
  141. guiUpdater.triggerAsyncUpdate();
  142. }
  143. if (! havePricesBeenFetched)
  144. {
  145. havePricesBeenFetched = true;
  146. StringArray identifiers;
  147. for (auto& voiceProduct : voiceProducts)
  148. identifiers.add (voiceProduct.identifier);
  149. inAppPurchases.getProductsInformation(identifiers);
  150. }
  151. }
  152. //==============================================================================
  153. int findVoiceIndexFromIdentifier (String identifier) const
  154. {
  155. identifier = identifier.toLowerCase();
  156. for (auto i = 0; i < voiceProducts.size(); ++i)
  157. if (String (voiceProducts.getReference (i).identifier) == identifier)
  158. return i;
  159. return -1;
  160. }
  161. //==============================================================================
  162. AsyncUpdater& guiUpdater;
  163. bool havePurchasesBeenRestored = false, havePricesBeenFetched = false;
  164. InAppPurchases inAppPurchases;
  165. Array<VoiceProduct> voiceProducts;
  166. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VoicePurchases)
  167. };