Library page. URL and view history.
This commit is contained in:
parent
47f56950a5
commit
244d54ed39
25 changed files with 1711 additions and 51 deletions
|
@ -169,9 +169,9 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
ClaimCacheKey key = new ClaimCacheKey();
|
||||
key.setClaimId(claimId);
|
||||
key.setUrl(url); // use the same url for the key so that we can match the key for any value that's the same
|
||||
|
||||
if (Lbry.claimCache.containsKey(key)) {
|
||||
claim = Lbry.claimCache.get(key);
|
||||
Helper.saveViewHistory(url, claim);
|
||||
checkAndResetNowPlayingClaim();
|
||||
if (claim.getFile() == null) {
|
||||
loadFile();
|
||||
|
@ -314,6 +314,7 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
if (Lbry.claimCache.containsKey(key)) {
|
||||
claim = Lbry.claimCache.get(key);
|
||||
Helper.saveUrlHistory(url, claim.getTitle(), UrlSuggestion.TYPE_FILE);
|
||||
Helper.saveViewHistory(url, claim);
|
||||
checkAndResetNowPlayingClaim();
|
||||
if (claim.getFile() == null) {
|
||||
loadFile();
|
||||
|
@ -423,7 +424,7 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
String claimId = claim.getClaimId();
|
||||
FileListTask task = new FileListTask(claimId, null, new FileListTask.FileListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<LbryFile> files) {
|
||||
public void onSuccess(List<LbryFile> files, boolean hasReachedEnd) {
|
||||
if (files.size() > 0) {
|
||||
claim.setFile(files.get(0));
|
||||
checkIsFileComplete();
|
||||
|
@ -445,7 +446,7 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
if (initialFileLoadDone) {
|
||||
restoreMainActionButton();
|
||||
}
|
||||
if (claim != null && claim.isFree()) {
|
||||
if (claim != null && claim.isFree() && (claim.isPlayable() || claim.isViewable())) {
|
||||
onMainActionButtonClicked();
|
||||
}
|
||||
}
|
||||
|
@ -491,6 +492,8 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
Helper.saveUrlHistory(url, claim.getTitle(), UrlSuggestion.TYPE_FILE);
|
||||
|
||||
// also save view history
|
||||
Helper.saveViewHistory(url, claim);
|
||||
|
||||
checkAndResetNowPlayingClaim();
|
||||
loadFile();
|
||||
renderClaim();
|
||||
|
@ -1576,9 +1579,11 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
String uri = intent.getStringExtra("uri");
|
||||
String outpoint = intent.getStringExtra("outpoint");
|
||||
String fileInfoJson = intent.getStringExtra("file_info");
|
||||
double progress = intent.getDoubleExtra("progress", 0);
|
||||
if (claim == null || uri == null || outpoint == null || (fileInfoJson == null && !"abort".equals(downloadAction))) {
|
||||
return;
|
||||
}
|
||||
onRelatedDownloadAction(downloadAction, uri, outpoint, fileInfoJson, progress);
|
||||
if (claim != null && !claim.getPermanentUrl().equalsIgnoreCase(uri)) {
|
||||
return;
|
||||
}
|
||||
|
@ -1604,7 +1609,6 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
} else if (DownloadManager.ACTION_UPDATE.equals(downloadAction)) {
|
||||
// handle download updated
|
||||
downloadInProgress = true;
|
||||
double progress = intent.getDoubleExtra("progress", 0);
|
||||
Helper.setViewVisibility(downloadProgressView, View.VISIBLE);
|
||||
downloadProgressView.setProgress(Double.valueOf(progress).intValue());
|
||||
downloadIconView.setImageResource(R.drawable.ic_stop);
|
||||
|
@ -1692,6 +1696,26 @@ public class FileViewActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
private void onRelatedDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (relatedContentAdapter != null) {
|
||||
relatedContentAdapter.clearFileForClaimOrUrl(outpoint, uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (relatedContentAdapter != null) {
|
||||
relatedContentAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
|
||||
private void bringMainTaskToFront() {
|
||||
if (backStackLost) {
|
||||
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.content.pm.PackageManager;
|
|||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
|
@ -32,11 +33,13 @@ import android.view.WindowManager;
|
|||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
||||
import com.google.android.exoplayer2.offline.Download;
|
||||
import com.google.android.exoplayer2.ui.PlayerView;
|
||||
import com.google.android.gms.cast.framework.CastContext;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
|
@ -78,6 +81,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -89,6 +93,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.DownloadActionListener;
|
||||
import io.lbry.browser.listener.FetchChannelsListener;
|
||||
import io.lbry.browser.listener.SdkStatusListener;
|
||||
import io.lbry.browser.listener.WalletBalanceListener;
|
||||
|
@ -121,6 +126,7 @@ import io.lbry.browser.ui.channel.ChannelFragment;
|
|||
import io.lbry.browser.ui.channel.ChannelManagerFragment;
|
||||
import io.lbry.browser.ui.editorschoice.EditorsChoiceFragment;
|
||||
import io.lbry.browser.ui.following.FollowingFragment;
|
||||
import io.lbry.browser.ui.library.LibraryFragment;
|
||||
import io.lbry.browser.ui.other.AboutFragment;
|
||||
import io.lbry.browser.ui.search.SearchFragment;
|
||||
import io.lbry.browser.ui.other.SettingsFragment;
|
||||
|
@ -133,6 +139,7 @@ import io.lbry.browser.utils.Lbry;
|
|||
import io.lbry.browser.utils.LbryAnalytics;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import io.lbry.lbrysdk.DownloadManager;
|
||||
import io.lbry.lbrysdk.LbrynetService;
|
||||
import io.lbry.lbrysdk.ServiceHelper;
|
||||
import io.lbry.lbrysdk.Utils;
|
||||
|
@ -246,6 +253,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
@Getter
|
||||
private DatabaseHelper dbHelper;
|
||||
private int selectedMenuItemId = -1;
|
||||
private List<DownloadActionListener> downloadActionListeners;
|
||||
private List<SdkStatusListener> sdkStatusListeners;
|
||||
private List<WalletBalanceListener> walletBalanceListeners;
|
||||
private List<FetchChannelsListener> fetchChannelsListeners;
|
||||
|
@ -278,6 +286,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
// your content
|
||||
NavMenuItem.ID_ITEM_CHANNELS,
|
||||
NavMenuItem.ID_ITEM_LIBRARY,
|
||||
|
||||
// wallet
|
||||
NavMenuItem.ID_ITEM_WALLET,
|
||||
|
@ -336,6 +345,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
// other
|
||||
openNavFragments = new HashMap<>();
|
||||
downloadActionListeners = new ArrayList<>();
|
||||
sdkStatusListeners = new ArrayList<>();
|
||||
walletBalanceListeners = new ArrayList<>();
|
||||
fetchChannelsListeners = new ArrayList<>();
|
||||
|
@ -355,6 +365,14 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
shouldOpenUserSelectedMenuItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawerSlide(View drawerView, float slideOffset) {
|
||||
if (slideOffset != 0) {
|
||||
clearWunderbarFocus(findViewById(R.id.wunderbar));
|
||||
}
|
||||
super.onDrawerSlide(drawerView, slideOffset);
|
||||
}
|
||||
};
|
||||
drawer.addDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
|
@ -435,7 +453,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
specialRouteFragmentClassMap.put("channels", ChannelManagerFragment.class);
|
||||
specialRouteFragmentClassMap.put("invite", InvitesFragment.class);
|
||||
specialRouteFragmentClassMap.put("invites", InvitesFragment.class);
|
||||
//specialRouteFragmentClassMap.put("library", LibraryFragment.class);
|
||||
specialRouteFragmentClassMap.put("library", LibraryFragment.class);
|
||||
//specialRouteFragmentClassMap.put("publish", PublishFragment.class);
|
||||
//specialRouteFragmentClassMap.put("publishes", PublishesFragment.class);
|
||||
specialRouteFragmentClassMap.put("following", FollowingFragment.class);
|
||||
|
@ -452,6 +470,16 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
checkNotificationOpenIntent(intent);
|
||||
}
|
||||
|
||||
public void addDownloadActionListener(DownloadActionListener listener) {
|
||||
if (!downloadActionListeners.contains(listener)) {
|
||||
downloadActionListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDownloadActionListener(DownloadActionListener listener) {
|
||||
downloadActionListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addSdkStatusListener(SdkStatusListener listener) {
|
||||
if (!sdkStatusListeners.contains(listener)) {
|
||||
sdkStatusListeners.add(listener);
|
||||
|
@ -504,6 +532,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
case NavMenuItem.ID_ITEM_CHANNELS:
|
||||
openFragment(ChannelManagerFragment.class, true, NavMenuItem.ID_ITEM_CHANNELS);
|
||||
break;
|
||||
case NavMenuItem.ID_ITEM_LIBRARY:
|
||||
openFragment(LibraryFragment.class, true, NavMenuItem.ID_ITEM_LIBRARY);
|
||||
break;
|
||||
|
||||
case NavMenuItem.ID_ITEM_WALLET:
|
||||
openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
|
||||
|
@ -1094,6 +1125,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
} else if (!appStarted) {
|
||||
// first run completed, startup
|
||||
startup();
|
||||
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
|
||||
openFragment(FollowingFragment.class, false, NavMenuItem.ID_ITEM_FOLLOWING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1146,9 +1179,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
|
||||
findViewById(R.id.global_sdk_initializing_status).setVisibility(View.GONE);
|
||||
|
||||
syncWalletAndLoadPreferences();
|
||||
scheduleWalletBalanceUpdate();
|
||||
scheduleWalletSyncTask();
|
||||
fetchChannels();
|
||||
|
||||
initFloatingWalletBalance();
|
||||
}
|
||||
|
||||
|
@ -1317,7 +1353,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
return walletSyncEnabled && Lbryio.isSignedIn();
|
||||
}
|
||||
|
||||
private void syncWalletAndLoadPreferences() {
|
||||
public void syncWalletAndLoadPreferences() {
|
||||
if (!userSyncEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1629,6 +1665,26 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
actionBar.show();
|
||||
}
|
||||
}
|
||||
private void renderStartupFailed(Map<Integer, Boolean> startupStages) {
|
||||
Map<Integer, Integer> startupStageIconIds = new HashMap<>();
|
||||
startupStageIconIds.put(STARTUP_STAGE_INSTALL_ID_LOADED, R.id.startup_stage_icon_install_id);
|
||||
startupStageIconIds.put(STARTUP_STAGE_KNOWN_TAGS_LOADED, R.id.startup_stage_icon_known_tags);
|
||||
startupStageIconIds.put(STARTUP_STAGE_EXCHANGE_RATE_LOADED, R.id.startup_stage_icon_exchange_rate);
|
||||
startupStageIconIds.put(STARTUP_STAGE_USER_AUTHENTICATED, R.id.startup_stage_icon_user_authenticated);
|
||||
startupStageIconIds.put(STARTUP_STAGE_NEW_INSTALL_DONE, R.id.startup_stage_icon_install_new);
|
||||
startupStageIconIds.put(STARTUP_STAGE_SUBSCRIPTIONS_LOADED, R.id.startup_stage_icon_subscriptions_loaded);
|
||||
startupStageIconIds.put(STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED, R.id.startup_stage_icon_subscriptions_resolved);
|
||||
|
||||
for (Integer key : startupStages.keySet()) {
|
||||
boolean stageDone = startupStages.get(key);
|
||||
ImageView icon = findViewById(startupStageIconIds.get(key));
|
||||
icon.setImageResource(stageDone ? R.drawable.ic_check : R.drawable.ic_close);
|
||||
icon.setColorFilter(stageDone ? Color.WHITE : Color.RED);
|
||||
}
|
||||
|
||||
findViewById(R.id.splash_view_loading_container).setVisibility(View.GONE);
|
||||
findViewById(R.id.splash_view_error_container).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void startup() {
|
||||
final Context context = this;
|
||||
|
@ -1636,11 +1692,23 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
// perform some tasks before launching
|
||||
(new AsyncTask<Void, Void, Boolean>() {
|
||||
private Map<Integer, Boolean> startupStages = new HashMap<>();
|
||||
|
||||
private void initStartupStages() {
|
||||
startupStages.put(STARTUP_STAGE_INSTALL_ID_LOADED, false);
|
||||
startupStages.put(STARTUP_STAGE_KNOWN_TAGS_LOADED, false);
|
||||
startupStages.put(STARTUP_STAGE_EXCHANGE_RATE_LOADED, false);
|
||||
startupStages.put(STARTUP_STAGE_USER_AUTHENTICATED, false);
|
||||
startupStages.put(STARTUP_STAGE_NEW_INSTALL_DONE, false);
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_LOADED, false);
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED, false);
|
||||
}
|
||||
protected void onPreExecute() {
|
||||
hideActionBar();
|
||||
lockDrawer();
|
||||
findViewById(R.id.splash_view).setVisibility(View.VISIBLE);
|
||||
LbryAnalytics.setCurrentScreen(MainActivity.this, "Splash", "Splash");
|
||||
initStartupStages();
|
||||
}
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
BufferedReader reader = null;
|
||||
|
@ -1652,29 +1720,35 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
String installId = reader.readLine();
|
||||
if (Helper.isNullOrEmpty(installId)) {
|
||||
// no install_id found (first run didn't start the sdk successfully?)
|
||||
startupStages.put(STARTUP_STAGE_INSTALL_ID_LOADED, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
Lbry.INSTALLATION_ID = installId;
|
||||
startupStages.put(STARTUP_STAGE_INSTALL_ID_LOADED, true);
|
||||
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
List<Tag> fetchedTags = DatabaseHelper.getTags(db);
|
||||
Lbry.knownTags = Helper.mergeKnownTags(fetchedTags);
|
||||
Collections.sort(Lbry.knownTags, new Tag());
|
||||
Lbry.followedTags = Helper.filterFollowedTags(Lbry.knownTags);
|
||||
startupStages.put(STARTUP_STAGE_KNOWN_TAGS_LOADED, true);
|
||||
|
||||
// load the exchange rate
|
||||
if (Lbryio.LBCUSDRate == 0) {
|
||||
Lbryio.loadExchangeRate();
|
||||
if (Lbryio.LBCUSDRate == 0) {
|
||||
return false;
|
||||
}
|
||||
startupStages.put(STARTUP_STAGE_EXCHANGE_RATE_LOADED, true);
|
||||
|
||||
Lbry.INSTALLATION_ID = installId;
|
||||
if (Lbryio.currentUser == null) {
|
||||
Lbryio.authenticate(context);
|
||||
}
|
||||
if (Lbryio.currentUser == null) {
|
||||
throw new Exception("Did not retrieve authenticated user.");
|
||||
}
|
||||
startupStages.put(STARTUP_STAGE_USER_AUTHENTICATED, true);
|
||||
|
||||
Lbryio.newInstall(context);
|
||||
startupStages.put(STARTUP_STAGE_NEW_INSTALL_DONE, true);
|
||||
|
||||
// (light) fetch subscriptions
|
||||
if (Lbryio.subscriptions.size() == 0) {
|
||||
|
@ -1701,6 +1775,13 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
Lbryio.cacheResolvedSubscriptions = resolvedSubs;
|
||||
}
|
||||
}
|
||||
|
||||
// if no exceptions occurred here, subscriptions have been loaded and resolved
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_LOADED, true);
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED, true);
|
||||
} else {
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_LOADED, true);
|
||||
startupStages.put(STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED, true);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// nope
|
||||
|
@ -1714,8 +1795,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
protected void onPostExecute(Boolean startupSuccessful) {
|
||||
if (!startupSuccessful) {
|
||||
Toast.makeText(context, R.string.startup_failed, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
// show which startup stage failed
|
||||
renderStartupFailed(startupStages);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1901,6 +1982,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
private void registerServiceActionsReceiver() {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_EVENT);
|
||||
intentFilter.addAction(LbrynetService.LBRY_SDK_SERVICE_STARTED);
|
||||
intentFilter.addAction(LbrynetService.ACTION_STOP_SERVICE);
|
||||
serviceActionsReceiver = new BroadcastReceiver() {
|
||||
|
@ -1920,6 +2002,19 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
notificationManager.notify(1, svcNotification);
|
||||
}
|
||||
}, 1000);
|
||||
} else if (DownloadManager.ACTION_DOWNLOAD_EVENT.equalsIgnoreCase(action)) {
|
||||
String downloadAction = intent.getStringExtra("action");
|
||||
String uri = intent.getStringExtra("uri");
|
||||
String outpoint = intent.getStringExtra("outpoint");
|
||||
String fileInfoJson = intent.getStringExtra("file_info");
|
||||
double progress = intent.getDoubleExtra("progress", 0);
|
||||
if (uri == null || outpoint == null || (fileInfoJson == null && !"abort".equals(downloadAction))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (DownloadActionListener listener : downloadActionListeners) {
|
||||
listener.onDownloadAction(downloadAction, uri, outpoint, fileInfoJson, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1968,8 +2063,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
yourContentGroup.setItems(Arrays.asList(
|
||||
//new NavMenuItem(NavMenuItem.ID_ITEM_NEW_PUBLISH, R.string.fa_upload, R.string.new_publish, "NewPublish", context),
|
||||
new NavMenuItem(NavMenuItem.ID_ITEM_CHANNELS, R.string.fa_at, R.string.channels, "Channels", context)
|
||||
//new NavMenuItem(NavMenuItem.ID_ITEM_LIBRARY, R.string.fa_download, R.string.library, "Library", context)
|
||||
new NavMenuItem(NavMenuItem.ID_ITEM_CHANNELS, R.string.fa_at, R.string.channels, "Channels", context),
|
||||
new NavMenuItem(NavMenuItem.ID_ITEM_LIBRARY, R.string.fa_download, R.string.library, "Library", context)
|
||||
//new NavMenuItem(NavMenuItem.ID_ITEM_PUBLISHES, R.string.fa_cloud_upload, R.string.publishes, "Publishes", context)
|
||||
));
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -17,11 +18,14 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.listener.SelectionModeListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
@ -33,6 +37,11 @@ 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
|
||||
|
||||
private Map<String, Claim> quickClaimIdMap;
|
||||
private Map<String, Claim> quickClaimUrlMap;
|
||||
private Map<String, Boolean> notFoundClaimIdMap;
|
||||
private Map<String, Boolean> notFoundClaimUrlMap;
|
||||
|
||||
@Setter
|
||||
private boolean canEnterSelectionMode;
|
||||
private Context context;
|
||||
|
@ -50,6 +59,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
this.context = context;
|
||||
this.items = new ArrayList<>(items);
|
||||
this.selectedItems = new ArrayList<>();
|
||||
quickClaimIdMap = new HashMap<>();
|
||||
quickClaimUrlMap = new HashMap<>();
|
||||
notFoundClaimIdMap = new HashMap<>();
|
||||
notFoundClaimUrlMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public List<Claim> getSelectedItems() {
|
||||
|
@ -77,6 +90,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
public void clearItems() {
|
||||
clearSelectedItems();
|
||||
this.items.clear();
|
||||
quickClaimIdMap.clear();
|
||||
quickClaimUrlMap.clear();
|
||||
notFoundClaimIdMap.clear();
|
||||
notFoundClaimUrlMap.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
@ -91,6 +108,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
items.add(claim);
|
||||
}
|
||||
}
|
||||
|
||||
notFoundClaimUrlMap.clear();
|
||||
notFoundClaimIdMap.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void setItems(List<Claim> claims) {
|
||||
|
@ -119,6 +139,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
protected View repostInfoView;
|
||||
protected TextView repostChannelView;
|
||||
protected View selectedOverlayView;
|
||||
protected TextView fileSizeView;
|
||||
protected ProgressBar downloadProgressView;
|
||||
protected TextView deviceView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
feeContainer = v.findViewById(R.id.claim_fee_container);
|
||||
|
@ -135,6 +158,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
repostInfoView = v.findViewById(R.id.claim_repost_info);
|
||||
repostChannelView = v.findViewById(R.id.claim_repost_channel);
|
||||
selectedOverlayView = v.findViewById(R.id.claim_selected_overlay);
|
||||
fileSizeView = v.findViewById(R.id.claim_file_size);
|
||||
downloadProgressView = v.findViewById(R.id.claim_download_progress);
|
||||
deviceView = v.findViewById(R.id.claim_view_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,6 +182,68 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
return Claim.TYPE_CHANNEL.equalsIgnoreCase(actualClaim.getValueType()) ? VIEW_TYPE_CHANNEL : VIEW_TYPE_STREAM;
|
||||
}
|
||||
|
||||
public void updateFileForClaimByIdOrUrl(LbryFile file, String claimId, String url) {
|
||||
updateFileForClaimByIdOrUrl(file, claimId, url, false);
|
||||
}
|
||||
public void updateFileForClaimByIdOrUrl(LbryFile file, String claimId, String url, boolean skipNotFound) {
|
||||
if (!skipNotFound) {
|
||||
if (notFoundClaimIdMap.containsKey(claimId) && notFoundClaimUrlMap.containsKey(url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (quickClaimIdMap.containsKey(claimId)) {
|
||||
quickClaimIdMap.get(claimId).setFile(file);
|
||||
notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
if (quickClaimUrlMap.containsKey(claimId)) {
|
||||
quickClaimUrlMap.get(claimId).setFile(file);
|
||||
notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean claimFound = false;
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
Claim claim = items.get(i);
|
||||
if (claimId.equalsIgnoreCase(claim.getClaimId()) || url.equalsIgnoreCase(claim.getPermanentUrl())) {
|
||||
quickClaimIdMap.put(claimId, claim);
|
||||
quickClaimUrlMap.put(url, claim);
|
||||
claim.setFile(file);
|
||||
notifyDataSetChanged();
|
||||
claimFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!claimFound) {
|
||||
notFoundClaimIdMap.put(claimId, true);
|
||||
notFoundClaimUrlMap.put(url, true);
|
||||
}
|
||||
}
|
||||
public void clearFileForClaimOrUrl(String outpoint, String url) {
|
||||
clearFileForClaimOrUrl(outpoint, url, false);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
public void clearFileForClaimOrUrl(String outpoint, String url, boolean remove) {
|
||||
int claimIndex = -1;
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
Claim claim = items.get(i);
|
||||
if (outpoint.equalsIgnoreCase(claim.getOutpoint()) || url.equalsIgnoreCase(claim.getPermanentUrl())) {
|
||||
claimIndex = i;
|
||||
claim.setFile(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remove && claimIndex > -1) {
|
||||
Claim removed = items.remove(claimIndex);
|
||||
selectedItems.remove(removed);
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClaimListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
int viewResourceId = -1;
|
||||
|
@ -290,6 +378,24 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
|
|||
publishTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
|
||||
vh.durationView.setVisibility(duration > 0 ? View.VISIBLE : View.GONE);
|
||||
vh.durationView.setText(Helper.formatDuration(duration));
|
||||
|
||||
LbryFile claimFile = item.getFile();
|
||||
boolean isDownloading = false;
|
||||
int progress = 0;
|
||||
String fileSizeString = claimFile == null ? null : Helper.formatBytes(claimFile.getTotalBytes(), false);
|
||||
if (claimFile != null && !claimFile.isCompleted() && claimFile.getWrittenBytes() < claimFile.getTotalBytes()) {
|
||||
isDownloading = true;
|
||||
progress = claimFile.getTotalBytes() > 0 ?
|
||||
Double.valueOf(((double) claimFile.getWrittenBytes() / (double) claimFile.getTotalBytes()) * 100.0).intValue() : 0;
|
||||
fileSizeString = String.format("%s / %s",
|
||||
Helper.formatBytes(claimFile.getWrittenBytes(), false),
|
||||
Helper.formatBytes(claimFile.getTotalBytes(), false));
|
||||
}
|
||||
|
||||
Helper.setViewText(vh.fileSizeView, fileSizeString);
|
||||
Helper.setViewVisibility(vh.downloadProgressView, isDownloading ? View.VISIBLE : View.INVISIBLE);
|
||||
Helper.setViewProgress(vh.downloadProgressView, progress);
|
||||
Helper.setViewText(vh.deviceView, item.getDevice());
|
||||
} else if (Claim.TYPE_CHANNEL.equalsIgnoreCase(item.getValueType())) {
|
||||
if (!Helper.isNullOrEmpty(thumbnailUrl)) {
|
||||
Glide.with(context.getApplicationContext()).
|
||||
|
|
|
@ -4,7 +4,10 @@ import android.content.Context;
|
|||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.opengl.Visibility;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -66,6 +69,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
private static final String SQL_INSERT_VIEW_HISTORY =
|
||||
"REPLACE INTO view_history (url, claim_id, claim_name, cost, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
private static final String SQL_GET_VIEW_HISTORY =
|
||||
"SELECT url, claim_id, claim_name, cost, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp " +
|
||||
"FROM view_history WHERE '' = ? OR timestamp < ? ORDER BY timestamp DESC LIMIT %d";
|
||||
private static final String SQL_CLEAR_VIEW_HISTORY = "DELETE FROM view_history";
|
||||
private static final String SQL_CLEAR_VIEW_HISTORY_BY_DEVICE = "DELETE FROM view_history WHERE device = ?";
|
||||
private static final String SQL_CLEAR_VIEW_HISTORY_BEFORE_TIME = "DELETE FROM view_history WHERE timestamp < ?";
|
||||
|
@ -147,6 +153,41 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
});
|
||||
}
|
||||
|
||||
public static List<ViewHistory> getViewHistory(String lastTimestamp, int pageLimit, SQLiteDatabase db) {
|
||||
List<ViewHistory> history = new ArrayList<>();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
String arg = lastTimestamp == null ? "" : lastTimestamp;
|
||||
cursor = db.rawQuery(String.format(SQL_GET_VIEW_HISTORY, pageLimit), new String[] { arg, arg });
|
||||
while (cursor.moveToNext()) {
|
||||
ViewHistory item = new ViewHistory();
|
||||
int cursorIndex = 0;
|
||||
item.setUri(LbryUri.tryParse(cursor.getString(cursorIndex++)));
|
||||
item.setClaimId(cursor.getString(cursorIndex++));
|
||||
item.setClaimName(cursor.getString(cursorIndex++));
|
||||
item.setCost(new BigDecimal(cursor.getDouble(cursorIndex++)));
|
||||
item.setTitle(cursor.getString(cursorIndex++));
|
||||
item.setPublisherClaimId(cursor.getString(cursorIndex++));
|
||||
item.setPublisherName(cursor.getString(cursorIndex++));
|
||||
item.setPublisherTitle(cursor.getString(cursorIndex++));
|
||||
item.setThumbnailUrl(cursor.getString(cursorIndex++));
|
||||
item.setDevice(cursor.getString(cursorIndex++));
|
||||
item.setReleaseTime(cursor.getLong(cursorIndex++));
|
||||
try {
|
||||
item.setTimestamp(new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).parse(cursor.getString(cursorIndex)));
|
||||
} catch (ParseException ex) {
|
||||
// invalid timestamp (which shouldn't happen). Skip this item
|
||||
continue;
|
||||
}
|
||||
|
||||
history.add(item);
|
||||
}
|
||||
} finally {
|
||||
Helper.closeCursor(cursor);
|
||||
}
|
||||
return history;
|
||||
}
|
||||
|
||||
public static void createOrUpdateTag(Tag tag, SQLiteDatabase db) {
|
||||
db.execSQL(SQL_INSERT_TAG, new Object[] { tag.getLowercaseName(), tag.isFollowed() ? 1 : 0 });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package io.lbry.browser.listener;
|
||||
|
||||
public interface DownloadActionListener {
|
||||
void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress);
|
||||
}
|
|
@ -82,6 +82,9 @@ public class Claim {
|
|||
private GenericMetadata value;
|
||||
private LbryFile file; // associated file if it exists
|
||||
|
||||
// device it was viewed on (for view history)
|
||||
private String device;
|
||||
|
||||
public static Claim claimFromOutput(JSONObject item) {
|
||||
// we only need name, permanent_url, txid and nout
|
||||
Claim claim = new Claim();
|
||||
|
@ -93,6 +96,10 @@ public class Claim {
|
|||
return claim;
|
||||
}
|
||||
|
||||
public String getOutpoint() {
|
||||
return String.format("%s:%d", txid, nout);
|
||||
}
|
||||
|
||||
public boolean isFree() {
|
||||
if (!(value instanceof StreamMetadata)) {
|
||||
return true;
|
||||
|
@ -246,6 +253,8 @@ public class Claim {
|
|||
claim.setName(viewHistory.getClaimName());
|
||||
claim.setValueType(TYPE_STREAM);
|
||||
claim.setPermanentUrl(viewHistory.getUri().toString());
|
||||
claim.setDevice(viewHistory.getDevice());
|
||||
claim.setConfirmations(1);
|
||||
|
||||
StreamMetadata value = new StreamMetadata();
|
||||
value.setTitle(viewHistory.getTitle());
|
||||
|
|
|
@ -9,9 +9,12 @@ import org.json.JSONObject;
|
|||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||
public class LbryFile {
|
||||
private Claim.StreamMetadata metadata;
|
||||
private long addedOn;
|
||||
|
@ -20,6 +23,7 @@ public class LbryFile {
|
|||
private int blobsRemaining;
|
||||
private String channelClaimId;
|
||||
private String channelName;
|
||||
@EqualsAndHashCode.Include
|
||||
private String claimId;
|
||||
private String claimName;
|
||||
private boolean completed;
|
||||
|
@ -39,16 +43,50 @@ public class LbryFile {
|
|||
private String streamName;
|
||||
private String streamingUrl;
|
||||
private String suggestedFileName;
|
||||
private long timestamp;
|
||||
private long totalBytes;
|
||||
private long totalBytesLowerBound;
|
||||
private String txid;
|
||||
private long writtenBytes;
|
||||
|
||||
private Claim generatedClaim;
|
||||
|
||||
public Claim getClaim() {
|
||||
if (generatedClaim != null) {
|
||||
return generatedClaim;
|
||||
}
|
||||
|
||||
generatedClaim = new Claim();
|
||||
generatedClaim.setValueType(Claim.TYPE_STREAM);
|
||||
generatedClaim.setPermanentUrl(LbryUri.tryParse(String.format("%s#%s", claimName, claimId)).toString());
|
||||
generatedClaim.setClaimId(claimId);
|
||||
generatedClaim.setName(claimName);
|
||||
generatedClaim.setValue(metadata);
|
||||
generatedClaim.setConfirmations(1);
|
||||
generatedClaim.setTxid(txid);
|
||||
generatedClaim.setNout(nout);
|
||||
generatedClaim.setFile(this);
|
||||
|
||||
if (channelClaimId != null) {
|
||||
Claim signingChannel = new Claim();
|
||||
signingChannel.setClaimId(channelClaimId);
|
||||
signingChannel.setName(channelName);
|
||||
signingChannel.setPermanentUrl(LbryUri.tryParse(String.format("%s#%s", claimName, claimId)).toString());
|
||||
generatedClaim.setSigningChannel(signingChannel);
|
||||
}
|
||||
|
||||
return generatedClaim;
|
||||
}
|
||||
|
||||
public static LbryFile fromJSONObject(JSONObject fileObject) {
|
||||
String fileJson = fileObject.toString();
|
||||
Type type = new TypeToken<LbryFile>(){}.getType();
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
LbryFile file = gson.fromJson(fileJson, type);
|
||||
|
||||
if (file.getMetadata() != null && file.getMetadata().getReleaseTime() == 0) {
|
||||
file.getMetadata().setReleaseTime(file.getTimestamp());
|
||||
}
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Date;
|
|||
|
||||
import io.lbry.browser.exceptions.LbryUriException;
|
||||
import io.lbry.browser.utils.LbryUri;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
|
@ -39,9 +40,12 @@ public class ViewHistory {
|
|||
Claim.StreamMetadata value = (Claim.StreamMetadata) metadata;
|
||||
history.setReleaseTime(value.getReleaseTime());
|
||||
if (value.getFee() != null) {
|
||||
history.setCost(new BigDecimal(value.getFee().getAmount()));
|
||||
history.setCost(claim.getActualCost(Lbryio.LBCUSDRate));
|
||||
}
|
||||
}
|
||||
if (history.getReleaseTime() == 0) {
|
||||
history.setReleaseTime(claim.getTimestamp());
|
||||
}
|
||||
|
||||
Claim signingChannel = claim.getSigningChannel();
|
||||
if (signingChannel != null) {
|
||||
|
|
|
@ -12,12 +12,18 @@ import io.lbry.browser.utils.Lbry;
|
|||
|
||||
public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
||||
private String claimId;
|
||||
private boolean downloads;
|
||||
private int page;
|
||||
private int pageSize;
|
||||
private FileListResultHandler handler;
|
||||
private View progressView;
|
||||
private ApiCallException error;
|
||||
|
||||
public FileListTask(View progressView, FileListResultHandler handler) {
|
||||
public FileListTask(int page, int pageSize, boolean downloads, View progressView, FileListResultHandler handler) {
|
||||
this(null, progressView, handler);
|
||||
this.page = page;
|
||||
this.pageSize = pageSize;
|
||||
this.downloads = downloads;
|
||||
}
|
||||
|
||||
public FileListTask(String claimId, View progressView, FileListResultHandler handler) {
|
||||
|
@ -30,7 +36,7 @@ public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
|||
}
|
||||
protected List<LbryFile> doInBackground(Void... params) {
|
||||
try {
|
||||
return Lbry.fileList(claimId);
|
||||
return Lbry.fileList(claimId, downloads, page, pageSize);
|
||||
} catch (ApiCallException ex) {
|
||||
error = ex;
|
||||
return null;
|
||||
|
@ -40,7 +46,7 @@ public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
|||
Helper.setViewVisibility(progressView, View.GONE);
|
||||
if (handler != null) {
|
||||
if (files != null) {
|
||||
handler.onSuccess(files);
|
||||
handler.onSuccess(files, files.size() < pageSize);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
|
@ -48,7 +54,7 @@ public class FileListTask extends AsyncTask<Void, Void, List<LbryFile>> {
|
|||
}
|
||||
|
||||
public interface FileListResultHandler {
|
||||
void onSuccess(List<LbryFile> files);
|
||||
void onSuccess(List<LbryFile> files, boolean hasReachedEnd);
|
||||
void onError(Exception error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package io.lbry.browser.tasks.localdata;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.data.DatabaseHelper;
|
||||
import io.lbry.browser.model.UrlSuggestion;
|
||||
import io.lbry.browser.model.ViewHistory;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
|
||||
public class FetchViewHistoryTask extends AsyncTask<Void, Void, List<ViewHistory>> {
|
||||
private DatabaseHelper dbHelper;
|
||||
private FetchViewHistoryHandler handler;
|
||||
private int pageSize;
|
||||
private Date lastDate;
|
||||
public FetchViewHistoryTask(Date lastDate, int pageSize, DatabaseHelper dbHelper, FetchViewHistoryHandler handler) {
|
||||
this.lastDate = lastDate;
|
||||
this.pageSize = pageSize;
|
||||
this.dbHelper = dbHelper;
|
||||
this.handler = handler;
|
||||
}
|
||||
protected List<ViewHistory> doInBackground(Void... params) {
|
||||
try {
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
return DatabaseHelper.getViewHistory(
|
||||
lastDate == null ? null : new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(lastDate), pageSize, db);
|
||||
} catch (SQLiteException ex) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
protected void onPostExecute(List<ViewHistory> history) {
|
||||
if (handler != null) {
|
||||
handler.onSuccess(history, history.size() < pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
public interface FetchViewHistoryHandler {
|
||||
void onSuccess(List<ViewHistory> history, boolean hasReachedEnd);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,45 @@
|
|||
package io.lbry.browser.tasks.localdata;
|
||||
|
||||
public class SaveViewHistoryTask {
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import io.lbry.browser.data.DatabaseHelper;
|
||||
import io.lbry.browser.model.ViewHistory;
|
||||
|
||||
public class SaveViewHistoryTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private DatabaseHelper dbHelper;
|
||||
private ViewHistory history;
|
||||
private SaveViewHistoryHandler handler;
|
||||
private Exception error;
|
||||
|
||||
public SaveViewHistoryTask(ViewHistory history, DatabaseHelper dbHelper, SaveViewHistoryHandler handler) {
|
||||
this.history = history;
|
||||
this.dbHelper = dbHelper;
|
||||
this.handler = handler;
|
||||
}
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
try {
|
||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||
DatabaseHelper.createOrUpdateViewHistoryItem(history, db);
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected void onPostExecute(Boolean result) {
|
||||
if (handler != null) {
|
||||
if (result) {
|
||||
handler.onSuccess(history);
|
||||
} else {
|
||||
handler.onError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface SaveViewHistoryHandler {
|
||||
void onSuccess(ViewHistory item);
|
||||
void onError(Exception error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,12 @@ import androidx.preference.PreferenceManager;
|
|||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.exoplayer2.offline.Download;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -30,8 +34,10 @@ import io.lbry.browser.dialog.ContentFromDialogFragment;
|
|||
import io.lbry.browser.dialog.ContentScopeDialogFragment;
|
||||
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
||||
import io.lbry.browser.dialog.CustomizeTagsDialogFragment;
|
||||
import io.lbry.browser.listener.DownloadActionListener;
|
||||
import io.lbry.browser.listener.TagListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.tasks.claim.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.FollowUnfollowTagTask;
|
||||
|
@ -43,7 +49,7 @@ import io.lbry.browser.utils.Predefined;
|
|||
import lombok.Getter;
|
||||
|
||||
// TODO: Similar code to FollowingFragment and Channel page fragment. Probably make common operations (sorting/filtering) into a control
|
||||
public class AllContentFragment extends BaseFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public class AllContentFragment extends BaseFragment implements DownloadActionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@Getter
|
||||
private boolean singleTagView;
|
||||
|
@ -374,6 +380,7 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
|
|||
} else {
|
||||
LbryAnalytics.setCurrentScreen(activity, "All Content", "AllContent");
|
||||
}
|
||||
activity.addDownloadActionListener(this);
|
||||
}
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
|
||||
|
@ -384,7 +391,11 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
|
|||
}
|
||||
|
||||
public void onPause() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this);
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
((MainActivity) context).removeDownloadActionListener(this);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@ -491,4 +502,24 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
|
|||
fetchClaimSearchContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearFileForClaimOrUrl(outpoint, uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ import androidx.preference.PreferenceManager;
|
|||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -27,14 +30,16 @@ import io.lbry.browser.R;
|
|||
import io.lbry.browser.adapter.ClaimListAdapter;
|
||||
import io.lbry.browser.dialog.ContentFromDialogFragment;
|
||||
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
||||
import io.lbry.browser.listener.DownloadActionListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.tasks.claim.ClaimSearchTask;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
import io.lbry.browser.utils.Predefined;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ChannelContentFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public class ChannelContentFragment extends Fragment implements DownloadActionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@Setter
|
||||
private String channelId;
|
||||
|
@ -189,12 +194,20 @@ public class ChannelContentFragment extends Fragment implements SharedPreference
|
|||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
((MainActivity) context).addDownloadActionListener(this);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
|
||||
fetchClaimSearchContent();
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
((MainActivity) context).removeDownloadActionListener(this);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@ -300,4 +313,24 @@ public class ChannelContentFragment extends Fragment implements SharedPreference
|
|||
fetchClaimSearchContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearFileForClaimOrUrl(outpoint, uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -35,7 +38,9 @@ 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.listener.DownloadActionListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
|
||||
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||
|
@ -53,7 +58,9 @@ import io.lbry.browser.utils.Predefined;
|
|||
|
||||
public class FollowingFragment extends BaseFragment implements
|
||||
FetchSubscriptionsTask.FetchSubscriptionsHandler,
|
||||
ChannelItemSelectionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
ChannelItemSelectionListener,
|
||||
DownloadActionListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
public static boolean resetClaimSearchContent;
|
||||
private static final int SUGGESTED_PAGE_SIZE = 45;
|
||||
|
@ -334,6 +341,7 @@ public class FollowingFragment extends BaseFragment implements
|
|||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
LbryAnalytics.setCurrentScreen(activity, "Subscriptions", "Subscriptions");
|
||||
activity.addDownloadActionListener(this);
|
||||
}
|
||||
|
||||
// check if subscriptions exist
|
||||
|
@ -351,7 +359,11 @@ public class FollowingFragment extends BaseFragment implements
|
|||
}
|
||||
}
|
||||
public void onPause() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this);
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).removeDownloadActionListener(this);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this);
|
||||
super.onPause();
|
||||
}
|
||||
public void fetchLoadedSubscriptions() {
|
||||
|
@ -767,4 +779,24 @@ public class FollowingFragment extends BaseFragment implements
|
|||
fetchClaimSearchContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearFileForClaimOrUrl(outpoint, uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
package io.lbry.browser.ui.library;
|
||||
|
||||
import android.content.Context;
|
||||
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.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.adapter.ClaimListAdapter;
|
||||
import io.lbry.browser.data.DatabaseHelper;
|
||||
import io.lbry.browser.listener.DownloadActionListener;
|
||||
import io.lbry.browser.listener.SdkStatusListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.model.ViewHistory;
|
||||
import io.lbry.browser.tasks.file.FileListTask;
|
||||
import io.lbry.browser.tasks.localdata.FetchViewHistoryTask;
|
||||
import io.lbry.browser.ui.BaseFragment;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbry;
|
||||
import io.lbry.browser.utils.LbryAnalytics;
|
||||
|
||||
public class LibraryFragment extends BaseFragment implements DownloadActionListener, SdkStatusListener {
|
||||
|
||||
private static final int FILTER_DOWNLOADS = 1;
|
||||
private static final int FILTER_HISTORY = 2;
|
||||
private static final int PAGE_SIZE = 50;
|
||||
|
||||
private int currentFilter;
|
||||
private List<LbryFile> currentFiles;
|
||||
private View layoutSdkInitializing;
|
||||
private RecyclerView contentList;
|
||||
private ClaimListAdapter contentListAdapter;
|
||||
private ProgressBar listLoading;
|
||||
private TextView linkFilterDownloads;
|
||||
private TextView linkFilterHistory;
|
||||
private View layoutListEmpty;
|
||||
private TextView textListEmpty;
|
||||
private int currentPage;
|
||||
private Date lastDate;
|
||||
private boolean listReachedEnd;
|
||||
|
||||
private CardView cardStats;
|
||||
private TextView linkStats;
|
||||
private TextView linkHide;
|
||||
private View viewStatsDistribution;
|
||||
private View viewVideoStatsBar;
|
||||
private View viewAudioStatsBar;
|
||||
private View viewImageStatsBar;
|
||||
private View viewOtherStatsBar;
|
||||
private TextView textStatsTotalSize;
|
||||
private TextView textStatsTotalSizeUnits;
|
||||
private TextView textStatsVideoSize;
|
||||
private TextView textStatsAudioSize;
|
||||
private TextView textStatsImageSize;
|
||||
private TextView textStatsOtherSize;
|
||||
private View legendVideo;
|
||||
private View legendAudio;
|
||||
private View legendImage;
|
||||
private View legendOther;
|
||||
|
||||
private long totalBytes;
|
||||
private long totalVideoBytes;
|
||||
private long totalAudioBytes;
|
||||
private long totalImageBytes;
|
||||
private long totalOtherBytes;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_library, container, false);
|
||||
|
||||
layoutSdkInitializing = root.findViewById(R.id.container_library_sdk_initializing);
|
||||
|
||||
LinearLayoutManager llm = new LinearLayoutManager(getContext());
|
||||
contentList = root.findViewById(R.id.library_list);
|
||||
contentList.setLayoutManager(llm);
|
||||
|
||||
listLoading = root.findViewById(R.id.library_list_loading);
|
||||
linkFilterDownloads = root.findViewById(R.id.library_filter_link_downloads);
|
||||
linkFilterHistory = root.findViewById(R.id.library_filter_link_history);
|
||||
|
||||
layoutListEmpty = root.findViewById(R.id.library_empty_container);
|
||||
textListEmpty = root.findViewById(R.id.library_list_empty_text);
|
||||
|
||||
currentFilter = FILTER_DOWNLOADS;
|
||||
linkFilterDownloads.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
showDownloads();
|
||||
}
|
||||
});
|
||||
linkFilterHistory.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
showHistory();
|
||||
}
|
||||
});
|
||||
|
||||
// stats
|
||||
linkStats = root.findViewById(R.id.library_show_stats);
|
||||
linkHide = root.findViewById(R.id.library_hide_stats);
|
||||
cardStats = root.findViewById(R.id.library_storage_stats_card);
|
||||
viewStatsDistribution = root.findViewById(R.id.library_storage_stat_distribution);
|
||||
viewVideoStatsBar = root.findViewById(R.id.library_storage_stat_video_bar);
|
||||
viewAudioStatsBar = root.findViewById(R.id.library_storage_stat_audio_bar);
|
||||
viewImageStatsBar = root.findViewById(R.id.library_storage_stat_image_bar);
|
||||
viewOtherStatsBar = root.findViewById(R.id.library_storage_stat_other_bar);
|
||||
textStatsTotalSize = root.findViewById(R.id.library_storage_stat_used);
|
||||
textStatsTotalSizeUnits = root.findViewById(R.id.library_storage_stat_unit);
|
||||
textStatsVideoSize = root.findViewById(R.id.library_storage_stat_video_size);
|
||||
textStatsAudioSize = root.findViewById(R.id.library_storage_stat_audio_size);
|
||||
textStatsImageSize = root.findViewById(R.id.library_storage_stat_image_size);
|
||||
textStatsOtherSize = root.findViewById(R.id.library_storage_stat_other_size);
|
||||
legendVideo = root.findViewById(R.id.library_storage_legend_video);
|
||||
legendAudio = root.findViewById(R.id.library_storage_legend_audio);
|
||||
legendImage = root.findViewById(R.id.library_storage_legend_image);
|
||||
legendOther = root.findViewById(R.id.library_storage_legend_other);
|
||||
|
||||
linkStats.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
updateStats();
|
||||
cardStats.setVisibility(View.VISIBLE);
|
||||
checkStatsLink();
|
||||
}
|
||||
});
|
||||
linkHide.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
cardStats.setVisibility(View.GONE);
|
||||
checkStatsLink();
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
LbryAnalytics.setCurrentScreen(activity, "Library", "Library");
|
||||
activity.addDownloadActionListener(this);
|
||||
}
|
||||
|
||||
layoutSdkInitializing.setVisibility(
|
||||
!Lbry.SDK_READY && currentFilter == FILTER_DOWNLOADS ? View.VISIBLE : View.GONE);
|
||||
if (!Lbry.SDK_READY) {
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.addSdkStatusListener(this);
|
||||
}
|
||||
} else {
|
||||
onSdkReady();
|
||||
}
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.removeSdkStatusListener(this);
|
||||
activity.removeDownloadActionListener(this);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
public void onSdkReady() {
|
||||
layoutSdkInitializing.setVisibility(View.GONE);
|
||||
if (currentFilter == FILTER_DOWNLOADS) {
|
||||
showDownloads();
|
||||
} else if (currentFilter == FILTER_HISTORY) {
|
||||
showHistory();
|
||||
}
|
||||
}
|
||||
|
||||
private void showDownloads() {
|
||||
currentFilter = FILTER_DOWNLOADS;
|
||||
linkFilterDownloads.setTypeface(null, Typeface.BOLD);
|
||||
linkFilterHistory.setTypeface(null, Typeface.NORMAL);
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearItems();
|
||||
contentListAdapter.setCanEnterSelectionMode(true);
|
||||
}
|
||||
|
||||
checkStatsLink();
|
||||
layoutSdkInitializing.setVisibility(Lbry.SDK_READY ? View.GONE : View.VISIBLE);
|
||||
currentPage = 1;
|
||||
if (Lbry.SDK_READY) {
|
||||
fetchDownloads();
|
||||
}
|
||||
}
|
||||
|
||||
private void showHistory() {
|
||||
currentFilter = FILTER_HISTORY;
|
||||
linkFilterDownloads.setTypeface(null, Typeface.NORMAL);
|
||||
linkFilterHistory.setTypeface(null, Typeface.BOLD);
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearItems();
|
||||
contentListAdapter.setCanEnterSelectionMode(false);
|
||||
}
|
||||
|
||||
cardStats.setVisibility(View.GONE);
|
||||
checkStatsLink();
|
||||
|
||||
layoutSdkInitializing.setVisibility(View.GONE);
|
||||
lastDate = null;
|
||||
fetchHistory();
|
||||
}
|
||||
|
||||
private void initContentListAdapter(List<Claim> claims) {
|
||||
contentListAdapter = new ClaimListAdapter(claims, getContext());
|
||||
contentListAdapter.setCanEnterSelectionMode(true);
|
||||
contentListAdapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
|
||||
@Override
|
||||
public void onClaimClicked(Claim claim) {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) getContext();
|
||||
if (claim.getName().startsWith("@")) {
|
||||
activity.openChannelUrl(claim.getPermanentUrl());
|
||||
} else {
|
||||
MainActivity.openFileUrl(claim.getPermanentUrl(), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchDownloads() {
|
||||
Helper.setViewVisibility(linkStats, View.GONE);
|
||||
Helper.setViewVisibility(layoutListEmpty, View.GONE);
|
||||
FileListTask task = new FileListTask(currentPage, PAGE_SIZE, true, listLoading, new FileListTask.FileListResultHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<LbryFile> files, boolean hasReachedEnd) {
|
||||
listReachedEnd = hasReachedEnd;
|
||||
List<LbryFile> filteredFiles = Helper.filterDownloads(files);
|
||||
List<Claim> claims = Helper.claimsFromFiles(filteredFiles);
|
||||
|
||||
addFiles(filteredFiles);
|
||||
updateStats();
|
||||
checkStatsLink();
|
||||
|
||||
if (contentListAdapter == null) {
|
||||
initContentListAdapter(claims);
|
||||
} else {
|
||||
contentListAdapter.addItems(claims);
|
||||
}
|
||||
contentList.setAdapter(contentListAdapter);
|
||||
checkListEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception error) {
|
||||
// pass
|
||||
checkStatsLink();
|
||||
checkListEmpty();
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void fetchHistory() {
|
||||
Helper.setViewVisibility(layoutListEmpty, View.GONE);
|
||||
DatabaseHelper dbHelper = DatabaseHelper.getInstance();
|
||||
if (dbHelper != null) {
|
||||
FetchViewHistoryTask task = new FetchViewHistoryTask(lastDate, PAGE_SIZE, dbHelper, new FetchViewHistoryTask.FetchViewHistoryHandler() {
|
||||
@Override
|
||||
public void onSuccess(List<ViewHistory> history, boolean hasReachedEnd) {
|
||||
listReachedEnd = hasReachedEnd;
|
||||
List<Claim> claims = Helper.claimsFromViewHistory(history);
|
||||
if (contentListAdapter == null) {
|
||||
initContentListAdapter(claims);
|
||||
} else {
|
||||
contentListAdapter.addItems(claims);
|
||||
}
|
||||
contentList.setAdapter(contentListAdapter);
|
||||
checkListEmpty();
|
||||
}
|
||||
});
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
checkListEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.clearFileForClaimOrUrl(outpoint, uri, currentFilter == FILTER_DOWNLOADS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (contentListAdapter != null) {
|
||||
contentListAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri, true);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
|
||||
private void checkListEmpty() {
|
||||
layoutListEmpty.setVisibility(contentListAdapter == null || contentListAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
textListEmpty.setText(currentFilter == FILTER_DOWNLOADS ? R.string.library_no_downloads : R.string.library_no_history);
|
||||
}
|
||||
|
||||
private void addFiles(List<LbryFile> files) {
|
||||
if (currentFiles == null) {
|
||||
currentFiles = new ArrayList<>();
|
||||
}
|
||||
for (LbryFile file : files) {
|
||||
if (!currentFiles.contains(file)) {
|
||||
currentFiles.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStats() {
|
||||
totalBytes = 0;
|
||||
totalVideoBytes = 0;
|
||||
totalAudioBytes = 0;
|
||||
totalImageBytes = 0;
|
||||
totalOtherBytes = 0;
|
||||
if (currentFiles != null) {
|
||||
for (LbryFile file : currentFiles) {
|
||||
long writtenBytes = file.getWrittenBytes();
|
||||
String mime = file.getMimeType();
|
||||
if (mime != null) {
|
||||
if (mime.startsWith("video/")) {
|
||||
totalVideoBytes += writtenBytes;
|
||||
} else if (mime.startsWith("audio/")) {
|
||||
totalAudioBytes += writtenBytes;
|
||||
} else if (mime.startsWith("image/")) {
|
||||
totalImageBytes += writtenBytes;
|
||||
} else {
|
||||
totalOtherBytes += writtenBytes;
|
||||
}
|
||||
}
|
||||
|
||||
totalBytes += writtenBytes;
|
||||
}
|
||||
}
|
||||
|
||||
renderStats();
|
||||
}
|
||||
|
||||
private void renderStats() {
|
||||
String[] totalSizeParts = Helper.formatBytesParts(totalBytes, false);
|
||||
textStatsTotalSize.setText(totalSizeParts[0]);
|
||||
textStatsTotalSizeUnits.setText(totalSizeParts[1]);
|
||||
|
||||
viewStatsDistribution.setVisibility(totalBytes > 0 ? View.VISIBLE : View.GONE);
|
||||
|
||||
int percentVideo = normalizePercent((double) totalVideoBytes / (double) totalBytes * 100.0);
|
||||
legendVideo.setVisibility(totalVideoBytes > 0 ? View.VISIBLE : View.GONE);
|
||||
textStatsVideoSize.setText(Helper.formatBytes(totalVideoBytes, false));
|
||||
applyLayoutWeight(viewVideoStatsBar, percentVideo);
|
||||
|
||||
int percentAudio = normalizePercent((double) totalAudioBytes / (double) totalBytes * 100.0);
|
||||
legendAudio.setVisibility(totalAudioBytes > 0 ? View.VISIBLE : View.GONE);
|
||||
textStatsAudioSize.setText(Helper.formatBytes(totalAudioBytes, false));
|
||||
applyLayoutWeight(viewAudioStatsBar, percentAudio);
|
||||
|
||||
int percentImage = normalizePercent((double) totalImageBytes / (double) totalBytes * 100.0);
|
||||
legendImage.setVisibility(totalImageBytes > 0 ? View.VISIBLE : View.GONE);
|
||||
textStatsImageSize.setText(Helper.formatBytes(totalImageBytes, false));
|
||||
applyLayoutWeight(viewImageStatsBar, percentImage);
|
||||
|
||||
int percentOther = normalizePercent((double) totalOtherBytes / (double) totalBytes * 100.0);
|
||||
legendOther.setVisibility(totalOtherBytes > 0 ? View.VISIBLE : View.GONE);
|
||||
textStatsOtherSize.setText(Helper.formatBytes(totalOtherBytes, false));
|
||||
applyLayoutWeight(viewOtherStatsBar, percentOther);
|
||||
|
||||
// We have to get to 100 (or adjust the container accordingly)
|
||||
int totalPercent = percentVideo + percentAudio + percentImage + percentOther;
|
||||
((LinearLayout) viewStatsDistribution).setWeightSum(totalPercent);
|
||||
}
|
||||
|
||||
private void applyLayoutWeight(View view, int weight) {
|
||||
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
|
||||
params.weight = weight;
|
||||
}
|
||||
|
||||
private static int normalizePercent(double value) {
|
||||
if (value > 0 && value < 1) {
|
||||
return 1;
|
||||
}
|
||||
return Double.valueOf(Math.floor(value)).intValue();
|
||||
}
|
||||
|
||||
private void checkStatsLink() {
|
||||
linkStats.setVisibility(cardStats.getVisibility() == View.VISIBLE ||
|
||||
listLoading.getVisibility() == View.VISIBLE ||
|
||||
currentFilter == FILTER_HISTORY ?
|
||||
View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
|
@ -15,13 +15,20 @@ import androidx.preference.PreferenceManager;
|
|||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.exoplayer2.offline.Download;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.MainActivity;
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.adapter.ClaimListAdapter;
|
||||
import io.lbry.browser.listener.DownloadActionListener;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.ClaimCacheKey;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||
import io.lbry.browser.tasks.claim.ClaimSearchTask;
|
||||
import io.lbry.browser.tasks.LighthouseSearchTask;
|
||||
|
@ -34,10 +41,10 @@ import io.lbry.browser.utils.LbryUri;
|
|||
import lombok.Setter;
|
||||
|
||||
public class SearchFragment extends BaseFragment implements
|
||||
ClaimListAdapter.ClaimListItemListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private ClaimListAdapter resultListAdapter;
|
||||
ClaimListAdapter.ClaimListItemListener, DownloadActionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final int PAGE_SIZE = 25;
|
||||
|
||||
private ClaimListAdapter resultListAdapter;
|
||||
private ProgressBar loadingView;
|
||||
private RecyclerView resultList;
|
||||
private TextView noQueryView;
|
||||
|
@ -95,6 +102,7 @@ public class SearchFragment extends BaseFragment implements
|
|||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
LbryAnalytics.setCurrentScreen(activity, "Search", "Search");
|
||||
activity.addDownloadActionListener(this);
|
||||
}
|
||||
if (!Helper.isNullOrEmpty(currentQuery)) {
|
||||
logSearch(currentQuery);
|
||||
|
@ -106,7 +114,11 @@ public class SearchFragment extends BaseFragment implements
|
|||
}
|
||||
|
||||
public void onPause() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this);
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
((MainActivity) context).removeDownloadActionListener(this);
|
||||
}
|
||||
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
|
@ -262,4 +274,24 @@ public class SearchFragment extends BaseFragment implements
|
|||
search(currentQuery, currentFrom);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDownloadAction(String downloadAction, String uri, String outpoint, String fileInfoJson, double progress) {
|
||||
if ("abort".equals(downloadAction)) {
|
||||
if (resultListAdapter != null) {
|
||||
resultListAdapter.clearFileForClaimOrUrl(outpoint, uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject fileInfo = new JSONObject(fileInfoJson);
|
||||
LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
|
||||
String claimId = claimFile.getClaimId();
|
||||
if (resultListAdapter != null) {
|
||||
resultListAdapter.updateFileForClaimByIdOrUrl(claimFile, claimId, uri);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// invalid file info for download
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,11 +401,11 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
|
|||
LbryAnalytics.setCurrentScreen(activity, "Wallet", "Wallet");
|
||||
}
|
||||
|
||||
Helper.setViewVisibility(layoutAccountRecommended, hasSkippedAccount() || Lbryio.isSignedIn() ? View.GONE : View.VISIBLE);
|
||||
if (!Lbry.SDK_READY) {
|
||||
if (context instanceof MainActivity) {
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.addSdkStatusListener(this);
|
||||
activity.addWalletBalanceListener(this);
|
||||
}
|
||||
|
||||
checkReceiveAddress();
|
||||
|
@ -441,7 +441,9 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
|
|||
public void onSdkReady() {
|
||||
Context context = getContext();
|
||||
if (context instanceof MainActivity) {
|
||||
((MainActivity) context).removeSdkStatusListener(this);
|
||||
MainActivity activity = (MainActivity) context;
|
||||
activity.syncWalletAndLoadPreferences();
|
||||
activity.addWalletBalanceListener(this);
|
||||
}
|
||||
|
||||
// update view
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.provider.DocumentsContract;
|
|||
import android.provider.MediaStore;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
@ -45,9 +46,12 @@ import io.lbry.browser.data.DatabaseHelper;
|
|||
import io.lbry.browser.dialog.ContentFromDialogFragment;
|
||||
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
||||
import io.lbry.browser.model.Claim;
|
||||
import io.lbry.browser.model.LbryFile;
|
||||
import io.lbry.browser.model.Tag;
|
||||
import io.lbry.browser.model.UrlSuggestion;
|
||||
import io.lbry.browser.model.ViewHistory;
|
||||
import io.lbry.browser.tasks.localdata.SaveUrlHistoryTask;
|
||||
import io.lbry.browser.tasks.localdata.SaveViewHistoryTask;
|
||||
import okhttp3.MediaType;
|
||||
|
||||
public final class Helper {
|
||||
|
@ -61,6 +65,7 @@ public final class Helper {
|
|||
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 String FILE_SIZE_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";
|
||||
|
@ -121,6 +126,12 @@ public final class Helper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void setViewProgress(ProgressBar progressBar, int progress) {
|
||||
if (progressBar != null) {
|
||||
progressBar.setProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setViewText(TextView view, int stringResourceId) {
|
||||
if (view != null) {
|
||||
view.setText(stringResourceId);
|
||||
|
@ -183,6 +194,43 @@ public final class Helper {
|
|||
}
|
||||
return String.format("%d:%02d", minutes, seconds);
|
||||
}
|
||||
public static String[] formatBytesParts(long bytes, boolean showTB) {
|
||||
DecimalFormat formatter = new DecimalFormat(FILE_SIZE_FORMAT_PATTERN);
|
||||
if (bytes < 1048576) {
|
||||
// less than 1MB
|
||||
return new String[] { formatter.format(bytes / 1024.0), "KB" };
|
||||
}
|
||||
if (bytes < 1073741824) {
|
||||
// less than 1GB
|
||||
return new String[] { formatter.format(bytes / (1024.0 * 1024.0)), "MB" };
|
||||
}
|
||||
if (showTB) {
|
||||
if (bytes < (1073741824L * 1024L)) {
|
||||
return new String[] { formatter.format(bytes / (1024.0 * 1024.0 * 1024.0)), "GB" };
|
||||
}
|
||||
return new String[] { formatter.format(bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)), "TB" };
|
||||
}
|
||||
return new String[] { formatter.format(bytes / (1024.0 * 1024.0 * 1024.0)), "GB" };
|
||||
}
|
||||
|
||||
public static String formatBytes(long bytes, boolean showTB) {
|
||||
DecimalFormat formatter = new DecimalFormat(FILE_SIZE_FORMAT_PATTERN);
|
||||
if (bytes < 1048576) {
|
||||
// less than 1MB
|
||||
return String.format("%sKB", formatter.format(bytes / 1024.0));
|
||||
}
|
||||
if (bytes < 1073741824) {
|
||||
// less than 1GB
|
||||
return String.format("%sMB", formatter.format(bytes / (1024.0 * 1024.0)));
|
||||
}
|
||||
if (showTB) {
|
||||
if (bytes < (1073741824L * 1024L)) {
|
||||
return String.format("%sGB", formatter.format(bytes / (1024.0 * 1024.0 * 1024.0)));
|
||||
}
|
||||
return String.format("%sTB", formatter.format(bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)));
|
||||
}
|
||||
return String.format("%sGB", formatter.format(bytes / (1024.0 * 1024.0 * 1024.0)));
|
||||
}
|
||||
|
||||
public static JSONObject getJSONObject(String name, JSONObject object) {
|
||||
try {
|
||||
|
@ -571,6 +619,33 @@ public final class Helper {
|
|||
return filtered;
|
||||
}
|
||||
|
||||
public static List<LbryFile> filterDownloads(List<LbryFile> files) {
|
||||
List<LbryFile> filtered = new ArrayList<>();
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
LbryFile file = files.get(i);
|
||||
if (!Helper.isNullOrEmpty(file.getDownloadPath())) {
|
||||
filtered.add(file);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public static List<Claim> claimsFromFiles(List<LbryFile> files) {
|
||||
List<Claim> claims = new ArrayList<>();
|
||||
for (LbryFile file : files) {
|
||||
claims.add(file.getClaim());
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
public static List<Claim> claimsFromViewHistory(List<ViewHistory> history) {
|
||||
List<Claim> claims = new ArrayList<>();
|
||||
for (ViewHistory item : history) {
|
||||
claims.add(Claim.fromViewHistory(item));
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
public static void saveUrlHistory(String url, String title, int type) {
|
||||
DatabaseHelper dbHelper = DatabaseHelper.getInstance();
|
||||
if (dbHelper != null) {
|
||||
|
@ -581,4 +656,12 @@ public final class Helper {
|
|||
new SaveUrlHistoryTask(suggestion, dbHelper, null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveViewHistory(String url, Claim claim) {
|
||||
DatabaseHelper dbHelper = DatabaseHelper.getInstance();
|
||||
if (dbHelper != null) {
|
||||
ViewHistory viewHistory = ViewHistory.fromClaimWithUrlAndDeviceName(claim, url, getDeviceName());
|
||||
new SaveViewHistoryTask(viewHistory, dbHelper, null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -307,12 +307,22 @@ public final class Lbry {
|
|||
return file;
|
||||
}
|
||||
|
||||
public static List<LbryFile> fileList(String claimId) throws ApiCallException {
|
||||
public static List<LbryFile> fileList(String claimId, boolean downloads, int page, int pageSize) throws ApiCallException {
|
||||
List<LbryFile> files = new ArrayList<>();
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (!Helper.isNullOrEmpty(claimId)) {
|
||||
params.put("claim_id", claimId);
|
||||
}
|
||||
/*if (downloads) {
|
||||
params.put("file_name", null);
|
||||
params.put("comparison", "ne");
|
||||
}*/
|
||||
if (page > 0) {
|
||||
params.put("page", page);
|
||||
}
|
||||
if (pageSize > 0) {
|
||||
params.put("page_size", pageSize);
|
||||
}
|
||||
try {
|
||||
JSONObject result = (JSONObject) parseResponse(apiCall(METHOD_FILE_LIST, params));
|
||||
JSONArray items = result.getJSONArray("items");
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
<LinearLayout
|
||||
android:id="@+id/splash_view_loading_container"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -89,6 +90,198 @@
|
|||
android:layout_height="24dp"
|
||||
android:layout_marginTop="48dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/splash_view_error_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:padding="24dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/oops_something_went_wrong"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/white" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/startup_failed"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_install_id"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/installation_id_loaded"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_known_tags"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/known_tags_loaded"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_exchange_rate"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/exchange_rate_loaded"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_user_authenticated"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/user_authenticated"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_install_new"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/installation_registered"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_subscriptions_loaded"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/subscriptions_loaded"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/startup_stage_icon_subscriptions_resolved"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/white"
|
||||
android:src="@drawable/ic_check" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/subscriptions_resolved"
|
||||
android:textColor="@color/white"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
347
app/src/main/res/layout/fragment_library.xml
Normal file
347
app/src/main/res/layout/fragment_library.xml
Normal file
|
@ -0,0 +1,347 @@
|
|||
<?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">
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/library_filter_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp">
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp">
|
||||
<TextView
|
||||
android:id="@+id/library_filter_link_downloads"
|
||||
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/downloads"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/library_filter_link_history"
|
||||
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/library_filter_link_downloads"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/history"
|
||||
android:textSize="14sp" />
|
||||
<ProgressBar
|
||||
android:id="@+id/library_list_loading"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:visibility="gone" />
|
||||
<TextView
|
||||
android:id="@+id/library_show_stats"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/stats"
|
||||
android:textColor="@color/lbryGreen"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/library_storage_stats_card"
|
||||
android:layout_below="@id/library_filter_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_used"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/zero"
|
||||
android:textColor="@color/lbryGreen"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="30sp" />
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_unit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/mb"
|
||||
android:textColor="@color/lbryGreen"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/library_hide_stats"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/hide"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/library_storage_stat_distribution"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="100"
|
||||
android:visibility="gone">
|
||||
<View
|
||||
android:id="@+id/library_storage_stat_video_bar"
|
||||
android:background="@color/statsVideo"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
<View
|
||||
android:id="@+id/library_storage_stat_audio_bar"
|
||||
android:background="@color/statsAudio"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
<View
|
||||
android:id="@+id/library_storage_stat_image_bar"
|
||||
android:background="@color/statsImage"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
<View
|
||||
android:id="@+id/library_storage_stat_other_bar"
|
||||
android:background="@color/statsOther"
|
||||
android:layout_weight="0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/library_storage_legend_video"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone">
|
||||
<View
|
||||
android:id="@+id/library_storage_legend_video_icon"
|
||||
android:background="@color/statsVideo"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_centerVertical="true" />
|
||||
<TextView
|
||||
android:layout_toRightOf="@id/library_storage_legend_video_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/video"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_video_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/zero_mb"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/library_storage_legend_audio"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone">
|
||||
<View
|
||||
android:id="@+id/library_storage_legend_audio_icon"
|
||||
android:background="@color/statsAudio"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_centerVertical="true" />
|
||||
<TextView
|
||||
android:layout_toRightOf="@id/library_storage_legend_audio_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/audio"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_audio_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/zero_mb"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/library_storage_legend_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone">
|
||||
<View
|
||||
android:id="@+id/library_storage_legend_image_icon"
|
||||
android:background="@color/statsImage"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_centerVertical="true" />
|
||||
<TextView
|
||||
android:layout_toRightOf="@id/library_storage_legend_image_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/images"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_image_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/zero_mb"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/library_storage_legend_other"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone">
|
||||
<View
|
||||
android:id="@+id/library_storage_legend_other_icon"
|
||||
android:background="@color/statsOther"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_centerVertical="true" />
|
||||
<TextView
|
||||
android:layout_toRightOf="@id/library_storage_legend_other_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/other"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/library_storage_stat_other_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/zero_mb"
|
||||
android:textFontWeight="300"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/library_list"
|
||||
android:clipToPadding="false"
|
||||
android:layout_below="@id/library_storage_stats_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/library_empty_container"
|
||||
android:background="@color/pageBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:padding="36dp">
|
||||
<ImageView
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="300dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/gerbil_happy" />
|
||||
<TextView
|
||||
android:id="@+id/library_list_empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:text="@string/library_no_downloads"
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp"
|
||||
android:textFontWeight="300" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/container_library_sdk_initializing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/library_filter_card"
|
||||
android:visibility="gone">
|
||||
<include layout="@layout/container_sdk_initializing" android:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
|
@ -168,6 +168,9 @@
|
|||
android:textColor="@color/lbryGreen"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="12sp" />
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<TextView
|
||||
android:id="@+id/claim_publish_time"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -185,7 +188,36 @@
|
|||
android:textStyle="italic"
|
||||
android:textFontWeight="300"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/claim_file_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="11sp"
|
||||
android:textFontWeight="300" />
|
||||
</RelativeLayout>
|
||||
<!-- download progress bar -->
|
||||
<ProgressBar
|
||||
android:id="@+id/claim_download_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="invisible"
|
||||
style="?android:progressBarStyleHorizontal" />
|
||||
<TextView
|
||||
android:id="@+id/claim_view_device"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_gravity="end"
|
||||
android:ellipsize="end"
|
||||
android:fontFamily="@font/inter"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/lightGrey"
|
||||
android:textSize="10sp"
|
||||
android:textFontWeight="300" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
|
@ -48,6 +48,7 @@
|
|||
<color name="uriDescBlue">#3971DB</color>
|
||||
<color name="rewardDriverBlue">#2196f3</color>
|
||||
|
||||
<color name="statsVideo">@color/nextLbryGreen</color>
|
||||
<color name="statsAudio">#F6A637</color>
|
||||
<color name="statsImage">#FF4A7D</color>
|
||||
<color name="statsOther">#26BCF7</color>
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<color name="uriDescBlue">#3971DB</color>
|
||||
<color name="rewardDriverBlue">#2196f3</color>
|
||||
|
||||
<color name="statsVideo">@color/nextLbryGreen</color>
|
||||
<color name="statsAudio">#F6A637</color>
|
||||
<color name="statsImage">#FF4A7D</color>
|
||||
<color name="statsOther">#26BCF7</color>
|
||||
|
|
|
@ -93,6 +93,16 @@
|
|||
<item quantity="other">%1$s followers</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Splash -->
|
||||
<string name="oops_something_went_wrong">Oops! Something went wrong.</string>
|
||||
<string name="installation_id_loaded">Loaded Installation ID.</string>
|
||||
<string name="known_tags_loaded">Loaded local known and followed tags.</string>
|
||||
<string name="exchange_rate_loaded">Loaded LBC/USD exchange rate.</string>
|
||||
<string name="user_authenticated">User authenticated.</string>
|
||||
<string name="installation_registered">Installation registered.</string>
|
||||
<string name="subscriptions_loaded">Loaded subscriptions.</string>
|
||||
<string name="subscriptions_resolved">Resolved subscriptions.</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="user_interface">Content & User interface</string>
|
||||
<string name="other">Other</string>
|
||||
|
@ -363,6 +373,21 @@
|
|||
<string name="invite_link_copied">Invite link copied.</string>
|
||||
<string name="invite_sent_to">Invite sent to %1$s</string>
|
||||
|
||||
<!-- Library -->
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="history">History</string>
|
||||
<string name="library_no_downloads">You have not downloaded any content to this device.</string>
|
||||
<string name="library_no_history">You have not viewed any content on this device.</string>
|
||||
<string name="hide">Hide</string>
|
||||
<string name="stats">Stats</string>
|
||||
<string name="video">Video</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="mb">MB</string>
|
||||
<string name="kb">KB</string>
|
||||
<string name="gb">GB</string>
|
||||
<string name="zero_mb">0MB</string>
|
||||
|
||||
<!-- About -->
|
||||
<string name="about_lbry">About LBRY</string>
|
||||
<string name="content_freedom">Content Freedom</string>
|
||||
|
|
Loading…
Reference in a new issue