Fix first time wallet sync. add Discover dialog to Following page.

This commit is contained in:
Akinwale Ariwodola 2020-04-29 01:35:51 +01:00
parent 10175470de
commit 59584c1be7
10 changed files with 316 additions and 69 deletions

View file

@ -43,7 +43,7 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
public static class ViewHolder extends RecyclerView.ViewHolder {
protected View mediaContainer;
protected View alphaContainer;
protected TextView allTextView;
protected View allView;
protected ImageView thumbnailView;
protected TextView alphaView;
protected TextView titleView;
@ -54,7 +54,7 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
alphaView = v.findViewById(R.id.channel_filter_alpha_view);
thumbnailView = v.findViewById(R.id.channel_filter_thumbnail);
titleView = v.findViewById(R.id.channel_filter_title);
allTextView = v.findViewById(R.id.channel_filter_all);
allView = v.findViewById(R.id.channel_filter_all_container);
}
}
@ -85,8 +85,8 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
public void onBindViewHolder(ChannelFilterListAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position);
vh.alphaView.setVisibility(claim.isPlaceholder() ? View.GONE : View.VISIBLE);
vh.titleView.setVisibility(claim.isPlaceholder() ? View.GONE : View.VISIBLE);
vh.allTextView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
vh.titleView.setVisibility(claim.isPlaceholder() ? View.INVISIBLE : View.VISIBLE);
vh.allView.setVisibility(claim.isPlaceholder() ? View.VISIBLE : View.GONE);
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
String thumbnailUrl = claim.getThumbnailUrl();

View file

@ -35,12 +35,14 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
}
public static class ViewHolder extends RecyclerView.ViewHolder {
protected View noThumbnailView;
protected ImageView thumbnailView;
protected TextView alphaView;
protected TextView titleView;
protected TextView tagView;
public ViewHolder(View v) {
super(v);
noThumbnailView = v.findViewById(R.id.suggested_channel_no_thumbnail);
alphaView = v.findViewById(R.id.suggested_channel_alpha_view);
thumbnailView = v.findViewById(R.id.suggested_channel_thumbnail);
titleView = v.findViewById(R.id.suggested_channel_title);
@ -82,18 +84,18 @@ public class SuggestedChannelGridAdapter extends RecyclerView.Adapter<SuggestedC
@Override
public void onBindViewHolder(SuggestedChannelGridAdapter.ViewHolder vh, int position) {
Claim claim = items.get(position);
String thumbnailUrl = claim.getThumbnailUrl();
int bgColor = Helper.generateRandomColorForValue(claim.getClaimId());
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.INVISIBLE : View.VISIBLE);
vh.alphaView.setText(claim.getName().substring(1, 2));
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
vh.alphaView.setVisibility(View.GONE);
vh.thumbnailView.setVisibility(View.VISIBLE);
Glide.with(context.getApplicationContext()).load(thumbnailUrl).apply(RequestOptions.circleCropTransform()).into(vh.thumbnailView);
} else {
vh.alphaView.setVisibility(View.VISIBLE);
vh.thumbnailView.setVisibility(View.GONE);
}
vh.alphaView.setText(claim.getFirstCharacter());
vh.titleView.setText(Helper.isNullOrEmpty(claim.getTitle()) ? claim.getName() : claim.getTitle());
String firstTag = claim.getFirstTag();

View file

@ -0,0 +1,101 @@
package io.lbry.browser.dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.button.MaterialButton;
import io.lbry.browser.R;
import io.lbry.browser.adapter.SuggestedChannelGridAdapter;
import lombok.Getter;
import lombok.Setter;
public class DiscoverDialogFragment extends BottomSheetDialogFragment {
public static final String TAG = "DiscoverDialog";
@Getter
private SuggestedChannelGridAdapter adapter;
@Setter
private DiscoverDialogListener dialogActionsListener;
public static DiscoverDialogFragment newInstance() {
return new DiscoverDialogFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_discover, container, false);
RecyclerView grid = view.findViewById(R.id.discover_channel_grid);
GridLayoutManager glm = new GridLayoutManager(getContext(), 3);
grid.setLayoutManager(glm);
grid.setAdapter(adapter);
grid.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
GridLayoutManager lm = (GridLayoutManager) recyclerView.getLayoutManager();
if (lm != null) {
int visibleItemCount = lm.getChildCount();
int totalItemCount = lm.getItemCount();
int pastVisibleItems = lm.findFirstVisibleItemPosition();
if (pastVisibleItems + visibleItemCount >= totalItemCount) {
if (dialogActionsListener != null) {
dialogActionsListener.onScrollEndReached();
}
}
}
}
});
MaterialButton doneButton = view.findViewById(R.id.discover_done_button);
doneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
return view;
}
public void setAdapter(SuggestedChannelGridAdapter adapter) {
this.adapter = adapter;
if (getView() != null) {
((RecyclerView) getView().findViewById(R.id.discover_channel_grid)).setAdapter(adapter);
}
}
public void setLoading(boolean loading) {
if (getView() != null) {
getView().findViewById(R.id.discover_loading).setVisibility(loading ? View.VISIBLE : View.GONE);
}
}
@Override
public void onResume() {
super.onResume();
if (dialogActionsListener != null) {
dialogActionsListener.onResume();
}
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (dialogActionsListener != null) {
dialogActionsListener.onCancel();
}
}
public interface DiscoverDialogListener {
void onResume();
void onCancel();
void onScrollEndReached();
}
}

View file

@ -31,6 +31,7 @@ import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.SuggestedChannelGridAdapter;
import io.lbry.browser.dialog.ContentFromDialogFragment;
import io.lbry.browser.dialog.ContentSortDialogFragment;
import io.lbry.browser.dialog.DiscoverDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Subscription;
@ -50,6 +51,8 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
private static final int SUGGESTED_PAGE_SIZE = 45;
private static final int MIN_SUGGESTED_SUBSCRIBE_COUNT = 5;
private DiscoverDialogFragment discoverDialog;
private List<String> excludeChannelIdsForDiscover;
private MaterialButton suggestedDoneButton;
private TextView titleView;
private TextView infoView;
@ -64,11 +67,13 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
private TextView sortLinkText;
private View contentFromLink;
private TextView contentFromLinkText;
private View discoverLink;
private int currentSortBy;
private int currentContentFrom;
private String contentReleaseTime;
private List<String> contentSortOrder;
private boolean contentClaimSearchLoading = false;
private boolean suggestedClaimSearchLoading = false;
private List<Integer> queuedContentPages = new ArrayList<>();
private List<Integer> queuedSuggestedPages = new ArrayList<>();
@ -116,10 +121,33 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
bigContentLoading = root.findViewById(R.id.following_main_progress);
contentLoading = root.findViewById(R.id.following_content_progress);
channelListLoading = root.findViewById(R.id.following_channel_load_progress);
discoverLink = root.findViewById(R.id.following_discover_link);
Context context = getContext();
GridLayoutManager glm = new GridLayoutManager(context, 3);
suggestedChannelGrid.setLayoutManager(glm);
suggestedChannelGrid.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (suggestedClaimSearchLoading) {
return;
}
GridLayoutManager lm = (GridLayoutManager) recyclerView.getLayoutManager();
if (lm != null) {
int visibleItemCount = lm.getChildCount();
int totalItemCount = lm.getItemCount();
int pastVisibleItems = lm.findFirstVisibleItemPosition();
if (pastVisibleItems + visibleItemCount >= totalItemCount) {
if (!suggestedHasReachedEnd) {
// load more
currentSuggestedPage++;
fetchSuggestedChannels();
}
}
}
}
});
LinearLayoutManager cllm = new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false);
horizontalChannelList.setLayoutManager(cllm);
@ -132,7 +160,6 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
if (contentClaimSearchLoading) {
return;
}
LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
if (lm != null) {
int visibleItemCount = lm.getChildCount();
@ -201,6 +228,43 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
}
}
});
discoverLink.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
discoverDialog = DiscoverDialogFragment.newInstance();
excludeChannelIdsForDiscover = channelIds != null ? new ArrayList<>(channelIds) : null;
discoverDialog.setAdapter(suggestedChannelAdapter);
discoverDialog.setDialogActionsListener(new DiscoverDialogFragment.DiscoverDialogListener() {
@Override
public void onScrollEndReached() {
if (suggestedClaimSearchLoading) {
return;
}
currentSuggestedPage++;
fetchSuggestedChannels();
}
@Override
public void onCancel() {
discoverDialog = null;
excludeChannelIdsForDiscover = null;
}
@Override
public void onResume() {
if (suggestedChannelAdapter == null || suggestedChannelAdapter.getItemCount() == 0) {
discoverDialog.setLoading(true);
fetchSuggestedChannels();
}
}
});
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
discoverDialog.show(activity.getSupportFragmentManager(), DiscoverDialogFragment.TAG);
}
}
});
return root;
}
@ -291,7 +355,7 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
null,
null,
null,
null,
excludeChannelIdsForDiscover,
Arrays.asList(Claim.ORDER_BY_EFFECTIVE_AMOUNT),
null,
currentSuggestedPage == 0 ? 1 : currentSuggestedPage,
@ -506,6 +570,50 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
}
}
private void fetchSuggestedChannels() {
suggestedClaimSearchLoading = true;
if (discoverDialog != null) {
discoverDialog.setLoading(true);
}
suggestedChannelClaimSearchTask = new ClaimSearchTask(
buildSuggestedOptions(),
Lbry.LBRY_TV_CONNECTION_STRING,
suggestedChannelAdapter == null || suggestedChannelAdapter.getItemCount() == 0 ? bigContentLoading : contentLoading,
new ClaimSearchTask.ClaimSearchResultHandler() {
@Override
public void onSuccess(List<Claim> claims, boolean hasReachedEnd) {
suggestedHasReachedEnd = hasReachedEnd;
suggestedClaimSearchLoading = false;
if (discoverDialog != null) {
discoverDialog.setLoading(true);
}
if (suggestedChannelAdapter == null) {
suggestedChannelAdapter = new SuggestedChannelGridAdapter(claims, getContext());
suggestedChannelAdapter.setListener(FollowingFragment.this);
if (suggestedChannelGrid != null) {
suggestedChannelGrid.setAdapter(suggestedChannelAdapter);
}
if (discoverDialog != null) {
discoverDialog.setAdapter(suggestedChannelAdapter);
}
} else {
suggestedChannelAdapter.addClaims(claims);
}
}
@Override
public void onError(Exception error) {
suggestedClaimSearchLoading = false;
if (discoverDialog != null) {
discoverDialog.setLoading(false);
}
}
});
suggestedChannelClaimSearchTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
// handler methods
public void onSuccess(List<Subscription> subscriptions) {
if (subscriptions.size() == 0) {
@ -516,30 +624,7 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
loadingSuggested = true;
loadingContent = false;
suggestedChannelClaimSearchTask = new ClaimSearchTask(
buildSuggestedOptions(),
Lbry.LBRY_TV_CONNECTION_STRING,
suggestedChannelAdapter == null ? bigContentLoading : contentLoading,
new ClaimSearchTask.ClaimSearchResultHandler() {
@Override
public void onSuccess(List<Claim> claims, boolean hasReachedEnd) {
if (suggestedChannelAdapter == null) {
suggestedChannelAdapter = new SuggestedChannelGridAdapter(claims, getContext());
suggestedChannelAdapter.setListener(FollowingFragment.this);
if (suggestedChannelGrid != null) {
suggestedChannelGrid.setAdapter(suggestedChannelAdapter);
}
} else {
suggestedChannelAdapter.addClaims(claims);
}
}
@Override
public void onError(Exception error) {
}
});
suggestedChannelClaimSearchTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
fetchSuggestedChannels();
showSuggestedChannels();
} else {
Lbryio.cacheSubscriptions = subscriptions;
@ -563,6 +648,10 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, false, null);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
updateSuggestedDoneButtonText();
if (discoverDialog != null) {
fetchSubscriptions();
}
}
public void onChannelItemDeselected(Claim claim) {
// unsubscribe
@ -574,6 +663,10 @@ public class FollowingFragment extends BaseFragment implements FetchSubscription
ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, true, null);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
updateSuggestedDoneButtonText();
if (discoverDialog != null) {
fetchSubscriptions();
}
}
public void onChannelSelectionCleared() {

View file

@ -95,6 +95,7 @@ public class WalletVerificationFragment extends Fragment {
@Override
public void onSyncGetSuccess(WalletSync walletSync) {
currentWalletSync = walletSync;
Lbryio.lastRemoteHash = walletSync.getHash();
processExistingWallet(walletSync);
}
@ -124,8 +125,8 @@ public class WalletVerificationFragment extends Fragment {
public void onSyncApplySuccess(String hash, String data) {
// check if local and remote hash are different, and then run sync set
Utils.setSecureValue(MainActivity.SECURE_VALUE_KEY_SAVED_PASSWORD, "", getContext(), Lbry.KEYSTORE);
if (!hash.equalsIgnoreCase(Lbryio.lastRemoteHash)) {
setSyncAfterApply(Lbryio.lastRemoteHash);
if (!hash.equalsIgnoreCase(Lbryio.lastRemoteHash) && !Helper.isNullOrEmpty(Lbryio.lastRemoteHash)) {
new SyncSetTask(Lbryio.lastRemoteHash, hash, data, null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
if (listener != null) {
listener.onWalletSyncEnabled();
@ -146,21 +147,6 @@ public class WalletVerificationFragment extends Fragment {
applyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void setSyncAfterApply(String oldHash) {
SyncApplyTask fetchTask = new SyncApplyTask(true, new DefaultSyncTaskHandler() {
@Override
public void onSyncApplySuccess(String hash, String data) {
SyncSetTask setTask = new SyncSetTask(oldHash, hash, data, null);
setTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
public void onSyncApplyError(Exception error) {
// pass
}
});
fetchTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void processExistingWalletWithPassword(String password) {
Helper.setViewVisibility(loading, View.VISIBLE);
Helper.setViewVisibility(textLoading, View.VISIBLE);
@ -178,9 +164,8 @@ public class WalletVerificationFragment extends Fragment {
public void onSyncApplySuccess(String hash, String data) {
Utils.setSecureValue(MainActivity.SECURE_VALUE_KEY_SAVED_PASSWORD, password, getContext(), Lbry.KEYSTORE);
// check if local and remote hash are different, and then run sync set
if (!hash.equalsIgnoreCase(Lbryio.lastRemoteHash)) {
SyncSetTask setTask = new SyncSetTask(Lbryio.lastRemoteHash, hash, data, null);
setTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if (!hash.equalsIgnoreCase(Lbryio.lastRemoteHash) && !Helper.isNullOrEmpty(Lbryio.lastRemoteHash)) {
new SyncSetTask(Lbryio.lastRemoteHash, hash, data, null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
if (listener != null) {
listener.onWalletSyncEnabled();

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<stroke android:color="@color/divider" android:width="0.5dp" />
</shape>

View file

@ -0,0 +1,54 @@
<?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="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/discover_title_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<TextView
android:id="@+id/discover_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/discover_channels"
android:textSize="20sp"
android:textFontWeight="300" />
<ProgressBar
android:id="@+id/discover_loading"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:visibility="gone" />
</RelativeLayout>
<ProgressBar
android:id="@+id/discover_main_loading"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/discover_channel_grid"
android:layout_above="@id/discover_done_button"
android:layout_below="@id/discover_title_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/discover_done_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:fontFamily="@font/inter"
android:text="@string/done" />
</RelativeLayout>

View file

@ -27,6 +27,11 @@
android:textColor="@color/white"
android:textFontWeight="300" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/channel_filter_all_container"
android:background="@drawable/bg_all_icon"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/channel_filter_all"
android:layout_width="wrap_content"
@ -35,6 +40,7 @@
android:fontFamily="@font/inter"
android:textFontWeight="300"
android:text="@string/all" />
</RelativeLayout>
<ImageView
android:id="@+id/channel_filter_thumbnail"
android:layout_width="match_parent"

View file

@ -17,17 +17,13 @@
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal">
<ImageView
android:id="@+id/suggested_channel_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_centerHorizontal="true"
android:background="@drawable/bg_channel_icon"
android:id="@+id/suggested_channel_no_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:visibility="invisible">
<TextView
android:id="@+id/suggested_channel_alpha_view"
android:layout_width="wrap_content"
@ -37,6 +33,11 @@
android:textSize="48sp"
android:textColor="@color/white" />
</RelativeLayout>
<ImageView
android:id="@+id/suggested_channel_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</RelativeLayout>
<TextView
android:id="@+id/suggested_channel_title"

View file

@ -52,6 +52,7 @@
<string name="n_remaining">%1$d remaining...</string>
<string name="done">Done</string>
<string name="all">ALL</string>
<string name="discover_channels">Discover new channels</string>
<!-- Claim lists -->
<string name="anonymous">Anonymous</string>