Instant verification #974
29 changed files with 1042 additions and 72 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -60,6 +60,7 @@ buck-out/
|
|||
|
||||
# Other Files
|
||||
app/google-services.json
|
||||
app/twitter.properties
|
||||
*.log
|
||||
.vagrant
|
||||
*.hprof
|
||||
|
|
|
@ -11,7 +11,7 @@ build apk:
|
|||
- apt-get -y update && apt-get -y install build-essential ca-certificates curl git gpg-agent openjdk-8-jdk software-properties-common wget zipalign
|
||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||
- export ANDROID_SDK_ROOT=~/.buildozer/android/platform/android-sdk-23
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||
artifacts:
|
||||
paths:
|
||||
- bin/browser-*-release__arm.apk
|
||||
|
@ -27,8 +27,8 @@ build apk:
|
|||
- yarn
|
||||
- chmod u+x ./release.sh
|
||||
- ./release.sh
|
||||
- cp bin/browser-$BUILD_VERSION-release__arm.apk /dev/null
|
||||
- cp bin/browser-$BUILD_VERSION-release__arm64.apk /dev/null
|
||||
- cp bin/browser-$BUILD_VERSION-release__arm.apk $CI_PROJECT_DIR
|
||||
- cp bin/browser-$BUILD_VERSION-release__arm64.apk $CI_PROJECT_DIR
|
||||
|
||||
deploy build.lbry.io:
|
||||
image: python:stretch
|
||||
|
@ -39,7 +39,7 @@ deploy build.lbry.io:
|
|||
- apt-get -y update && apt-get -y install openjdk-8-jdk
|
||||
- pip install awscli
|
||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
||||
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||
script:
|
||||
|
@ -58,7 +58,7 @@ release apk:
|
|||
- apt-get -y update && apt-get -y install openjdk-8-jdk
|
||||
- pip install awscli githubrelease
|
||||
- chmod u+x $CI_PROJECT_DIR/gradlew
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -q printVersionName --console=plain | tail -1)
|
||||
- export BUILD_VERSION=$($CI_PROJECT_DIR/gradlew -p $CI_PROJECT_DIR -q printVersionName --console=plain | tail -1)
|
||||
- export BUILD_APK_FILENAME__32=browser-$BUILD_VERSION-release__arm.apk
|
||||
- export BUILD_APK_FILENAME__64=browser-$BUILD_VERSION-release__arm64.apk
|
||||
script:
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,2 +1,3 @@
|
|||
lbry-android.keystore:0d958c531870694624cc877ea98ca1c583485f8ebbb3a5acca58b1930c190d65
|
||||
app/google-services.json:896a0bee8294a36d061f10fa926129d8a780528b34d0a2f03113400c4246d67c
|
||||
app/twitter.properties:01212d70712f2041efb5c814bf30ecbf6f72e1ca5179c7647c4f8cbd995dd033
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import com.google.gms.googleservices.GoogleServicesPlugin
|
||||
|
||||
Properties twitterProps = new Properties()
|
||||
try {
|
||||
twitterProps.load(project.file('twitter.properties').newDataInputStream())
|
||||
} catch (Exception ex) {
|
||||
throw new GradleException("Missing twitter.properties.")
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
@ -22,6 +29,10 @@ android {
|
|||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
__32bit {
|
||||
versionCode android.defaultConfig.versionCode * 10 + 1
|
||||
|
@ -38,7 +49,13 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
|
||||
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
|
||||
}
|
||||
release {
|
||||
resValue "string", "TWITTER_CONSUMER_KEY", "\"${twitterProps.getProperty("twitterConsumerKey")}\""
|
||||
resValue "string", "TWITTER_CONSUMER_SECRET", "\"${twitterProps.getProperty("twitterConsumerSecret")}\""
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
@ -51,6 +68,13 @@ task printVersionName {
|
|||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
exclude module: 'httpclient'
|
||||
exclude module: 'commons-logging'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
|
@ -76,6 +100,9 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-analytics:17.4.2'
|
||||
implementation 'com.google.android.gms:play-services-base:17.2.1'
|
||||
implementation 'com.google.firebase:firebase-messaging:20.2.0'
|
||||
implementation 'com.google.oauth-client:google-oauth-client:1.30.4'
|
||||
|
||||
implementation 'com.android.billingclient:billing:3.0.0'
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.11.4'
|
||||
|
|
Binary file not shown.
|
@ -10,6 +10,7 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
|
|
@ -47,6 +47,13 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.ConsumeParams;
|
||||
import com.android.billingclient.api.ConsumeResponseListener;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
|
@ -140,10 +147,13 @@ import io.lbry.browser.model.WalletBalance;
|
|||
import io.lbry.browser.model.WalletSync;
|
||||
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||
import io.lbry.browser.model.lbryinc.Reward;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.claim.ClaimListTask;
|
||||
import io.lbry.browser.tasks.lbryinc.AndroidPurchaseTask;
|
||||
import io.lbry.browser.tasks.lbryinc.ClaimRewardTask;
|
||||
import io.lbry.browser.tasks.lbryinc.FetchRewardsTask;
|
||||
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
|
||||
|
@ -192,6 +202,7 @@ import okhttp3.OkHttpClient;
|
|||
|
||||
public class MainActivity extends AppCompatActivity implements SdkStatusListener {
|
||||
|
||||
static final String SKU_SKIP = "lbryskip";
|
||||
private Map<String, Class> specialRouteFragmentClassMap;
|
||||
@Getter
|
||||
private boolean inPictureInPictureMode;
|
||||
|
@ -213,7 +224,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
public static boolean startingPermissionRequest = false;
|
||||
public static boolean startingSignInFlowActivity = false;
|
||||
|
||||
|
||||
private BillingClient billingClient;
|
||||
@Getter
|
||||
private boolean enteringPIPMode = false;
|
||||
private boolean fullSyncInProgress = false;
|
||||
|
@ -408,6 +419,24 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
// setup the billing client in main activity (to handle cases where the verification purchase flow may have been interrupted)
|
||||
billingClient = BillingClient.newBuilder(this)
|
||||
.setListener(new PurchasesUpdatedListener() {
|
||||
@Override
|
||||
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
|
||||
int responseCode = billingResult.getResponseCode();
|
||||
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
|
||||
{
|
||||
for (Purchase purchase : purchases) {
|
||||
handlePurchase(purchase);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.enablePendingPurchases()
|
||||
.build();
|
||||
establishBillingClientConnection();
|
||||
|
||||
playerNotificationManager = new PlayerNotificationManager(
|
||||
this, LbrynetService.NOTIFICATION_CHANNEL_ID, PLAYBACK_NOTIFICATION_ID, new PlayerNotificationDescriptionAdapter());
|
||||
|
||||
|
@ -1024,6 +1053,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
checkPurchases();
|
||||
enteringPIPMode = false;
|
||||
|
||||
applyNavbarSigninPadding();
|
||||
|
@ -1046,6 +1076,33 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}*/
|
||||
}
|
||||
|
||||
private void checkPurchases() {
|
||||
if (billingClient != null) {
|
||||
Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP);
|
||||
if (result.getPurchasesList() != null) {
|
||||
for (Purchase purchase : result.getPurchasesList()) {
|
||||
handlePurchase(purchase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePurchase(Purchase purchase) {
|
||||
handleBillingPurchase(purchase, billingClient, MainActivity.this, null, new RewardVerifiedHandler() {
|
||||
@Override
|
||||
public void onSuccess(RewardVerified rewardVerified) {
|
||||
if (Lbryio.currentUser != null) {
|
||||
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
// pass
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkPendingOpens() {
|
||||
if (pendingFollowingReload) {
|
||||
loadFollowingContent();
|
||||
|
@ -2536,8 +2593,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED, true);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// nope
|
||||
android.util.Log.e(TAG, String.format("App startup failed: %s", ex.getMessage()), ex);
|
||||
// nopecd
|
||||
Log.e(TAG, String.format("App startup failed: %s", ex.getMessage()), ex);
|
||||
return false;
|
||||
} finally {
|
||||
Helper.closeCloseable(reader);
|
||||
|
@ -3269,6 +3326,53 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
return (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
private void establishBillingClientConnection() {
|
||||
if (billingClient != null) {
|
||||
billingClient.startConnection(new BillingClientStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// no need to do anything here. purchases are always checked server-side
|
||||
checkPurchases();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
establishBillingClientConnection();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleBillingPurchase(
|
||||
Purchase purchase,
|
||||
BillingClient billingClient,
|
||||
Context context,
|
||||
View progressView,
|
||||
RewardVerifiedHandler handler) {
|
||||
String sku = purchase.getSku();
|
||||
if (SKU_SKIP.equalsIgnoreCase(sku)) {
|
||||
// send purchase token for verification
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED
|
||||
/*&& isSignatureValid(purchase)*/) {
|
||||
// consume the purchase
|
||||
String purchaseToken = purchase.getPurchaseToken();
|
||||
ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken).build();
|
||||
billingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
|
||||
@Override
|
||||
public void onConsumeResponse(@NonNull BillingResult billingResult, @NonNull String s) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// send the purchase token to the backend to complete verification
|
||||
AndroidPurchaseTask task = new AndroidPurchaseTask(purchaseToken, progressView, context, handler);
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface BackPressInterceptor {
|
||||
boolean onBackPressed();
|
||||
}
|
||||
|
|
|
@ -7,19 +7,35 @@ import android.content.IntentFilter;
|
|||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingFlowParams;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
import com.android.billingclient.api.SkuDetailsParams;
|
||||
import com.android.billingclient.api.SkuDetailsResponseListener;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.adapter.VerificationPagerAdapter;
|
||||
import io.lbry.browser.listener.SignInListener;
|
||||
import io.lbry.browser.listener.WalletSyncListener;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.model.lbryinc.User;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryAnalytics;
|
||||
|
@ -32,11 +48,59 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
public static final int VERIFICATION_FLOW_REWARDS = 2;
|
||||
public static final int VERIFICATION_FLOW_WALLET = 3;
|
||||
|
||||
private BillingClient billingClient;
|
||||
private BroadcastReceiver sdkReceiver;
|
||||
private String email;
|
||||
private boolean signedIn;
|
||||
private int flow;
|
||||
|
||||
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
|
||||
@Override
|
||||
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
|
||||
int responseCode = billingResult.getResponseCode();
|
||||
if (responseCode == BillingClient.BillingResponseCode.OK && purchases != null)
|
||||
{
|
||||
for (Purchase purchase : purchases) {
|
||||
if (MainActivity.SKU_SKIP.equalsIgnoreCase(purchase.getSku())) {
|
||||
showLoading();
|
||||
MainActivity.handleBillingPurchase(
|
||||
purchase,
|
||||
billingClient,
|
||||
VerificationActivity.this, null, new RewardVerifiedHandler() {
|
||||
@Override
|
||||
public void onSuccess(RewardVerified rewardVerified) {
|
||||
if (Lbryio.currentUser != null) {
|
||||
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
|
||||
}
|
||||
|
||||
if (!rewardVerified.isRewardApproved()) {
|
||||
// show pending purchase message (possible slow card tx)
|
||||
Snackbar.make(findViewById(R.id.verification_pager), R.string.purchase_request_pending, Snackbar.LENGTH_LONG).show();
|
||||
} else {
|
||||
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
setResult(RESULT_OK);
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
showFetchUserError(getString(R.string.purchase_request_failed_error));
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -73,6 +137,12 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
};
|
||||
registerReceiver(sdkReceiver, filter);
|
||||
|
||||
billingClient = BillingClient.newBuilder(this)
|
||||
.setListener(purchasesUpdatedListener)
|
||||
.enablePendingPurchases()
|
||||
.build();
|
||||
establishBillingClientConnection();
|
||||
|
||||
setContentView(R.layout.activity_verification);
|
||||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||
viewPager.setUserInputEnabled(false);
|
||||
|
@ -89,6 +159,24 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
});
|
||||
}
|
||||
|
||||
private void establishBillingClientConnection() {
|
||||
if (billingClient != null) {
|
||||
billingClient.startConnection(new BillingClientStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// no need to do anything here. purchases are always checked server-side
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
establishBillingClientConnection();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
|
||||
|
@ -104,11 +192,13 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
flowHandled = true;
|
||||
} else if (flow == VERIFICATION_FLOW_REWARDS) {
|
||||
User user = Lbryio.currentUser;
|
||||
if (!user.isIdentityVerified()) {
|
||||
// disable phone verification for now
|
||||
/*if (!user.isIdentityVerified()) {
|
||||
// phone number verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||
flowHandled = true;
|
||||
} else if (!user.isRewardApproved()) {
|
||||
} else */
|
||||
if (!user.isRewardApproved()) {
|
||||
// manual verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
flowHandled = true;
|
||||
|
@ -195,10 +285,14 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
ViewPager2 viewPager = findViewById(R.id.verification_pager);
|
||||
// for rewards, (show phone verification if not done, or manual verification if required)
|
||||
if (flow == VERIFICATION_FLOW_REWARDS) {
|
||||
if (!user.isIdentityVerified()) {
|
||||
// skipping phone verification
|
||||
/*if (!user.isIdentityVerified()) {
|
||||
// phone number verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
|
||||
} else if (!user.isRewardApproved()) {
|
||||
} else
|
||||
*/
|
||||
if (!user.isRewardApproved()) {
|
||||
|
||||
// manual verification required
|
||||
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
|
||||
} else {
|
||||
|
@ -289,6 +383,54 @@ public class VerificationActivity extends FragmentActivity implements SignInList
|
|||
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipQueueAction() {
|
||||
if (billingClient != null) {
|
||||
List<String> skuList = new ArrayList<>();
|
||||
skuList.add(MainActivity.SKU_SKIP);
|
||||
|
||||
SkuDetailsParams detailsParams = SkuDetailsParams.newBuilder().
|
||||
setType(BillingClient.SkuType.INAPP).
|
||||
setSkusList(skuList).build();
|
||||
billingClient.querySkuDetailsAsync(detailsParams, new SkuDetailsResponseListener() {
|
||||
@Override
|
||||
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
|
||||
if (list != null && list.size() > 0) {
|
||||
// we only queried one product, so it should be the first item in the list
|
||||
SkuDetails skuDetails = list.get(0);
|
||||
|
||||
// launch the billing flow for skip queue
|
||||
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().
|
||||
setSkuDetails(skuDetails).build();
|
||||
billingClient.launchBillingFlow(VerificationActivity.this, billingFlowParams);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTwitterVerified() {
|
||||
Snackbar.make(findViewById(R.id.verification_pager), R.string.reward_verification_successful, Snackbar.LENGTH_LONG).show();
|
||||
|
||||
setResult(RESULT_OK);
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onManualProgress(boolean progress) {
|
||||
if (progress) {
|
||||
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
|
||||
} else {
|
||||
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Helper.unregisterReceiver(sdkReceiver, this);
|
||||
|
|
|
@ -7,4 +7,7 @@ public interface SignInListener {
|
|||
void onPhoneAdded(String countryCode, String phoneNumber);
|
||||
void onPhoneVerified();
|
||||
void onManualVerifyContinue();
|
||||
void onSkipQueueAction();
|
||||
void onTwitterVerified();
|
||||
void onManualProgress(boolean progress);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.lbry.browser.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TwitterOauth {
|
||||
private String oauthToken;
|
||||
private String oauthTokenSecret;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package io.lbry.browser.model.lbryinc;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RewardVerified {
|
||||
private long userId;
|
||||
private boolean isRewardApproved;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package io.lbry.browser.tasks;
|
||||
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
|
||||
public interface RewardVerifiedHandler {
|
||||
void onSuccess(RewardVerified rewardVerified);
|
||||
void onError(Exception error);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package io.lbry.browser.tasks;
|
||||
|
||||
import io.lbry.browser.model.TwitterOauth;
|
||||
|
||||
public interface TwitterOauthHandler {
|
||||
void onSuccess(TwitterOauth twitterOauth);
|
||||
void onError(Exception error);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package io.lbry.browser.tasks.lbryinc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class AndroidPurchaseTask extends AsyncTask<Void, Void, RewardVerified> {
|
||||
private Context context;
|
||||
private View progressView;
|
||||
private String purchaseToken;
|
||||
private RewardVerifiedHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public AndroidPurchaseTask(String purchaseToken, View progressView, Context context, RewardVerifiedHandler handler) {
|
||||
this.purchaseToken = purchaseToken;
|
||||
this.progressView = progressView;
|
||||
this.context = context;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||
}
|
||||
|
||||
protected RewardVerified doInBackground(Void... params) {
|
||||
try {
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("purchase_token", purchaseToken);
|
||||
|
||||
JSONObject object = (JSONObject) Lbryio.parseResponse(Lbryio.call("verification", "android_purchase", options, context));
|
||||
Type type = new TypeToken<RewardVerified>(){}.getType();
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
return gson.fromJson(object.toString(), type);
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(RewardVerified result) {
|
||||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (result != null) {
|
||||
handler.onSuccess(result);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package io.lbry.browser.tasks.lbryinc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.model.TwitterOauth;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
||||
public class TwitterVerifyTask extends AsyncTask<Void, Void, RewardVerified> {
|
||||
private Context context;
|
||||
private View progressView;
|
||||
private TwitterOauth twitterOauth;
|
||||
private RewardVerifiedHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public TwitterVerifyTask(TwitterOauth twitterOauth, View progressView, Context context, RewardVerifiedHandler handler) {
|
||||
this.twitterOauth = twitterOauth;
|
||||
this.progressView = progressView;
|
||||
this.context = context;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||
}
|
||||
|
||||
protected RewardVerified doInBackground(Void... params) {
|
||||
try {
|
||||
Map<String, String> options = new HashMap<>();
|
||||
options.put("oauth_token", twitterOauth.getOauthToken());
|
||||
options.put("oauth_token_secret", twitterOauth.getOauthTokenSecret());
|
||||
|
||||
JSONObject object = (JSONObject) Lbryio.parseResponse(Lbryio.call("verification", "twitter_verify", options, context));
|
||||
Type type = new TypeToken<RewardVerified>(){}.getType();
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
return gson.fromJson(object.toString(), type);
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(RewardVerified result) {
|
||||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (result != null) {
|
||||
handler.onSuccess(result);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package io.lbry.browser.tasks.verification;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.google.api.client.auth.oauth.OAuthHmacSigner;
|
||||
import com.google.api.client.auth.oauth.OAuthParameters;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
|
||||
import io.lbry.browser.VerificationActivity;
|
||||
import io.lbry.browser.model.TwitterOauth;
|
||||
import io.lbry.browser.tasks.TwitterOauthHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class TwitterAccessTokenTask extends AsyncTask<Void, Void, String> {
|
||||
private static final String ENDPOINT = "https://api.twitter.com/oauth/access_token";
|
||||
|
||||
private Exception error;
|
||||
private String oauthParams;
|
||||
private TwitterOauthHandler handler;
|
||||
|
||||
public TwitterAccessTokenTask(String oauthParams, TwitterOauthHandler handler) {
|
||||
this.oauthParams = oauthParams;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public String doInBackground(Void... params) {
|
||||
try {
|
||||
String url = String.format("%s?%s", ENDPOINT, oauthParams);
|
||||
RequestBody body = RequestBody.create(new byte[0]);
|
||||
Request request = new Request.Builder().url(url).post(body).build();
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder().build();
|
||||
Response response = client.newCall(request).execute();
|
||||
return response.body().string();
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(String response) {
|
||||
if (!Helper.isNullOrEmpty(response)) {
|
||||
String[] pairs = response.split("&");
|
||||
TwitterOauth twitterOauth = new TwitterOauth();
|
||||
for (String pair : pairs) {
|
||||
String[] parts = pair.split("=");
|
||||
if (parts.length != 2) {
|
||||
continue;
|
||||
}
|
||||
String key = parts[0];
|
||||
String value = parts[1];
|
||||
if ("oauth_token".equalsIgnoreCase(key)) {
|
||||
twitterOauth.setOauthToken(value);
|
||||
} else if ("oauth_token_secret".equalsIgnoreCase(key)) {
|
||||
twitterOauth.setOauthTokenSecret(value);
|
||||
}
|
||||
}
|
||||
handler.onSuccess(twitterOauth);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package io.lbry.browser.tasks.verification;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.google.api.client.auth.oauth.OAuthHmacSigner;
|
||||
import com.google.api.client.auth.oauth.OAuthParameters;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import io.lbry.browser.VerificationActivity;
|
||||
import io.lbry.browser.model.TwitterOauth;
|
||||
import io.lbry.browser.tasks.TwitterOauthHandler;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class TwitterRequestTokenTask extends AsyncTask<Void, Void, String> {
|
||||
private static final String ENDPOINT = "https://api.twitter.com/oauth/request_token";
|
||||
|
||||
private String consumerKey;
|
||||
private String consumerSecret;
|
||||
private Exception error;
|
||||
private TwitterOauthHandler handler;
|
||||
|
||||
public TwitterRequestTokenTask(String consumerKey, String consumerSecret, TwitterOauthHandler handler) {
|
||||
this.consumerKey = consumerKey;
|
||||
this.consumerSecret = consumerSecret;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public String doInBackground(Void... params) {
|
||||
try {
|
||||
|
||||
OAuthHmacSigner signer = new OAuthHmacSigner();
|
||||
signer.clientSharedSecret = new String(
|
||||
Base64.decode(consumerSecret, Base64.NO_WRAP), StandardCharsets.UTF_8.name());
|
||||
|
||||
OAuthParameters oauthParams = new OAuthParameters();
|
||||
oauthParams.callback = "https://lbry.tv";
|
||||
oauthParams.consumerKey = new String(
|
||||
Base64.decode(consumerKey, Base64.NO_WRAP), StandardCharsets.UTF_8.name());;
|
||||
oauthParams.signatureMethod = "HMAC-SHA-1";
|
||||
oauthParams.signer = signer;
|
||||
oauthParams.computeNonce();
|
||||
oauthParams.computeTimestamp();
|
||||
oauthParams.computeSignature("POST", new GenericUrl(ENDPOINT));
|
||||
|
||||
RequestBody body = RequestBody.create(new byte[0]);
|
||||
Request request = new Request.Builder().url(ENDPOINT).addHeader(
|
||||
"Authorization", oauthParams.getAuthorizationHeader()).post(body).build();
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder().build();
|
||||
Response response = client.newCall(request).execute();
|
||||
return response.body().string();
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(String response) {
|
||||
if (!Helper.isNullOrEmpty(response)) {
|
||||
String[] pairs = response.split("&");
|
||||
TwitterOauth twitterOauth = new TwitterOauth();
|
||||
for (String pair : pairs) {
|
||||
String[] parts = pair.split("=");
|
||||
if (parts.length != 2) {
|
||||
continue;
|
||||
}
|
||||
String key = parts[0];
|
||||
String value = parts[1];
|
||||
if ("oauth_token".equalsIgnoreCase(key)) {
|
||||
twitterOauth.setOauthToken(value);
|
||||
} else if ("oauth_token_secret".equalsIgnoreCase(key)) {
|
||||
twitterOauth.setOauthTokenSecret(value);
|
||||
}
|
||||
}
|
||||
handler.onSuccess(twitterOauth);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,75 @@
|
|||
package io.lbry.browser.ui.verification;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.listener.SignInListener;
|
||||
import io.lbry.browser.model.TwitterOauth;
|
||||
import io.lbry.browser.model.lbryinc.RewardVerified;
|
||||
import io.lbry.browser.tasks.RewardVerifiedHandler;
|
||||
import io.lbry.browser.tasks.TwitterOauthHandler;
|
||||
import io.lbry.browser.tasks.lbryinc.TwitterVerifyTask;
|
||||
import io.lbry.browser.tasks.verification.TwitterAccessTokenTask;
|
||||
import io.lbry.browser.tasks.verification.TwitterRequestTokenTask;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ManualVerificationFragment extends Fragment {
|
||||
@Setter
|
||||
private SignInListener listener;
|
||||
private PopupWindow popup;
|
||||
private View mainView;
|
||||
private View loadingView;
|
||||
|
||||
private TwitterOauth currentOauth;
|
||||
private boolean twitterOauthInProgress = false;
|
||||
|
||||
private static final double SKIP_QUEUE_PRICE = 4.99;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_verification_manual, container, false);
|
||||
|
||||
Helper.applyHtmlForTextView((TextView) root.findViewById(R.id.verification_manual_discord_verify));
|
||||
mainView = root.findViewById(R.id.verification_manual_main);
|
||||
loadingView = root.findViewById(R.id.verification_manual_loading);
|
||||
|
||||
Context context = getContext();
|
||||
MaterialButton buttonSkipQueue = root.findViewById(R.id.verification_manual_skip_queue);
|
||||
buttonSkipQueue.setText(context.getString(R.string.skip_queue_button_text, String.valueOf(SKIP_QUEUE_PRICE)));
|
||||
|
||||
Helper.applyHtmlForTextView(root.findViewById(R.id.verification_manual_discord_verify));
|
||||
root.findViewById(R.id.verification_manual_twitter_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// start twitter verification
|
||||
if (currentOauth != null) {
|
||||
// Twitter three-legged oauth already completed, verify directly
|
||||
twitterVerify(currentOauth);
|
||||
} else {
|
||||
// show twitter sign-in flow
|
||||
twitterVerificationFlow();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
root.findViewById(R.id.verification_manual_continue_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
@ -31,6 +79,205 @@ public class ManualVerificationFragment extends Fragment {
|
|||
}
|
||||
});
|
||||
|
||||
root.findViewById(R.id.verification_manual_skip_queue).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (listener != null) {
|
||||
listener.onSkipQueueAction();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void twitterVerificationFlow() {
|
||||
twitterOauthInProgress = true;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
showLoading();
|
||||
String consumerKey = getResources().getString(R.string.TWITTER_CONSUMER_KEY);
|
||||
String consumerSecret = getResources().getString(R.string.TWITTER_CONSUMER_SECRET);
|
||||
TwitterRequestTokenTask task = new TwitterRequestTokenTask(consumerKey, consumerSecret, new TwitterOauthHandler() {
|
||||
@Override
|
||||
public void onSuccess(TwitterOauth twitterOauth) {
|
||||
twitterOauthInProgress = false;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
showTwitterAuthenticateWithToken(twitterOauth.getOauthToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
handleFlowError(null);
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public void showLoading() {
|
||||
Helper.setViewVisibility(mainView, View.INVISIBLE);
|
||||
Helper.setViewVisibility(loadingView, View.VISIBLE);
|
||||
}
|
||||
|
||||
public void hideLoading() {
|
||||
Helper.setViewVisibility(mainView, View.VISIBLE);
|
||||
Helper.setViewVisibility(loadingView, View.GONE);
|
||||
}
|
||||
|
||||
private void showTwitterAuthenticateWithToken(String oauthToken) {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
WebView webView = new WebView(context);
|
||||
webView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
webView.loadUrl(String.format("https://api.twitter.com/oauth/authorize?oauth_token=%s", oauthToken));
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
if (url.startsWith("https://lbry.tv") || url.equalsIgnoreCase("https://twitter.com/home") /* Return to Twitter */) {
|
||||
if (url.startsWith("https://lbry.tv") && url.contains("oauth_token") && url.contains("oauth_verifier")) {
|
||||
// finish 3-legged oauth
|
||||
twitterOauthInProgress = true;
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
finishTwitterOauth(url);
|
||||
}
|
||||
|
||||
if (popup != null) {
|
||||
popup.dismiss();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
view.loadUrl(url);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
View popupView = LayoutInflater.from(context).inflate(R.layout.popup_webview, null);
|
||||
((LinearLayout) popupView.findViewById(R.id.popup_webivew_container)).addView(webView);
|
||||
popupView.findViewById(R.id.popup_cancel_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (!twitterOauthInProgress && popup != null) {
|
||||
popup.dismiss();
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
float scale = getResources().getDisplayMetrics().density;
|
||||
popup = new PopupWindow(context);
|
||||
popup.setOnDismissListener(new PopupWindow.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
if (!twitterOauthInProgress) {
|
||||
hideLoading();
|
||||
}
|
||||
popup = null;
|
||||
}
|
||||
});
|
||||
popup.setWidth(Helper.getScaledValue(340, scale));
|
||||
popup.setHeight(Helper.getScaledValue(480, scale));
|
||||
popup.setContentView(popupView);
|
||||
|
||||
View parent = getView();
|
||||
popup.setFocusable(true);
|
||||
popup.showAtLocation(parent, Gravity.CENTER, 0, 0);
|
||||
popup.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void finishTwitterOauth(String callbackUrl) {
|
||||
String params = callbackUrl.substring(callbackUrl.indexOf('?') + 1);
|
||||
TwitterAccessTokenTask task = new TwitterAccessTokenTask(params, new TwitterOauthHandler() {
|
||||
@Override
|
||||
public void onSuccess(TwitterOauth twitterOauth) {
|
||||
// send request to finish verifying
|
||||
currentOauth = twitterOauth;
|
||||
twitterVerify(twitterOauth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
handleFlowError(null);
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void twitterVerify(TwitterOauth twitterOauth) {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
showLoading();
|
||||
twitterOauthInProgress = true;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
|
||||
TwitterVerifyTask task = new TwitterVerifyTask(twitterOauth, null, context, new RewardVerifiedHandler() {
|
||||
@Override
|
||||
public void onSuccess(RewardVerified rewardVerified) {
|
||||
twitterOauthInProgress = false;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
|
||||
if (Lbryio.currentUser != null) {
|
||||
Lbryio.currentUser.setRewardApproved(rewardVerified.isRewardApproved());
|
||||
}
|
||||
if (rewardVerified.isRewardApproved()) {
|
||||
if (listener != null) {
|
||||
listener.onTwitterVerified();
|
||||
}
|
||||
} else {
|
||||
View root = getView();
|
||||
if (root != null) {
|
||||
// reward approved wasn't set to true
|
||||
Snackbar.make(root, getString(R.string.twitter_verification_not_approved), Snackbar.LENGTH_LONG).
|
||||
setTextColor(Color.WHITE).
|
||||
setBackgroundTint(Color.RED).show();
|
||||
}
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
handleFlowError(error != null ? error.getMessage() : null);
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
twitterOauthInProgress = false;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFlowError(String extra) {
|
||||
hideLoading();
|
||||
twitterOauthInProgress = false;
|
||||
if (listener != null) {
|
||||
listener.onManualProgress(twitterOauthInProgress);
|
||||
}
|
||||
showFlowError(extra);
|
||||
}
|
||||
|
||||
private void showFlowError(String extra) {
|
||||
Context context = getContext();
|
||||
View root = getView();
|
||||
if (context != null && root != null) {
|
||||
String message = !Helper.isNullOrEmpty(extra) ?
|
||||
getString(R.string.twitter_account_ineligible, extra) :
|
||||
getString(R.string.twitter_verification_failed);
|
||||
|
||||
Snackbar.make(root, message, Snackbar.LENGTH_LONG).
|
||||
setTextColor(Color.WHITE).
|
||||
setBackgroundTint(Color.RED).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.lbry.browser.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -128,7 +130,7 @@ public final class Lbry {
|
|||
IS_STATUS_PARSED = true;
|
||||
} catch (JSONException | LbryResponseException ex) {
|
||||
// pass
|
||||
android.util.Log.e(TAG, "Could not parse status response.", ex);
|
||||
Log.e(TAG, "Could not parse status response.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ public final class Lbryio {
|
|||
}
|
||||
url = uriBuilder.build().toString();
|
||||
}
|
||||
|
||||
/*if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, String.format("Request Method: %s, Sending request to URL: %s", method, url));
|
||||
}*/
|
||||
|
@ -200,6 +201,7 @@ public final class Lbryio {
|
|||
throw new LbryioResponseException("Unknown API error signature.", response.code());
|
||||
}
|
||||
} catch (JSONException | IOException ex) {
|
||||
|
||||
throw new LbryioResponseException(String.format("Could not parse response: %s", responseString), ex);
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +232,7 @@ public final class Lbryio {
|
|||
}
|
||||
}
|
||||
|
||||
android.util.Log.e(TAG, "Could not retrieve the current user", ex);
|
||||
Log.e(TAG, "Could not retrieve the current user", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -308,7 +310,7 @@ public final class Lbryio {
|
|||
context.sendBroadcast(intent);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
android.util.Log.e(TAG, "Error sending encrypted auth token action broadcast", ex);
|
||||
Log.e(TAG, "Error sending encrypted auth token action broadcast", ex);
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/verification_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/verification_close_button"
|
||||
android:visibility="gone"
|
||||
|
@ -29,10 +34,6 @@
|
|||
android:tint="@color/white" />
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/verification_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<ProgressBar
|
||||
android:id="@+id/verification_loading_progress"
|
||||
android:visibility="gone"
|
||||
|
|
|
@ -4,6 +4,18 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/verification_manual_loading"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/verification_manual_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -11,13 +23,12 @@
|
|||
android:layout_centerVertical="true"
|
||||
android:visibility="visible"
|
||||
android:layout_margin="36dp">
|
||||
|
||||
<TextView
|
||||
android:textSize="28sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/manual_reward_verification"
|
||||
android:text="@string/reward_verification"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<TextView
|
||||
|
@ -26,7 +37,71 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/account_undergo_review"
|
||||
android:text="@string/get_instantly_verified"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:textSize="20sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="36dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/twitter_verification"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<TextView
|
||||
android:textSize="16sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/twitter_verification_desc"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/verification_manual_twitter_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/twitter_verify" />
|
||||
|
||||
<TextView
|
||||
android:textSize="20sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="36dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/skip_queue_verification"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<TextView
|
||||
android:textSize="16sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/skip_queue_verification_desc"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/verification_manual_skip_queue"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/skip_queue_button_text" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:textSize="20sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="36dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/manual_reward_verification"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
<TextView
|
||||
|
@ -34,11 +109,12 @@
|
|||
android:textSize="16sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/request_to_be_verified"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300" />
|
||||
|
||||
<TextView
|
||||
android:textSize="16sp"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -53,8 +129,9 @@
|
|||
android:id="@+id/verification_manual_continue_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/continue_text" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</RelativeLayout>
|
20
app/src/main/res/layout/popup_webview.xml
Normal file
20
app/src/main/res/layout/popup_webview.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="340dp"
|
||||
android:layout_height="480dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/popup_webivew_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@id/popup_cancel_button"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/popup_cancel_button"
|
||||
android:text="@string/cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"/>
|
||||
</RelativeLayout>
|
|
@ -422,8 +422,18 @@
|
|||
<string name="enter_phone_number">Please enter your phone number.</string>
|
||||
<string name="not_interested">Not interested</string>
|
||||
<string name="manual_reward_verification">Manual Reward Verification</string>
|
||||
<string name="reward_verification">Reward Verification</string>
|
||||
<string name="social_media_verification">Social Media Verification</string>
|
||||
<string name="skip_the_queue">Skip the Queue</string>
|
||||
<string name="skip_queue_button_text">Skip for $%1$s</string>
|
||||
<string name="account_undergo_review">This account must undergo review before you can participate in the rewards program. This can take anywhere from several minutes to several days.</string>
|
||||
<string name="request_to_be_verified">If you continue to see this message, please request to be verified on the <a href="https://discordapp.com/invite/Z3bERWA">LBRY Discord server</a>.</string>
|
||||
<string name="get_instantly_verified">You can get instantly verified to be able to participate in the rewards program using your Twitter account or skipping the manual verification queue.</string>
|
||||
<string name="twitter_verification">Twitter Verification</string>
|
||||
<string name="twitter_verification_desc">Get instantly verified using your Twitter account. Your Twitter email address must match the email that you provided and your account should be active.</string>
|
||||
<string name="twitter_verify">Verify with Twitter</string>
|
||||
<string name="skip_queue_verification">Skip the Queue</string>
|
||||
<string name="skip_queue_verification_desc">Skip the manual verification queue by paying a fee in order to start participating in the rewards program immediately.</string>
|
||||
<string name="request_to_be_verified">Please request to be verified on the <a href="https://discordapp.com/invite/Z3bERWA">LBRY Discord server</a>. A manual review can take anywhere from several minutes to several days.</string>
|
||||
<string name="enjoy_free_content">Please enjoy free content in the meantime!</string>
|
||||
<string name="verify_phone_number">Verify Phone Number</string>
|
||||
<string name="enter_phone_verify_code">Please enter the verification code sent to %1$s</string>
|
||||
|
@ -432,6 +442,12 @@
|
|||
<string name="please_enter_valid_phone">Please enter a valid phone number.</string>
|
||||
<string name="please_enter_verification_code">Please enter the verification code sent to your phone number.</string>
|
||||
<string name="fetch_current_user_error">User account could not be retrieved at this time. Please try again later.</string>
|
||||
<string name="purchase_request_pending">Your purchase request is still being processed. Please send an email to support@lbry.com.</string>
|
||||
<string name="purchase_request_failed_error">Your purchase request could not be completed at this time. Please send an email to support@lbry.com.</string>
|
||||
<string name="twitter_account_ineligible">Your Twitter account is not eligible at this time: %1$s</string>
|
||||
<string name="twitter_verification_not_approved">Your account was not approved for the rewards program. Please try again later.</string>
|
||||
<string name="twitter_verification_failed">Twitter verification failed. Please try again later.</string>
|
||||
<string name="reward_verification_successful">You are now eligible to participate in the rewards program!</string>
|
||||
|
||||
<!-- Forms -->
|
||||
<string name="no_added_tags">You have not added any tags yet. Add tags to improve discovery.</string>
|
||||
|
|
BIN
app/twitter.properties.secret
Normal file
BIN
app/twitter.properties.secret
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue