diff --git a/app/build.gradle b/app/build.gradle
index b6a9fdb..4140e14 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -78,6 +78,8 @@ dependencies {
implementation 'com.hbb20:ccp:2.3.8'
+ implementation 'com.github.chrisbanes:PhotoView:2.3.0'
+
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
@@ -86,8 +88,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
- __32bitImplementation files('libs/lbrysdk-0.72.0-release__arm.aar')
- __64bitImplementation files('libs/lbrysdk-0.72.0-release__arm64.aar')
+ __32bitImplementation files('libs/lbrysdk-0.73.1-release__arm.aar')
+ __64bitImplementation files('libs/lbrysdk-0.73.1-release__arm64.aar')
}
apply plugin: 'com.google.gms.google-services'
diff --git a/app/libs/lbrysdk-0.72.0-release__arm.aar b/app/libs/lbrysdk-0.73.1-release__arm.aar
similarity index 70%
rename from app/libs/lbrysdk-0.72.0-release__arm.aar
rename to app/libs/lbrysdk-0.73.1-release__arm.aar
index 4528d29..6058d44 100644
Binary files a/app/libs/lbrysdk-0.72.0-release__arm.aar and b/app/libs/lbrysdk-0.73.1-release__arm.aar differ
diff --git a/app/libs/lbrysdk-0.72.0-release__arm64.aar b/app/libs/lbrysdk-0.73.1-release__arm64.aar
similarity index 72%
rename from app/libs/lbrysdk-0.72.0-release__arm64.aar
rename to app/libs/lbrysdk-0.73.1-release__arm64.aar
index c35f7be..525e693 100644
Binary files a/app/libs/lbrysdk-0.72.0-release__arm64.aar and b/app/libs/lbrysdk-0.73.1-release__arm64.aar differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b5cb22f..ad1d564 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -80,5 +80,14 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/io/lbry/browser/FileViewActivity.java b/app/src/main/java/io/lbry/browser/FileViewActivity.java
index 628f244..4904047 100644
--- a/app/src/main/java/io/lbry/browser/FileViewActivity.java
+++ b/app/src/main/java/io/lbry/browser/FileViewActivity.java
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -15,7 +16,6 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.service.voice.VoiceInteractionSession;
import android.text.format.DateUtils;
import android.view.View;
import android.view.ViewGroup;
@@ -25,21 +25,22 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
+import com.github.chrisbanes.photoview.PhotoView;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
-import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
@@ -47,6 +48,10 @@ import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
@@ -58,42 +63,57 @@ import java.util.concurrent.TimeUnit;
import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.TagListAdapter;
+import io.lbry.browser.dialog.RepostClaimDialogFragment;
import io.lbry.browser.dialog.SendTipDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
+import io.lbry.browser.listener.WalletBalanceListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey;
import io.lbry.browser.model.Fee;
-import io.lbry.browser.model.File;
+import io.lbry.browser.model.LbryFile;
import io.lbry.browser.model.Tag;
import io.lbry.browser.model.lbryinc.Reward;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimSearchTask;
-import io.lbry.browser.tasks.FileListTask;
+import io.lbry.browser.model.lbryinc.Subscription;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
+import io.lbry.browser.tasks.file.DeleteFileTask;
+import io.lbry.browser.tasks.file.FileListTask;
import io.lbry.browser.tasks.GenericTaskHandler;
+import io.lbry.browser.tasks.file.GetFileTask;
import io.lbry.browser.tasks.LighthouseSearchTask;
-import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.claim.ResolveTask;
+import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
import io.lbry.browser.tasks.lbryinc.ClaimRewardTask;
import io.lbry.browser.tasks.lbryinc.FetchStatCountTask;
import io.lbry.browser.tasks.lbryinc.LogFileViewTask;
+import io.lbry.browser.ui.controls.SolidIconView;
+import io.lbry.browser.ui.following.FollowingFragment;
import io.lbry.browser.utils.Helper;
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;
public class FileViewActivity extends AppCompatActivity {
public static FileViewActivity instance = null;
private static final int RELATED_CONTENT_SIZE = 16;
- private static final int SHARE_REQUEST_CODE = 3001;
private static boolean startingShareActivity;
+ private boolean stopServiceReceived;
+ private boolean downloadInProgress;
+ private boolean downloadRequested;
+ private boolean walletBalanceInitialized;
+ private boolean inPictureInPictureMode;
private boolean hasLoadedFirstBalance;
private boolean loadFilePending;
private boolean resolving;
+ private boolean initialFileLoadDone;
private Claim claim;
private String currentUrl;
private ClaimListAdapter relatedContentAdapter;
- private File file;
private BroadcastReceiver sdkReceiver;
private Player.EventListener fileViewPlayerListener;
@@ -103,14 +123,10 @@ public class FileViewActivity extends AppCompatActivity {
private ScheduledExecutorService elapsedPlaybackScheduler;
private boolean playbackStarted;
private long startTimeMillis;
+ private GetFileTask getFileTask;
- private View buttonShareAction;
- private View buttonTipAction;
- private View buttonRepostAction;
- private View buttonDownloadAction;
- private View buttonEditAction;
- private View buttonDeleteAction;
- private View buttonReportAction;
+ private List walletBalanceListeners;
+ private BroadcastReceiver downloadEventReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -140,19 +156,22 @@ public class FileViewActivity extends AppCompatActivity {
if (Lbry.claimCache.containsKey(key)) {
claim = Lbry.claimCache.get(key);
checkAndResetNowPlayingClaim();
- file = claim.getFile();
- if (file == null) {
+ if (claim.getFile() == null) {
loadFile();
}
}
setContentView(R.layout.activity_file_view);
+ checkIsFileComplete();
currentUrl = url;
logUrlEvent(url);
if (claim == null) {
+ MainActivity.clearNowPlayingClaim(this);
resolveUrl(url);
}
+ walletBalanceListeners = new ArrayList<>();
+ registerDownloadEventReceiver();
registerSdkReceiver();
fileViewPlayerListener = new Player.EventListener() {
@@ -183,6 +202,16 @@ public class FileViewActivity extends AppCompatActivity {
renderClaim();
}
+ public void addWalletBalanceListener(WalletBalanceListener listener) {
+ if (!walletBalanceListeners.contains(listener)) {
+ walletBalanceListeners.add(listener);
+ }
+ }
+
+ public void removeWalletBalanceListener(WalletBalanceListener listener) {
+ walletBalanceListeners.remove(listener);
+ }
+
private void logUrlEvent(String url) {
Bundle bundle = new Bundle();
bundle.putString("uri", url);
@@ -212,9 +241,11 @@ public class FileViewActivity extends AppCompatActivity {
view.setPlayer(null);
view.setPlayer(MainActivity.appPlayer);
}
+
return;
}
+ initialFileLoadDone = false;
currentUrl = newUrl;
logUrlEvent(newUrl);
resetViewCount();
@@ -228,13 +259,16 @@ public class FileViewActivity extends AppCompatActivity {
if (Lbry.claimCache.containsKey(key)) {
claim = Lbry.claimCache.get(key);
checkAndResetNowPlayingClaim();
- file = claim.getFile();
- if (file == null) {
+ if (claim.getFile() == null) {
loadFile();
+ } else {
+ initialFileLoadDone = true;
+ checkInitialFileLoadDone();
}
renderClaim();
} else {
findViewById(R.id.file_view_claim_display_area).setVisibility(View.INVISIBLE);
+ MainActivity.clearNowPlayingClaim(this);
resolveUrl(newUrl);
}
}
@@ -243,18 +277,23 @@ public class FileViewActivity extends AppCompatActivity {
private void registerSdkReceiver() {
IntentFilter filter = new IntentFilter();
+ filter.addAction(LbrynetService.ACTION_STOP_SERVICE);
filter.addAction(MainActivity.ACTION_SDK_READY);
filter.addAction(MainActivity.ACTION_WALLET_BALANCE_UPDATED);
sdkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equalsIgnoreCase(MainActivity.ACTION_SDK_READY)) {
- // authenticate after we receive the sdk ready event
+ if (LbrynetService.ACTION_STOP_SERVICE.equalsIgnoreCase(action)) {
+ stopServiceReceived = true;
+ finish();
+ } else if (MainActivity.ACTION_SDK_READY.equalsIgnoreCase(action)) {
if (loadFilePending) {
loadFile();
}
- } else if (action.equalsIgnoreCase(MainActivity.ACTION_WALLET_BALANCE_UPDATED)) {
+
+ initFloatingWalletBalance();
+ } else if (MainActivity.ACTION_WALLET_BALANCE_UPDATED.equalsIgnoreCase(action)) {
onWalletBalanceUpdated();
}
}
@@ -262,6 +301,20 @@ public class FileViewActivity extends AppCompatActivity {
registerReceiver(sdkReceiver, filter);
}
+ private void initFloatingWalletBalance() {
+ if (walletBalanceInitialized) {
+ return;
+ }
+ findViewById(R.id.floating_balance_container).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ sendBroadcast(new Intent(MainActivity.ACTION_OPEN_WALLET_PAGE));
+ moveTaskToBack(true);
+ }
+ });
+ walletBalanceInitialized = true;
+ }
+
private void onWalletBalanceUpdated() {
if (Lbry.SDK_READY) {
if (!hasLoadedFirstBalance) {
@@ -272,12 +325,28 @@ public class FileViewActivity extends AppCompatActivity {
((TextView) findViewById(R.id.floating_balance_value)).setText(
Helper.shortCurrencyFormat(Lbry.walletBalance.getAvailable().doubleValue()));
+
+ for (WalletBalanceListener listener : walletBalanceListeners) {
+ if (listener != null) {
+ listener.onWalletBalanceUpdated(Lbry.walletBalance);
+ }
+ }
}
}
private String getStreamingUrl() {
- if (file != null && !Helper.isNullOrEmpty(file.getStreamingUrl())) {
- return file.getStreamingUrl();
+ LbryFile lbryFile = claim.getFile();
+ if (lbryFile != null) {
+ if (!Helper.isNullOrEmpty(lbryFile.getDownloadPath()) && lbryFile.isCompleted()) {
+ File file = new File(lbryFile.getDownloadPath());
+ if (file.exists()) {
+ return Uri.fromFile(file).toString();
+ }
+ }
+
+ if (!Helper.isNullOrEmpty(lbryFile.getStreamingUrl())) {
+ return lbryFile.getStreamingUrl();
+ }
}
return buildLbryTvStreamingUrl();
@@ -295,28 +364,42 @@ public class FileViewActivity extends AppCompatActivity {
}
loadFilePending = false;
- // TODO: Check if it's paid content and then wait for the user to explicitly request the file
String claimId = claim.getClaimId();
FileListTask task = new FileListTask(claimId, null, new FileListTask.FileListResultHandler() {
@Override
- public void onSuccess(List files) {
+ public void onSuccess(List files) {
if (files.size() > 0) {
- file = files.get(0);
- claim.setFile(file);
+ claim.setFile(files.get(0));
+ checkIsFileComplete();
}
+ initialFileLoadDone = true;
+ checkInitialFileLoadDone();
}
@Override
public void onError(Exception error) {
-
+ initialFileLoadDone = true;
+ checkInitialFileLoadDone();
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ private void checkInitialFileLoadDone() {
+ if (initialFileLoadDone) {
+ restoreMainActionButton();
+ }
+ if (claim != null && claim.isFree()) {
+ onMainActionButtonClicked();
+ }
+ }
+
protected void onResume() {
super.onResume();
MainActivity.startingFileViewActivity = false;
+ if (Lbry.SDK_READY) {
+ initFloatingWalletBalance();
+ }
}
private void resolveUrl(String url) {
@@ -326,7 +409,7 @@ public class FileViewActivity extends AppCompatActivity {
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, loadingView, new ClaimListResultHandler() {
@Override
public void onSuccess(List claims) {
- if (claims.size() > 0) {
+ if (claims.size() > 0 && !Helper.isNullOrEmpty(claims.get(0).getClaimId())) {
claim = claims.get(0);
if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType())) {
claim = claim.getRepostedClaim();
@@ -339,6 +422,8 @@ public class FileViewActivity extends AppCompatActivity {
checkAndResetNowPlayingClaim();
loadFile();
renderClaim();
+ } else {
+ // render nothing at location
}
}
@@ -415,6 +500,93 @@ public class FileViewActivity extends AppCompatActivity {
}
});
+ findViewById(R.id.file_view_action_repost).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (!Lbry.SDK_READY) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), R.string.sdk_initializing_functionality, Snackbar.LENGTH_LONG).show();
+ return;
+ }
+
+ if (claim != null) {
+ RepostClaimDialogFragment dialog = RepostClaimDialogFragment.newInstance();
+ dialog.setClaim(claim);
+ dialog.setListener(new RepostClaimDialogFragment.RepostClaimListener() {
+ @Override
+ public void onClaimReposted(Claim claim) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), R.string.content_successfully_reposted, Snackbar.LENGTH_LONG).show();
+ }
+ });
+ dialog.show(getSupportFragmentManager(), RepostClaimDialogFragment.TAG);
+ }
+ }
+ });
+
+ findViewById(R.id.file_view_action_delete).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (!Lbry.SDK_READY) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), R.string.sdk_initializing_functionality, Snackbar.LENGTH_LONG).show();
+ return;
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(FileViewActivity.this).
+ setTitle(R.string.delete_file).
+ setMessage(R.string.confirm_delete_file_message)
+ .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ deleteClaimFile();
+ }
+ }).setNegativeButton(R.string.no, null);
+ builder.show();
+ }
+ });
+
+ findViewById(R.id.file_view_action_download).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (!Lbry.SDK_READY) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), R.string.sdk_initializing_functionality, Snackbar.LENGTH_LONG).show();
+ return;
+ }
+
+ if (claim != null) {
+ if (downloadInProgress) {
+ onDownloadAborted();
+
+ // file is already downloading and not completed
+ Intent intent = new Intent(LbrynetService.ACTION_DELETE_DOWNLOAD);
+ intent.putExtra("uri", claim.getPermanentUrl());
+ intent.putExtra("nativeDelete", true);
+ sendBroadcast(intent);
+ } else {
+ downloadInProgress = true;
+ Helper.setViewVisibility(findViewById(R.id.file_view_download_progress), View.VISIBLE);
+ ((ImageView) findViewById(R.id.file_view_action_download_icon)).setImageResource(R.drawable.ic_stop);
+
+ if (!claim.isFree()) {
+ downloadRequested = true;
+ onMainActionButtonClicked();
+ } else {
+ // download the file
+ fileGet(true);
+ }
+ }
+ }
+ }
+ });
+
+ findViewById(R.id.file_view_action_report).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (claim != null) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("https://lbry.com/dmca/%s", claim.getClaimId())));
+ startActivity(intent);
+ }
+ }
+ });
+
findViewById(R.id.player_toggle_full_screen).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -427,18 +599,96 @@ public class FileViewActivity extends AppCompatActivity {
}
});
+ findViewById(R.id.file_view_publisher_name).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (claim != null && claim.getSigningChannel() != null) {
+ Claim publisher = claim.getSigningChannel();
+ Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
+ intent.putExtra("url", !Helper.isNullOrEmpty(publisher.getShortUrl()) ? publisher.getShortUrl() : publisher.getPermanentUrl());
+ sendBroadcast(intent);
+ moveTaskToBack(true);
+ }
+ }
+ });
+
+ View buttonFollowUnfollow = findViewById(R.id.file_view_icon_follow_unfollow);
+ buttonFollowUnfollow.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (claim != null && claim.getSigningChannel() != null) {
+ Claim publisher = claim.getSigningChannel();
+ boolean isFollowing = Lbryio.isFollowing(publisher);
+ Subscription subscription = Subscription.fromClaim(publisher);
+ buttonFollowUnfollow.setEnabled(false);
+ new ChannelSubscribeTask(FileViewActivity.this, publisher.getClaimId(), subscription, isFollowing, new ChannelSubscribeTask.ChannelSubscribeHandler() {
+ @Override
+ public void onSuccess() {
+ if (isFollowing) {
+ Lbryio.removeSubscription(subscription);
+ Lbryio.removeCachedResolvedSubscription(publisher);
+ } else {
+ Lbryio.addSubscription(subscription);
+ Lbryio.addCachedResolvedSubscription(publisher);
+ }
+ buttonFollowUnfollow.setEnabled(true);
+ checkIsFollowing();
+ FollowingFragment.resetClaimSearchContent = true;
+
+ // Save shared user state
+ sendBroadcast(new Intent(MainActivity.ACTION_SAVE_SHARED_USER_STATE));
+ }
+
+ @Override
+ public void onError(Exception exception) {
+ buttonFollowUnfollow.setEnabled(true);
+ }
+ }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+ });
+
RecyclerView relatedContentList = findViewById(R.id.file_view_related_content_list);
relatedContentList.setNestedScrollingEnabled(false);
LinearLayoutManager llm = new LinearLayoutManager(this);
relatedContentList.setLayoutManager(llm);
}
+ private void deleteClaimFile() {
+ if (claim != null) {
+ View actionDelete = findViewById(R.id.file_view_action_delete);
+ DeleteFileTask task = new DeleteFileTask(claim.getClaimId(), new GenericTaskHandler() {
+ @Override
+ public void beforeStart() {
+ actionDelete.setEnabled(false);
+ }
+
+ @Override
+ public void onSuccess() {
+ actionDelete.setVisibility(View.GONE);
+ findViewById(R.id.file_view_action_download).setVisibility(View.VISIBLE);
+ findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
+ actionDelete.setEnabled(true);
+ restoreMainActionButton();
+ }
+
+ @Override
+ public void onError(Exception error) {
+ actionDelete.setEnabled(true);
+ showError(error.getMessage());
+ }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
private void renderClaim() {
if (claim == null) {
return;
}
loadViewCount();
+ checkIsFollowing();
((NestedScrollView) findViewById(R.id.file_view_scroll_view)).scrollTo(0, 0);
findViewById(R.id.file_view_claim_display_area).setVisibility(View.VISIBLE);
@@ -497,7 +747,6 @@ public class FileViewActivity extends AppCompatActivity {
}
});
- boolean isFree = true;
if (metadata instanceof Claim.StreamMetadata) {
Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
long publishTime = streamMetadata.getReleaseTime() > 0 ? streamMetadata.getReleaseTime() * 1000 : claim.getTimestamp() * 1000;
@@ -506,23 +755,23 @@ public class FileViewActivity extends AppCompatActivity {
Fee fee = streamMetadata.getFee();
if (fee != null && Helper.parseDouble(fee.getAmount(), 0) > 0) {
- isFree = false;
findViewById(R.id.file_view_fee_container).setVisibility(View.VISIBLE);
((TextView) findViewById(R.id.file_view_fee)).setText(Helper.shortCurrencyFormat(Helper.parseDouble(fee.getAmount(), 0)));
}
- MaterialButton mainActionButton = findViewById(R.id.file_view_main_action_button);
- String mediaType = streamMetadata.getSource().getMediaType();
- if (mediaType.startsWith("audio") || mediaType.startsWith("video")) {
- mainActionButton.setText(R.string.play);
- } else if (mediaType.startsWith("text") || mediaType.startsWith("image")) {
- mainActionButton.setText(R.string.view);
- } else {
- mainActionButton.setText(R.string.download);
- }
+
}
- if (isFree) {
+ MaterialButton mainActionButton = findViewById(R.id.file_view_main_action_button);
+ if (claim.isPlayable()) {
+ mainActionButton.setText(R.string.play);
+ } else if (claim.isViewable()) {
+ mainActionButton.setText(R.string.view);
+ } else {
+ mainActionButton.setText(R.string.download);
+ }
+
+ if (claim.isFree() && (claim.isPlayable() || claim.isViewable())) {
onMainActionButtonClicked();
}
@@ -531,13 +780,18 @@ public class FileViewActivity extends AppCompatActivity {
private void showUnsupportedView() {
findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE);
-
findViewById(R.id.file_view_unsupported_container).setVisibility(View.VISIBLE);
+ String fileNameString = "";
+ if (claim.getFile() != null) {
+ LbryFile lbryFile = claim.getFile();
+ File file = new File(lbryFile.getDownloadPath());
+ fileNameString = String.format("\"%s\" ", file.getName());
+ }
+ ((TextView) findViewById(R.id.file_view_unsupported_text)).setText(getString(R.string.unsupported_content_desc, fileNameString));
}
private void showExoplayerView() {
findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
-
findViewById(R.id.file_view_exoplayer_container).setVisibility(View.VISIBLE);
}
@@ -545,15 +799,14 @@ public class FileViewActivity extends AppCompatActivity {
boolean newPlayerCreated = false;
if (MainActivity.appPlayer == null) {
MainActivity.appPlayer = new SimpleExoPlayer.Builder(this).build();
- MainActivity.appPlayer.setPlayWhenReady(true);
- MainActivity.appPlayer.addListener(fileViewPlayerListener);
newPlayerCreated = true;
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+
PlayerView view = findViewById(R.id.file_view_exoplayer_view);
view.setPlayer(MainActivity.appPlayer);
-
if (MainActivity.nowPlayingClaim != null &&
MainActivity.nowPlayingClaim.getClaimId().equalsIgnoreCase(claim.getClaimId()) &&
!newPlayerCreated) {
@@ -563,12 +816,17 @@ public class FileViewActivity extends AppCompatActivity {
resetPlayer();
showBuffering();
+
+ MainActivity.appPlayer.addListener(fileViewPlayerListener);
MainActivity.setNowPlayingClaim(claim, FileViewActivity.this);
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
+
+ String mediaSourceUrl = getStreamingUrl();
MediaSource mediaSource = new ProgressiveMediaSource.Factory(
new DefaultDataSourceFactory(this, userAgent),
new DefaultExtractorsFactory()
- ).createMediaSource(Uri.parse(getStreamingUrl()));
+ ).createMediaSource(Uri.parse(mediaSourceUrl));
+ MainActivity.appPlayer.setPlayWhenReady(true);
MainActivity.appPlayer.prepare(mediaSource, true, true);
}
@@ -608,12 +866,12 @@ public class FileViewActivity extends AppCompatActivity {
Claim.GenericMetadata metadata = claim.getValue();
if (metadata instanceof Claim.StreamMetadata) {
Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
-
- Fee fee = streamMetadata.getFee();
- if (fee != null && Helper.parseDouble(fee.getAmount(), 0) > 0) {
- // not free, perform a purchase
-
+ if (claim.getFile() == null && !claim.isFree()) {
+ // not free (and the user does not own the claim yet), perform a purchase
+ confirmPurchaseUrl();
} else {
+ findViewById(R.id.file_view_main_action_button).setVisibility(View.INVISIBLE);
+ findViewById(R.id.file_view_main_action_loading).setVisibility(View.VISIBLE);
handleMainActionForClaim();
}
} else {
@@ -621,32 +879,141 @@ public class FileViewActivity extends AppCompatActivity {
}
}
- private void handleMainActionForClaim() {
- startTimeMillis = System.currentTimeMillis();
- Claim.GenericMetadata metadata = claim.getValue();
- if (metadata instanceof Claim.StreamMetadata) {
- Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
- // Check the metadata type
- String mediaType = streamMetadata.getSource().getMediaType();
- // Use Exoplayer view if it's video / audio
- if (mediaType.startsWith("audio") || mediaType.startsWith("video")) {
- showExoplayerView();
- playMedia();
- } else if (mediaType.startsWith("text")) {
+ private void confirmPurchaseUrl() {
+ if (claim != null) {
+ Fee fee = ((Claim.StreamMetadata) claim.getValue()).getFee();
+ double cost = Helper.parseDouble(fee.getAmount(), 0);
+ String message = getResources().getQuantityString(R.plurals.confirm_purchase_message, cost == 1 ? 1 : 2, claim.getTitle(), cost);
+ AlertDialog.Builder builder = new AlertDialog.Builder(this).
+ setTitle(R.string.confirm_purchase).
+ setMessage(message)
+ .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ Bundle bundle = new Bundle();
+ bundle.putString("uri", currentUrl);
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_PURCHASE_URI, bundle);
- } else if (mediaType.startsWith("image")) {
-
- } else {
- // unsupported type
- showUnsupportedView();
- }
- } else {
- showError(getString(R.string.cannot_view_claim));
+ findViewById(R.id.file_view_main_action_button).setVisibility(View.INVISIBLE);
+ findViewById(R.id.file_view_main_action_loading).setVisibility(View.VISIBLE);
+ handleMainActionForClaim();
+ }
+ }).setNegativeButton(R.string.no, null);
+ builder.show();
}
}
- private void showError(String message) {
- Snackbar.make(findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
+ private void handleMainActionForClaim() {
+ if (Lbry.SDK_READY) {
+ // Check if the file already exists for the claim
+ if (claim.getFile() != null) {
+ playOrViewMedia();
+ } else {
+ fileGet(downloadRequested || !claim.isPlayable());
+ downloadRequested = false;
+ }
+ } else {
+ if (claim.isPlayable()) {
+ startTimeMillis = System.currentTimeMillis();
+ showExoplayerView();
+ playMedia();
+ } else {
+ Snackbar.make(findViewById(R.id.file_view_global_layout), R.string.sdk_initializing_functionality, Snackbar.LENGTH_LONG).show();
+ }
+ }
+ }
+
+ private void fileGet(boolean save) {
+ if (getFileTask != null && getFileTask.getStatus() != AsyncTask.Status.FINISHED) {
+ return;
+ }
+ getFileTask = new GetFileTask(claim.getPermanentUrl(), save, null, new GetFileTask.GetFileHandler() {
+ @Override
+ public void beforeStart() {
+
+ }
+
+ @Override
+ public void onSuccess(LbryFile file, boolean saveFile) {
+ // queue the download
+ if (claim != null) {
+ if (!claim.isPlayable()) {
+ logFileView(claim.getPermanentUrl(), 0);
+ }
+
+ claim.setFile(file);
+ if (saveFile) {
+ // download
+ String outpoint = String.format("%s:%d", claim.getTxid(), claim.getNout());
+ Intent intent = new Intent(LbrynetService.ACTION_QUEUE_DOWNLOAD);
+ intent.putExtra("outpoint", outpoint);
+ sendBroadcast(intent);
+ } else {
+ // streaming
+ playOrViewMedia();
+ }
+ }
+ }
+
+ @Override
+ public void onError(Exception error) {
+ showError(getString(R.string.unable_to_view_url, currentUrl));
+ restoreMainActionButton();
+ }
+ });
+ getFileTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private void playOrViewMedia() {
+ boolean handled = false;
+ String mediaType = claim.getMediaType();
+ if (!Helper.isNullOrEmpty(mediaType)) {
+ if (claim.isPlayable()) {
+ startTimeMillis = System.currentTimeMillis();
+ showExoplayerView();
+ playMedia();
+ handled = true;
+ } else if (claim.isViewable()) {
+ // check type and display
+ if (mediaType.startsWith("image")) {
+ // display the image
+ View container = findViewById(R.id.file_view_imageviewer_container);
+ PhotoView photoView = findViewById(R.id.file_view_imageviewer);
+
+ boolean fileExists = false;
+ LbryFile claimFile = claim.getFile();
+ if (claimFile != null && !Helper.isNullOrEmpty(claimFile.getDownloadPath())) {
+ File file = new File(claimFile.getDownloadPath());
+ fileExists = file.exists();
+
+ if (fileExists) {
+ Uri fileUri = Uri.fromFile(file);
+ Glide.with(getApplicationContext()).load(fileUri).centerInside().into(photoView);
+ hideFloatingWalletBalance();
+ container.setVisibility(View.VISIBLE);
+ }
+ }
+
+ if (!fileExists) {
+ showError(getString(R.string.claim_file_not_found, claimFile != null ? claimFile.getDownloadPath() : ""));
+ }
+ } else if (mediaType.startsWith("text")) {
+ // show browser (and parse markdown too)
+ }
+ handled = true;
+ }
+ }
+
+ if (!handled) {
+ showUnsupportedView();
+ }
+ }
+
+ public void showError(String message) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG).
+ setTextColor(Color.WHITE).
+ setBackgroundTint(Color.RED).
+ show();
}
private void loadRelatedContent() {
@@ -674,11 +1041,19 @@ public class FileViewActivity extends AppCompatActivity {
relatedContentAdapter.setListener(new ClaimListAdapter.ClaimListItemListener() {
@Override
public void onClaimClicked(Claim claim) {
- Intent intent = new Intent(FileViewActivity.this, FileViewActivity.class);
- intent.putExtra("claimId", claim.getClaimId());
- intent.putExtra("url", claim.getPermanentUrl());
- MainActivity.startingFileViewActivity = true;
- startActivity(intent);
+ if (claim.getName().startsWith("@")) {
+ // opening a channel
+ Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
+ intent.putExtra("url", !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
+ sendBroadcast(intent);
+ moveTaskToBack(true);
+ } else {
+ Intent intent = new Intent(FileViewActivity.this, FileViewActivity.class);
+ intent.putExtra("claimId", claim.getClaimId());
+ intent.putExtra("url", !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
+ MainActivity.startingFileViewActivity = true;
+ startActivity(intent);
+ }
}
});
@@ -703,13 +1078,30 @@ public class FileViewActivity extends AppCompatActivity {
return;
}
+ if (isImageViewerVisible()) {
+ findViewById(R.id.file_view_imageviewer_container).setVisibility(View.GONE);
+ return;
+ }
+
MainActivity.mainActive = true;
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
+ private boolean isImageViewerVisible() {
+ return findViewById(R.id.file_view_imageviewer_container).getVisibility() == View.VISIBLE;
+ }
+
+ private boolean isWebViewVisible() {
+ return false;
+ }
+
protected void onUserLeaveHint() {
+ if (stopServiceReceived) {
+ return;
+ }
+
if (startingShareActivity) {
// share activity triggered this, so reset the flag at this point
new Handler().postDelayed(new Runnable() {
@@ -727,20 +1119,25 @@ public class FileViewActivity extends AppCompatActivity {
}
protected void onStop() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- if (isInPictureInPictureMode() && MainActivity.appPlayer != null) {
- MainActivity.appPlayer.setPlayWhenReady(false);
- }
+ if (inPictureInPictureMode && MainActivity.appPlayer != null) {
+ MainActivity.appPlayer.setPlayWhenReady(false);
}
super.onStop();
}
+
protected void onDestroy() {
+ Helper.unregisterReceiver(downloadEventReceiver, this);
Helper.unregisterReceiver(sdkReceiver, this);
if (MainActivity.appPlayer != null && fileViewPlayerListener != null) {
MainActivity.appPlayer.removeListener(fileViewPlayerListener);
}
instance = null;
+
+ if (stopServiceReceived) {
+ MainActivity.stopExoplayer();
+ }
+
super.onDestroy();
}
@@ -757,6 +1154,7 @@ public class FileViewActivity extends AppCompatActivity {
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
+ inPictureInPictureMode = isInPictureInPictureMode;
if (isInPictureInPictureMode) {
renderPictureInPictureMode();
} else {
@@ -829,6 +1227,9 @@ public class FileViewActivity extends AppCompatActivity {
private void resetPlayer() {
elapsedDuration = 0;
totalDuration = 0;
+ renderElapsedDuration();
+ renderTotalDuration();
+
elapsedPlaybackScheduled = false;
if (elapsedPlaybackScheduler != null) {
elapsedPlaybackScheduler.shutdownNow();
@@ -837,6 +1238,8 @@ public class FileViewActivity extends AppCompatActivity {
playbackStarted = false;
startTimeMillis = 0;
+
+ MainActivity.appPlayer.removeListener(fileViewPlayerListener);
}
private void showBuffering() {
@@ -864,7 +1267,7 @@ public class FileViewActivity extends AppCompatActivity {
bundle.putLong("time_to_start_seconds", Double.valueOf(timeToStartMillis / 1000.0).longValue());
LbryAnalytics.logEvent(LbryAnalytics.EVENT_PLAY, bundle);
- logFileView(url, timeToStartMillis);
+ logFileView(claim.getPermanentUrl(), timeToStartMillis);
}
private void logFileView(String url, long timeToStart) {
@@ -885,6 +1288,17 @@ public class FileViewActivity extends AppCompatActivity {
}
}
+ private void checkIsFollowing() {
+ if (claim != null && claim.getSigningChannel() != null) {
+ boolean isFollowing = Lbryio.isFollowing(claim.getSigningChannel());
+ SolidIconView iconFollowUnfollow = findViewById(R.id.file_view_icon_follow_unfollow);
+ if (iconFollowUnfollow != null) {
+ iconFollowUnfollow.setText(isFollowing ? R.string.fa_heart_broken : R.string.fa_heart);
+ iconFollowUnfollow.setTextColor(ContextCompat.getColor(this, isFollowing ? R.color.foreground : R.color.red));
+ }
+ }
+ }
+
private void claimEligibleRewards() {
// attempt to claim eligible rewards after viewing or playing a file (fail silently)
ClaimRewardTask firstStreamTask = new ClaimRewardTask(Reward.TYPE_FIRST_STREAM, null, null, this, eligibleRewardHandler);
@@ -910,4 +1324,101 @@ public class FileViewActivity extends AppCompatActivity {
// pass
}
};
+
+ private void registerDownloadEventReceiver() {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_EVENT);
+ downloadEventReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String downloadAction = intent.getStringExtra("action");
+ String uri = intent.getStringExtra("uri");
+ String outpoint = intent.getStringExtra("outpoint");
+ String fileInfoJson = intent.getStringExtra("file_info");
+
+ if (uri == null || outpoint == null || (fileInfoJson == null && !"abort".equals(downloadAction))) {
+ return;
+ }
+
+ if (claim != null && !claim.getPermanentUrl().equalsIgnoreCase(uri)) {
+ return;
+ }
+
+ if ("abort".equals(downloadAction)) {
+ // handle download aborted
+ onDownloadAborted();
+ return;
+ }
+
+ ImageView downloadIconView = findViewById(R.id.file_view_action_download_icon);
+ ProgressBar downloadProgressView = findViewById(R.id.file_view_download_progress);
+
+ try {
+ JSONObject fileInfo = new JSONObject(fileInfoJson);
+ LbryFile claimFile = LbryFile.fromJSONObject(fileInfo);
+ claim.setFile(claimFile);
+
+ if (DownloadManager.ACTION_START.equals(downloadAction)) {
+ downloadInProgress = true;
+ Helper.setViewVisibility(downloadProgressView, View.VISIBLE);
+ downloadProgressView.setProgress(0);
+ downloadIconView.setImageResource(R.drawable.ic_stop);
+ } 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);
+ }
+ else if (DownloadManager.ACTION_COMPLETE.equals(downloadAction)) {
+ downloadInProgress = false;
+ downloadProgressView.setProgress(100);
+ Helper.setViewVisibility(downloadProgressView, View.GONE);
+ playOrViewMedia();
+ }
+ checkIsFileComplete();
+ } catch (JSONException ex) {
+ // invalid file info for download
+ }
+ }
+ };
+ registerReceiver(downloadEventReceiver, intentFilter);
+ }
+
+ private void checkIsFileComplete() {
+ if (claim == null) {
+ return;
+ }
+ if (claim.getFile() != null && claim.getFile().isCompleted()) {
+ Helper.setViewVisibility(findViewById(R.id.file_view_action_delete), View.VISIBLE);
+ Helper.setViewVisibility(findViewById(R.id.file_view_action_download), View.GONE);
+ } else {
+ Helper.setViewVisibility(findViewById(R.id.file_view_action_delete), View.GONE);
+ Helper.setViewVisibility(findViewById(R.id.file_view_action_download), View.VISIBLE);
+ }
+ }
+
+ private void hideFloatingWalletBalance() {
+ findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE);
+ }
+
+ private void onDownloadAborted() {
+ downloadInProgress = false;
+
+ if (claim != null) {
+ claim.setFile(null);
+ }
+ ((ImageView) findViewById(R.id.file_view_action_download_icon)).setImageResource(R.drawable.ic_download);
+ Helper.setViewVisibility(findViewById(R.id.file_view_download_progress), View.GONE);
+ Helper.setViewVisibility(findViewById(R.id.file_view_unsupported_container), View.GONE);
+
+ checkIsFileComplete();
+ restoreMainActionButton();
+ }
+
+ private void restoreMainActionButton() {
+ findViewById(R.id.file_view_main_action_loading).setVisibility(View.INVISIBLE);
+ findViewById(R.id.file_view_main_action_button).setVisibility(View.VISIBLE);
+ }
}
diff --git a/app/src/main/java/io/lbry/browser/LocalFileProvider.java b/app/src/main/java/io/lbry/browser/LocalFileProvider.java
new file mode 100644
index 0000000..87964c2
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/LocalFileProvider.java
@@ -0,0 +1,7 @@
+package io.lbry.browser;
+
+import androidx.core.content.FileProvider;
+
+public class LocalFileProvider extends FileProvider {
+
+}
diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java
index e19d205..654816c 100644
--- a/app/src/main/java/io/lbry/browser/MainActivity.java
+++ b/app/src/main/java/io/lbry/browser/MainActivity.java
@@ -25,8 +25,11 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.util.Base64;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.View;
import android.view.Menu;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
@@ -96,12 +99,12 @@ import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.model.WalletSync;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.Subscription;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimListTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimListTask;
import io.lbry.browser.tasks.lbryinc.FetchRewardsTask;
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
import io.lbry.browser.tasks.MergeSubscriptionsTask;
-import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.claim.ResolveTask;
import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler;
import io.lbry.browser.tasks.wallet.LoadSharedUserStateTask;
import io.lbry.browser.tasks.wallet.SaveSharedUserStateTask;
@@ -115,8 +118,9 @@ 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.other.AboutFragment;
import io.lbry.browser.ui.search.SearchFragment;
-import io.lbry.browser.ui.settings.SettingsFragment;
+import io.lbry.browser.ui.other.SettingsFragment;
import io.lbry.browser.ui.allcontent.AllContentFragment;
import io.lbry.browser.ui.wallet.InvitesFragment;
import io.lbry.browser.ui.wallet.RewardsFragment;
@@ -133,6 +137,8 @@ import lombok.Getter;
public class MainActivity extends AppCompatActivity implements SdkStatusListener {
+ private Map specialRouteFragmentClassMap;
+ private boolean inPictureInPictureMode;
public static SimpleExoPlayer appPlayer;
public static Claim nowPlayingClaim;
public static boolean startingFilePickerActivity = false;
@@ -141,24 +147,29 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static boolean startingSignInFlowActivity = false;
public static boolean mainActive = false;
private boolean enteringPIPMode = false;
+
+ @Getter
private String firebaseMessagingToken;
private Map openNavFragments;
private static final Map fragmentClassNavIdMap = new HashMap<>();
static {
fragmentClassNavIdMap.put(FollowingFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
- fragmentClassNavIdMap.put(WalletFragment.class, NavMenuItem.ID_ITEM_WALLET);
- fragmentClassNavIdMap.put(SettingsFragment.class, NavMenuItem.ID_ITEM_SETTINGS);
+ fragmentClassNavIdMap.put(EditorsChoiceFragment.class, NavMenuItem.ID_ITEM_EDITORS_CHOICE);
fragmentClassNavIdMap.put(AllContentFragment.class, NavMenuItem.ID_ITEM_ALL_CONTENT);
fragmentClassNavIdMap.put(ChannelManagerFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
+ fragmentClassNavIdMap.put(WalletFragment.class, NavMenuItem.ID_ITEM_WALLET);
+ fragmentClassNavIdMap.put(RewardsFragment.class, NavMenuItem.ID_ITEM_REWARDS);
+ fragmentClassNavIdMap.put(InvitesFragment.class, NavMenuItem.ID_ITEM_INVITES);
+
+ fragmentClassNavIdMap.put(SettingsFragment.class, NavMenuItem.ID_ITEM_SETTINGS);
+ fragmentClassNavIdMap.put(AboutFragment.class, NavMenuItem.ID_ITEM_ABOUT);
// Internal (sub-)pages
fragmentClassNavIdMap.put(ChannelFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
fragmentClassNavIdMap.put(SearchFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
-
- //fragmentClassNavIdMap.put(ChannelFormFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
}
@@ -179,6 +190,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final String ACTION_NOW_PLAYING_CLAIM_CLEARED = "io.lbry.browser.Broadcast.NowPlayingClaimCleared";
public static final String ACTION_OPEN_ALL_CONTENT_TAG = "io.lbry.browser.Broadcast.OpenAllContentTag";
public static final String ACTION_WALLET_BALANCE_UPDATED = "io.lbry.browser.Broadcast.WalletBalanceUpdated";
+ public static final String ACTION_OPEN_CHANNEL_URL = "io.lbry.browser.Broadcast.OpenChannelUrl";
+ public static final String ACTION_OPEN_WALLET_PAGE = "io.lbry.browser.Broadcast.OpenWalletPage";
+ public static final String ACTION_OPEN_REWARDS_PAGE = "io.lbry.browser.Broadcast.OpenRewardsPage";
+ public static final String ACTION_SAVE_SHARED_USER_STATE = "io.lbry.browser.Broadcast.SaveSharedUserState";
// preference keys
public static final String PREFERENCE_KEY_DARK_MODE = "io.lbry.browser.preference.userinterface.DarkMode";
@@ -236,6 +251,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private boolean walletSyncScheduled;
private String pendingAllContentTag;
private String pendingChannelUrl;
+ private boolean pendingOpenWalletPage;
+ private boolean pendingOpenRewardsPage;
private boolean pendingFollowingReload;
// startup stages (to be able to determine how far a user made it if startup fails)
@@ -262,7 +279,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
NavMenuItem.ID_ITEM_REWARDS,
NavMenuItem.ID_ITEM_INVITES,
- NavMenuItem.ID_ITEM_SETTINGS
+ NavMenuItem.ID_ITEM_SETTINGS,
+ NavMenuItem.ID_ITEM_ABOUT
);
public boolean isDarkMode() {
@@ -281,6 +299,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (!isDarkMode()) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
+ initSpecialRouteMap();
LbryAnalytics.init(this);
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener() {
@@ -346,6 +365,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override
public void onClick(View view) {
stopExoplayer();
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
nowPlayingClaim = null;
findViewById(R.id.global_now_playing_card).setVisibility(View.GONE);
}
@@ -400,6 +420,24 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
});
}
+ private void initSpecialRouteMap() {
+ specialRouteFragmentClassMap = new HashMap<>();
+ specialRouteFragmentClassMap.put("about", AboutFragment.class);
+ specialRouteFragmentClassMap.put("allContent", AllContentFragment.class);
+ specialRouteFragmentClassMap.put("channels", ChannelManagerFragment.class);
+ specialRouteFragmentClassMap.put("invite", InvitesFragment.class);
+ specialRouteFragmentClassMap.put("invites", InvitesFragment.class);
+ //specialRouteFragmentClassMap.put("library", LibraryFragment.class);
+ //specialRouteFragmentClassMap.put("publish", PublishFragment.class);
+ //specialRouteFragmentClassMap.put("publishes", PublishesFragment.class);
+ specialRouteFragmentClassMap.put("following", FollowingFragment.class);
+ specialRouteFragmentClassMap.put("rewards", RewardsFragment.class);
+ specialRouteFragmentClassMap.put("settings", SettingsFragment.class);
+ specialRouteFragmentClassMap.put("subscriptions", FollowingFragment.class);
+ specialRouteFragmentClassMap.put("wallet", WalletFragment.class);
+ specialRouteFragmentClassMap.put("discover", FollowingFragment.class);
+ }
+
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
checkUrlIntent(intent);
@@ -471,6 +509,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
case NavMenuItem.ID_ITEM_SETTINGS:
openFragment(SettingsFragment.class, true, NavMenuItem.ID_ITEM_SETTINGS);
break;
+ case NavMenuItem.ID_ITEM_ABOUT:
+ openFragment(AboutFragment.class, true, NavMenuItem.ID_ITEM_ABOUT);
+ break;
}
}
@@ -586,7 +627,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
super.onDestroy();
}
- private static void stopExoplayer() {
+ public static void stopExoplayer() {
if (appPlayer != null) {
appPlayer.stop(true);
appPlayer.release();
@@ -612,6 +653,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
Lbry.walletBalance = walletBalance;
updateFloatingWalletBalance();
+ updateUsdWalletBalanceInNav();
sendBroadcast(new Intent(ACTION_WALLET_BALANCE_UPDATED));
}
@@ -636,19 +678,34 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
serviceRunning = isServiceRunning(this, LbrynetService.class);
if (!serviceRunning) {
Lbry.SDK_READY = false;
+ findViewById(R.id.global_sdk_initializing_status).setVisibility(View.VISIBLE);
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
}
checkSdkReady();
showSignedInUser();
+ checkPendingOpens();
- if (!Helper.isNullOrEmpty(pendingAllContentTag)) {
- openAllContentFragmentWithTag(pendingAllContentTag);
- pendingAllContentTag = null;
+ if (Lbry.SDK_READY) {
+ findViewById(R.id.global_sdk_initializing_status).setVisibility(View.GONE);
}
+ }
+
+ private void checkPendingOpens() {
if (pendingFollowingReload) {
loadFollowingContent();
pendingFollowingReload = false;
}
+ if (!Helper.isNullOrEmpty(pendingAllContentTag)) {
+ openAllContentFragmentWithTag(pendingAllContentTag);
+ pendingAllContentTag = null;
+ } else if (!Helper.isNullOrEmpty(pendingChannelUrl)) {
+ openChannelUrl(pendingChannelUrl);
+ pendingChannelUrl = null;
+ } else if (pendingOpenWalletPage) {
+ openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET);
+ } else if (pendingOpenRewardsPage) {
+ openFragment(RewardsFragment.class, true, NavMenuItem.ID_ITEM_REWARDS);
+ }
}
@Override
@@ -679,7 +736,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
clearWunderbarFocus(view);
}
});
- findViewById(R.id.wunderbar).setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ EditText wunderbar = findViewById(R.id.wunderbar);
+ wunderbar.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (hasFocus) {
@@ -693,7 +752,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
});
- ((EditText) findViewById(R.id.wunderbar)).addTextChangedListener(new TextWatcher() {
+ wunderbar.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
@@ -711,6 +770,40 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
});
+ wunderbar.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
+ if (actionId == EditorInfo.IME_ACTION_GO) {
+ String input = Helper.getValue(wunderbar.getText());
+ boolean handled = false;
+ if (input.startsWith(LbryUri.PROTO_DEFAULT) && !input.equalsIgnoreCase(LbryUri.PROTO_DEFAULT)) {
+ try {
+ LbryUri uri = LbryUri.parse(input);
+ if (uri.isChannel()) {
+ openChannelUrl(uri.toString());
+ clearWunderbarFocus(wunderbar);
+ handled = true;
+ } else {
+ openFileUrl(uri.toString(), MainActivity.this);
+ clearWunderbarFocus(wunderbar);
+ handled = true;
+ }
+ } catch (LbryUriException ex) {
+ // pass
+ }
+ }
+ if (!handled) {
+ // search
+ launchSearch(input);
+ clearWunderbarFocus(wunderbar);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ });
urlSuggestionListAdapter = new UrlSuggestionListAdapter(this);
urlSuggestionListAdapter.setListener(new UrlSuggestionListAdapter.UrlSuggestionClickListener() {
@@ -942,6 +1035,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
playerView.setPlayer(null);
playerView.setPlayer(appPlayer);
playerView.setUseController(false);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
@@ -1014,6 +1109,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
checkSyncedWallet();
}
+ findViewById(R.id.global_sdk_initializing_status).setVisibility(View.GONE);
scheduleWalletBalanceUpdate();
scheduleWalletSyncTask();
fetchChannels();
@@ -1045,6 +1141,16 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
});
}
+ private void updateUsdWalletBalanceInNav() {
+ double usdBalance = Lbry.walletBalance.getAvailable().doubleValue() * Lbryio.LBCUSDRate;
+ if (navMenuAdapter != null) {
+ navMenuAdapter.setExtraLabelForItem(
+ NavMenuItem.ID_ITEM_WALLET,
+ Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.USD_CURRENCY_FORMAT.format(usdBalance)) : null
+ );
+ }
+ }
+
private void updateFloatingWalletBalance() {
if (!hasLoadedFirstBalance) {
findViewById(R.id.floating_balance_loading).setVisibility(View.GONE);
@@ -1222,18 +1328,30 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private void registerRequestsReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_AUTH_TOKEN_GENERATED);
- intentFilter.addAction(ACTION_OPEN_ALL_CONTENT_TAG);
intentFilter.addAction(ACTION_USER_SIGN_IN_SUCCESS);
+ intentFilter.addAction(ACTION_OPEN_ALL_CONTENT_TAG);
+ intentFilter.addAction(ACTION_OPEN_CHANNEL_URL);
+ intentFilter.addAction(ACTION_OPEN_WALLET_PAGE);
+ intentFilter.addAction(ACTION_OPEN_REWARDS_PAGE);
+ intentFilter.addAction(ACTION_SAVE_SHARED_USER_STATE);
requestsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_AUTH_TOKEN_GENERATED.equalsIgnoreCase(action)) {
handleAuthTokenGenerated(intent);
- } else if (ACTION_OPEN_ALL_CONTENT_TAG.equalsIgnoreCase(action)) {
- handleOpenContentTag(intent);
} else if (ACTION_USER_SIGN_IN_SUCCESS.equalsIgnoreCase(action)) {
handleUserSignInSuccess(intent);
+ } else if (ACTION_OPEN_ALL_CONTENT_TAG.equalsIgnoreCase(action)) {
+ handleOpenContentTag(intent);
+ } else if (ACTION_OPEN_CHANNEL_URL.equalsIgnoreCase(action)) {
+ handleOpenChannelUrl(intent);
+ } else if (ACTION_OPEN_WALLET_PAGE.equalsIgnoreCase(action)) {
+ pendingOpenWalletPage = true;
+ } else if (ACTION_OPEN_REWARDS_PAGE.equalsIgnoreCase(action)) {
+ pendingOpenRewardsPage = true;
+ } else if (ACTION_SAVE_SHARED_USER_STATE.equalsIgnoreCase(action)) {
+ saveSharedUserState();
}
}
@@ -1253,7 +1371,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private void handleUserSignInSuccess(Intent intent) {
pendingFollowingReload = true;
}
- private void handleOpenChannelUrl(String url) {
+ private void handleOpenChannelUrl(Intent intent) {
+ String url = intent.getStringExtra("url");
pendingChannelUrl = url;
}
};
@@ -1294,6 +1413,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
findViewById(R.id.global_now_playing_card).setVisibility(View.GONE);
((TextView) findViewById(R.id.global_now_playing_title)).setText(null);
((TextView) findViewById(R.id.global_now_playing_channel_title)).setText(null);
+ if (MainActivity.appPlayer != null) {
+ MainActivity.appPlayer.setPlayWhenReady(false);
+ }
}
};
registerReceiver(userActionsReceiver, intentFilter);
@@ -1592,6 +1714,13 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
if (Lbryio.totalUnclaimedRewardAmount > 0) {
showFloatingUnclaimedRewards();
+ double usdRewardAmount = Lbryio.totalUnclaimedRewardAmount * Lbryio.LBCUSDRate;
+ if (navMenuAdapter != null) {
+ navMenuAdapter.setExtraLabelForItem(
+ NavMenuItem.ID_ITEM_REWARDS,
+ Lbryio.LBCUSDRate > 0 ? String.format("$%s", Helper.USD_CURRENCY_FORMAT.format(usdRewardAmount)) : null
+ );
+ }
}
}
@@ -1620,9 +1749,15 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
String url = data.toString();
// check special urls
if (url.startsWith("lbry://?")) {
- String pagePath = url.substring(8);
+ String specialPath = url.substring(8);
+ if (specialRouteFragmentClassMap.containsKey(specialPath)) {
+ Class fragmentClass = specialRouteFragmentClassMap.get(specialPath);
+ if (fragmentClassNavIdMap.containsKey(fragmentClass)) {
+ openFragment(specialRouteFragmentClassMap.get(specialPath), true, fragmentClassNavIdMap.get(fragmentClass));
+ }
+ }
- // TODO: Handle special page paths
+ // unrecognised path will open the following by default
} else {
try {
LbryUri uri = LbryUri.parse(url);
@@ -1770,10 +1905,10 @@ 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_PUBLISHES, R.string.fa_cloud_upload, R.string.publishes, "Publishes", context)
+ //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_PUBLISHES, R.string.fa_cloud_upload, R.string.publishes, "Publishes", context)
));
walletGroup.setItems(Arrays.asList(
@@ -1837,7 +1972,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
// TODO: Broadcast startup status changes
JSONObject startupStatus = status.getJSONObject("startup_status");
- sdkReady = startupStatus.getBoolean("stream_manager") && startupStatus.getBoolean("wallet");
+ sdkReady = startupStatus.getBoolean("file_manager") && startupStatus.getBoolean("wallet");
}
} catch (ConnectException ex) {
// pass
@@ -1921,6 +2056,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
+ inPictureInPictureMode = isInPictureInPictureMode;
enteringPIPMode = false;
if (isInPictureInPictureMode) {
// Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.
@@ -1932,10 +2068,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
protected void onStop() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- if (!MainActivity.startingFileViewActivity && appPlayer != null && isInPictureInPictureMode()) {
- appPlayer.setPlayWhenReady(false);
- }
+ if (!MainActivity.startingFileViewActivity && appPlayer != null && inPictureInPictureMode) {
+ appPlayer.setPlayWhenReady(false);
}
super.onStop();
}
@@ -2044,5 +2178,4 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static boolean hasPermission(String permission, Context context) {
return (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
}
-
}
diff --git a/app/src/main/java/io/lbry/browser/adapter/NavigationMenuAdapter.java b/app/src/main/java/io/lbry/browser/adapter/NavigationMenuAdapter.java
index 2f1de9b..f5c75a5 100644
--- a/app/src/main/java/io/lbry/browser/adapter/NavigationMenuAdapter.java
+++ b/app/src/main/java/io/lbry/browser/adapter/NavigationMenuAdapter.java
@@ -16,6 +16,7 @@ import java.util.List;
import io.lbry.browser.R;
import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.ui.controls.SolidIconView;
+import io.lbry.browser.utils.Helper;
import lombok.Getter;
import lombok.Setter;
@@ -44,6 +45,16 @@ public class NavigationMenuAdapter extends RecyclerView.Adapter adapterView, View view, int position, long l) {
+ Object item = adapterView.getItemAtPosition(position);
+ if (item instanceof Claim) {
+ Claim claim = (Claim) item;
+ textNamePrefix.setText(String.format("%s%s/", LbryUri.PROTO_DEFAULT, claim.getName()));
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView) {
+
+ }
+ });
+
+ inputDeposit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ inputDeposit.setHint(hasFocus ? getString(R.string.zero) : "");
+ inlineBalanceContainer.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
+ }
+ });
+
+ linkCancel.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dismiss();
+ }
+ });
+
+ linkToggleAdvanced.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (advancedContainer.getVisibility() != View.VISIBLE) {
+ advancedContainer.setVisibility(View.VISIBLE);
+ linkToggleAdvanced.setText(R.string.hide_advanced);
+ } else {
+ advancedContainer.setVisibility(View.GONE);
+ linkToggleAdvanced.setText(R.string.show_advanced);
+ }
+ }
+ });
+
+ buttonRepost.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ validateAndRepostClaim();
+ }
+ });
+
+ onWalletBalanceUpdated(Lbry.walletBalance);
+
+ return view;
+ }
+
+ public void onResume() {
+ super.onResume();
+ Context context = getContext();
+ if (context instanceof FileViewActivity) {
+ ((FileViewActivity) context).addWalletBalanceListener(this);
+ }
+ fetchChannels();
+ }
+
+ public void onPause() {
+ Context context = getContext();
+ if (context instanceof FileViewActivity) {
+ ((FileViewActivity) context).removeWalletBalanceListener(this);
+ }
+ inputDeposit.clearFocus();
+ super.onPause();
+ }
+
+
+ private void fetchChannels() {
+ if (Lbry.ownChannels == null || Lbry.ownChannels.size() == 0) {
+ startLoading();
+ ClaimListTask task = new ClaimListTask(Claim.TYPE_CHANNEL, repostProgress, new ClaimListResultHandler() {
+ @Override
+ public void onSuccess(List claims) {
+ Lbry.ownChannels = new ArrayList<>(claims);
+ loadChannels(claims);
+ finishLoading();
+ }
+
+ @Override
+ public void onError(Exception error) {
+ // could not fetch channels
+ Context context = getContext();
+ if (context instanceof FileViewActivity) {
+ ((FileViewActivity) context).showError(error.getMessage());
+ }
+ dismiss();
+ }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ } else {
+ loadChannels(Lbry.ownChannels);
+ }
+ }
+
+ private void loadChannels(List channels) {
+ if (channelSpinnerAdapter == null) {
+ Context context = getContext();
+ channelSpinnerAdapter = new InlineChannelSpinnerAdapter(context, R.layout.spinner_item_channel, channels);
+ channelSpinner.setAdapter(channelSpinnerAdapter);
+ channelSpinnerAdapter.notifyDataSetChanged();
+ } else {
+ channelSpinnerAdapter.clear();
+ channelSpinnerAdapter.addAll(channels);
+ channelSpinnerAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onWalletBalanceUpdated(WalletBalance walletBalance) {
+ if (walletBalance != null && inlineBalanceValue != null) {
+ inlineBalanceValue.setText(Helper.shortCurrencyFormat(walletBalance.getAvailable().doubleValue()));
+ }
+ }
+
+ private void validateAndRepostClaim() {
+ String name = Helper.getValue(inputName.getText());
+ if (Helper.isNullOrEmpty(name) || !LbryUri.isNameValid(name)) {
+ showError(getString(R.string.repost_name_invalid_characters));
+ return;
+ }
+
+ String depositString = Helper.getValue(inputDeposit.getText());
+ if (Helper.isNullOrEmpty(depositString)) {
+ showError(getString(R.string.invalid_amount));
+ return;
+ }
+
+ BigDecimal bid = new BigDecimal(depositString);
+ if (bid.doubleValue() > Lbry.walletBalance.getAvailable().doubleValue()) {
+ showError(getString(R.string.insufficient_balance));
+ return;
+ }
+
+ Claim channel = (Claim) channelSpinner.getSelectedItem();
+ StreamRepostTask task = new StreamRepostTask(name, bid, claim.getClaimId(), channel.getClaimId(), repostProgress, new ClaimResultHandler() {
+ @Override
+ public void beforeStart() {
+ startLoading();
+ }
+
+ @Override
+ public void onSuccess(Claim claimResult) {
+ if (listener != null) {
+ listener.onClaimReposted(claimResult);
+ }
+ finishLoading();
+ dismiss();
+ }
+
+ @Override
+ public void onError(Exception error) {
+ showError(error.getMessage());
+ finishLoading();
+ }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private void showError(String message) {
+ Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
+ setBackgroundTint(Color.RED).
+ setTextColor(Color.WHITE).
+ show();
+ }
+
+ private void startLoading() {
+ Dialog dialog = getDialog();
+ if (dialog != null) {
+ dialog.setCanceledOnTouchOutside(false);
+ }
+ linkCancel.setEnabled(false);
+ buttonRepost.setEnabled(false);
+ inputName.setEnabled(false);
+ channelSpinner.setEnabled(false);
+ linkToggleAdvanced.setVisibility(View.INVISIBLE);
+ }
+ private void finishLoading() {
+ Dialog dialog = getDialog();
+ if (dialog != null) {
+ dialog.setCanceledOnTouchOutside(true);
+ }
+ linkCancel.setEnabled(true);
+ buttonRepost.setEnabled(true);
+ inputName.setEnabled(true);
+ channelSpinner.setEnabled(true);
+ linkToggleAdvanced.setVisibility(View.VISIBLE);
+ }
+
+ public interface RepostClaimListener {
+ void onClaimReposted(Claim claim);
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/dialog/SendTipDialogFragment.java b/app/src/main/java/io/lbry/browser/dialog/SendTipDialogFragment.java
index 1f97d49..6d9151a 100644
--- a/app/src/main/java/io/lbry/browser/dialog/SendTipDialogFragment.java
+++ b/app/src/main/java/io/lbry/browser/dialog/SendTipDialogFragment.java
@@ -1,6 +1,8 @@
package io.lbry.browser.dialog;
+import android.app.Dialog;
import android.content.Context;
+import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
@@ -21,6 +23,7 @@ import com.google.android.material.textfield.TextInputEditText;
import java.math.BigDecimal;
import java.text.DecimalFormat;
+import io.lbry.browser.FileViewActivity;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.listener.WalletBalanceListener;
@@ -52,12 +55,18 @@ public class SendTipDialogFragment extends BottomSheetDialogFragment implements
}
private void disableControls() {
- getDialog().setCanceledOnTouchOutside(false);
+ Dialog dialog = getDialog();
+ if (dialog != null) {
+ dialog.setCanceledOnTouchOutside(false);
+ }
sendButton.setEnabled(false);
cancelLink.setEnabled(false);
}
private void enableControls() {
- getDialog().setCanceledOnTouchOutside(true);
+ Dialog dialog = getDialog();
+ if (dialog != null) {
+ dialog.setCanceledOnTouchOutside(true);
+ }
sendButton.setEnabled(true);
cancelLink.setEnabled(true);
}
@@ -155,15 +164,15 @@ public class SendTipDialogFragment extends BottomSheetDialogFragment implements
public void onResume() {
super.onResume();
Context context = getContext();
- if (context instanceof MainActivity) {
- ((MainActivity) context).addWalletBalanceListener(this);
+ if (context instanceof FileViewActivity) {
+ ((FileViewActivity) context).addWalletBalanceListener(this);
}
}
public void onPause() {
Context context = getContext();
- if (context instanceof MainActivity) {
- ((MainActivity) context).removeWalletBalanceListener(this);
+ if (context instanceof FileViewActivity) {
+ ((FileViewActivity) context).removeWalletBalanceListener(this);
}
super.onPause();
}
@@ -176,8 +185,10 @@ public class SendTipDialogFragment extends BottomSheetDialogFragment implements
}
private void showError(String message) {
- Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).setBackgroundTint(
- ContextCompat.getColor(getContext(), R.color.red)).show();
+ Snackbar.make(getView(), message, Snackbar.LENGTH_LONG).
+ setBackgroundTint(Color.RED).
+ setTextColor(Color.WHITE).
+ show();
}
public interface SendTipListener {
diff --git a/app/src/main/java/io/lbry/browser/model/Claim.java b/app/src/main/java/io/lbry/browser/model/Claim.java
index 123aa04..3f24dde 100644
--- a/app/src/main/java/io/lbry/browser/model/Claim.java
+++ b/app/src/main/java/io/lbry/browser/model/Claim.java
@@ -79,7 +79,57 @@ public class Claim {
private String repostChannelUrl;
private boolean isChannelSignatureValid;
private GenericMetadata value;
- private File file; // associated file if it exists
+ private LbryFile file; // associated file if it exists
+
+ public static Claim claimFromOutput(JSONObject item) {
+ // we only need name, permanent_url, txid and nout
+ Claim claim = new Claim();
+ claim.setClaimId(Helper.getJSONString("claim_id", null, item));
+ claim.setName(Helper.getJSONString("name", null, item));
+ claim.setPermanentUrl(Helper.getJSONString("permanent_url", null, item));
+ claim.setTxid(Helper.getJSONString("txid", null, item));
+ claim.setNout(Helper.getJSONInt("nout", -1, item));
+ return claim;
+ }
+
+ public boolean isFree() {
+ if (!(value instanceof StreamMetadata)) {
+ return true;
+ }
+
+ Fee fee = ((StreamMetadata) value).getFee();
+ return fee == null || Helper.parseDouble(fee.getAmount(), 0) == 0;
+ }
+
+ public String getMediaType() {
+ if (value instanceof StreamMetadata) {
+ StreamMetadata metadata = (StreamMetadata) value;
+ String mediaType = metadata.getSource() != null ? metadata.getSource().getMediaType() : null;
+ return mediaType;
+ }
+ return null;
+ }
+
+ public boolean isPlayable() {
+ if (value instanceof StreamMetadata) {
+ StreamMetadata metadata = (StreamMetadata) value;
+ String mediaType = metadata.getSource() != null ? metadata.getSource().getMediaType() : null;
+ if (mediaType != null) {
+ return mediaType.startsWith("video") || mediaType.startsWith("audio");
+ }
+ }
+ return false;
+ }
+ public boolean isViewable() {
+ if (value instanceof StreamMetadata) {
+ StreamMetadata metadata = (StreamMetadata) value;
+ String mediaType = metadata.getSource() != null ? metadata.getSource().getMediaType() : null;
+ if (mediaType != null) {
+ return mediaType.startsWith("image") || mediaType.startsWith("text");
+ }
+ }
+ return false;
+ }
public String getThumbnailUrl() {
if (value != null && value.getThumbnail() != null) {
diff --git a/app/src/main/java/io/lbry/browser/model/File.java b/app/src/main/java/io/lbry/browser/model/LbryFile.java
similarity index 87%
rename from app/src/main/java/io/lbry/browser/model/File.java
rename to app/src/main/java/io/lbry/browser/model/LbryFile.java
index ca68e86..b9df418 100644
--- a/app/src/main/java/io/lbry/browser/model/File.java
+++ b/app/src/main/java/io/lbry/browser/model/LbryFile.java
@@ -12,7 +12,7 @@ import java.lang.reflect.Type;
import lombok.Data;
@Data
-public class File {
+public class LbryFile {
private Claim.StreamMetadata metadata;
private long addedOn;
private int blobsCompleted;
@@ -44,11 +44,11 @@ public class File {
private String txid;
private long writtenBytes;
- public static File fromJSONObject(JSONObject fileObject) {
+ public static LbryFile fromJSONObject(JSONObject fileObject) {
String fileJson = fileObject.toString();
- Type type = new TypeToken(){}.getType();
+ Type type = new TypeToken(){}.getType();
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
- File file = gson.fromJson(fileJson, type);
+ LbryFile file = gson.fromJson(fileJson, type);
return file;
}
}
diff --git a/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java b/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
index 8b9a2ea..7ee1c35 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
@@ -14,6 +14,7 @@ import java.util.Map;
import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.model.Claim;
+import io.lbry.browser.tasks.claim.ClaimResultHandler;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
@@ -65,7 +66,7 @@ public class ChannelCreateUpdateTask extends AsyncTask {
for (int i = 0; i < outputs.length(); i++) {
JSONObject output = outputs.getJSONObject(i);
if (output.has("claim_id") && output.has("claim_op")) {
- claimResult = claimFromResult(output);
+ claimResult = Claim.claimFromOutput(output);
break;
}
}
@@ -77,17 +78,6 @@ public class ChannelCreateUpdateTask extends AsyncTask {
return claimResult;
}
- private static Claim claimFromResult(JSONObject item) {
- // we only need name, permanent_url, txid and nout
- Claim claim = new Claim();
- claim.setClaimId(Helper.getJSONString("claim_id", null, item));
- claim.setName(Helper.getJSONString("name", null, item));
- claim.setPermanentUrl(Helper.getJSONString("permanent_url", null, item));
- claim.setTxid(Helper.getJSONString("txid", null, item));
- claim.setNout(Helper.getJSONInt("nout", -1, item));
- return claim;
- }
-
protected void onPostExecute(Claim result) {
Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) {
diff --git a/app/src/main/java/io/lbry/browser/tasks/LighthouseSearchTask.java b/app/src/main/java/io/lbry/browser/tasks/LighthouseSearchTask.java
index 7003399..ae3f907 100644
--- a/app/src/main/java/io/lbry/browser/tasks/LighthouseSearchTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/LighthouseSearchTask.java
@@ -9,6 +9,7 @@ import java.util.List;
import io.lbry.browser.exceptions.LbryRequestException;
import io.lbry.browser.exceptions.LbryResponseException;
import io.lbry.browser.model.Claim;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lighthouse;
diff --git a/app/src/main/java/io/lbry/browser/tasks/ClaimListResultHandler.java b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimListResultHandler.java
similarity index 83%
rename from app/src/main/java/io/lbry/browser/tasks/ClaimListResultHandler.java
rename to app/src/main/java/io/lbry/browser/tasks/claim/ClaimListResultHandler.java
index 2f4ce40..2d427e8 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ClaimListResultHandler.java
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimListResultHandler.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.claim;
import java.util.List;
diff --git a/app/src/main/java/io/lbry/browser/tasks/ClaimListTask.java b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimListTask.java
similarity index 98%
rename from app/src/main/java/io/lbry/browser/tasks/ClaimListTask.java
rename to app/src/main/java/io/lbry/browser/tasks/claim/ClaimListTask.java
index 67a33d3..90fa345 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ClaimListTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimListTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.claim;
import android.os.AsyncTask;
import android.view.View;
diff --git a/app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimResultHandler.java
similarity index 82%
rename from app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java
rename to app/src/main/java/io/lbry/browser/tasks/claim/ClaimResultHandler.java
index deb0544..5171486 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimResultHandler.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.claim;
import io.lbry.browser.model.Claim;
diff --git a/app/src/main/java/io/lbry/browser/tasks/ClaimSearchTask.java b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimSearchTask.java
similarity index 97%
rename from app/src/main/java/io/lbry/browser/tasks/ClaimSearchTask.java
rename to app/src/main/java/io/lbry/browser/tasks/claim/ClaimSearchTask.java
index f8bc710..e480d5d 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ClaimSearchTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/ClaimSearchTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.claim;
import android.os.AsyncTask;
import android.view.View;
diff --git a/app/src/main/java/io/lbry/browser/tasks/ResolveTask.java b/app/src/main/java/io/lbry/browser/tasks/claim/ResolveTask.java
similarity index 94%
rename from app/src/main/java/io/lbry/browser/tasks/ResolveTask.java
rename to app/src/main/java/io/lbry/browser/tasks/claim/ResolveTask.java
index 52e3725..5cab8c9 100644
--- a/app/src/main/java/io/lbry/browser/tasks/ResolveTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/ResolveTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.claim;
import android.os.AsyncTask;
import android.view.View;
@@ -8,6 +8,7 @@ import java.util.List;
import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.model.Claim;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
diff --git a/app/src/main/java/io/lbry/browser/tasks/claim/StreamRepostTask.java b/app/src/main/java/io/lbry/browser/tasks/claim/StreamRepostTask.java
new file mode 100644
index 0000000..a1fbed8
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/tasks/claim/StreamRepostTask.java
@@ -0,0 +1,75 @@
+package io.lbry.browser.tasks.claim;
+
+import android.os.AsyncTask;
+import android.view.View;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.lbry.browser.exceptions.ApiCallException;
+import io.lbry.browser.model.Claim;
+import io.lbry.browser.utils.Helper;
+import io.lbry.browser.utils.Lbry;
+
+public class StreamRepostTask extends AsyncTask {
+ private String name;
+ private BigDecimal bid;
+ private String claimId;
+ private String channelId;
+ private View progressView;
+ private ClaimResultHandler handler;
+ private Exception error;
+
+ public StreamRepostTask(String name, BigDecimal bid, String claimId, String channelId, View progressView, ClaimResultHandler handler) {
+ this.name = name;
+ this.bid = bid;
+ this.claimId = claimId;
+ this.channelId = channelId;
+ this.progressView = progressView;
+ this.handler = handler;
+ }
+
+ protected Claim doInBackground(Void... params) {
+ Claim claimResult = null;
+ try {
+ Map options = new HashMap<>();
+ options.put("name", name);
+ options.put("bid", new DecimalFormat(Helper.SDK_AMOUNT_FORMAT).format(bid.doubleValue()));
+ options.put("claim_id", claimId);
+ options.put("channel_id", channelId);
+
+ JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_STREAM_REPOST, options);
+ if (result.has("outputs")) {
+ JSONArray outputs = result.getJSONArray("outputs");
+ for (int i = 0; i < outputs.length(); i++) {
+ JSONObject output = outputs.getJSONObject(i);
+ if (output.has("claim_id") && output.has("claim_op")) {
+ claimResult = Claim.claimFromOutput(output);
+ break;
+ }
+ }
+ }
+ } catch (ApiCallException | ClassCastException | JSONException ex) {
+ error = ex;
+ }
+
+ return claimResult;
+ }
+
+ protected void onPostExecute(Claim result) {
+ Helper.setViewVisibility(progressView, View.GONE);
+ if (handler != null) {
+ if (result != null) {
+ handler.onSuccess(result);
+ } else {
+ handler.onError(error);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/tasks/file/DeleteFileTask.java b/app/src/main/java/io/lbry/browser/tasks/file/DeleteFileTask.java
new file mode 100644
index 0000000..ba587bb
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/tasks/file/DeleteFileTask.java
@@ -0,0 +1,42 @@
+package io.lbry.browser.tasks.file;
+
+import android.os.AsyncTask;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.lbry.browser.exceptions.ApiCallException;
+import io.lbry.browser.tasks.GenericTaskHandler;
+import io.lbry.browser.utils.Lbry;
+
+public class DeleteFileTask extends AsyncTask {
+ private String claimId;
+ private Exception error;
+ private GenericTaskHandler handler;
+
+ public DeleteFileTask(String claimId, GenericTaskHandler handler) {
+ this.claimId = claimId;
+ this.handler = handler;
+ }
+
+ protected Boolean doInBackground(Void... params) {
+ try {
+ Map options = new HashMap<>();
+ options.put("claim_id", claimId);
+ options.put("delete_from_download_dir", true);
+ return (boolean) Lbry.genericApiCall(Lbry.METHOD_FILE_DELETE, options);
+ } catch (ApiCallException ex) {
+ return false;
+ }
+ }
+
+ protected void onPostExecute(Boolean result) {
+ if (handler != null) {
+ if (result) {
+ handler.onSuccess();
+ } else {
+ handler.onError(error);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/tasks/FileListTask.java b/app/src/main/java/io/lbry/browser/tasks/file/FileListTask.java
similarity index 80%
rename from app/src/main/java/io/lbry/browser/tasks/FileListTask.java
rename to app/src/main/java/io/lbry/browser/tasks/file/FileListTask.java
index c57128b..58ef143 100644
--- a/app/src/main/java/io/lbry/browser/tasks/FileListTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/file/FileListTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks;
+package io.lbry.browser.tasks.file;
import android.os.AsyncTask;
import android.view.View;
@@ -6,11 +6,11 @@ import android.view.View;
import java.util.List;
import io.lbry.browser.exceptions.ApiCallException;
-import io.lbry.browser.model.File;
+import io.lbry.browser.model.LbryFile;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
-public class FileListTask extends AsyncTask> {
+public class FileListTask extends AsyncTask> {
private String claimId;
private FileListResultHandler handler;
private View progressView;
@@ -28,7 +28,7 @@ public class FileListTask extends AsyncTask> {
protected void onPreExecute() {
Helper.setViewVisibility(progressView, View.VISIBLE);
}
- protected List doInBackground(Void... params) {
+ protected List doInBackground(Void... params) {
try {
return Lbry.fileList(claimId);
} catch (ApiCallException ex) {
@@ -36,7 +36,7 @@ public class FileListTask extends AsyncTask> {
return null;
}
}
- protected void onPostExecute(List files) {
+ protected void onPostExecute(List files) {
Helper.setViewVisibility(progressView, View.GONE);
if (handler != null) {
if (files != null) {
@@ -48,7 +48,7 @@ public class FileListTask extends AsyncTask> {
}
public interface FileListResultHandler {
- void onSuccess(List files);
+ void onSuccess(List files);
void onError(Exception error);
}
}
diff --git a/app/src/main/java/io/lbry/browser/tasks/file/GetFileTask.java b/app/src/main/java/io/lbry/browser/tasks/file/GetFileTask.java
new file mode 100644
index 0000000..6460195
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/tasks/file/GetFileTask.java
@@ -0,0 +1,72 @@
+package io.lbry.browser.tasks.file;
+
+import android.os.AsyncTask;
+import android.view.View;
+
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.lbry.browser.exceptions.ApiCallException;
+import io.lbry.browser.model.LbryFile;
+import io.lbry.browser.utils.Helper;
+import io.lbry.browser.utils.Lbry;
+
+public class GetFileTask extends AsyncTask {
+ private String uri;
+ private boolean saveFile;
+ private View progressView;
+ private GetFileHandler handler;
+ private Exception error;
+
+ public GetFileTask(String uri, boolean saveFile, View progressView, GetFileHandler handler) {
+ this.uri = uri;
+ this.saveFile = saveFile;
+ this.progressView = progressView;
+ this.handler = handler;
+ }
+
+ protected void onPreExecute() {
+ Helper.setViewVisibility(progressView, View.VISIBLE);
+ if (handler != null) {
+ handler.beforeStart();
+ }
+ }
+
+ protected LbryFile doInBackground(Void... params) {
+ LbryFile file = null;
+ try {
+ Map options = new HashMap<>();
+ options.put("uri", uri);
+ options.put("save_file", saveFile);
+ JSONObject streamInfo = (JSONObject) Lbry.genericApiCall("get", options);
+ if (streamInfo.has("error")) {
+ throw new ApiCallException(Helper.getJSONString("error", "", streamInfo));
+ }
+
+ file = LbryFile.fromJSONObject(streamInfo);
+ } catch (ApiCallException ex) {
+ error = ex;
+ }
+
+ return file;
+ }
+
+ protected void onPostExecute(LbryFile file) {
+ Helper.setViewVisibility(progressView, View.GONE);
+ if (handler != null) {
+ if (file != null) {
+ handler.onSuccess(file, saveFile);
+ } else {
+ handler.onError(error);
+ }
+ }
+ }
+
+ public interface GetFileHandler {
+ void beforeStart();
+ void onSuccess(LbryFile file, boolean saveFile);
+ void onError(Exception error);
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java b/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
index 64b9fd5..9eb165e 100644
--- a/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
@@ -33,7 +33,7 @@ import io.lbry.browser.dialog.CustomizeTagsDialogFragment;
import io.lbry.browser.listener.TagListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.Tag;
-import io.lbry.browser.tasks.ClaimSearchTask;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.tasks.FollowUnfollowTagTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
index 542ee2e..ad4c337 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
@@ -28,7 +28,7 @@ import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.dialog.ContentFromDialogFragment;
import io.lbry.browser.dialog.ContentSortDialogFragment;
import io.lbry.browser.model.Claim;
-import io.lbry.browser.tasks.ClaimSearchTask;
+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;
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
index d546a1e..926143d 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
@@ -45,7 +45,7 @@ import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.tasks.UpdateSuggestedTagsTask;
import io.lbry.browser.tasks.UploadImageTask;
import io.lbry.browser.tasks.ChannelCreateUpdateTask;
-import io.lbry.browser.tasks.ClaimResultHandler;
+import io.lbry.browser.tasks.claim.ClaimResultHandler;
import io.lbry.browser.tasks.lbryinc.LogPublishTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
index 73f17a5..d08d253 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
@@ -37,8 +37,8 @@ import io.lbry.browser.listener.FetchChannelsListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ResolveTask;
import io.lbry.browser.tasks.lbryinc.FetchStatCountTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.ui.controls.SolidIconView;
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
index 0d0207e..62c1b38 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
@@ -10,11 +10,9 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -22,7 +20,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -35,8 +32,8 @@ import io.lbry.browser.listener.SdkStatusListener;
import io.lbry.browser.listener.SelectionModeListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.NavMenuItem;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimListTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimListTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
diff --git a/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java b/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
index 8cfa9b3..25a0649 100644
--- a/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
@@ -25,17 +25,14 @@ import java.util.Map;
import io.lbry.browser.FileViewActivity;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
-import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.EditorsChoiceItemAdapter;
-import io.lbry.browser.dialog.ContentScopeDialogFragment;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.EditorsChoiceItem;
-import io.lbry.browser.tasks.ClaimSearchTask;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
import io.lbry.browser.utils.LbryAnalytics;
-import io.lbry.browser.utils.Predefined;
public class EditorsChoiceFragment extends BaseFragment {
diff --git a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
index 8a9b8fd..be5f3fa 100644
--- a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
@@ -38,10 +38,10 @@ import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimSearchTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.tasks.lbryinc.FetchSubscriptionsTask;
-import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.claim.ResolveTask;
import io.lbry.browser.listener.ChannelItemSelectionListener;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
diff --git a/app/src/main/java/io/lbry/browser/ui/other/AboutFragment.java b/app/src/main/java/io/lbry/browser/ui/other/AboutFragment.java
new file mode 100644
index 0000000..bf7e753
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/ui/other/AboutFragment.java
@@ -0,0 +1,245 @@
+package io.lbry.browser.ui.other;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.core.content.FileProvider;
+import androidx.preference.PreferenceManager;
+
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.android.material.snackbar.Snackbar;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.InstanceIdResult;
+
+import org.json.JSONObject;
+
+import java.io.File;
+
+import io.lbry.browser.MainActivity;
+import io.lbry.browser.R;
+import io.lbry.browser.exceptions.ApiCallException;
+import io.lbry.browser.listener.SdkStatusListener;
+import io.lbry.browser.ui.BaseFragment;
+import io.lbry.browser.utils.Helper;
+import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
+import io.lbry.browser.utils.Lbryio;
+import io.lbry.lbrysdk.Utils;
+
+public class AboutFragment extends BaseFragment implements SdkStatusListener {
+
+ private static final String FILE_PROVIDER = "io.lbry.browser.fileprovider";
+
+ private TextView textLinkWhatIsLBRY;
+ private TextView textLinkAndroidBasics;
+ private TextView textLinkFAQ;
+ private TextView textLinkDiscord;
+ private TextView textLinkFacebook;
+ private TextView textLinkInstagram;
+ private TextView textLinkReddit;
+ private TextView textLinkTelegram;
+ private TextView textLinkTwitter;
+
+ private TextView textConnectedEmail;
+ private TextView textAppVersion;
+ private TextView textLbrySdkVersion;
+ private TextView textPlatform;
+ private TextView textInstallationId;
+ private TextView textFirebaseToken;
+ private View linkSendLog;
+ private View linkUpdateMailingPreferences;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.fragment_about, container, false);
+
+ textLinkWhatIsLBRY = root.findViewById(R.id.about_link_what_is_lbry);
+ textLinkAndroidBasics = root.findViewById(R.id.about_link_android_basics);
+ textLinkFAQ = root.findViewById(R.id.about_link_faq);
+ textLinkDiscord = root.findViewById(R.id.about_link_discord);
+ textLinkFacebook = root.findViewById(R.id.about_link_facebook);
+ textLinkInstagram = root.findViewById(R.id.about_link_instagram);
+ textLinkReddit = root.findViewById(R.id.about_link_reddit);
+ textLinkTelegram = root.findViewById(R.id.about_link_telegram);
+ textLinkTwitter = root.findViewById(R.id.about_link_twitter);
+
+ TextView[] textLinks = {
+ textLinkWhatIsLBRY, textLinkAndroidBasics, textLinkFAQ, textLinkDiscord, textLinkFacebook,
+ textLinkInstagram, textLinkReddit, textLinkTelegram, textLinkTwitter
+ };
+ for (TextView view : textLinks) {
+ Helper.applyHtmlForTextView(view);
+ }
+
+ textConnectedEmail = root.findViewById(R.id.about_connected_email);
+ textAppVersion = root.findViewById(R.id.about_app_version);
+ textLbrySdkVersion = root.findViewById(R.id.about_lbry_sdk);
+ textPlatform = root.findViewById(R.id.about_platform);
+ textInstallationId = root.findViewById(R.id.about_installation_id);
+ textFirebaseToken = root.findViewById(R.id.about_firebase_token);
+ linkSendLog = root.findViewById(R.id.about_send_log);
+ linkUpdateMailingPreferences = root.findViewById(R.id.about_update_mailing_preferences);
+
+ if (Lbryio.isSignedIn()) {
+ textConnectedEmail.setText(Lbryio.getSignedInEmail());
+ textConnectedEmail.setTypeface(null, Typeface.NORMAL);
+ linkUpdateMailingPreferences.setVisibility(View.VISIBLE);
+ } else {
+ linkUpdateMailingPreferences.setVisibility(View.GONE);
+ }
+
+ Context context = getContext();
+ String appVersion = getString(R.string.unknown);
+ if (context != null) {
+ try {
+ PackageManager manager = context.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
+ appVersion = info.versionName;
+ } catch (PackageManager.NameNotFoundException ex) {
+ // pass
+ }
+ }
+ textAppVersion.setText(appVersion);
+ textInstallationId.setText(Lbry.INSTALLATION_ID);
+ textPlatform.setText(String.format("Android %s (API %d)", Utils.getAndroidRelease(), Utils.getAndroidSdk()));
+
+ linkUpdateMailingPreferences.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("http://lbry.com/list/edit/%s", Lbryio.AUTH_TOKEN)));
+ startActivity(intent);
+ }
+ });
+
+ linkSendLog.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ shareLogFile();
+ }
+ });
+
+ return root;
+ }
+
+ private void shareLogFile() {
+ Context context = getContext();
+ if (context != null) {
+ String logFileName = "lbrynet.log";
+ File logFile = new File(String.format("%s/%s", Utils.getAppInternalStorageDir(context), "lbrynet"), logFileName);
+ if (!logFile.exists()) {
+ Snackbar.make(getView(), R.string.cannot_find_lbrynet_log, Snackbar.LENGTH_LONG).
+ setBackgroundTint(Color.RED).
+ setTextColor(Color.WHITE).
+ show();
+ return;
+ }
+
+ try {
+ Uri fileUri = FileProvider.getUriForFile(getContext(), FILE_PROVIDER, logFile);
+ if (fileUri != null) {
+ MainActivity.startingShareActivity = true;
+ Intent shareIntent = new Intent();
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ shareIntent.setAction(Intent.ACTION_SEND);
+ shareIntent.setType("text/plain");
+ shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
+
+ Intent sendLogIntent = Intent.createChooser(shareIntent, "Send LBRY log");
+ sendLogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(sendLogIntent);
+ }
+ } catch (IllegalArgumentException e) {
+ Snackbar.make(getView(), R.string.cannot_share_lbrynet_log, Snackbar.LENGTH_LONG).
+ setBackgroundTint(Color.RED).
+ setTextColor(Color.WHITE).
+ show();
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ MainActivity activity = (MainActivity) getContext();
+ if (activity != null) {
+ activity.hideSearchBar();
+ activity.showNavigationBackIcon();
+ activity.lockDrawer();
+ activity.hideFloatingWalletBalance();
+
+ ActionBar actionBar = activity.getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(R.string.about_lbry);
+ }
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Settings", "Settings");
+
+ if (!Lbry.SDK_READY) {
+ activity.addSdkStatusListener(this);
+ } else {
+ onSdkReady();
+ }
+ }
+ FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(Task task) {
+ Helper.setViewText(textFirebaseToken, task.isSuccessful() ? task.getResult().getToken() : getString(R.string.unknown));
+ }
+ });
+
+ }
+
+ @Override
+ public void onStop() {
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) getContext();
+ activity.removeSdkStatusListener(this);
+ activity.restoreToggle();
+ activity.showFloatingWalletBalance();
+ }
+ super.onStop();
+ }
+
+ public void onSdkReady() {
+ loadLbryVersion();
+ }
+
+ private void loadLbryVersion() {
+ (new AsyncTask() {
+ protected String doInBackground(Void... params) {
+ try {
+ JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_VERSION);
+ return Helper.getJSONString("lbrynet_version", null, result);
+ } catch (ApiCallException | ClassCastException ex) {
+ // pass
+ return null;
+ }
+ }
+ protected void onPostExecute(String version) {
+ Helper.setViewText(textLbrySdkVersion, Helper.isNullOrEmpty(version) ? getString(R.string.unknown) : version);
+ }
+ }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java b/app/src/main/java/io/lbry/browser/ui/other/SettingsFragment.java
similarity index 98%
rename from app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java
rename to app/src/main/java/io/lbry/browser/ui/other/SettingsFragment.java
index 65a7377..4ac2b59 100644
--- a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/other/SettingsFragment.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.ui.settings;
+package io.lbry.browser.ui.other;
import android.content.Context;
import android.content.SharedPreferences;
diff --git a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
index 208e8b9..feeb654 100644
--- a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
@@ -22,10 +22,10 @@ import io.lbry.browser.R;
import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimSearchTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.tasks.LighthouseSearchTask;
-import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.claim.ResolveTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
@@ -129,6 +129,7 @@ public class SearchFragment extends BaseFragment implements
claim.setName(query);
claim.setFeatured(true);
claim.setUnresolved(true);
+ claim.setConfirmations(1);
return claim;
}
@@ -150,7 +151,7 @@ public class SearchFragment extends BaseFragment implements
ResolveTask task = new ResolveTask(vanityUrl, Lbry.LBRY_TV_CONNECTION_STRING, null, new ClaimListResultHandler() {
@Override
public void onSuccess(List claims) {
- if (claims.size() > 0) {
+ if (claims.size() > 0 && !Helper.isNullOrEmpty(claims.get(0).getClaimId())) {
Claim resolved = claims.get(0);
Lbry.claimCache.put(key, resolved);
updateFeaturedItemFromResolvedClaim(resolved);
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
index 0d1a906..b1781b2 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
@@ -38,11 +38,11 @@ import io.lbry.browser.listener.WalletBalanceListener;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.WalletBalance;
import io.lbry.browser.model.lbryinc.Invitee;
-import io.lbry.browser.tasks.ClaimListResultHandler;
-import io.lbry.browser.tasks.ClaimListTask;
+import io.lbry.browser.tasks.claim.ClaimListResultHandler;
+import io.lbry.browser.tasks.claim.ClaimListTask;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.ChannelCreateUpdateTask;
-import io.lbry.browser.tasks.ClaimResultHandler;
+import io.lbry.browser.tasks.claim.ClaimResultHandler;
import io.lbry.browser.tasks.lbryinc.LogPublishTask;
import io.lbry.browser.tasks.lbryinc.FetchInviteStatusTask;
import io.lbry.browser.tasks.lbryinc.FetchReferralCodeTask;
diff --git a/app/src/main/java/io/lbry/browser/utils/ExoplayerAudioRenderer.java b/app/src/main/java/io/lbry/browser/utils/ExoplayerAudioRenderer.java
new file mode 100644
index 0000000..832db7f
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/utils/ExoplayerAudioRenderer.java
@@ -0,0 +1,53 @@
+package io.lbry.browser.utils;
+
+import android.content.Context;
+import android.os.Handler;
+
+import androidx.annotation.Nullable;
+
+import com.google.android.exoplayer2.DefaultRenderersFactory;
+import com.google.android.exoplayer2.Renderer;
+import com.google.android.exoplayer2.audio.AudioProcessor;
+import com.google.android.exoplayer2.audio.AudioRendererEventListener;
+import com.google.android.exoplayer2.audio.TeeAudioProcessor;
+import com.google.android.exoplayer2.drm.DrmSessionManager;
+import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
+import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
+
+import java.util.ArrayList;
+
+public class ExoplayerAudioRenderer extends DefaultRenderersFactory {
+
+ private TeeAudioProcessor.AudioBufferSink audioBufferSink;
+
+ public ExoplayerAudioRenderer(Context context, TeeAudioProcessor.AudioBufferSink audioBufferSink) {
+ super(context);
+ this.audioBufferSink = audioBufferSink;
+ }
+
+ @Override
+ protected void buildAudioRenderers(
+ Context context,
+ int extensionRendererMode,
+ MediaCodecSelector mediaCodecSelector,
+ @Nullable DrmSessionManager drmSessionManager,
+ boolean playClearSamplesWithoutKeys,
+ boolean enableDecoderFallback,
+ AudioProcessor[] audioProcessors,
+ Handler eventHandler,
+ AudioRendererEventListener eventListener,
+ ArrayList out) {
+ AudioProcessor[] audioProcessorList = { new TeeAudioProcessor(audioBufferSink) };
+ super.buildAudioRenderers(
+ context,
+ extensionRendererMode,
+ mediaCodecSelector,
+ drmSessionManager,
+ playClearSamplesWithoutKeys,
+ enableDecoderFallback,
+ audioProcessorList,
+ eventHandler,
+ eventListener,
+ out);
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/utils/Lbry.java b/app/src/main/java/io/lbry/browser/utils/Lbry.java
index 680f695..3c2117c 100644
--- a/app/src/main/java/io/lbry/browser/utils/Lbry.java
+++ b/app/src/main/java/io/lbry/browser/utils/Lbry.java
@@ -1,18 +1,10 @@
package io.lbry.browser.utils;
-import com.google.gson.FieldNamingPolicy;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.reflect.TypeToken;
-
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
-import java.lang.reflect.Type;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
@@ -29,12 +21,10 @@ import io.lbry.browser.exceptions.LbryResponseException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey;
import io.lbry.browser.model.ClaimSearchCacheValue;
-import io.lbry.browser.model.File;
+import io.lbry.browser.model.LbryFile;
import io.lbry.browser.model.Tag;
import io.lbry.browser.model.Transaction;
import io.lbry.browser.model.WalletBalance;
-import io.lbry.browser.model.lbryinc.Reward;
-import io.lbry.browser.model.lbryinc.User;
import io.lbry.lbrysdk.Utils;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -68,11 +58,13 @@ public final class Lbry {
public static final String METHOD_RESOLVE = "resolve";
public static final String METHOD_CLAIM_SEARCH = "claim_search";
public static final String METHOD_FILE_LIST = "file_list";
+ public static final String METHOD_FILE_DELETE = "file_delete";
public static final String METHOD_GET = "get";
public static final String METHOD_WALLET_BALANCE = "wallet_balance";
public static final String METHOD_WALLET_ENCRYPT = "wallet_encrypt";
public static final String METHOD_WALLET_DECRYPT = "wallet_decrypt";
+ public static final String METHOD_VERSION = "version";
public static final String METHOD_WALLET_LIST = "wallet_list";
public static final String METHOD_WALLET_SEND = "wallet_send";
@@ -95,6 +87,7 @@ public final class Lbry {
public static final String METHOD_CHANNEL_UPDATE = "channel_update";
public static final String METHOD_CLAIM_LIST = "claim_list";
+ public static final String METHOD_STREAM_REPOST = "stream_repost";
public static KeyStore KEYSTORE;
public static boolean SDK_READY = false;
@@ -205,7 +198,7 @@ public final class Lbry {
} else {
errorMessage = ((JSONObject) jsonError).getString("message");
}
- throw new LbryResponseException(json.getString("error"));
+ throw new LbryResponseException(!Helper.isNullOrEmpty(errorMessage) ? errorMessage : json.getString("error"));
} else {
throw new LbryResponseException("Protocol error with unknown response signature.");
}
@@ -284,13 +277,13 @@ public final class Lbry {
return transactions;
}
- public static File get(boolean saveFile) throws ApiCallException {
- File file = null;
+ public static LbryFile get(boolean saveFile) throws ApiCallException {
+ LbryFile file = null;
Map params = new HashMap<>();
params.put("save_file", saveFile);
try {
JSONObject result = (JSONObject) parseResponse(apiCall(METHOD_GET, params));
- file = File.fromJSONObject(result);
+ file = LbryFile.fromJSONObject(result);
if (file != null) {
String fileClaimId = file.getClaimId();
@@ -309,8 +302,8 @@ public final class Lbry {
return file;
}
- public static List fileList(String claimId) throws ApiCallException {
- List files = new ArrayList<>();
+ public static List fileList(String claimId) throws ApiCallException {
+ List files = new ArrayList<>();
Map params = new HashMap<>();
if (!Helper.isNullOrEmpty(claimId)) {
params.put("claim_id", claimId);
@@ -320,7 +313,7 @@ public final class Lbry {
JSONArray items = result.getJSONArray("items");
for (int i = 0; i < items.length(); i++) {
JSONObject fileObject = items.getJSONObject(i);
- File file = File.fromJSONObject(fileObject);
+ LbryFile file = LbryFile.fromJSONObject(fileObject);
files.add(file);
String fileClaimId = file.getClaimId();
diff --git a/app/src/main/java/io/lbry/browser/utils/Lbryio.java b/app/src/main/java/io/lbry/browser/utils/Lbryio.java
index 6262d86..12fab55 100644
--- a/app/src/main/java/io/lbry/browser/utils/Lbryio.java
+++ b/app/src/main/java/io/lbry/browser/utils/Lbryio.java
@@ -43,6 +43,9 @@ import okhttp3.Response;
@Data
public final class Lbryio {
+ // TODO: Get this from the bundled aar
+ public static String SDK_VERSION = "0.73.1";
+
public static User currentUser;
public static boolean userHasSyncedWallet = false;
public static String lastRemoteHash;
@@ -212,7 +215,7 @@ public final class Lbryio {
options.put("app_version", appVersion);
options.put("app_id", Lbry.INSTALLATION_ID);
options.put("node_id", "");
- options.put("daemon_version", "0.67.1");
+ options.put("daemon_version", SDK_VERSION);
options.put("operating_system", "android");
options.put("platform", String.format("Android %s (API %d)", Utils.getAndroidRelease(), Utils.getAndroidSdk()));
try {
diff --git a/app/src/main/res/drawable-anydpi/ic_stop.xml b/app/src/main/res/drawable-anydpi/ic_stop.xml
new file mode 100644
index 0000000..34bc28f
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi/ic_stop.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable-hdpi/ic_stop.png b/app/src/main/res/drawable-hdpi/ic_stop.png
new file mode 100644
index 0000000..b9164b8
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stop.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stop.png b/app/src/main/res/drawable-mdpi/ic_stop.png
new file mode 100644
index 0000000..307fe3a
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stop.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stop.png b/app/src/main/res/drawable-xhdpi/ic_stop.png
new file mode 100644
index 0000000..3db50c5
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stop.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_stop.png b/app/src/main/res/drawable-xxhdpi/ic_stop.png
new file mode 100644
index 0000000..98e9f13
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stop.png differ
diff --git a/app/src/main/res/drawable/determinate_progress_circle.xml b/app/src/main/res/drawable/determinate_progress_circle.xml
new file mode 100644
index 0000000..6a3b230
--- /dev/null
+++ b/app/src/main/res/drawable/determinate_progress_circle.xml
@@ -0,0 +1,26 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_file_view.xml b/app/src/main/res/layout/activity_file_view.xml
index 93619cd..29bfa6f 100644
--- a/app/src/main/res/layout/activity_file_view.xml
+++ b/app/src/main/res/layout/activity_file_view.xml
@@ -42,7 +42,7 @@
android:layout_weight="10"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:visibility="invisible">
+ android:visibility="visible">
+
+ android:text="@string/fa_coins"
+ android:textColor="@android:color/black" />
@@ -108,10 +116,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:controller_layout_id="@layout/exo_playback_control_view"/>
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+ android:visibility="gone">
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
-
-
-
-
-
-
+
+
+
+ android:layout_height="0.5dp" />
-
+
+ android:layout_height="0.5dp" />
@@ -499,7 +561,7 @@
android:layout_width="match_parent"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
- android:layout_height="1dp" />
+ android:layout_height="0.5dp" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml
index 35955a6..ba9ed15 100644
--- a/app/src/main/res/layout/app_bar_main.xml
+++ b/app/src/main/res/layout/app_bar_main.xml
@@ -36,6 +36,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/uri_placeholder"
+ android:imeOptions="actionGo"
android:selectAllOnFocus="true"
android:singleLine="true"
android:textFontWeight="300"
diff --git a/app/src/main/res/layout/card_wallet_balance.xml b/app/src/main/res/layout/card_wallet_balance.xml
index 0653678..3468bda 100644
--- a/app/src/main/res/layout/card_wallet_balance.xml
+++ b/app/src/main/res/layout/card_wallet_balance.xml
@@ -77,8 +77,9 @@
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:fontFamily="@font/inter"
- android:textSize="12sp"
- android:text="@string/convert_credits" />
+ android:text="@string/convert_credits"
+ android:textColorLink="@color/lbryGreen"
+ android:textSize="12sp" />
+ android:text="@string/convert_credits_bittrex"
+ android:textColorLink="@color/lbryGreen"
+ android:textSize="16sp" />
diff --git a/app/src/main/res/layout/card_wallet_recent_transactions.xml b/app/src/main/res/layout/card_wallet_recent_transactions.xml
index 0bee6c1..3a67e1d 100644
--- a/app/src/main/res/layout/card_wallet_recent_transactions.xml
+++ b/app/src/main/res/layout/card_wallet_recent_transactions.xml
@@ -41,7 +41,7 @@
@@ -115,14 +115,16 @@
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:text="@string/manual_backup" />
+ android:text="@string/manual_backup"
+ android:textColorLink="@color/lbryGreen" />
+ android:text="@string/sync_faq"
+ android:textColorLink="@color/lbryGreen"/>
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
index f87abc3..7a78d48 100644
--- a/app/src/main/res/layout/content_main.xml
+++ b/app/src/main/res/layout/content_main.xml
@@ -31,6 +31,36 @@
+
+
+
+
+
+
+
+ app:layout_constraintBottom_toTopOf="@id/global_sdk_initializing_status">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_send_tip.xml b/app/src/main/res/layout/dialog_send_tip.xml
index c5a034b..6912778 100644
--- a/app/src/main/res/layout/dialog_send_tip.xml
+++ b/app/src/main/res/layout/dialog_send_tip.xml
@@ -19,7 +19,7 @@
android:textSize="20sp" />
diff --git a/app/src/main/res/layout/exo_playback_control_view.xml b/app/src/main/res/layout/exo_playback_control_view.xml
index c3adccf..dff3ceb 100644
--- a/app/src/main/res/layout/exo_playback_control_view.xml
+++ b/app/src/main/res/layout/exo_playback_control_view.xml
@@ -8,25 +8,18 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_channel_form.xml b/app/src/main/res/layout/fragment_channel_form.xml
index 01a3740..8ee27cf 100644
--- a/app/src/main/res/layout/fragment_channel_form.xml
+++ b/app/src/main/res/layout/fragment_channel_form.xml
@@ -294,7 +294,7 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
- android:textSize="12sp"
+ android:textSize="14sp"
android:text="@string/cancel" />
diff --git a/app/src/main/res/layout/fragment_verification_phone.xml b/app/src/main/res/layout/fragment_verification_phone.xml
index 2010f9c..6048ef3 100644
--- a/app/src/main/res/layout/fragment_verification_phone.xml
+++ b/app/src/main/res/layout/fragment_verification_phone.xml
@@ -53,7 +53,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent"
- android:paddingTop="2dp"
android:fontFamily="@font/inter"
android:singleLine="true"
android:textSize="20sp"
diff --git a/app/src/main/res/layout/list_item_featured_search_result.xml b/app/src/main/res/layout/list_item_featured_search_result.xml
index 6c45038..0804a85 100644
--- a/app/src/main/res/layout/list_item_featured_search_result.xml
+++ b/app/src/main/res/layout/list_item_featured_search_result.xml
@@ -106,7 +106,8 @@
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:textSize="8dp"
- android:text="@string/fa_coins" />
+ android:text="@string/fa_coins"
+ android:textColor="@android:color/black"/>
diff --git a/app/src/main/res/layout/list_item_stream.xml b/app/src/main/res/layout/list_item_stream.xml
index 635ac17..0085541 100644
--- a/app/src/main/res/layout/list_item_stream.xml
+++ b/app/src/main/res/layout/list_item_stream.xml
@@ -110,7 +110,8 @@
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:textSize="8dp"
- android:text="@string/fa_coins" />
+ android:text="@string/fa_coins"
+ android:textColor="@android:color/black"/>
diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml
index dbdc2cd..d33feba 100644
--- a/app/src/main/res/layout/nav_header_main.xml
+++ b/app/src/main/res/layout/nav_header_main.xml
@@ -15,6 +15,7 @@
android:layout_gravity="bottom"
android:clickable="true"
android:paddingTop="38dp"
+ android:foreground="?attr/selectableItemBackground"
android:background="@color/lbryGreen">
+ android:layout_height="0.5dp" />
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index df610a7..1dca2ec 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -52,7 +52,7 @@
#FF4A7D
#26BCF7
- #D5D5D5
+ #252525
#CAEDB9
#CC333333
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ec5bf9a..cf73086 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,22 +55,32 @@
Edit
Delete
Download
+ Open
Report
Loading decentralized data...
Related Content
Share LBRY content
View
Play
-
- - %1$s view
- - %1$s views
-
Unsupported Content
- Sorry, we are unable to display this content in the app. You can find the file named %1$s in your downloads folder.
+ Sorry, we are unable to display this content in the app. You can find the file %1$sin your downloads folder.
There\'s nothing at this location.
Publish something here
This content cannot be accessed at this time. Please try again later.
00:00
+ The file at "%1$s" does not exist.
+ Confirm Purchase
+ Delete file
+ Are you sure you want to remove this file from your device?
+ Failed to load %1$s. Please try again later.
+
+ - %1$s view
+ - %1$s views
+
+
+ - This will purchase "%1$s" for %2$s credit
+ - This will purchase "%1$s" for %2$s credits
+
There\'s nothing here yet.\nPlease check back later.
@@ -215,7 +225,15 @@
This will appear as a tip for %1$s, which will boost its ability to be discovered while active. <a href="https://lbry.com/faq/tipping">Learn more</a>.
This will appear as a tip for %1$s, which will boost the channel\'s ability to be discovered while active. <a href="https://lbry.com/faq/tipping">Learn more</a>.
Cancel
-
+ Repost %1$s
+ Repost your favorite content to help more people discover them!
+ Channel to post on
+ Show advanced
+ Hide advanced
+ Name
+ 0.01
+ The content was successfully reposted!
+ The repost name contains invalid characters.
- You sent %1$s credit as a tip, Mahalo!
- You sent %1$s credits as a tip, Mahalo!
@@ -344,6 +362,36 @@
Invite link copied.
Invite sent to %1$s
+
+ About LBRY
+ Content Freedom
+ LBRY is a free, open, and community-run digital marketplace. It is a decentralized peer-to-peer content distribution platform for creators to upload and share content, and earn LBRY credits for their effort. Users will be able to find a wide selection of videos, music, ebooks and other digital content they are interested in.
+ Get Social
+ You can interact with the LBRY team and members of the community on Discord, Facebook, Instagram, Twitter or Reddit.
+ App info
+ Loading...
+ <a href="https://lbry.com/faq/what-is-lbry">What is LBRY?</a>
+ <a href="https://lbry.com/faq/android-basics">Android Basics</a>
+ <a href="https://lbry.com/faq">FAQ</a>
+ <a href="https://discordapp.com/invite/Z3bERWA">Discord</a>
+ <a href="https://www.facebook.com/LBRYio">Facebook</a>
+ <a href="https://www.instagram.com/LBRYio">Instagram</a>
+ <a href="https://reddit.com/r/lbry">Reddit</a>
+ <a href="https://t.me/lbryofficial">Telegram</a>
+ <a href="https://twitter.com/LBRYio">Twitter</a>
+ Update mailing preferences
+ App version
+ LBRY SDK
+ Platform
+ Installation ID
+ Firebase Token
+ Logs
+ Send log
+ Connected email
+ Unknown
+ The lbrynet.log file could not be found.
+ The lbrynet.log file cannot be shared due to permission restrictions.
+
@@ -366,4 +414,5 @@
+
diff --git a/app/src/main/res/xml/filepaths.xml b/app/src/main/res/xml/filepaths.xml
new file mode 100644
index 0000000..a6fad46
--- /dev/null
+++ b/app/src/main/res/xml/filepaths.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index ad32875..e14841d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ allprojects {
repositories {
google()
jcenter()
-
+ maven { url "https://jitpack.io" }
}
}