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.

195 lines
6.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 (products.size() != 0)
  82. {
  83. for (auto product : products)
  84. {
  85. auto idx = findVoiceIndexFromIdentifier (product.identifier);
  86. if (isPositiveAndBelow (idx, voiceProducts.size()))
  87. {
  88. auto& voiceProduct = voiceProducts.getReference (idx);
  89. voiceProduct.priceIsKnown = true;
  90. voiceProduct.purchasePrice = product.price;
  91. }
  92. }
  93. }
  94. else if (! inAppPurchases.isInAppPurchasesSupported())
  95. {
  96. for (auto idx = 1; idx < voiceProducts.size(); ++idx)
  97. {
  98. auto& voiceProduct = voiceProducts.getReference (idx);
  99. voiceProduct.isPurchased = false;
  100. voiceProduct.priceIsKnown = false;
  101. voiceProduct.purchasePrice = "In-App purcahses unavailable";
  102. }
  103. }
  104. guiUpdater.triggerAsyncUpdate();
  105. }
  106. void productPurchaseFinished (const PurchaseInfo& info, bool success, const String&) override
  107. {
  108. auto idx = findVoiceIndexFromIdentifier (info.purchase.productId);
  109. if (isPositiveAndBelow (idx, voiceProducts.size()))
  110. {
  111. auto& voiceProduct = voiceProducts.getReference (idx);
  112. voiceProduct.isPurchased = success;
  113. voiceProduct.purchaseInProgress = false;
  114. guiUpdater.triggerAsyncUpdate();
  115. }
  116. }
  117. void purchasesListRestored (const Array<PurchaseInfo>& infos, bool success, const String&) override
  118. {
  119. if (success)
  120. {
  121. for (auto& info : infos)
  122. {
  123. auto idx = findVoiceIndexFromIdentifier (info.purchase.productId);
  124. if (isPositiveAndBelow (idx, voiceProducts.size()))
  125. {
  126. auto& voiceProduct = voiceProducts.getReference (idx);
  127. voiceProduct.isPurchased = true;
  128. }
  129. }
  130. guiUpdater.triggerAsyncUpdate();
  131. }
  132. if (! havePricesBeenFetched)
  133. {
  134. havePricesBeenFetched = true;
  135. StringArray identifiers;
  136. for (auto& voiceProduct : voiceProducts)
  137. identifiers.add (voiceProduct.identifier);
  138. inAppPurchases.getProductsInformation(identifiers);
  139. }
  140. }
  141. //==============================================================================
  142. int findVoiceIndexFromIdentifier (String identifier) const
  143. {
  144. identifier = identifier.toLowerCase();
  145. for (auto i = 0; i < voiceProducts.size(); ++i)
  146. if (String (voiceProducts.getReference (i).identifier) == identifier)
  147. return i;
  148. return -1;
  149. }
  150. //==============================================================================
  151. AsyncUpdater& guiUpdater;
  152. bool havePurchasesBeenRestored = false, havePricesBeenFetched = false;
  153. InAppPurchases inAppPurchases;
  154. Array<VoiceProduct> voiceProducts;
  155. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VoicePurchases)
  156. };