From d7396bb04425c9c37e87b4b3f651071ee03d4aaa Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Sat, 13 Jun 2020 16:14:06 +0100
Subject: [PATCH] add MoonPay 'Buy LBC' button (#937)

* add MoonPay 'Buy LBC' button
* tweak button style
* tweak MoonPay parameters
---
 app/build.gradle                              |  1 +
 .../browser/ui/wallet/WalletFragment.java     | 66 +++++++++++++++++++
 .../main/res/layout/card_wallet_balance.xml   | 13 +++-
 app/src/main/res/values/strings.xml           |  4 ++
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/app/build.gradle b/app/build.gradle
index 19e47f47..482876ef 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -69,6 +69,7 @@ dependencies {
     implementation 'androidx.camera:camera-camera2:1.0.0-beta03'
     implementation 'androidx.camera:camera-lifecycle:1.0.0-beta03'
     implementation 'androidx.camera:camera-view:1.0.0-alpha10'
+    implementation 'androidx.browser:browser:1.2.0'
 
     implementation 'com.github.bumptech.glide:glide:4.11.0'
     implementation 'com.squareup.okhttp3:okhttp:4.4.1'
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
index 38245035..c22a4109 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
@@ -6,8 +6,10 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
 import android.graphics.Color;
+import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.util.Base64;
 import android.view.GestureDetector;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -19,6 +21,7 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
+import androidx.browser.customtabs.CustomTabsIntent;
 import androidx.core.content.ContextCompat;
 import androidx.preference.PreferenceManager;
 import androidx.recyclerview.widget.DividerItemDecoration;
@@ -30,12 +33,20 @@ import com.google.android.material.snackbar.Snackbar;
 import com.google.android.material.switchmaterial.SwitchMaterial;
 import com.google.android.material.textfield.TextInputEditText;
 
+import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.util.List;
 import java.util.Locale;
 
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
 import io.lbry.browser.MainActivity;
 import io.lbry.browser.R;
 import io.lbry.browser.adapter.TransactionListAdapter;
@@ -57,6 +68,10 @@ import io.lbry.browser.utils.Lbryio;
 
 public class WalletFragment extends BaseFragment implements SdkStatusListener, WalletBalanceListener {
 
+    private static final String MOONPAY_KEY = "c2tfbGl2ZV9ueVJqVXNDbE5pcnVSdnlCMkJLWW5JcFA5VnA3dWU=";
+    private static final String MOONPAY_URL_FORMAT =
+            "https://buy.moonpay.io?apiKey=pk_live_xNFffrN5NWKy6fu0ggbV8VQIwRieRzy&colorCode=%%232F9176&currencyCode=LBC&showWalletAddressForm=true&walletAddress=%s&externalCustomerId=%s";
+
     private View layoutAccountRecommended;
     private View layoutSdkInitializing;
     private View linkSkipAccount;
@@ -75,6 +90,7 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
     private View inlineBalanceContainer;
     private TextView textWalletInlineBalance;
     private MaterialButton buttonSignUp;
+    private MaterialButton buttonBuyLBC;
     private RecyclerView recentTransactionsList;
     private View linkViewAll;
     private TextView textConvertCredits;
@@ -125,6 +141,7 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
         recentTransactionsList = root.findViewById(R.id.wallet_recent_transactions_list);
         linkViewAll = root.findViewById(R.id.wallet_link_view_all);
         textNoRecentTransactions = root.findViewById(R.id.wallet_no_recent_transactions);
+        buttonBuyLBC = root.findViewById(R.id.wallet_buy_lbc_button);
         textConvertCredits = root.findViewById(R.id.wallet_hint_convert_credits);
         textConvertCreditsBittrex = root.findViewById(R.id.wallet_hint_convert_credits_bittrex);
         textEarnMoreTips = root.findViewById(R.id.wallet_hint_earn_more_tips);
@@ -313,6 +330,13 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
             }
         });
 
+        buttonBuyLBC.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                launchMoonpayFlow();
+            }
+        });
+
         inputSendAddress.setOnFocusChangeListener(new View.OnFocusChangeListener() {
             @Override
             public void onFocusChange(View view, boolean hasFocus) {
@@ -481,6 +505,48 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
         return sp.getBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_SKIP_WALLET_ACCOUNT, false);
     }
 
+    public void launchMoonpayFlow() {
+        Context context = getContext();
+        String receiveAddress = null;
+        if (context != null) {
+            try {
+                SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+                receiveAddress = sp.getString(MainActivity.PREFERENCE_KEY_INTERNAL_WALLET_RECEIVE_ADDRESS, null);
+                if (Helper.isNullOrEmpty(receiveAddress)) {
+                    showError(getString(R.string.receive_address_not_set));
+                    return;
+                }
+
+                long userId = Lbryio.currentUser != null ? Lbryio.currentUser.getId() : 0;
+                String url = String.format(MOONPAY_URL_FORMAT, receiveAddress,
+                        URLEncoder.encode(String.format("android-%d", userId), StandardCharsets.UTF_8.name()));
+                String email = Lbryio.getSignedInEmail();
+                if (!Helper.isNullOrEmpty(email)) {
+                    url = String.format("%s&email=%s", url, URLEncoder.encode(email, StandardCharsets.UTF_8.name()));
+                }
+                // Sign the URL
+                String query = url.substring(url.indexOf("?"));
+                Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
+
+                SecretKeySpec secretKey = new SecretKeySpec(
+                        new String(Base64.decode(MOONPAY_KEY, Base64.NO_WRAP), StandardCharsets.UTF_8.name()).getBytes(), "HmacSHA256");
+                hmacSHA256.init(secretKey);
+                String signature = new String(
+                        Base64.encode(hmacSHA256.doFinal(query.getBytes(StandardCharsets.UTF_8.name())), Base64.NO_WRAP),
+                        StandardCharsets.UTF_8.name());
+                url = String.format("%s&signature=%s", url, URLEncoder.encode(signature, StandardCharsets.UTF_8.name()));
+
+                CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder().setToolbarColor(
+                        ContextCompat.getColor(context, R.color.lbryGreen)
+                );
+                CustomTabsIntent intent = builder.build();
+                intent.launchUrl(context, Uri.parse(url));
+            } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException ex) {
+                showError(getString(R.string.hash_not_supported));
+            }
+        }
+    }
+
     public void onResume() {
         super.onResume();
         Context context = getContext();
diff --git a/app/src/main/res/layout/card_wallet_balance.xml b/app/src/main/res/layout/card_wallet_balance.xml
index 8e07d85f..550f8849 100644
--- a/app/src/main/res/layout/card_wallet_balance.xml
+++ b/app/src/main/res/layout/card_wallet_balance.xml
@@ -69,11 +69,22 @@
                 android:textFontWeight="300" />
         </RelativeLayout>
 
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/wallet_buy_lbc_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fontFamily="@font/inter"
+            android:text="@string/buy_lbc"
+            android:layout_marginTop="8dp"
+            android:layout_marginLeft="12dp"
+            android:layout_marginRight="12dp"
+            android:textSize="16sp" />
+
         <TextView
             android:id="@+id/wallet_hint_convert_credits"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="16dp"
+            android:layout_marginTop="6dp"
             android:layout_marginLeft="16dp"
             android:layout_marginRight="16dp"
             android:fontFamily="@font/inter"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 172c111f..09da5fbf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -334,6 +334,10 @@
     <string name="confirm_unlock_tips">Are you sure you want to unlock all your tips?</string>
     <string name="min_spend_required">Please enter an amount more than 0.0001 credits.</string>
 
+    <string name="buy_lbc">Buy LBC</string>
+    <string name="hash_not_supported">Your device does not support the minimum requirements for securing your purchase request.</string>
+    <string name="receive_address_not_set">You do not have a wallet address set. Please generate a new address and try again.</string>
+
     <plurals name="you_sent_credits">
         <item quantity="one">You sent %1$s credit</item>
         <item quantity="other">You sent %1$s credits</item>