Abandon channels and bulk delete files tasks. Some visual tweaks.
This commit is contained in:
parent
a42442b13b
commit
5eb35e3283
17 changed files with 380 additions and 14 deletions
|
@ -823,7 +823,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
closeIcon.setVisibility(visible ? View.VISIBLE : View.GONE);
|
closeIcon.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getScaledValue(int value) {
|
public int getScaledValue(int value) {
|
||||||
float scale = getResources().getDisplayMetrics().density;
|
float scale = getResources().getDisplayMetrics().density;
|
||||||
return (int) (value * scale + 0.5f);
|
return (int) (value * scale + 0.5f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.lbry.browser.MainActivity;
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
import io.lbry.browser.listener.SelectionModeListener;
|
import io.lbry.browser.listener.SelectionModeListener;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
|
@ -54,6 +55,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
private boolean inSelectionMode;
|
private boolean inSelectionMode;
|
||||||
@Setter
|
@Setter
|
||||||
private SelectionModeListener selectionModeListener;
|
private SelectionModeListener selectionModeListener;
|
||||||
|
private float scale;
|
||||||
|
|
||||||
public ClaimListAdapter(List<Claim> items, Context context) {
|
public ClaimListAdapter(List<Claim> items, Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -63,6 +65,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
quickClaimUrlMap = new HashMap<>();
|
quickClaimUrlMap = new HashMap<>();
|
||||||
notFoundClaimIdMap = new HashMap<>();
|
notFoundClaimIdMap = new HashMap<>();
|
||||||
notFoundClaimUrlMap = new HashMap<>();
|
notFoundClaimUrlMap = new HashMap<>();
|
||||||
|
if (context != null) {
|
||||||
|
scale = context.getResources().getDisplayMetrics().density;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Claim> getSelectedItems() {
|
public List<Claim> getSelectedItems() {
|
||||||
|
@ -87,6 +92,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Claim> getItems() {
|
||||||
|
return new ArrayList<>(this.items);
|
||||||
|
}
|
||||||
|
|
||||||
public void clearItems() {
|
public void clearItems() {
|
||||||
clearSelectedItems();
|
clearSelectedItems();
|
||||||
this.items.clear();
|
this.items.clear();
|
||||||
|
@ -122,6 +131,11 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeItems(List<Claim> claims) {
|
||||||
|
items.removeAll(claims);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public void removeItem(Claim claim) {
|
public void removeItem(Claim claim) {
|
||||||
items.remove(claim);
|
items.remove(claim);
|
||||||
selectedItems.remove(claim);
|
selectedItems.remove(claim);
|
||||||
|
@ -261,9 +275,18 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
||||||
return new ClaimListAdapter.ViewHolder(v);
|
return new ClaimListAdapter.ViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getScaledValue(int value) {
|
||||||
|
return (int) (value * scale + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
|
public void onBindViewHolder(ClaimListAdapter.ViewHolder vh, int position) {
|
||||||
int type = getItemViewType(position);
|
int type = getItemViewType(position);
|
||||||
|
int paddingTop = position == 0 ? 16 : 8;
|
||||||
|
int paddingBottom = position == getItemCount() - 1 ? 16 : 8;
|
||||||
|
int paddingTopScaled = getScaledValue(paddingTop);
|
||||||
|
int paddingBottomScaled = getScaledValue(paddingBottom);
|
||||||
|
vh.itemView.setPadding(vh.itemView.getPaddingLeft(), paddingTopScaled, vh.itemView.getPaddingRight(), paddingBottomScaled);
|
||||||
|
|
||||||
Claim original = items.get(position);
|
Claim original = items.get(position);
|
||||||
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
|
boolean isRepost = Claim.TYPE_REPOST.equalsIgnoreCase(original.getValueType());
|
||||||
|
|
|
@ -24,6 +24,19 @@ public class User {
|
||||||
private String primaryEmail;
|
private String primaryEmail;
|
||||||
private String rewardStatusChangeTrigger;
|
private String rewardStatusChangeTrigger;
|
||||||
private String updatedAt;
|
private String updatedAt;
|
||||||
private List<String> youtubeChannels;
|
private List<YoutubeChannel> youtubeChannels;
|
||||||
private List<String> deviceTypes;
|
private List<String> deviceTypes;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class YoutubeChannel {
|
||||||
|
String ytChannelName;
|
||||||
|
String lbryChannelName;
|
||||||
|
String channelClaimId;
|
||||||
|
String syncStatus;
|
||||||
|
String statusToken;
|
||||||
|
boolean transferable;
|
||||||
|
String transferState;
|
||||||
|
List<String> publishToAddress;
|
||||||
|
String publicKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package io.lbry.browser.tasks.claim;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
|
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
|
public class AbandonChannelTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
private List<String> claimIds;
|
||||||
|
private List<String> successfulClaimIds;
|
||||||
|
private List<String> failedClaimIds;
|
||||||
|
private List<Exception> failedExceptions;
|
||||||
|
private View progressView;
|
||||||
|
private AbandonHandler handler;
|
||||||
|
|
||||||
|
public AbandonChannelTask(List<String> claimIds, View progressView, AbandonHandler handler) {
|
||||||
|
this.claimIds = claimIds;
|
||||||
|
this.progressView = progressView;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPreExecute() {
|
||||||
|
Helper.setViewVisibility(progressView, View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean doInBackground(Void... params) {
|
||||||
|
successfulClaimIds = new ArrayList<>();
|
||||||
|
failedClaimIds = new ArrayList<>();
|
||||||
|
failedExceptions = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String claimId : claimIds) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> options = new HashMap<>();
|
||||||
|
options.put("claim_id", claimId);
|
||||||
|
options.put("blocking", false);
|
||||||
|
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_CHANNEL_ABANDON, options);
|
||||||
|
successfulClaimIds.add(claimId);
|
||||||
|
} catch (ApiCallException ex) {
|
||||||
|
failedClaimIds.add(claimId);
|
||||||
|
failedExceptions.add(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onPostExecute(Boolean result) {
|
||||||
|
Helper.setViewVisibility(progressView, View.GONE);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.onComplete(successfulClaimIds, failedClaimIds, failedExceptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package io.lbry.browser.tasks.claim;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AbandonHandler {
|
||||||
|
void onComplete(List<String> successfulClaimIds, List<String> failedClaimIds, List<Exception> errors);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package io.lbry.browser.tasks.file;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.lbry.browser.exceptions.ApiCallException;
|
||||||
|
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||||
|
import io.lbry.browser.utils.Lbry;
|
||||||
|
|
||||||
|
// Just run delete on the specified claim IDs (no need for a handler)
|
||||||
|
public class BulkDeleteFilesTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
private List<String> claimIds;
|
||||||
|
public BulkDeleteFilesTask(List<String> claimIds) {
|
||||||
|
this.claimIds = claimIds;
|
||||||
|
}
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
for (String claimId : claimIds) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> options = new HashMap<>();
|
||||||
|
options.put("claim_id", claimId);
|
||||||
|
options.put("delete_from_download_dir", true);
|
||||||
|
Lbry.genericApiCall(Lbry.METHOD_FILE_DELETE, options);
|
||||||
|
} catch (ApiCallException ex) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ public class DeleteFileTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
options.put("delete_from_download_dir", true);
|
options.put("delete_from_download_dir", true);
|
||||||
return (boolean) Lbry.genericApiCall(Lbry.METHOD_FILE_DELETE, options);
|
return (boolean) Lbry.genericApiCall(Lbry.METHOD_FILE_DELETE, options);
|
||||||
} catch (ApiCallException ex) {
|
} catch (ApiCallException ex) {
|
||||||
|
error = ex;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.lbry.browser.ui.channel;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -19,6 +20,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -32,6 +34,8 @@ import io.lbry.browser.listener.SdkStatusListener;
|
||||||
import io.lbry.browser.listener.SelectionModeListener;
|
import io.lbry.browser.listener.SelectionModeListener;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
import io.lbry.browser.model.NavMenuItem;
|
import io.lbry.browser.model.NavMenuItem;
|
||||||
|
import io.lbry.browser.tasks.claim.AbandonChannelTask;
|
||||||
|
import io.lbry.browser.tasks.claim.AbandonHandler;
|
||||||
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||||
import io.lbry.browser.tasks.claim.ClaimListTask;
|
import io.lbry.browser.tasks.claim.ClaimListTask;
|
||||||
import io.lbry.browser.ui.BaseFragment;
|
import io.lbry.browser.ui.BaseFragment;
|
||||||
|
@ -144,7 +148,7 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
|
||||||
ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, getLoading(), new ClaimListResultHandler() {
|
ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, getLoading(), new ClaimListResultHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(List<Claim> claims) {
|
public void onSuccess(List<Claim> claims) {
|
||||||
Lbry.ownChannels = new ArrayList<>(claims);
|
Lbry.ownChannels = Helper.filterDeletedClaims(new ArrayList<>(claims));
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if (adapter == null) {
|
if (adapter == null) {
|
||||||
adapter = new ClaimListAdapter(claims, context);
|
adapter = new ClaimListAdapter(claims, context);
|
||||||
|
@ -260,7 +264,7 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
|
||||||
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
//handleDeleteSelectedClaims(selectedClaims);
|
handleDeleteSelectedClaims(selectedClaims);
|
||||||
}
|
}
|
||||||
}).setNegativeButton(R.string.no, null);
|
}).setNegativeButton(R.string.no, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
|
@ -270,4 +274,48 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleDeleteSelectedClaims(List<Claim> selectedClaims) {
|
||||||
|
List<String> claimIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Claim claim : selectedClaims) {
|
||||||
|
claimIds.add(claim.getClaimId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
Helper.setViewVisibility(channelList, View.INVISIBLE);
|
||||||
|
Helper.setViewVisibility(fabNewChannel, View.INVISIBLE);
|
||||||
|
AbandonChannelTask task = new AbandonChannelTask(claimIds, bigLoading, new AbandonHandler() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(List<String> successfulClaimIds, List<String> failedClaimIds, List<Exception> errors) {
|
||||||
|
View root = getView();
|
||||||
|
if (root != null) {
|
||||||
|
if (failedClaimIds.size() > 0) {
|
||||||
|
Snackbar.make(root, R.string.one_or_more_channels_failed_abandon, Snackbar.LENGTH_LONG).
|
||||||
|
setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show();
|
||||||
|
} else if (successfulClaimIds.size() == claimIds.size()) {
|
||||||
|
try {
|
||||||
|
String message = getResources().getQuantityString(R.plurals.channels_deleted, successfulClaimIds.size());
|
||||||
|
Snackbar.make(root, message, Snackbar.LENGTH_LONG).show();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lbry.abandonedClaimIds.addAll(successfulClaimIds);
|
||||||
|
if (adapter != null) {
|
||||||
|
adapter.setItems(Helper.filterDeletedClaims(adapter.getItems()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Helper.setViewVisibility(channelList, View.VISIBLE);
|
||||||
|
Helper.setViewVisibility(fabNewChannel, View.VISIBLE);
|
||||||
|
checkNoChannels();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,7 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
resetViewCount();
|
resetViewCount();
|
||||||
|
resetFee();
|
||||||
checkNewClaimAndUrl(newClaim, newUrl);
|
checkNewClaimAndUrl(newClaim, newUrl);
|
||||||
|
|
||||||
if (newClaim != null) {
|
if (newClaim != null) {
|
||||||
|
@ -364,6 +365,7 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
currentUrl = url;
|
currentUrl = url;
|
||||||
logUrlEvent(url);
|
logUrlEvent(url);
|
||||||
resetViewCount();
|
resetViewCount();
|
||||||
|
resetFee();
|
||||||
View root = getView();
|
View root = getView();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
((RecyclerView) root.findViewById(R.id.file_view_related_content_list)).setAdapter(null);
|
((RecyclerView) root.findViewById(R.id.file_view_related_content_list)).setAdapter(null);
|
||||||
|
@ -431,6 +433,7 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
|
|
||||||
public void openClaimUrl(String url) {
|
public void openClaimUrl(String url) {
|
||||||
resetViewCount();
|
resetViewCount();
|
||||||
|
resetFee();
|
||||||
currentUrl = url;
|
currentUrl = url;
|
||||||
|
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
|
@ -508,6 +511,7 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
View root = getView();
|
View root = getView();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
PlayerView view = root.findViewById(R.id.file_view_exoplayer_view);
|
PlayerView view = root.findViewById(R.id.file_view_exoplayer_view);
|
||||||
|
view.setPlayer(null);
|
||||||
view.setPlayer(MainActivity.appPlayer);
|
view.setPlayer(MainActivity.appPlayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -896,6 +900,10 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
getView().findViewById(R.id.file_view_action_download).setVisibility(View.VISIBLE);
|
getView().findViewById(R.id.file_view_action_download).setVisibility(View.VISIBLE);
|
||||||
getView().findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
|
getView().findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
|
||||||
actionDelete.setEnabled(true);
|
actionDelete.setEnabled(true);
|
||||||
|
|
||||||
|
claim.setFile(null);
|
||||||
|
Lbry.unsetFilesForCachedClaims(Arrays.asList(claim.getClaimId()));
|
||||||
|
|
||||||
restoreMainActionButton();
|
restoreMainActionButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1135,10 +1143,21 @@ public class FileViewFragment extends BaseFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetViewCount() {
|
private void resetViewCount() {
|
||||||
TextView textViewCount = getView().findViewById(R.id.file_view_view_count);
|
View root = getView();
|
||||||
|
if (root != null) {
|
||||||
|
TextView textViewCount = root.findViewById(R.id.file_view_view_count);
|
||||||
Helper.setViewText(textViewCount, null);
|
Helper.setViewText(textViewCount, null);
|
||||||
Helper.setViewVisibility(textViewCount, View.GONE);
|
Helper.setViewVisibility(textViewCount, View.GONE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
private void resetFee() {
|
||||||
|
View root = getView();
|
||||||
|
if (root != null) {
|
||||||
|
TextView feeView = root.findViewById(R.id.file_view_fee);
|
||||||
|
feeView.setText(null);
|
||||||
|
Helper.setViewVisibility(root.findViewById(R.id.file_view_fee_container), View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void loadViewCount() {
|
private void loadViewCount() {
|
||||||
if (claim != null) {
|
if (claim != null) {
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package io.lbry.browser.ui.library;
|
package io.lbry.browser.ui.library;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
@ -12,16 +15,23 @@ import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.view.ActionMode;
|
||||||
import androidx.cardview.widget.CardView;
|
import androidx.cardview.widget.CardView;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.nio.channels.AsynchronousChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
import io.lbry.browser.MainActivity;
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
|
@ -29,22 +39,31 @@ import io.lbry.browser.adapter.ClaimListAdapter;
|
||||||
import io.lbry.browser.data.DatabaseHelper;
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.listener.DownloadActionListener;
|
import io.lbry.browser.listener.DownloadActionListener;
|
||||||
import io.lbry.browser.listener.SdkStatusListener;
|
import io.lbry.browser.listener.SdkStatusListener;
|
||||||
|
import io.lbry.browser.listener.SelectionModeListener;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
import io.lbry.browser.model.LbryFile;
|
import io.lbry.browser.model.LbryFile;
|
||||||
|
import io.lbry.browser.model.NavMenuItem;
|
||||||
import io.lbry.browser.model.ViewHistory;
|
import io.lbry.browser.model.ViewHistory;
|
||||||
|
import io.lbry.browser.tasks.claim.AbandonChannelTask;
|
||||||
|
import io.lbry.browser.tasks.claim.AbandonHandler;
|
||||||
|
import io.lbry.browser.tasks.file.BulkDeleteFilesTask;
|
||||||
|
import io.lbry.browser.tasks.file.DeleteFileTask;
|
||||||
import io.lbry.browser.tasks.file.FileListTask;
|
import io.lbry.browser.tasks.file.FileListTask;
|
||||||
import io.lbry.browser.tasks.localdata.FetchViewHistoryTask;
|
import io.lbry.browser.tasks.localdata.FetchViewHistoryTask;
|
||||||
import io.lbry.browser.ui.BaseFragment;
|
import io.lbry.browser.ui.BaseFragment;
|
||||||
|
import io.lbry.browser.ui.channel.ChannelFormFragment;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.Lbry;
|
import io.lbry.browser.utils.Lbry;
|
||||||
import io.lbry.browser.utils.LbryAnalytics;
|
import io.lbry.browser.utils.LbryAnalytics;
|
||||||
|
|
||||||
public class LibraryFragment extends BaseFragment implements DownloadActionListener, SdkStatusListener {
|
public class LibraryFragment extends BaseFragment implements
|
||||||
|
ActionMode.Callback, DownloadActionListener, SelectionModeListener, SdkStatusListener {
|
||||||
|
|
||||||
private static final int FILTER_DOWNLOADS = 1;
|
private static final int FILTER_DOWNLOADS = 1;
|
||||||
private static final int FILTER_HISTORY = 2;
|
private static final int FILTER_HISTORY = 2;
|
||||||
private static final int PAGE_SIZE = 50;
|
private static final int PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
private ActionMode actionMode;
|
||||||
private int currentFilter;
|
private int currentFilter;
|
||||||
private List<LbryFile> currentFiles;
|
private List<LbryFile> currentFiles;
|
||||||
private View layoutSdkInitializing;
|
private View layoutSdkInitializing;
|
||||||
|
@ -244,6 +263,9 @@ public class LibraryFragment extends BaseFragment implements DownloadActionListe
|
||||||
currentFilter = FILTER_HISTORY;
|
currentFilter = FILTER_HISTORY;
|
||||||
linkFilterDownloads.setTypeface(null, Typeface.NORMAL);
|
linkFilterDownloads.setTypeface(null, Typeface.NORMAL);
|
||||||
linkFilterHistory.setTypeface(null, Typeface.BOLD);
|
linkFilterHistory.setTypeface(null, Typeface.BOLD);
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.finish();
|
||||||
|
}
|
||||||
if (contentListAdapter != null) {
|
if (contentListAdapter != null) {
|
||||||
contentListAdapter.clearItems();
|
contentListAdapter.clearItems();
|
||||||
contentListAdapter.setCanEnterSelectionMode(false);
|
contentListAdapter.setCanEnterSelectionMode(false);
|
||||||
|
@ -261,6 +283,7 @@ public class LibraryFragment extends BaseFragment implements DownloadActionListe
|
||||||
private void initContentListAdapter(List<Claim> claims) {
|
private void initContentListAdapter(List<Claim> claims) {
|
||||||
contentListAdapter = new ClaimListAdapter(claims, getContext());
|
contentListAdapter = new ClaimListAdapter(claims, getContext());
|
||||||
contentListAdapter.setCanEnterSelectionMode(true);
|
contentListAdapter.setCanEnterSelectionMode(true);
|
||||||
|
contentListAdapter.setSelectionModeListener(this);
|
||||||
contentListAdapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
|
contentListAdapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClaimClicked(Claim claim) {
|
public void onClaimClicked(Claim claim) {
|
||||||
|
@ -459,4 +482,104 @@ public class LibraryFragment extends BaseFragment implements DownloadActionListe
|
||||||
currentFilter == FILTER_HISTORY ?
|
currentFilter == FILTER_HISTORY ?
|
||||||
View.GONE : View.VISIBLE);
|
View.GONE : View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||||
|
this.actionMode = actionMode;
|
||||||
|
Context context = getContext();
|
||||||
|
if (context instanceof MainActivity) {
|
||||||
|
MainActivity activity = (MainActivity) context;
|
||||||
|
if (!activity.isDarkMode()) {
|
||||||
|
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMode.getMenuInflater().inflate(R.menu.menu_claim_list, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onDestroyActionMode(ActionMode actionMode) {
|
||||||
|
if (contentListAdapter != null) {
|
||||||
|
contentListAdapter.clearSelectedItems();
|
||||||
|
contentListAdapter.setInSelectionMode(false);
|
||||||
|
contentListAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
Context context = getContext();
|
||||||
|
if (context != null) {
|
||||||
|
MainActivity activity = (MainActivity) context;
|
||||||
|
if (!activity.isDarkMode()) {
|
||||||
|
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.actionMode = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareActionMode(androidx.appcompat.view.ActionMode actionMode, Menu menu) {
|
||||||
|
menu.findItem(R.id.action_edit).setVisible(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onActionItemClicked(androidx.appcompat.view.ActionMode actionMode, MenuItem menuItem) {
|
||||||
|
if (R.id.action_delete == menuItem.getItemId()) {
|
||||||
|
if (contentListAdapter != null && contentListAdapter.getSelectedCount() > 0) {
|
||||||
|
final List<Claim> selectedClaims = new ArrayList<>(contentListAdapter.getSelectedItems());
|
||||||
|
String message = getResources().getQuantityString(R.plurals.confirm_delete_files, selectedClaims.size());
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()).
|
||||||
|
setTitle(R.string.delete_selection).
|
||||||
|
setMessage(message)
|
||||||
|
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
handleDeleteSelectedClaims(selectedClaims);
|
||||||
|
}
|
||||||
|
}).setNegativeButton(R.string.no, null);
|
||||||
|
builder.show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleDeleteSelectedClaims(List<Claim> selectedClaims) {
|
||||||
|
List<String> claimIds = new ArrayList<>();
|
||||||
|
for (Claim claim : selectedClaims) {
|
||||||
|
claimIds.add(claim.getClaimId());
|
||||||
|
}
|
||||||
|
|
||||||
|
new BulkDeleteFilesTask(claimIds).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
Lbry.unsetFilesForCachedClaims(claimIds);
|
||||||
|
if (currentFilter == FILTER_DOWNLOADS) {
|
||||||
|
contentListAdapter.removeItems(selectedClaims);
|
||||||
|
}
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.finish();
|
||||||
|
}
|
||||||
|
View root = getView();
|
||||||
|
if (root != null) {
|
||||||
|
String message = getResources().getQuantityString(R.plurals.files_deleted, claimIds.size());
|
||||||
|
Snackbar.make(root, message, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnterSelectionMode() {
|
||||||
|
Context context = getContext();
|
||||||
|
if (context instanceof MainActivity) {
|
||||||
|
MainActivity activity = (MainActivity) context;
|
||||||
|
activity.startSupportActionMode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onItemSelectionToggled() {
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.setTitle(String.valueOf(contentListAdapter.getSelectedCount()));
|
||||||
|
actionMode.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onExitSelectionMode() {
|
||||||
|
if (actionMode != null) {
|
||||||
|
actionMode.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,6 +402,15 @@ public final class Helper {
|
||||||
}
|
}
|
||||||
return followedTags;
|
return followedTags;
|
||||||
}
|
}
|
||||||
|
public static List<Claim> filterDeletedClaims(List<Claim> claims) {
|
||||||
|
List<Claim> filtered = new ArrayList<>();
|
||||||
|
for (Claim claim : claims) {
|
||||||
|
if (!Lbry.abandonedClaimIds.contains(claim.getClaimId())) {
|
||||||
|
filtered.add(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setWunderbarValue(String value, Context context) {
|
public static void setWunderbarValue(String value, Context context) {
|
||||||
if (context instanceof MainActivity) {
|
if (context instanceof MainActivity) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ public final class Lbry {
|
||||||
public static List<Tag> followedTags = new ArrayList<>();
|
public static List<Tag> followedTags = new ArrayList<>();
|
||||||
public static List<Claim> ownClaims = new ArrayList<>();
|
public static List<Claim> ownClaims = new ArrayList<>();
|
||||||
public static List<Claim> ownChannels = new ArrayList<>(); // Make this a subset of ownClaims?
|
public static List<Claim> ownChannels = new ArrayList<>(); // Make this a subset of ownClaims?
|
||||||
|
public static List<String> abandonedClaimIds = new ArrayList<>();
|
||||||
|
|
||||||
public static final int TTL_CLAIM_SEARCH_VALUE = 120000; // 2-minute TTL for cache
|
public static final int TTL_CLAIM_SEARCH_VALUE = 120000; // 2-minute TTL for cache
|
||||||
public static final String SDK_CONNECTION_STRING = "http://127.0.0.1:5279";
|
public static final String SDK_CONNECTION_STRING = "http://127.0.0.1:5279";
|
||||||
|
@ -97,6 +98,7 @@ public final class Lbry {
|
||||||
public static boolean SDK_READY = false;
|
public static boolean SDK_READY = false;
|
||||||
|
|
||||||
public static void startupInit() {
|
public static void startupInit() {
|
||||||
|
abandonedClaimIds = new ArrayList<>();
|
||||||
ownChannels = new ArrayList<>();
|
ownChannels = new ArrayList<>();
|
||||||
ownClaims = new ArrayList<>();
|
ownClaims = new ArrayList<>();
|
||||||
knownTags = new ArrayList<>();
|
knownTags = new ArrayList<>();
|
||||||
|
@ -474,4 +476,14 @@ public final class Lbry {
|
||||||
claimCache.put(shortUrlKey, claim);
|
claimCache.put(shortUrlKey, claim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void unsetFilesForCachedClaims(List<String> claimIds) {
|
||||||
|
for (String claimId : claimIds) {
|
||||||
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
|
key.setClaimId(claimId);
|
||||||
|
if (claimCache.containsKey(key)) {
|
||||||
|
claimCache.get(key).setFile(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,8 +192,9 @@ public final class Lbryio {
|
||||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||||
User user = gson.fromJson(object.toString(), type);
|
User user = gson.fromJson(object.toString(), type);
|
||||||
return user;
|
return user;
|
||||||
} catch (LbryioRequestException | LbryioResponseException | ClassCastException ex) {
|
} catch (LbryioRequestException | LbryioResponseException | ClassCastException | IllegalStateException ex) {
|
||||||
android.util.Log.e(TAG, "Cannot retrieve the current user", ex);
|
LbryAnalytics.logException(String.format("/user/me failed: %s", ex.getMessage()), ex.getClass().getName());
|
||||||
|
android.util.Log.e(TAG, "Could not retrieve the current user", ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="12dp"
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
android:layout_above="@+id/channel_view_tabs"
|
android:layout_above="@+id/channel_view_tabs"
|
||||||
android:layout_toRightOf="@id/channel_view_icon_container"
|
android:layout_toRightOf="@id/channel_view_icon_container"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
@ -66,7 +67,9 @@
|
||||||
android:paddingRight="4dp"
|
android:paddingRight="4dp"
|
||||||
android:paddingTop="2dp"
|
android:paddingTop="2dp"
|
||||||
android:paddingBottom="2dp"
|
android:paddingBottom="2dp"
|
||||||
|
android:ellipsize="end"
|
||||||
android:fontFamily="@font/inter"
|
android:fontFamily="@font/inter"
|
||||||
|
android:maxLines="2"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textColor="@color/white" />
|
android:textColor="@color/white" />
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -300,9 +300,7 @@
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:layout_below="@id/library_storage_stats_card"
|
android:layout_below="@id/library_storage_stats_card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="16dp" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/library_empty_container"
|
android:id="@+id/library_empty_container"
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
android:paddingBottom="8dp"
|
android:paddingBottom="8dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackground">
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:background="@drawable/bg_selected_list_item">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/claim_repost_info"
|
android:id="@+id/claim_repost_info"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -323,6 +323,7 @@
|
||||||
<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="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>
|
<string name="pending">Pending</string>
|
||||||
<string name="create">Create</string>
|
<string name="create">Create</string>
|
||||||
|
<string name="one_or_more_channels_failed_abandon">One or moe channels could not be deleted at this time. Please try again later.</string>
|
||||||
<plurals name="min_deposit_required">
|
<plurals name="min_deposit_required">
|
||||||
<item quantity="one">A minimum deposit of %1$s credit is required.</item>
|
<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>
|
<item quantity="other">A minimum deposit of %1$s credits is required.</item>
|
||||||
|
@ -331,6 +332,10 @@
|
||||||
<item quantity="one">Are you sure you want to delete the selected channel?</item>
|
<item quantity="one">Are you sure you want to delete the selected channel?</item>
|
||||||
<item quantity="other">Are you sure you want to delete the selected channels?</item>
|
<item quantity="other">Are you sure you want to delete the selected channels?</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="channels_deleted">
|
||||||
|
<item quantity="one">The channel was successfully deleted.</item>
|
||||||
|
<item quantity="other">The channels were successfully deleted.</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
<!-- Rewards -->
|
<!-- Rewards -->
|
||||||
<string name="lbry_credits_allow">LBRY credits allow you to publish or purchase content.</string>
|
<string name="lbry_credits_allow">LBRY credits allow you to publish or purchase content.</string>
|
||||||
|
@ -388,6 +393,14 @@
|
||||||
<string name="kb">KB</string>
|
<string name="kb">KB</string>
|
||||||
<string name="gb">GB</string>
|
<string name="gb">GB</string>
|
||||||
<string name="zero_mb">0MB</string>
|
<string name="zero_mb">0MB</string>
|
||||||
|
<plurals name="confirm_delete_files">
|
||||||
|
<item quantity="one">Are you sure you want to remove the selected file from your device?</item>
|
||||||
|
<item quantity="other">Are you sure you want to remove the selected files from your device?</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="files_deleted">
|
||||||
|
<item quantity="one">The file was successfully deleted.</item>
|
||||||
|
<item quantity="other">The files were successfully deleted.</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
<!-- About -->
|
<!-- About -->
|
||||||
<string name="about_lbry">About LBRY</string>
|
<string name="about_lbry">About LBRY</string>
|
||||||
|
|
Loading…
Reference in a new issue