diff --git a/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java index d463d97c..490de509 100644 --- a/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java @@ -43,7 +43,7 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter= 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(); + } +} diff --git a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java index 39354664..e9b9f6b5 100644 --- a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java @@ -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 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 contentSortOrder; private boolean contentClaimSearchLoading = false; + private boolean suggestedClaimSearchLoading = false; private List queuedContentPages = new ArrayList<>(); private List 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 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 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 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() { diff --git a/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java b/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java index 06d13562..df568c5c 100644 --- a/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java @@ -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(); diff --git a/app/src/main/res/drawable/bg_all_icon.xml b/app/src/main/res/drawable/bg_all_icon.xml new file mode 100644 index 00000000..e6e37658 --- /dev/null +++ b/app/src/main/res/drawable/bg_all_icon.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_discover.xml b/app/src/main/res/layout/dialog_discover.xml new file mode 100644 index 00000000..e9a32daf --- /dev/null +++ b/app/src/main/res/layout/dialog_discover.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_channel_filter.xml b/app/src/main/res/layout/list_item_channel_filter.xml index a8ad20f3..eff97a43 100644 --- a/app/src/main/res/layout/list_item_channel_filter.xml +++ b/app/src/main/res/layout/list_item_channel_filter.xml @@ -27,14 +27,20 @@ android:textColor="@color/white" android:textFontWeight="300" /> - + + + - + android:layout_height="match_parent" + android:visibility="invisible"> + %1$d remaining... Done ALL + Discover new channels Anonymous