phone number verification and rewards page

This commit is contained in:
Akinwale Ariwodola 2020-05-10 23:11:48 +01:00
parent 2df4d76927
commit bc2e8b7ec0
45 changed files with 2122 additions and 63 deletions

View file

@ -76,6 +76,8 @@ dependencies {
implementation 'com.google.android:flexbox:2.0.1'
implementation 'com.hbb20:ccp:2.3.8'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

View file

@ -81,6 +81,7 @@ import io.lbry.browser.adapter.UrlSuggestionListAdapter;
import io.lbry.browser.data.DatabaseHelper;
import io.lbry.browser.dialog.ContentScopeDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.listener.FetchChannelsListener;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.listener.WalletBalanceListener;
import io.lbry.browser.model.Claim;
@ -90,8 +91,11 @@ import io.lbry.browser.model.Tag;
import io.lbry.browser.model.UrlSuggestion;
import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.model.WalletSync;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.ClaimListResultHandler;
import io.lbry.browser.tasks.ClaimListTask;
import io.lbry.browser.tasks.FetchRewardsTask;
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
import io.lbry.browser.tasks.MergeSubscriptionsTask;
import io.lbry.browser.tasks.ResolveTask;
@ -111,6 +115,7 @@ import io.lbry.browser.ui.following.FollowingFragment;
import io.lbry.browser.ui.search.SearchFragment;
import io.lbry.browser.ui.settings.SettingsFragment;
import io.lbry.browser.ui.allcontent.AllContentFragment;
import io.lbry.browser.ui.wallet.RewardsFragment;
import io.lbry.browser.ui.wallet.WalletFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
@ -125,8 +130,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static SimpleExoPlayer appPlayer;
public static Claim nowPlayingClaim;
public static boolean startingFilePickerActivity = false;
public static boolean startingShareActivity = false;
public static boolean startingFileViewActivity = false;
public static boolean startingSignInFlowActivity = false;
public static boolean mainActive = false;
private boolean enteringPIPMode = false;
@ -152,6 +159,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final int REQUEST_STORAGE_PERMISSION = 1001;
public static final int REQUEST_SIMPLE_SIGN_IN = 2001;
public static final int REQUEST_WALLET_SYNC_SIGN_IN = 2002;
public static final int REQUEST_REWARDS_VERIFY_SIGN_IN = 2003;
public static final int REQUEST_FILE_PICKER = 5001;
@ -180,6 +188,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final String PREFERENCE_KEY_INTERNAL_SKIP_WALLET_ACCOUNT = "io.lbry.browser.preference.internal.WalletSkipAccount";
public static final String PREFERENCE_KEY_INTERNAL_WALLET_SYNC_ENABLED = "io.lbry.browser.preference.internal.WalletSyncEnabled";
public static final String PREFERENCE_KEY_INTERNAL_WALLET_RECEIVE_ADDRESS = "io.lbry.browser.preference.internal.WalletReceiveAddress";
public static final String PREFERENCE_KEY_INTERNAL_REWARDS_NOT_INTERESTED = "io.lbry.browser.preference.internal.RewardsNotInterested";
private final int CHECK_SDK_READY_INTERVAL = 1000;
@ -210,6 +219,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private int selectedMenuItemId = -1;
private List<SdkStatusListener> sdkStatusListeners;
private List<WalletBalanceListener> walletBalanceListeners;
private List<FetchChannelsListener> fetchChannelsListeners;
@Getter
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private boolean walletBalanceUpdateScheduled;
@ -230,6 +240,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
// wallet
NavMenuItem.ID_ITEM_WALLET,
NavMenuItem.ID_ITEM_REWARDS,
NavMenuItem.ID_ITEM_SETTINGS
);
@ -267,6 +280,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
openNavFragments = new HashMap<>();
sdkStatusListeners = new ArrayList<>();
walletBalanceListeners = new ArrayList<>();
fetchChannelsListeners = new ArrayList<>();
sdkStatusListeners.add(this);
@ -379,6 +393,22 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
walletBalanceListeners.remove(listener);
}
public void removeNavFragment(Class fragmentClass, int navItemId) {
String key = buildNavFragmentKey(fragmentClass, navItemId);
if (openNavFragments.containsKey(key)) {
openNavFragments.remove(key);
}
}
public void addFetchChannelsListener(FetchChannelsListener listener) {
if (!fetchChannelsListeners.contains(listener)) {
fetchChannelsListeners.add(listener);
}
}
public void removeFetchChannelsListener(FetchChannelsListener listener) {
fetchChannelsListeners.remove(listener);
}
private void openSelectedMenuItem() {
switch (selectedMenuItemId) {
// TODO: reverse map lookup for class?
@ -399,6 +429,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
case NavMenuItem.ID_ITEM_WALLET:
openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
break;
case NavMenuItem.ID_ITEM_REWARDS:
openFragment(RewardsFragment.class, true, NavMenuItem.ID_ITEM_REWARDS);
break;
case NavMenuItem.ID_ITEM_SETTINGS:
openFragment(SettingsFragment.class, true, NavMenuItem.ID_ITEM_SETTINGS);
@ -567,6 +600,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
// check (and start) the LBRY SDK service
serviceRunning = isServiceRunning(this, LbrynetService.class);
if (!serviceRunning) {
Lbry.SDK_READY = false;
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
}
checkSdkReady();
@ -682,11 +716,14 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
urlSuggestionList.setAdapter(urlSuggestionListAdapter);
}
private void clearWunderbarFocus(View view) {
public void clearWunderbarFocus(View view) {
findViewById(R.id.wunderbar).clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
public View getWunderbar() {
return findViewById(R.id.wunderbar);
}
private void launchSearch(String text) {
Fragment currentFragment = getCurrentFragment();
@ -944,6 +981,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
scheduleWalletBalanceUpdate();
scheduleWalletSyncTask();
fetchChannels();
initFloatingWalletBalance();
}
@ -955,13 +993,18 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
private void initFloatingWalletBalance() {
findViewById(R.id.floating_balance_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
}
});
findViewById(R.id.floating_reward_container).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
openFragment(RewardsFragment.class, true, NavMenuItem.ID_ITEM_REWARDS);
}
});
}
private void updateFloatingWalletBalance() {
@ -1278,6 +1321,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
startActivityForResult(intent, REQUEST_WALLET_SYNC_SIGN_IN);
}
public void rewardsSignIn() {
Intent intent = new Intent(this, VerificationActivity.class);
intent.putExtra("flow", VerificationActivity.VERIFICATION_FLOW_REWARDS);
startActivityForResult(intent, REQUEST_REWARDS_VERIFY_SIGN_IN);
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
@ -1309,6 +1358,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_FILE_PICKER) {
startingFilePickerActivity = false;
ChannelFormFragment channelFormFragment = null;
//PublishFormFragment publishFormFragment = null;
for (Fragment fragment : openNavFragments.values()) {
@ -1326,7 +1376,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
} else {
if (channelFormFragment != null) {
channelFormFragment.onFilePicked(null);
channelFormFragment.onFilePickerCancelled();
}
}
} else if (requestCode == REQUEST_SIMPLE_SIGN_IN || requestCode == REQUEST_WALLET_SYNC_SIGN_IN) {
@ -1476,6 +1526,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
loadLastFragment();
showSignedInUser();
fetchRewards();
checkUrlIntent(getIntent());
appStarted = true;
@ -1483,6 +1534,30 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void fetchRewards() {
FetchRewardsTask task = new FetchRewardsTask(null, new FetchRewardsTask.FetchRewardsHandler() {
@Override
public void onSuccess(List<Reward> rewards) {
Lbryio.updateRewardsLists(rewards);
for (Fragment fragment : openNavFragments.values()) {
if (fragment instanceof RewardsFragment) {
((RewardsFragment) fragment).updateUnclaimedRewardsValue();
}
}
if (Lbryio.totalUnclaimedRewardAmount > 0) {
((TextView) findViewById(R.id.floating_reward_value)).setText(Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
findViewById(R.id.floating_reward_container).setVisibility(View.VISIBLE);
}
}
@Override
public void onError(Exception error) {
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void checkUrlIntent(Intent intent) {
if (intent != null) {
Uri data = intent.getData();
@ -1555,7 +1630,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
appPlayer != null &&
FileViewActivity.instance == null &&
!startingFileViewActivity) {
!startingFileViewActivity &&
!startingFilePickerActivity &&
!startingSignInFlowActivity) {
enteringPIPMode = true;
getSupportActionBar().hide();
@ -1784,6 +1861,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public void showSearchBar() {
findViewById(R.id.wunderbar_container).setVisibility(View.VISIBLE);
clearWunderbarFocus(findViewById(R.id.wunderbar));
}
@Override
@ -1861,6 +1939,24 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
}
public void fetchChannels() {
ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, null, new ClaimListResultHandler() {
@Override
public void onSuccess(List<Claim> claims) {
Lbry.ownChannels = new ArrayList<>(claims);
for (FetchChannelsListener listener : fetchChannelsListeners) {
listener.onChannelsFetched(claims);
}
}
@Override
public void onError(Exception error) {
// pass
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void checkSyncedWallet() {
String password = Utils.getSecureValue(SECURE_VALUE_KEY_SAVED_PASSWORD, this, Lbry.KEYSTORE);
// Just check if the current user has a synced wallet, no need to do anything else here

View file

@ -1,6 +1,8 @@
package io.lbry.browser;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
@ -11,13 +13,22 @@ import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.VerificationPagerAdapter;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.User;
import io.lbry.browser.tasks.ClaimListResultHandler;
import io.lbry.browser.tasks.ClaimListTask;
import io.lbry.browser.tasks.FetchCurrentUserTask;
import io.lbry.browser.ui.channel.ChannelManagerFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.Lbryio;
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
@ -59,10 +70,6 @@ public class VerificationActivity extends FragmentActivity implements SignInList
viewPager.setSaveEnabled(false);
viewPager.setAdapter(new VerificationPagerAdapter(this));
if (Lbryio.isSignedIn() && flow == VERIFICATION_FLOW_WALLET) {
viewPager.setCurrentItem(1);
}
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
findViewById(R.id.verification_close_button).setOnClickListener(new View.OnClickListener() {
@Override
@ -73,6 +80,51 @@ public class VerificationActivity extends FragmentActivity implements SignInList
});
}
public void onResume() {
super.onResume();
checkFlow();
}
public void checkFlow() {
ViewPager2 viewPager = findViewById(R.id.verification_pager);
if (Lbryio.isSignedIn()) {
boolean flowHandled = false;
if (flow == VERIFICATION_FLOW_WALLET) {
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_WALLET, false);
flowHandled = true;
} else if (flow == VERIFICATION_FLOW_REWARDS) {
User user = Lbryio.currentUser;
if (!user.isIdentityVerified()) {
// phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
flowHandled = true;
} else if (!user.isRewardApproved()) {
// manual verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
flowHandled = true;
}
}
if (!flowHandled) {
// user has already been verified and or reward approved
setResult(RESULT_CANCELED);
finish();
return;
}
}
}
public void showLoading() {
findViewById(R.id.verification_loading_progress).setVisibility(View.VISIBLE);
findViewById(R.id.verification_pager).setVisibility(View.INVISIBLE);
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
}
public void hideLoading() {
findViewById(R.id.verification_loading_progress).setVisibility(View.GONE);
findViewById(R.id.verification_pager).setVisibility(View.VISIBLE);
}
@Override
public void onBackPressed() {
// ignore back press
@ -96,6 +148,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
resultIntent.putExtra("email", email);
// only sign in required, don't do anything else
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) {
@ -106,29 +159,94 @@ public class VerificationActivity extends FragmentActivity implements SignInList
@Override
public void onError(Exception error) {
setResult(RESULT_CANCELED);
finish();
showFetchUserError(error.getMessage());
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
// change pager view depending on flow
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) { Lbryio.currentUser = user; }
public void onSuccess(User user) {
hideLoading();
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
Lbryio.currentUser = user;
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()) {
// phone number verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_PHONE, false);
} else if (!user.isRewardApproved()) {
// manual verification required
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
} else {
// fully verified
setResult(RESULT_OK);
finish();
}
} else if (flow == VERIFICATION_FLOW_WALLET) {
// for wallet sync, if password unlock is required, show password entry page
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_WALLET, false);
}
}
@Override
public void onError(Exception error) { }
public void onError(Exception error) {
showFetchUserError(error.getMessage());
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
ViewPager2 viewPager = findViewById(R.id.verification_pager);
// for rewards, (show phone verification if not done, or manual verification if required)
// for wallet sync, if password unlock is required, show password entry page
viewPager.setCurrentItem(1);
}
}
@Override
public void onPhoneAdded(String countryCode, String phoneNumber) {
}
@Override
public void onPhoneVerified() {
showLoading();
FetchCurrentUserTask task = new FetchCurrentUserTask(new FetchCurrentUserTask.FetchUserTaskHandler() {
@Override
public void onSuccess(User user) {
Lbryio.currentUser = user;
if (user.isIdentityVerified() && user.isRewardApproved()) {
// verified for rewards
setResult(RESULT_OK);
finish();
return;
}
// show manual verification page if the user is still not reward approved
ViewPager2 viewPager = findViewById(R.id.verification_pager);
viewPager.setCurrentItem(VerificationPagerAdapter.PAGE_VERIFICATION_MANUAL, false);
hideLoading();
}
@Override
public void onError(Exception error) {
showFetchUserError(error.getMessage());
hideLoading();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void showFetchUserError(String message) {
Snackbar.make(findViewById(R.id.verification_pager), message, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
}
@Override
public void onManualVerifyContinue() {
setResult(RESULT_OK);
finish();
}
@Override
public void onWalletSyncProcessing() {
findViewById(R.id.verification_close_button).setVisibility(View.GONE);

View file

@ -7,11 +7,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.snackbar.Snackbar;
import java.math.BigDecimal;
import java.util.ArrayList;
@ -30,6 +32,8 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
private static final int VIEW_TYPE_CHANNEL = 2;
private static final int VIEW_TYPE_FEATURED = 3; // featured search result
@Setter
private boolean canEnterSelectionMode;
private Context context;
private List<Claim> items;
private List<Claim> selectedItems;
@ -110,6 +114,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
protected TextView titleView;
protected TextView publisherView;
protected TextView publishTimeView;
protected TextView pendingTextView;
protected View repostInfoView;
protected TextView repostChannelView;
protected View selectedOverlayView;
@ -125,6 +130,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
titleView = v.findViewById(R.id.claim_title);
publisherView = v.findViewById(R.id.claim_publisher);
publishTimeView = v.findViewById(R.id.claim_publish_time);
pendingTextView = v.findViewById(R.id.claim_pending_text);
repostInfoView = v.findViewById(R.id.claim_repost_info);
repostChannelView = v.findViewById(R.id.claim_repost_channel);
selectedOverlayView = v.findViewById(R.id.claim_selected_overlay);
@ -182,12 +188,18 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
bgColor = Helper.generateRandomColorForValue(item.getName());
}
boolean isPending = item.getConfirmations() == 0;
boolean isSelected = isClaimSelected(item);
vh.itemView.setSelected(isSelected);
vh.selectedOverlayView.setVisibility(isSelected ? View.VISIBLE : View.GONE);
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (isPending) {
Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
return;
}
if (inSelectionMode) {
toggleSelectedClaim(item);
} else {
@ -200,6 +212,15 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (!canEnterSelectionMode) {
return false;
}
if (isPending) {
Snackbar.make(vh.itemView, R.string.item_pending_blockchain, Snackbar.LENGTH_LONG).show();
return false;
}
if (!inSelectionMode) {
inSelectionMode = true;
if (selectionModeListener != null) {
@ -220,6 +241,8 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
}
});
vh.publishTimeView.setVisibility(!isPending ? View.VISIBLE : View.GONE);
vh.pendingTextView.setVisibility(isPending ? View.VISIBLE : View.GONE);
vh.repostInfoView.setVisibility(isRepost ? View.VISIBLE : View.GONE);
vh.repostChannelView.setText(isRepost ? original.getSigningChannel().getName() : null);
vh.repostChannelView.setOnClickListener(new View.OnClickListener() {

View file

@ -0,0 +1,216 @@
package io.lbry.browser.adapter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio;
import lombok.Getter;
import lombok.Setter;
public class RewardListAdapter extends RecyclerView.Adapter<RewardListAdapter.ViewHolder> {
public static final int DISPLAY_MODE_ALL = 1;
public static final int DISPLAY_MODE_UNCLAIMED = 2;
private Context context;
@Setter
private List<Reward> all;
private List<Reward> items;
@Setter
private RewardClickListener clickListener;
@Getter
private int displayMode;
public RewardListAdapter(List<Reward> all, Context context) {
this.all = new ArrayList<>(all);
this.items = new ArrayList<>(all);
this.context = context;
this.displayMode = DISPLAY_MODE_ALL;
addCustomReward();
}
public void setRewards(List<Reward> rewards) {
this.all = new ArrayList<>(rewards);
updateItemsForDisplayMode();
notifyDataSetChanged();
}
public void setDisplayMode(int displayMode) {
this.displayMode = displayMode;
updateItemsForDisplayMode();
notifyDataSetChanged();
}
private void updateItemsForDisplayMode() {
if (displayMode == DISPLAY_MODE_ALL) {
items = new ArrayList<>(all);
} else if (displayMode == DISPLAY_MODE_UNCLAIMED) {
items = new ArrayList<>();
for (Reward reward : all) {
if (!reward.isClaimed()) {
items.add(reward);
}
}
}
addCustomReward();
}
private void addCustomReward() {
Reward custom = new Reward();
custom.setCustom(true);
custom.setRewardTitle(context.getString(R.string.custom_reward_title));
custom.setRewardDescription(context.getString(R.string.custom_reward_description));
items.add(custom);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected View iconClaimed;
protected View loading;
protected View upTo;
protected TextView textTitle;
protected TextView textDescription;
protected TextView textLbcValue;
protected TextView textUsdValue;
protected TextView textLinkTransaction;
protected EditText inputCustomCode;
protected MaterialButton buttonClaimCustom;
public ViewHolder(View v) {
super(v);
iconClaimed = v.findViewById(R.id.reward_item_claimed_icon);
upTo = v.findViewById(R.id.reward_item_up_to);
loading = v.findViewById(R.id.reward_item_loading);
textTitle = v.findViewById(R.id.reward_item_title);
textDescription = v.findViewById(R.id.reward_item_description);
textLbcValue = v.findViewById(R.id.reward_item_lbc_value);
textLinkTransaction = v.findViewById(R.id.reward_item_tx_link);
textUsdValue = v.findViewById(R.id.reward_item_usd_value);
inputCustomCode = v.findViewById(R.id.reward_item_custom_code_input);
buttonClaimCustom = v.findViewById(R.id.reward_item_custom_claim_button);
}
}
public int getItemCount() {
return items != null ? items.size() : 0;
}
public void addReward(Reward reward) {
if (!items.contains(reward)) {
items.add(reward);
}
notifyDataSetChanged();
}
public List<Reward> getRewards() {
return new ArrayList<>(items);
}
@Override
public RewardListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item_reward, root, false);
return new RewardListAdapter.ViewHolder(v);
}
@Override
public void onBindViewHolder(RewardListAdapter.ViewHolder vh, int position) {
Reward reward = items.get(position);
String displayAmount = reward.getDisplayAmount();
double rewardAmount = 0;
if (!"?".equals(displayAmount)) {
rewardAmount = Double.valueOf(displayAmount);
}
boolean hasTransaction = !Helper.isNullOrEmpty(reward.getTransactionId());
vh.iconClaimed.setVisibility(reward.isClaimed() ? View.VISIBLE : View.INVISIBLE);
vh.inputCustomCode.setVisibility(reward.isCustom() ? View.VISIBLE : View.GONE);
vh.buttonClaimCustom.setVisibility(reward.isCustom() ? View.VISIBLE : View.GONE);
vh.textTitle.setText(reward.getRewardTitle());
vh.textDescription.setText(reward.getRewardDescription());
vh.upTo.setVisibility(reward.shouldDisplayRange() ? View.VISIBLE : View.INVISIBLE);
vh.textLbcValue.setText(reward.isCustom() ? "?" : Helper.LBC_CURRENCY_FORMAT.format(Helper.parseDouble(reward.getDisplayAmount(), 0)));
vh.textLinkTransaction.setVisibility(hasTransaction ? View.VISIBLE : View.GONE);
vh.textLinkTransaction.setText(hasTransaction ? reward.getTransactionId().substring(0, 7) : null);
vh.textLinkTransaction.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s/%s", Helper.EXPLORER_TX_PREFIX, reward.getTransactionId())));
context.startActivity(intent);
}
}
});
vh.textUsdValue.setText(reward.isCustom() || Lbryio.LBCUSDRate == 0 ? null :
String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(rewardAmount * Lbryio.LBCUSDRate)));
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (reward.isClaimed()) {
return;
}
if (clickListener != null) {
clickListener.onRewardClicked(reward, vh.loading);
}
}
});
vh.inputCustomCode.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String value = charSequence.toString().trim();
vh.buttonClaimCustom.setEnabled(value.length() > 0);
}
@Override
public void afterTextChanged(Editable editable) {
}
});
vh.buttonClaimCustom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String claimCode = Helper.getValue(vh.inputCustomCode.getText());
if (Helper.isNullOrEmpty(claimCode)) {
Snackbar.make(view, R.string.please_enter_claim_code, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
return;
}
if (clickListener != null) {
clickListener.onCustomClaimButtonClicked(claimCode, vh.inputCustomCode, vh.buttonClaimCustom, vh.loading);
}
}
});
}
public interface RewardClickListener {
void onRewardClicked(Reward reward, View loadingView);
void onCustomClaimButtonClicked(String code, EditText inputCustomCode, MaterialButton buttonClaim, View loadingView);
}
}

View file

@ -23,7 +23,6 @@ import lombok.Setter;
public class TransactionListAdapter extends RecyclerView.Adapter<TransactionListAdapter.ViewHolder> {
private static final String EXPLORER_TX_PREFIX = "https://explorer.lbry.com/tx";
private static final DecimalFormat TX_LIST_AMOUNT_FORMAT = new DecimalFormat("#,##0.0000");
private static final SimpleDateFormat TX_LIST_DATE_FORMAT = new SimpleDateFormat("MMM d");
@ -92,7 +91,7 @@ public class TransactionListAdapter extends RecyclerView.Adapter<TransactionList
@Override
public void onClick(View view) {
if (context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s/%s", EXPLORER_TX_PREFIX, item.getTxid())));
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s/%s", Helper.EXPLORER_TX_PREFIX, item.getTxid())));
context.startActivity(intent);
}
}

View file

@ -7,6 +7,8 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.ui.verification.EmailVerificationFragment;
import io.lbry.browser.ui.verification.ManualVerificationFragment;
import io.lbry.browser.ui.verification.PhoneVerificationFragment;
import io.lbry.browser.ui.verification.WalletVerificationFragment;
import lombok.SneakyThrows;
@ -18,6 +20,11 @@ import lombok.SneakyThrows;
* - Manual verification page
*/
public class VerificationPagerAdapter extends FragmentStateAdapter {
public static final int PAGE_VERIFICATION_EMAIL = 0;
public static final int PAGE_VERIFICATION_PHONE = 1;
public static final int PAGE_VERIFICATION_WALLET = 2;
public static final int PAGE_VERIFICATION_MANUAL = 3;
private FragmentActivity activity;
public VerificationPagerAdapter(FragmentActivity activity) {
@ -37,16 +44,28 @@ public class VerificationPagerAdapter extends FragmentStateAdapter {
}
return evFragment;
case 1:
PhoneVerificationFragment pvFragment = PhoneVerificationFragment.class.newInstance();
if (activity instanceof SignInListener) {
pvFragment.setListener((SignInListener) activity);
}
return pvFragment;
case 2:
WalletVerificationFragment wvFragment = WalletVerificationFragment.class.newInstance();
if (activity instanceof WalletSyncListener) {
wvFragment.setListener((WalletSyncListener) activity);
}
return wvFragment;
case 3:
ManualVerificationFragment mvFragment = ManualVerificationFragment.class.newInstance();
if (activity instanceof SignInListener) {
mvFragment.setListener((SignInListener) activity);
}
return mvFragment;
}
}
@Override
public int getItemCount() {
return 2;
return 4;
}
}

View file

@ -0,0 +1,9 @@
package io.lbry.browser.listener;
import java.util.List;
import io.lbry.browser.model.Claim;
public interface FetchChannelsListener {
void onChannelsFetched(List<Claim> channels);
}

View file

@ -4,4 +4,7 @@ public interface SignInListener {
void onEmailAdded(String email);
void onEmailEdit();
void onEmailVerified();
void onPhoneAdded(String countryCode, String phoneNumber);
void onPhoneVerified();
void onManualVerifyContinue();
}

View file

@ -28,6 +28,7 @@ public class Transaction {
private TransactionInfo abandonInfo;
private TransactionInfo claimInfo;
private TransactionInfo supportInfo;
private TransactionInfo updateInfo;
public LbryUri getClaimUrl() {
if (!Helper.isNullOrEmpty(claim) && !Helper.isNullOrEmpty(claimId)) {
@ -77,6 +78,14 @@ public class Transaction {
transaction.setSupportInfo(info);
}
}
if (info == null && jsonObject.has("update_info")) {
JSONArray array = jsonObject.getJSONArray("update_info");
if (array.length() > 0) {
info = TransactionInfo.fromJSONObject(array.getJSONObject(0));
descStringId = info.getClaimName().startsWith("@") ? R.string.channel_update : R.string.publish_update;
transaction.setUpdateInfo(info);
}
}
if (info != null) {
transaction.setClaim(info.getClaimName());
transaction.setClaimId(info.getClaimId());

View file

@ -0,0 +1,69 @@
package io.lbry.browser.model.lbryinc;
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 io.lbry.browser.model.Claim;
import io.lbry.browser.utils.Helper;
import lombok.Data;
@Data
public class Reward {
public static final String TYPE_NEW_DEVELOPER = "new_developer";
public static final String TYPE_NEW_USER = "new_user";
public static final String TYPE_CONFIRM_EMAIL = "email_provided";
public static final String TYPE_FIRST_CHANNEL = "new_channel";
public static final String TYPE_FIRST_STREAM = "first_stream";
public static final String TYPE_MANY_DOWNLOADS = "many_downloads";
public static final String TYPE_FIRST_PUBLISH = "first_publish";
public static final String TYPE_REFERRAL = "referrer";
public static final String TYPE_REFEREE = "referee";
public static final String TYPE_REWARD_CODE = "reward_code";
public static final String TYPE_SUBSCRIPTION = "subscription";
public static final String YOUTUBE_CREATOR = "youtube_creator";
public static final String TYPE_DAILY_VIEW = "daily_view";
public static final String TYPE_NEW_ANDROID = "new_android";
private boolean custom;
private long id;
private String rewardType;
private double rewardAmount;
private String transactionId;
private String createdAt;
private String updatedAt;
private String rewardTitle;
private String rewardDescription;
private String rewardNotification;
private String rewardRange;
public String getDisplayAmount() {
if (shouldDisplayRange()) {
return rewardRange.split("-")[1];
}
if (rewardAmount > 0) {
return String.valueOf(rewardAmount);
}
return "?";
}
public boolean isClaimed() {
return !Helper.isNullOrEmpty(transactionId);
}
public boolean shouldDisplayRange() {
return (!isClaimed() && !Helper.isNullOrEmpty(rewardRange) && rewardRange.indexOf('-') > -1);
}
public static Reward fromJSONObject(JSONObject rewardObject) {
String rewardJson = rewardObject.toString();
Type type = new TypeToken<Reward>(){}.getType();
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
return gson.fromJson(rewardJson, type);
}
}

View file

@ -0,0 +1,86 @@
package io.lbry.browser.tasks;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import io.lbry.browser.R;
import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.Lbryio;
public class ClaimRewardTask extends AsyncTask<Void, Void, String> {
private Context context;
private String type;
private String claimCode;
private View progressView;
private double amountClaimed;
private ClaimRewardHandler handler;
private Exception error;
public ClaimRewardTask(String type, String claimCode, View progressView, Context context, ClaimRewardHandler handler) {
this.type = type;
this.claimCode = claimCode;
this.progressView = progressView;
this.context = context;
this.handler = handler;
}
protected void onPreExecute() {
Helper.setViewVisibility(progressView, View.VISIBLE);
}
public String doInBackground(Void... params) {
String message = null;
try {
// Get a new wallet address for the reward
String address = (String) Lbry.genericApiCall(Lbry.METHOD_ADDRESS_UNUSED);
Map<String, String> options = new HashMap<>();
options.put("reward_type", type);
options.put("wallet_address", address);
if (!Helper.isNullOrEmpty(claimCode)) {
options.put("claim_code", claimCode);
}
JSONObject reward = (JSONObject) Lbryio.parseResponse(
Lbryio.call("reward", "claim", options, Helper.METHOD_POST, null));
amountClaimed = Helper.getJSONDouble("reward_amount", 0, reward);
String defaultMessage = context != null ?
context.getResources().getQuantityString(
R.plurals.claim_reward_message,
amountClaimed == 1 ? 1 : 2,
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed)) : "";
message = Helper.getJSONString("reward_notification", defaultMessage, reward);
} catch (ApiCallException | LbryioRequestException | LbryioResponseException ex) {
error = ex;
}
return message;
}
protected void onPostExecute(String message) {
Helper.setViewVisibility(progressView, View.INVISIBLE);
if (handler != null) {
if (message != null) {
handler.onSuccess(amountClaimed, message);
} else {
handler.onError(error);
}
}
}
public interface ClaimRewardHandler {
void onSuccess(double amountClaimed, String message);
void onError(Exception error);
}
}

View file

@ -0,0 +1,66 @@
package io.lbry.browser.tasks;
import android.os.AsyncTask;
import android.view.View;
import org.json.JSONArray;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio;
public class FetchRewardsTask extends AsyncTask<Void, Void, List<Reward>> {
private FetchRewardsHandler handler;
private View progressView;
private Exception error;
public FetchRewardsTask(View progressView, FetchRewardsHandler handler) {
this.progressView = progressView;
this.handler = handler;
}
protected void onPreExecute() {
Helper.setViewVisibility(progressView, View.VISIBLE);
}
protected List<Reward> doInBackground(Void... params) {
List<Reward> rewards = null;
try {
Map<String, String> options = new HashMap<>();
options.put("multiple_rewards_per_type", "true");
JSONArray results = (JSONArray) Lbryio.parseResponse(Lbryio.call("reward", "list", null, null));
rewards = new ArrayList<>();
for (int i = 0; i < results.length(); i++) {
rewards.add(Reward.fromJSONObject(results.getJSONObject(i)));
}
} catch (ClassCastException | LbryioRequestException | LbryioResponseException | JSONException ex) {
error = ex;
}
return rewards;
}
protected void onPostExecute(List<Reward> rewards) {
Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) {
if (rewards != null) {
handler.onSuccess(rewards);
} else {
handler.onError(error);
}
}
}
public interface FetchRewardsHandler {
void onSuccess(List<Reward> rewards);
void onError(Exception error);
}
}

View file

@ -3,6 +3,8 @@ package io.lbry.browser.tasks.content;
import android.os.AsyncTask;
import android.view.View;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.math.BigDecimal;
@ -16,15 +18,15 @@ import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Boolean> {
public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Claim> {
private Claim claim;
private BigDecimal deposit;
private boolean update;
private Exception error;
private GenericTaskHandler handler;
private ClaimResultHandler handler;
private View progressView;
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, GenericTaskHandler handler) {
public ChannelCreateUpdateTask(Claim claim, BigDecimal deposit, boolean update, View progressView, ClaimResultHandler handler) {
this.claim = claim;
this.deposit = deposit;
this.update = update;
@ -38,7 +40,7 @@ public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Boolean> {
handler.beforeStart();
}
}
protected Boolean doInBackground(Void... params) {
protected Claim doInBackground(Void... params) {
Map<String, Object> options = new HashMap<>();
if (!update) {
options.put("name", claim.getName());
@ -55,21 +57,43 @@ public class ChannelCreateUpdateTask extends AsyncTask<Void, Void, Boolean> {
options.put("tags", claim.getTags());
options.put("blocking", true);
Claim claimResult = null;
String method = !update ? Lbry.METHOD_CHANNEL_CREATE : Lbry.METHOD_CHANNEL_UPDATE;
try {
Lbry.genericApiCall(method, options);
} catch (ApiCallException | ClassCastException ex) {
JSONObject result = (JSONObject) Lbry.genericApiCall(method, options);
if (result.has("outputs")) {
JSONArray outputs = result.getJSONArray("outputs");
for (int i = 0; i < outputs.length(); i++) {
JSONObject output = outputs.getJSONObject(i);
if (output.has("claim_id") && output.has("claim_op")) {
claimResult = claimFromResult(output);
break;
}
}
}
} catch (ApiCallException | ClassCastException | JSONException ex) {
error = ex;
return false;
}
return true;
return claimResult;
}
protected void onPostExecute(Boolean result) {
private static Claim claimFromResult(JSONObject item) {
// we only need name, permanent_url, txid and nout
Claim claim = new Claim();
claim.setClaimId(Helper.getJSONString("claim_id", null, item));
claim.setName(Helper.getJSONString("name", null, item));
claim.setPermanentUrl(Helper.getJSONString("permanent_url", null, item));
claim.setTxid(Helper.getJSONString("txid", null, item));
claim.setNout(Helper.getJSONInt("nout", -1, item));
return claim;
}
protected void onPostExecute(Claim result) {
Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) {
if (result) {
handler.onSuccess();
if (result != null) {
handler.onSuccess(result);
} else {
handler.onError(error);
}

View file

@ -0,0 +1,9 @@
package io.lbry.browser.tasks.content;
import io.lbry.browser.model.Claim;
public interface ClaimResultHandler {
void beforeStart();
void onSuccess(Claim claimResult);
void onError(Exception error);
}

View file

@ -1,4 +1,35 @@
package io.lbry.browser.tasks.content;
public class LogPublishTask {
import android.os.AsyncTask;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.utils.Lbryio;
import okhttp3.Response;
public class LogPublishTask extends AsyncTask<Void, Void, Void> {
private Claim claimResult;
public LogPublishTask(Claim claimResult) {
this.claimResult = claimResult;
}
protected Void doInBackground(Void... params) {
try {
Map<String, String> options = new HashMap<>();
options.put("uri", claimResult.getPermanentUrl());
options.put("claim_id", claimResult.getClaimId());
options.put("outpoint", String.format("%s:%d", claimResult.getTxid(), claimResult.getNout()));
if (claimResult.getSigningChannel() != null) {
options.put("channel_claim_id", claimResult.getSigningChannel().getClaimId());
}
Lbryio.call("event", "publish", options, null).close();
} catch (LbryioRequestException | LbryioResponseException ex) {
// pass
}
return null;
}
}

View file

@ -0,0 +1,65 @@
package io.lbry.browser.tasks.verification;
import android.os.AsyncTask;
import android.view.View;
import java.util.HashMap;
import java.util.Map;
import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbryio;
public class PhoneNewVerifyTask extends AsyncTask<Void, Void, Boolean> {
private String countryCode;
private String phoneNumber;
private String verificationCode;
private View progressView;
private GenericTaskHandler handler;
private Exception error;
public PhoneNewVerifyTask(String countryCode, String phoneNumber, String verificationCode, View progressView, GenericTaskHandler handler) {
this.countryCode = countryCode;
this.phoneNumber = phoneNumber;
this.verificationCode = verificationCode;
this.progressView = progressView;
this.handler = handler;
}
protected void onPreExecute() {
Helper.setViewVisibility(progressView, View.VISIBLE);
if (handler != null) {
handler.beforeStart();
}
}
protected Boolean doInBackground(Void... params) {
try {
boolean isVerify = !Helper.isNullOrEmpty(verificationCode);
Map<String, String> options = new HashMap<>();
options.put("country_code", countryCode);
options.put("phone_number", phoneNumber.replace(" ", "").replace("-", ""));
if (isVerify) {
options.put("verification_code", verificationCode);
}
String action = isVerify ? "phone_number_confirm" : "phone_number_new";
Lbryio.parseResponse(Lbryio.call("user", action, options, Helper.METHOD_POST, null));
} catch (LbryioResponseException | LbryioRequestException ex) {
error = ex;
return false;
}
return true;
}
protected void onPostExecute(Boolean result) {
Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) {
if (result) {
handler.onSuccess();
} else {
handler.onError(error);
}
}
}
}

View file

@ -0,0 +1,4 @@
package io.lbry.browser.tasks.verification;
public class PhoneResendTask {
}

View file

@ -32,17 +32,21 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import io.lbry.browser.BuildConfig;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.adapter.TagListAdapter;
import io.lbry.browser.listener.WalletBalanceListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.model.Tag;
import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.UpdateSuggestedTagsTask;
import io.lbry.browser.tasks.UploadImageTask;
import io.lbry.browser.tasks.content.ChannelCreateUpdateTask;
import io.lbry.browser.tasks.content.ClaimResultHandler;
import io.lbry.browser.tasks.content.LogPublishTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
@ -63,6 +67,7 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
private TextView linkShowOptional;
private MaterialButton buttonSave;
private View inlineBalanceContainer;
private TextView inlineBalanceValue;
private View uploadProgress;
private View containerOptionalFields;
@ -120,6 +125,7 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
iconContainer = root.findViewById(R.id.channel_form_icon_container);
imageCover = root.findViewById(R.id.channel_form_cover_image);
imageThumbnail = root.findViewById(R.id.channel_form_thumbnail);
inlineBalanceContainer = root.findViewById(R.id.channel_form_inline_balance_container);
inlineBalanceValue = root.findViewById(R.id.channel_form_inline_balance_value);
uploadProgress = root.findViewById(R.id.channel_form_upload_progress);
channelSaveProgress = root.findViewById(R.id.channel_form_save_progress);
@ -146,6 +152,12 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
buttonSave = root.findViewById(R.id.channel_form_save_button);
inputDeposit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
Helper.setViewVisibility(inlineBalanceContainer, hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});
linkShowOptional.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -161,6 +173,8 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
linkCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clearInputFocus();
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).onBackPressed();
@ -295,15 +309,22 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
return;
}
ChannelCreateUpdateTask task = new ChannelCreateUpdateTask(claim, new BigDecimal(depositString), editMode, channelSaveProgress, new GenericTaskHandler() {
ChannelCreateUpdateTask task = new ChannelCreateUpdateTask(claim, new BigDecimal(depositString), editMode, channelSaveProgress, new ClaimResultHandler() {
@Override
public void beforeStart() {
preSave();
}
@Override
public void onSuccess() {
public void onSuccess(Claim claimResult) {
postSave();
// Run the logPublish task
if (!BuildConfig.DEBUG) {
LogPublishTask logPublish = new LogPublishTask(claimResult);
logPublish.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
@ -354,13 +375,18 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
private void launchFilePicker() {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity.startingFilePickerActivity = true;
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("image/*");
((MainActivity) context).startActivityForResult(
Intent.createChooser(intent, getString(coverFilePickerActive ? R.string.select_cover : R.string.select_thumbnail)),
MainActivity.REQUEST_FILE_PICKER);
}
}
public void onFilePickerCancelled() {
coverFilePickerActive = false;
thumbnailFilePickerActive = false;
}
public void onFilePicked(String filePath) {
@ -455,6 +481,12 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
}
}
@Override
public void onPause() {
clearInputFocus();
super.onPause();
}
@Override
public void onStop() {
Context context = getContext();
@ -463,6 +495,9 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
activity.removeWalletBalanceListener(this);
activity.restoreToggle();
activity.showFloatingWalletBalance();
if (!MainActivity.startingFilePickerActivity) {
activity.removeNavFragment(ChannelFormFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
}
}
super.onStop();
}
@ -472,6 +507,16 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
checkParams();
updateFieldsFromCurrentClaim();
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
if (editMode) {
ActionBar actionBar = activity.getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.edit_channel);
}
}
}
String filterText = Helper.getValue(inputTagFilter.getText());
updateSuggestedTags(filterText, SUGGESTED_LIMIT, true);
}
@ -583,9 +628,22 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
Helper.setViewVisibility(linkShowOptional, View.VISIBLE);
Helper.setViewEnabled(linkCancel, true);
Helper.setViewEnabled(buttonSave, true);
clearInputFocus();
saveInProgress = false;
}
public void clearInputFocus() {
inputChannelName.clearFocus();
inputDeposit.clearFocus();
inputWebsite.clearFocus();
inputEmail.clearFocus();
inputDescription.clearFocus();
inputTitle.clearFocus();
inputTagFilter.clearFocus();
}
@Override
public void onTagClicked(Tag tag, int customizeMode) {
if (customizeMode == TagListAdapter.CUSTOMIZE_MODE_ADD) {

View file

@ -32,6 +32,8 @@ import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.dialog.SendTipDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.listener.FetchChannelsListener;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.ChannelSubscribeTask;
@ -46,7 +48,7 @@ import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import lombok.SneakyThrows;
public class ChannelFragment extends BaseFragment {
public class ChannelFragment extends BaseFragment implements FetchChannelsListener {
private Claim claim;
private boolean subscribing;
private String url;
@ -62,6 +64,8 @@ public class ChannelFragment extends BaseFragment {
private TabLayout tabLayout;
private ViewPager2 tabPager;
private View buttonEdit;
private View buttonDelete;
private View buttonShare;
private View buttonTip;
private View buttonFollowUnfollow;
@ -81,6 +85,8 @@ public class ChannelFragment extends BaseFragment {
textTitle = root.findViewById(R.id.channel_view_title);
textFollowerCount = root.findViewById(R.id.channel_view_follower_count);
buttonEdit = root.findViewById(R.id.channel_view_edit);
buttonDelete = root.findViewById(R.id.channel_view_delete);
buttonShare = root.findViewById(R.id.channel_view_share);
buttonTip = root.findViewById(R.id.channel_view_tip);
buttonFollowUnfollow = root.findViewById(R.id.channel_view_follow_unfollow);
@ -90,6 +96,27 @@ public class ChannelFragment extends BaseFragment {
tabLayout = root.findViewById(R.id.channel_view_tabs);
tabPager.setSaveEnabled(false);
buttonEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (claim != null) {
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).openChannelForm(claim);
}
}
}
});
buttonDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (claim != null) {
// show confirmation?
// delete claim task and redirect
}
}
});
buttonShare.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -203,12 +230,39 @@ public class ChannelFragment extends BaseFragment {
}
}
public void onChannelsFetched(List<Claim> channels) {
checkOwnChannel();
}
private void checkOwnChannel() {
if (claim != null) {
boolean isOwnChannel = Lbry.ownChannels.contains(claim);
Helper.setViewVisibility(buttonEdit, isOwnChannel ? View.VISIBLE : View.GONE);
Helper.setViewVisibility(buttonDelete, isOwnChannel ? View.VISIBLE : View.GONE);
}
}
public void onResume() {
super.onResume();
Context context = getContext();
Map<String, Object> params = getParams();
String url = params != null && params.containsKey("url") ? (String) params.get("url") : null;
Helper.setWunderbarValue(url, getContext());
Helper.setWunderbarValue(url, context);
if (context instanceof MainActivity) {
((MainActivity) context).addFetchChannelsListener(this);
}
checkParams();
checkOwnChannel();
}
public void onPause() {
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).removeFetchChannelsListener(this);
}
super.onPause();
}
private void checkParams() {
@ -252,7 +306,7 @@ public class ChannelFragment extends BaseFragment {
if (claims.size() > 0) {
claim = claims.get(0);
renderClaim();
// TODO: Load follower count
checkOwnChannel();
} else {
renderNothingAtLocation();
}

View file

@ -57,7 +57,6 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_channel_manager, container, false);
buttonNewChannel = root.findViewById(R.id.channel_manager_create_button);
fabNewChannel = root.findViewById(R.id.channel_manager_fab_new_channel);
buttonNewChannel.setOnClickListener(newChannelClickListener);
@ -149,6 +148,7 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
Context context = getContext();
if (adapter == null) {
adapter = new ClaimListAdapter(claims, context);
adapter.setCanEnterSelectionMode(true);
adapter.setSelectionModeListener(ChannelManagerFragment.this);
adapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
@Override

View file

@ -0,0 +1,36 @@
package io.lbry.browser.ui.verification;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import io.lbry.browser.R;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class ManualVerificationFragment extends Fragment {
@Setter
private SignInListener listener;
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));
root.findViewById(R.id.verification_manual_continue_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onManualVerifyContinue();
}
}
});
return root;
}
}

View file

@ -0,0 +1,165 @@
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.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.Fragment;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
import com.hbb20.CountryCodePicker;
import io.lbry.browser.R;
import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.verification.PhoneNewVerifyTask;
import io.lbry.browser.utils.Helper;
import lombok.Setter;
public class PhoneVerificationFragment extends Fragment {
@Setter
private SignInListener listener;
private View layoutCollect;
private View layoutVerify;
private MaterialButton continueButton;
private MaterialButton verifyButton;
private View editButton;
private TextView textVerifyParagraph;
private CountryCodePicker countryCodePicker;
private EditText inputPhoneNumber;
private EditText inputVerificationCode;
private ProgressBar newLoading;
private ProgressBar verifyLoading;
private String currentCountryCode;
private String currentPhoneNumber;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_verification_phone, container, false);
layoutCollect = root.findViewById(R.id.verification_phone_collect_container);
layoutVerify = root.findViewById(R.id.verification_phone_verify_container);
continueButton = root.findViewById(R.id.verification_phone_continue_button);
verifyButton = root.findViewById(R.id.verification_phone_verify_button);
editButton = root.findViewById(R.id.verification_phone_edit_button);
textVerifyParagraph = root.findViewById(R.id.verification_phone_verify_paragraph);
countryCodePicker = root.findViewById(R.id.verification_phone_country_code);
inputPhoneNumber = root.findViewById(R.id.verification_phone_input);
inputVerificationCode = root.findViewById(R.id.verification_phone_code_input);
newLoading = root.findViewById(R.id.verification_phone_new_progress);
verifyLoading = root.findViewById(R.id.verification_phone_verify_progress);
Context context = getContext();
countryCodePicker.setTypeFace(ResourcesCompat.getFont(context, R.font.inter_light));
countryCodePicker.registerCarrierNumberEditText(inputPhoneNumber);
continueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
currentCountryCode = countryCodePicker.getSelectedCountryCode();
currentPhoneNumber = Helper.getValue(inputPhoneNumber.getText());
if (Helper.isNullOrEmpty(currentPhoneNumber) || !countryCodePicker.isValidFullNumber()) {
Snackbar.make(getView(), R.string.please_enter_valid_phone, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
return;
}
addPhoneNumber();
}
});
verifyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String code = Helper.getValue(inputVerificationCode.getText());
if (Helper.isNullOrEmpty(code)) {
Snackbar.make(getView(), R.string.please_enter_verification_code, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
return;
}
verifyPhoneNumber(code);
}
});
editButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
layoutVerify.setVisibility(View.GONE);
layoutCollect.setVisibility(View.VISIBLE);
}
});
return root;
}
private void addPhoneNumber() {
PhoneNewVerifyTask task = new PhoneNewVerifyTask(currentCountryCode, currentPhoneNumber, null, newLoading, new GenericTaskHandler() {
@Override
public void beforeStart() {
continueButton.setEnabled(false);
continueButton.setVisibility(View.GONE);
}
@Override
public void onSuccess() {
if (listener != null) {
listener.onPhoneAdded(currentCountryCode, currentPhoneNumber);
}
textVerifyParagraph.setText(getString(R.string.enter_phone_verify_code, countryCodePicker.getFullNumberWithPlus()));
layoutCollect.setVisibility(View.GONE);
layoutVerify.setVisibility(View.VISIBLE);
continueButton.setEnabled(true);
continueButton.setVisibility(View.VISIBLE);
}
@Override
public void onError(Exception error) {
Snackbar.make(getView(), error.getMessage(), Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
continueButton.setEnabled(true);
continueButton.setVisibility(View.VISIBLE);
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void verifyPhoneNumber(String verificationCode) {
PhoneNewVerifyTask task = new PhoneNewVerifyTask(currentCountryCode, currentPhoneNumber, verificationCode, verifyLoading, new GenericTaskHandler() {
@Override
public void beforeStart() {
verifyButton.setEnabled(false);
editButton.setEnabled(false);
}
@Override
public void onSuccess() {
if (listener != null) {
listener.onPhoneVerified();
}
verifyButton.setEnabled(true);
editButton.setEnabled(true);
}
@Override
public void onError(Exception error) {
Snackbar.make(getView(), error.getMessage(), Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
verifyButton.setEnabled(true);
editButton.setEnabled(true);
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}

View file

@ -0,0 +1,264 @@
package io.lbry.browser.ui.wallet;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
import java.text.DecimalFormat;
import java.util.List;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.adapter.RewardListAdapter;
import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.tasks.ClaimRewardTask;
import io.lbry.browser.tasks.FetchRewardsTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.Lbryio;
public class RewardsFragment extends BaseFragment implements RewardListAdapter.RewardClickListener, SdkStatusListener {
private boolean rewardClaimInProgress;
private View layoutAccountDriver;
private View layoutSdkInitializing;
private View linkNotInterested;
private TextView textAccountDriverTitle;
private TextView textFreeCreditsWorth;
private TextView textLearnMoreLink;
private MaterialButton buttonGetStarted;
private ProgressBar rewardsLoading;
private RewardListAdapter adapter;
private RecyclerView rewardList;
private TextView linkFilterUnclaimed;
private TextView linkFilterAll;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_rewards, container, false);
layoutAccountDriver = root.findViewById(R.id.rewards_account_driver_container);
layoutSdkInitializing = root.findViewById(R.id.container_sdk_initializing);
linkNotInterested = root.findViewById(R.id.rewards_not_interested_link);
textAccountDriverTitle = root.findViewById(R.id.rewards_account_driver_title);
textFreeCreditsWorth = root.findViewById(R.id.rewards_account_driver_credits_worth);
textLearnMoreLink = root.findViewById(R.id.rewards_account_driver_learn_more);
buttonGetStarted = root.findViewById(R.id.rewards_get_started_button);
linkFilterUnclaimed = root.findViewById(R.id.rewards_filter_link_unclaimed);
linkFilterAll = root.findViewById(R.id.rewards_filter_link_all);
rewardList = root.findViewById(R.id.rewards_list);
rewardsLoading = root.findViewById(R.id.rewards_list_loading);
Context context = getContext();
LinearLayoutManager llm = new LinearLayoutManager(context);
rewardList.setLayoutManager(llm);
adapter = new RewardListAdapter(Lbryio.allRewards, context);
adapter.setClickListener(this);
adapter.setDisplayMode(RewardListAdapter.DISPLAY_MODE_UNCLAIMED);
rewardList.setAdapter(adapter);
initUi();
return root;
}
public void onResume() {
super.onResume();
checkRewardsStatus();
fetchRewards();
if (!Lbry.SDK_READY) {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.addSdkStatusListener(this);
}
} else {
onSdkReady();
}
}
public void onSdkReady() {
Helper.setViewVisibility(layoutSdkInitializing, View.GONE);
}
public void onStart() {
super.onStart();
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.setWunderbarValue(null);
activity.hideFloatingWalletBalance();
}
}
public void onStop() {
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.removeSdkStatusListener(this);
activity.showFloatingWalletBalance();
}
super.onStop();
}
private void fetchRewards() {
Helper.setViewVisibility(rewardList, View.INVISIBLE);
FetchRewardsTask task = new FetchRewardsTask(rewardsLoading, new FetchRewardsTask.FetchRewardsHandler() {
@Override
public void onSuccess(List<Reward> rewards) {
Lbryio.updateRewardsLists(rewards);
updateUnclaimedRewardsValue();
if (adapter == null) {
adapter = new RewardListAdapter(rewards, getContext());
adapter.setClickListener(RewardsFragment.this);
adapter.setDisplayMode(RewardListAdapter.DISPLAY_MODE_UNCLAIMED);
rewardList.setAdapter(adapter);
} else {
adapter.setRewards(rewards);
}
Helper.setViewVisibility(rewardList, View.VISIBLE);
}
@Override
public void onError(Exception error) {
// pass
Helper.setViewVisibility(rewardList, View.VISIBLE);
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void initUi() {
layoutSdkInitializing.setVisibility(Lbry.SDK_READY ? View.GONE : View.VISIBLE);
linkNotInterested.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).onBackPressed();
}
}
});
buttonGetStarted.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).rewardsSignIn();
}
}
});
linkFilterAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
linkFilterUnclaimed.setTypeface(null, Typeface.NORMAL);
linkFilterAll.setTypeface(null, Typeface.BOLD);
adapter.setDisplayMode(RewardListAdapter.DISPLAY_MODE_ALL);
if (adapter.getItemCount() == 1) {
fetchRewards();
}
}
});
linkFilterUnclaimed.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
linkFilterUnclaimed.setTypeface(null, Typeface.BOLD);
linkFilterAll.setTypeface(null, Typeface.NORMAL);
adapter.setDisplayMode(RewardListAdapter.DISPLAY_MODE_UNCLAIMED);
if (adapter.getItemCount() == 1) {
fetchRewards();
}
}
});
updateUnclaimedRewardsValue();
layoutAccountDriver.setVisibility(Lbryio.currentUser != null && Lbryio.currentUser.isRewardApproved() ? View.GONE : View.VISIBLE);
Helper.applyHtmlForTextView(textLearnMoreLink);
}
private void checkRewardsStatus() {
Helper.setViewVisibility(layoutAccountDriver, Lbryio.currentUser != null && Lbryio.currentUser.isRewardApproved() ? View.GONE : View.VISIBLE);
}
public void updateUnclaimedRewardsValue() {
String accountDriverTitle = getResources().getQuantityString(
R.plurals.available_credits,
Lbryio.totalUnclaimedRewardAmount == 1 ? 1 : 2,
Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
double unclaimedRewardAmountUsd = Lbryio.totalUnclaimedRewardAmount * Lbryio.LBCUSDRate;
Helper.setViewText(textAccountDriverTitle, accountDriverTitle);
Helper.setViewText(textFreeCreditsWorth, getString(R.string.free_credits_worth, Helper.USD_CURRENCY_FORMAT.format(unclaimedRewardAmountUsd)));
}
@Override
public void onRewardClicked(Reward reward, View loadingView) {
if (rewardClaimInProgress || reward.isCustom()) {
return;
}
claimReward(reward.getRewardType(), null, null, null, loadingView);
}
@Override
public void onCustomClaimButtonClicked(String code, EditText inputCustomCode, MaterialButton buttonClaim, View loadingView) {
if (rewardClaimInProgress) {
return;
}
claimReward(Reward.TYPE_REWARD_CODE, code, inputCustomCode, buttonClaim, loadingView);
}
private void claimReward(String type, String code, EditText inputClaimCode, MaterialButton buttonClaim, View loadingView) {
rewardClaimInProgress = true;
Helper.setViewEnabled(buttonClaim, false);
Helper.setViewEnabled(inputClaimCode, false);
ClaimRewardTask task = new ClaimRewardTask(type, code, loadingView, getContext(), new ClaimRewardTask.ClaimRewardHandler() {
@Override
public void onSuccess(double amountClaimed, String message) {
if (Helper.isNullOrEmpty(message)) {
message = getResources().getQuantityString(
R.plurals.claim_reward_message,
amountClaimed == 1 ? 1 : 2,
new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed));
}
Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).show();
Helper.setViewEnabled(buttonClaim, true);
Helper.setViewEnabled(inputClaimCode, true);
rewardClaimInProgress = false;
fetchRewards();
}
@Override
public void onError(Exception error) {
Snackbar.make(getView(), error.getMessage(), Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
Helper.setViewEnabled(buttonClaim, true);
Helper.setViewEnabled(inputClaimCode, true);
rewardClaimInProgress = false;
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}

View file

@ -4,9 +4,9 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@ -17,7 +17,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.text.HtmlCompat;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -178,7 +177,7 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
String amountString = Helper.getValue(inputSendAmount.getText());
if (!recipientAddress.matches(LbryUri.REGEX_ADDRESS)) {
Snackbar.make(getView(), R.string.invalid_recipient_address, Snackbar.LENGTH_LONG).
setBackgroundTint(getResources().getColor(R.color.red)).show();
setBackgroundTint(Color.RED).show();
return false;
}
@ -206,11 +205,11 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
private void initUi() {
onWalletBalanceUpdated(Lbry.walletBalance);
applyHtmlForTextView(textConvertCredits);
applyHtmlForTextView(textConvertCreditsBittrex);
applyHtmlForTextView(textWhatSyncMeans);
applyHtmlForTextView(linkManualBackup);
applyHtmlForTextView(linkSyncFAQ);
Helper.applyHtmlForTextView(textConvertCredits);
Helper.applyHtmlForTextView(textConvertCreditsBittrex);
Helper.applyHtmlForTextView(textWhatSyncMeans);
Helper.applyHtmlForTextView(linkManualBackup);
Helper.applyHtmlForTextView(linkSyncFAQ);
Context context = getContext();
LinearLayoutManager llm = new LinearLayoutManager(context);
@ -387,11 +386,6 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
}
}
private static void applyHtmlForTextView(TextView textView) {
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(HtmlCompat.fromHtml(textView.getText().toString(), HtmlCompat.FROM_HTML_MODE_LEGACY));
}
private boolean hasSkippedAccount() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
return sp.getBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_SKIP_WALLET_ACCOUNT, false);
@ -475,24 +469,21 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private static final DecimalFormat LBC_CURRENCY_FORMAT = new DecimalFormat("#,###.##");
private static final DecimalFormat USD_CURRENCY_FORMAT = new DecimalFormat("#,##0.00");
public void onWalletBalanceUpdated(WalletBalance walletBalance) {
double balance = walletBalance.getAvailable().doubleValue();
double usdBalance = balance * Lbryio.LBCUSDRate;
double tipsBalance = walletBalance.getTips().doubleValue();
double tipsUsdBalance = tipsBalance * Lbryio.LBCUSDRate;
Helper.setViewText(textWalletBalance, LBC_CURRENCY_FORMAT.format(balance));
Helper.setViewText(textWalletBalance, Helper.LBC_CURRENCY_FORMAT.format(balance));
Helper.setViewText(textTipsBalance, Helper.shortCurrencyFormat(tipsBalance));
Helper.setViewText(textClaimsBalance, Helper.shortCurrencyFormat(walletBalance.getClaims().doubleValue()));
Helper.setViewText(textSupportsBalance, Helper.shortCurrencyFormat(walletBalance.getSupports().doubleValue()));
Helper.setViewText(textWalletInlineBalance, Helper.shortCurrencyFormat(balance));
if (Lbryio.LBCUSDRate > 0) {
// only update display usd values if the rate is loaded
Helper.setViewText(textWalletBalanceUSD, String.format("≈$%s", USD_CURRENCY_FORMAT.format(usdBalance)));
Helper.setViewText(textTipsBalanceUSD, String.format("≈$%s", USD_CURRENCY_FORMAT.format(tipsUsdBalance)));
Helper.setViewText(textWalletBalanceUSD, String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(usdBalance)));
Helper.setViewText(textTipsBalanceUSD, String.format("≈$%s", Helper.USD_CURRENCY_FORMAT.format(tipsUsdBalance)));
}
}
}

View file

@ -16,10 +16,12 @@ import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.core.text.HtmlCompat;
import org.json.JSONArray;
import org.json.JSONException;
@ -54,6 +56,10 @@ public final class Helper {
public static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
public static final int CONTENT_PAGE_SIZE = 25;
public static final double MIN_DEPOSIT = 0.05;
public static final String LBC_CURRENCY_FORMAT_PATTERN = "#,###.##";
public static final DecimalFormat LBC_CURRENCY_FORMAT = new DecimalFormat(LBC_CURRENCY_FORMAT_PATTERN);
public static final DecimalFormat USD_CURRENCY_FORMAT = new DecimalFormat("#,##0.00");
public static final String EXPLORER_TX_PREFIX = "https://explorer.lbry.com/tx";
public static boolean isNull(String value) {
return value == null;
@ -153,6 +159,14 @@ public final class Helper {
}
}
public static Double parseDouble(Object value, double defaultValue) {
try {
return Double.parseDouble(String.valueOf(value));
} catch (NumberFormatException ex) {
return defaultValue;
}
}
public static String formatDuration(long duration) {
long seconds = duration;
long hours = Double.valueOf(Math.floor(seconds / 3600.0)).longValue();
@ -536,4 +550,9 @@ public final class Helper {
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
public static void applyHtmlForTextView(TextView textView) {
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(HtmlCompat.fromHtml(textView.getText().toString(), HtmlCompat.FROM_HTML_MODE_LEGACY));
}
}

View file

@ -33,6 +33,7 @@ import io.lbry.browser.model.File;
import io.lbry.browser.model.Tag;
import io.lbry.browser.model.Transaction;
import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.User;
import io.lbry.lbrysdk.Utils;
import okhttp3.OkHttpClient;

View file

@ -30,6 +30,7 @@ import io.lbry.browser.exceptions.LbryioRequestException;
import io.lbry.browser.exceptions.LbryioResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.WalletSync;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.model.lbryinc.User;
import io.lbry.lbrysdk.Utils;
@ -57,6 +58,10 @@ public final class Lbryio {
public static String AUTH_TOKEN;
private static boolean generatingAuthToken = false;
public static List<Reward> allRewards = new ArrayList<>();
public static List<Reward> unclaimedRewards = new ArrayList<>();
public static double totalUnclaimedRewardAmount = 0;
public static Response call(String resource, String action, Context context) throws LbryioRequestException, LbryioResponseException {
return call(resource, action, null, Helper.METHOD_GET, context);
}
@ -312,4 +317,20 @@ public final class Lbryio {
public static boolean isFollowing(Claim claim) {
return subscriptions.contains(Subscription.fromClaim(claim));
}
public static void updateRewardsLists(List<Reward> rewards) {
synchronized (lock) {
allRewards.clear();
unclaimedRewards.clear();
totalUnclaimedRewardAmount = 0;
for (int i = 0; i < rewards.size(); i++) {
Reward reward = rewards.get(i);
allRewards.add(reward);
if (!reward.isClaimed()) {
unclaimedRewards.add(reward);
totalUnclaimedRewardAmount += reward.getRewardAmount();
}
}
}
}
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

View file

@ -33,5 +33,14 @@
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"
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true">
<ProgressBar
android:id="@+id/channel_manager_list_big_loading"
android:layout_width="36dp"

View file

@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/pageBackground">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<androidx.cardview.widget.CardView
android:id="@+id/rewards_filter_card"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp">
<TextView
android:id="@+id/rewards_filter_link_unclaimed"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/unclaimed"
android:textStyle="bold" />
<TextView
android:id="@+id/rewards_filter_link_all"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="16dp"
android:layout_toRightOf="@id/rewards_filter_link_unclaimed"
android:fontFamily="@font/inter"
android:text="@string/all"
android:textSize="14sp" />
<ProgressBar
android:id="@+id/rewards_list_loading"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="gone" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rewards_list"
android:clipToPadding="false"
android:layout_below="@id/rewards_filter_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="16dp" />
</RelativeLayout>
<include layout="@layout/container_sdk_initializing" />
<RelativeLayout
android:id="@+id/rewards_account_driver_container"
android:background="@color/lbryGreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/rewards_account_driver_actions"
android:orientation="vertical">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<io.lbry.browser.ui.controls.SolidIconView
android:layout_width="36dp"
android:layout_height="36dp"
android:textSize="24dp"
android:layout_gravity="center_vertical"
android:text="@string/fa_award"
android:textColor="@color/white" />
<TextView
android:id="@+id/rewards_account_driver_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:fontFamily="@font/inter"
android:textSize="24sp"
android:textColor="@color/white" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:textSize="16sp"
android:layout_marginTop="16dp"
android:text="@string/lbry_credits_allow"
android:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:id="@+id/rewards_account_driver_credits_worth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:textSize="16sp"
android:layout_marginTop="16dp"
android:text="@string/free_credits_worth"
android:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:id="@+id/rewards_account_driver_learn_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:textSize="16sp"
android:layout_marginTop="16dp"
android:text="@string/rewards_learn_more"
android:textColor="@color/white"
android:textFontWeight="300" />
</LinearLayout>
<RelativeLayout
android:id="@+id/rewards_account_driver_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<TextView
android:id="@+id/rewards_not_interested_link"
android:background="?attr/selectableItemBackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/not_interested"
android:textColor="@color/white" />
<com.google.android.material.button.MaterialButton
android:id="@+id/rewards_get_started_button"
android:layout_alignParentRight="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/get_started" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
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:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/inter"
android:text="@string/account_undergo_review"
android:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:id="@+id/verification_manual_discord_verify"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
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"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/inter"
android:text="@string/enjoy_free_content"
android:textColor="@color/white"
android:textFontWeight="300" />
<com.google.android.material.button.MaterialButton
android:id="@+id/verification_manual_continue_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/continue_text" />
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/verification_phone_collect_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
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/phone_number"
android:layout_marginBottom="16dp"
android:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/enter_phone_number"
android:textColor="@color/white"
android:textFontWeight="300" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<com.hbb20.CountryCodePicker
android:id="@+id/verification_phone_country_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
app:ccp_arrowColor="@color/white"
app:ccp_countryPreference="US,IN,NG,CH,BR,TH"
app:ccp_defaultNameCode="US"
app:ccp_textSize="20sp"
app:ccpDialog_showTitle="false" />
<EditText
android:id="@+id/verification_phone_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent"
android:paddingTop="2dp"
android:fontFamily="@font/inter"
android:singleLine="true"
android:textSize="20sp"
android:textFontWeight="300" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/verification_phone_continue_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/continue_text" />
<ProgressBar
android:id="@+id/verification_phone_new_progress"
android:visibility="gone"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/verification_phone_verify_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_margin="36dp"
android:visibility="gone">
<TextView
android:textSize="28sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/verify_phone_number"
android:layout_marginBottom="16dp"
android:textColor="@color/white"
android:textFontWeight="300" />
<TextView
android:id="@+id/verification_phone_verify_paragraph"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/enter_phone_verify_code"
android:textColor="@color/white"
android:textFontWeight="300" />
<EditText
android:id="@+id/verification_phone_code_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@android:color/transparent"
android:fontFamily="@font/inter"
android:singleLine="true"
android:hint="@string/code_placeholder"
android:inputType="number"
android:letterSpacing="1.25"
android:textAlignment="center"
android:textSize="48sp"
android:textFontWeight="300" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/verification_phone_verify_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="@string/verify" />
<ProgressBar
android:id="@+id/verification_phone_verify_progress"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_toRightOf="@id/verification_phone_verify_button"
android:layout_marginLeft="16dp"
android:layout_centerVertical="true"
android:visibility="gone" />
<TextView
android:id="@+id/verification_phone_edit_button"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:fontFamily="@font/inter"
android:text="@string/edit"
android:textColor="@color/white"
android:textFontWeight="300" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View file

@ -158,6 +158,16 @@
android:fontFamily="@font/inter"
android:textSize="11sp"
android:textFontWeight="300" />
<TextView
android:id="@+id/claim_pending_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/pending"
android:textSize="11sp"
android:textStyle="italic"
android:textFontWeight="300"
android:visibility="gone" />
<!-- download progress bar -->
</LinearLayout>
</RelativeLayout>

View file

@ -38,6 +38,7 @@
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:fontFamily="@font/inter"
android:textAllCaps="true"
android:textFontWeight="300"
android:text="@string/all" />
</RelativeLayout>

View file

@ -174,6 +174,17 @@
android:textColor="@android:color/white"
android:textSize="11sp"
android:textFontWeight="300" />
<TextView
android:id="@+id/claim_pending_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/pending"
android:textColor="@color/white"
android:textSize="11sp"
android:textStyle="italic"
android:textFontWeight="300"
android:visibility="gone" />
<!-- download progress bar -->
</LinearLayout>

View file

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:orientation="horizontal"
android:weightSum="10">
<RelativeLayout
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/reward_item_claimed_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_centerInParent="true"
android:tint="@color/lbryGreen"
android:src="@drawable/ic_check_circle"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/reward_item_loading"
android:layout_centerInParent="true"
android:layout_width="16dp"
android:layout_height="16dp"
android:visibility="invisible" />
</RelativeLayout>
<LinearLayout
android:layout_weight="7"
android:layout_width="0dp"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/reward_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="@font/inter"
android:singleLine="true"
android:textColor="@color/lbryGreen"
android:textSize="16sp"
android:textFontWeight="300" />
<TextView
android:id="@+id/reward_item_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:textFontWeight="300" />
<TextView
android:id="@+id/reward_item_tx_link"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:fontFamily="@font/inter"
android:textColor="@color/lbryGreen"
android:textFontWeight="300"
android:textSize="12sp"
android:visibility="gone" />
<EditText
android:id="@+id/reward_item_custom_code_input"
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/inter"
android:letterSpacing="1.1"
android:hint="@string/reward_code_placeholder"
android:singleLine="true"
android:textSize="16sp"
android:textFontWeight="300"
android:visibility="gone" />
<com.google.android.material.button.MaterialButton
android:id="@+id/reward_item_custom_claim_button"
android:enabled="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/claim"
android:fontFamily="@font/inter"
android:textFontWeight="300"
android:layout_gravity="end"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/reward_item_up_to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/up_to"
android:fontFamily="@font/inter"
android:textSize="10sp"
android:textFontWeight="300"
android:visibility="invisible" />
<TextView
android:id="@+id/reward_item_lbc_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:fontFamily="@font/inter"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:fontFamily="@font/inter"
android:textSize="12sp"
android:text="@string/lbc"
android:textFontWeight="300" />
<TextView
android:id="@+id/reward_item_usd_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_gravity="center_horizontal"
android:fontFamily="@font/inter"
android:textSize="12sp"
android:textFontWeight="300" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View file

@ -173,7 +173,16 @@
android:fontFamily="@font/inter"
android:textSize="11sp"
android:textFontWeight="300" />
<TextView
android:id="@+id/claim_pending_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:text="@string/pending"
android:textSize="11sp"
android:textStyle="italic"
android:textFontWeight="300"
android:visibility="gone" />
<!-- download progress bar -->
</LinearLayout>
</RelativeLayout>

View file

@ -41,7 +41,7 @@
<string name="select_five_subscriptions">Please select up to 5 creators to continue.</string>
<string name="n_remaining">%1$d remaining...</string>
<string name="done">Done</string>
<string name="all">ALL</string>
<string name="all">All</string>
<string name="discover_channels">Discover new channels</string>
<!-- Claim lists -->
@ -134,6 +134,8 @@
<string name="support">Support</string>
<string name="abandon">Abandon</string>
<string name="channel">Channel</string>
<string name="channel_update">Channel Update</string>
<string name="publish_update">Publish Update</string>
<string name="wallet_sync">Wallet Sync</string>
<string name="sync_status">Sync status</string>
@ -224,6 +226,19 @@
<string name="password">Password</string>
<string name="enable_sync">Enable sync</string>
<string name="wallet_sync_op_failed">The wallet sync operation could not be completed at this time. Please try again later. If this problem persists, please send an email to hello@lbry.com.</string>
<string name="phone_number">Phone Number</string>
<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="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 &lt;a href="https://discordapp.com/invite/Z3bERWA"&gt;LBRY Discord server&lt;/a&gt;.</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>
<string name="code_placeholder">0000</string>
<string name="verify">Verify</string>
<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>
<!-- Forms -->
<string name="no_added_tags">You have not added any tags yet. Add tags to improve discovery.</string>
@ -261,7 +276,8 @@
<string name="deposit_more_than_balance">Deposit cannot be higher than your balance.</string>
<string name="channel_save_failed">The channel save request failed. Please try again.</string>
<string name="channel_save_successful">The channel was successfully saved.</string>
<string name="channel_pending_blockchain">The channel is pending publish on the blockchain. You will be able to access or edit the channel in a few moments.</string>
<string name="item_pending_blockchain">The claim is pending publish on the blockchain. You will be able to access or edit the claim in a few moments.</string>
<string name="pending">Pending</string>
<plurals name="min_deposit_required">
<item quantity="one">A minimum deposit of %1$s credit is required.</item>
<item quantity="other">A minimum deposit of %1$s credits is required.</item>
@ -271,6 +287,27 @@
<item quantity="other">Are you sure you want to delete the selected channels?</item>
</plurals>
<!-- Rewards -->
<string name="lbry_credits_allow">LBRY credits allow you to publish or purchase content.</string>
<string name="free_credits_worth">You can obtain free credits worth $%1$s after you provide an email address.</string>
<string name="rewards_learn_more">&lt;a href="https://lbry.com/faq/earn-credits"&gt;Learn more&lt;/a&gt;.</string>
<string name="get_started">Get started</string>
<string name="reward_code_placeholder">abc123</string>
<string name="claim">Claim</string>
<string name="please_enter_claim_code">Please enter a custom reward code to claim.</string>
<string name="unclaimed">Unclaimed</string>
<string name="custom_reward_title">Custom Code</string>
<string name="up_to">up to</string>
<string name="custom_reward_description">Are you a supermodel or rockstar that received a custom reward code? Claim it here.</string>
<plurals name="claim_reward_message">
<item quantity="one">You have claimed %1$s credit as a reward.</item>
<item quantity="other">You have claimed %1$s credits as a reward.</item>
</plurals>
<plurals name="available_credits">
<item quantity="one">%1$s available credit</item>
<item quantity="other">%1$s available credits</item>
</plurals>
<!-- Font Awesome -->
<string name="fa_gift">&#xf06b;</string>
<string name="fa_lock">&#xf023;</string>

View file

@ -8,7 +8,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.google.gms:google-services:4.2.0'
// NOTE: Do not place your application dependencies here; they belong