Native rewrite #878
|
@ -20,6 +20,9 @@
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true">
|
||||||
|
|
||||||
|
<meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||||
|
android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
android:resource="@drawable/ic_lbry" />
|
android:resource="@drawable/ic_lbry" />
|
||||||
|
@ -39,7 +42,7 @@
|
||||||
android:supportsPictureInPicture="true"
|
android:supportsPictureInPicture="true"
|
||||||
android:theme="@style/AppTheme.NoActionBar"
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:windowSoftInputMode="adjustPan">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.lbry.browser;
|
package io.lbry.browser;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.PictureInPictureParams;
|
import android.app.PictureInPictureParams;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
@ -34,7 +33,6 @@ import android.widget.TextView;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.core.app.NavUtils;
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.widget.NestedScrollView;
|
import androidx.core.widget.NestedScrollView;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
@ -43,11 +41,15 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.github.chrisbanes.photoview.PhotoView;
|
import com.github.chrisbanes.photoview.PhotoView;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
||||||
|
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
|
||||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
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.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
@ -84,6 +86,7 @@ import io.lbry.browser.model.ClaimCacheKey;
|
||||||
import io.lbry.browser.model.Fee;
|
import io.lbry.browser.model.Fee;
|
||||||
import io.lbry.browser.model.LbryFile;
|
import io.lbry.browser.model.LbryFile;
|
||||||
import io.lbry.browser.model.Tag;
|
import io.lbry.browser.model.Tag;
|
||||||
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
import io.lbry.browser.model.lbryinc.Reward;
|
import io.lbry.browser.model.lbryinc.Reward;
|
||||||
import io.lbry.browser.model.lbryinc.Subscription;
|
import io.lbry.browser.model.lbryinc.Subscription;
|
||||||
import io.lbry.browser.tasks.ReadTextFileTask;
|
import io.lbry.browser.tasks.ReadTextFileTask;
|
||||||
|
@ -115,6 +118,8 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
private static final int RELATED_CONTENT_SIZE = 16;
|
private static final int RELATED_CONTENT_SIZE = 16;
|
||||||
private static boolean startingShareActivity;
|
private static boolean startingShareActivity;
|
||||||
|
|
||||||
|
private PlayerControlView castControlView;
|
||||||
|
private Player currentPlayer;
|
||||||
private boolean backStackLost;
|
private boolean backStackLost;
|
||||||
private boolean loadingNewClaim;
|
private boolean loadingNewClaim;
|
||||||
private boolean stopServiceReceived;
|
private boolean stopServiceReceived;
|
||||||
|
@ -163,11 +168,8 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
instance = this;
|
instance = this;
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setClaimId(claimId);
|
key.setClaimId(claimId);
|
||||||
if (url.contains("#")) {
|
key.setUrl(url); // use the same url for the key so that we can match the key for any value that's the same
|
||||||
key.setPermanentUrl(url); // use the same url for the key so that we can match the key for any value that's the same
|
|
||||||
key.setCanonicalUrl(url);
|
|
||||||
key.setShortUrl(url);
|
|
||||||
}
|
|
||||||
if (Lbry.claimCache.containsKey(key)) {
|
if (Lbry.claimCache.containsKey(key)) {
|
||||||
claim = Lbry.claimCache.get(key);
|
claim = Lbry.claimCache.get(key);
|
||||||
checkAndResetNowPlayingClaim();
|
checkAndResetNowPlayingClaim();
|
||||||
|
@ -181,6 +183,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
|
|
||||||
currentUrl = url;
|
currentUrl = url;
|
||||||
logUrlEvent(url);
|
logUrlEvent(url);
|
||||||
|
Helper.saveUrlHistory(url, claim != null ? claim.getTitle() : null, UrlSuggestion.TYPE_FILE);
|
||||||
if (claim == null) {
|
if (claim == null) {
|
||||||
MainActivity.clearNowPlayingClaim(this);
|
MainActivity.clearNowPlayingClaim(this);
|
||||||
resolveUrl(url);
|
resolveUrl(url);
|
||||||
|
@ -218,6 +221,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
castControlView = findViewById(R.id.file_view_cast_control_view);
|
||||||
initUi();
|
initUi();
|
||||||
onWalletBalanceUpdated();
|
onWalletBalanceUpdated();
|
||||||
renderClaim();
|
renderClaim();
|
||||||
|
@ -278,9 +282,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setClaimId(newClaimId);
|
key.setClaimId(newClaimId);
|
||||||
if (!Helper.isNullOrEmpty(newUrl) && newUrl.contains("#")) {
|
if (!Helper.isNullOrEmpty(newUrl) && newUrl.contains("#")) {
|
||||||
key.setPermanentUrl(newUrl);
|
key.setUrl(newUrl);
|
||||||
key.setCanonicalUrl(newUrl);
|
|
||||||
key.setShortUrl(newUrl);
|
|
||||||
}
|
}
|
||||||
loadClaimForCacheKey(key, newUrl);
|
loadClaimForCacheKey(key, newUrl);
|
||||||
} else if (!Helper.isNullOrEmpty(newUrl)) {
|
} else if (!Helper.isNullOrEmpty(newUrl)) {
|
||||||
|
@ -290,9 +292,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
|
|
||||||
onNewClaim(newUrl);
|
onNewClaim(newUrl);
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setPermanentUrl(newUrl);
|
key.setUrl(newUrl);
|
||||||
key.setCanonicalUrl(newUrl);
|
|
||||||
key.setShortUrl(newUrl);
|
|
||||||
loadClaimForCacheKey(key, newUrl);
|
loadClaimForCacheKey(key, newUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
private void loadClaimForCacheKey(ClaimCacheKey key, String url) {
|
private void loadClaimForCacheKey(ClaimCacheKey key, String url) {
|
||||||
if (Lbry.claimCache.containsKey(key)) {
|
if (Lbry.claimCache.containsKey(key)) {
|
||||||
claim = Lbry.claimCache.get(key);
|
claim = Lbry.claimCache.get(key);
|
||||||
|
Helper.saveUrlHistory(url, claim.getTitle(), UrlSuggestion.TYPE_FILE);
|
||||||
checkAndResetNowPlayingClaim();
|
checkAndResetNowPlayingClaim();
|
||||||
if (claim.getFile() == null) {
|
if (claim.getFile() == null) {
|
||||||
loadFile();
|
loadFile();
|
||||||
|
@ -322,6 +323,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
renderClaim();
|
renderClaim();
|
||||||
} else {
|
} else {
|
||||||
|
Helper.saveUrlHistory(url, null, UrlSuggestion.TYPE_FILE);
|
||||||
findViewById(R.id.file_view_claim_display_area).setVisibility(View.INVISIBLE);
|
findViewById(R.id.file_view_claim_display_area).setVisibility(View.INVISIBLE);
|
||||||
MainActivity.clearNowPlayingClaim(this);
|
MainActivity.clearNowPlayingClaim(this);
|
||||||
resolveUrl(url);
|
resolveUrl(url);
|
||||||
|
@ -452,6 +454,8 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
MainActivity.mainActive = false;
|
MainActivity.mainActive = false;
|
||||||
MainActivity.startingFileViewActivity = false;
|
MainActivity.startingFileViewActivity = false;
|
||||||
|
|
||||||
|
loadAndScheduleDurations();
|
||||||
if (Lbry.SDK_READY) {
|
if (Lbry.SDK_READY) {
|
||||||
initFloatingWalletBalance();
|
initFloatingWalletBalance();
|
||||||
}
|
}
|
||||||
|
@ -468,12 +472,25 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
claim = claims.get(0);
|
claim = claims.get(0);
|
||||||
if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType())) {
|
if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType())) {
|
||||||
claim = claim.getRepostedClaim();
|
claim = claim.getRepostedClaim();
|
||||||
|
|
||||||
// cache the reposted claim too for subsequent loads
|
// cache the reposted claim too for subsequent loads
|
||||||
ClaimCacheKey key = ClaimCacheKey.fromClaim(claim);
|
Lbry.addClaimToCache(claim);
|
||||||
Lbry.claimCache.put(key, claim);
|
if (claim.getName().startsWith("@")) {
|
||||||
|
// this is a reposted channel, so finish this activity and launch the channel url
|
||||||
|
Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
|
||||||
|
intent.putExtra("url", !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
|
||||||
|
sendBroadcast(intent);
|
||||||
|
|
||||||
|
bringMainTaskToFront();
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Lbry.addClaimToCache(claim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Helper.saveUrlHistory(url, claim.getTitle(), UrlSuggestion.TYPE_FILE);
|
||||||
|
|
||||||
|
// also save view history
|
||||||
checkAndResetNowPlayingClaim();
|
checkAndResetNowPlayingClaim();
|
||||||
loadFile();
|
loadFile();
|
||||||
renderClaim();
|
renderClaim();
|
||||||
|
@ -644,7 +661,14 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
findViewById(R.id.player_toggle_full_screen).setOnClickListener(new View.OnClickListener() {
|
findViewById(R.id.player_toggle_cast).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
toggleCast();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findViewById(R.id.player_toggle_fullscreen).setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
// check full screen mode
|
// check full screen mode
|
||||||
|
@ -664,7 +688,6 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
|
Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
|
||||||
intent.putExtra("url", !Helper.isNullOrEmpty(publisher.getShortUrl()) ? publisher.getShortUrl() : publisher.getPermanentUrl());
|
intent.putExtra("url", !Helper.isNullOrEmpty(publisher.getShortUrl()) ? publisher.getShortUrl() : publisher.getPermanentUrl());
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
|
|
||||||
bringMainTaskToFront();
|
bringMainTaskToFront();
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -862,12 +885,12 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
boolean newPlayerCreated = false;
|
boolean newPlayerCreated = false;
|
||||||
if (MainActivity.appPlayer == null) {
|
if (MainActivity.appPlayer == null) {
|
||||||
MainActivity.appPlayer = new SimpleExoPlayer.Builder(this).build();
|
MainActivity.appPlayer = new SimpleExoPlayer.Builder(this).build();
|
||||||
|
MainActivity.castPlayer = new CastPlayer(MainActivity.castContext);
|
||||||
|
|
||||||
newPlayerCreated = true;
|
newPlayerCreated = true;
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
PlayerView view = findViewById(R.id.file_view_exoplayer_view);
|
PlayerView view = findViewById(R.id.file_view_exoplayer_view);
|
||||||
view.setPlayer(MainActivity.appPlayer);
|
view.setPlayer(MainActivity.appPlayer);
|
||||||
if (MainActivity.nowPlayingClaim != null &&
|
if (MainActivity.nowPlayingClaim != null &&
|
||||||
|
@ -881,6 +904,20 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
showBuffering();
|
showBuffering();
|
||||||
|
|
||||||
MainActivity.appPlayer.addListener(fileViewPlayerListener);
|
MainActivity.appPlayer.addListener(fileViewPlayerListener);
|
||||||
|
MainActivity.castPlayer.addListener(fileViewPlayerListener);
|
||||||
|
MainActivity.castPlayer.setSessionAvailabilityListener(new SessionAvailabilityListener() {
|
||||||
|
@Override
|
||||||
|
public void onCastSessionAvailable() {
|
||||||
|
setCurrentPlayer(MainActivity.castPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCastSessionUnavailable() {
|
||||||
|
setCurrentPlayer(MainActivity.appPlayer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
castControlView.setPlayer(MainActivity.castPlayer);
|
||||||
MainActivity.setNowPlayingClaim(claim, FileViewActivity.this);
|
MainActivity.setNowPlayingClaim(claim, FileViewActivity.this);
|
||||||
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
|
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
|
||||||
|
|
||||||
|
@ -893,6 +930,47 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
MainActivity.appPlayer.prepare(mediaSource, true, true);
|
MainActivity.appPlayer.prepare(mediaSource, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setCurrentPlayer(Player currentPlayer) {
|
||||||
|
if (this.currentPlayer == currentPlayer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// View management.
|
||||||
|
if (currentPlayer == MainActivity.appPlayer) {
|
||||||
|
//localPlayerView.setVisibility(View.VISIBLE);
|
||||||
|
castControlView.hide();
|
||||||
|
((ImageView) findViewById(R.id.player_image_cast_toggle)).setImageResource(R.drawable.ic_cast);
|
||||||
|
} else /* currentPlayer == castPlayer */ {
|
||||||
|
castControlView.show();
|
||||||
|
((ImageView) findViewById(R.id.player_image_cast_toggle)).setImageResource(R.drawable.ic_cast_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player state management.
|
||||||
|
long playbackPositionMs = C.TIME_UNSET;
|
||||||
|
int windowIndex = C.INDEX_UNSET;
|
||||||
|
boolean playWhenReady = false;
|
||||||
|
|
||||||
|
Player previousPlayer = this.currentPlayer;
|
||||||
|
if (previousPlayer != null) {
|
||||||
|
// Save state from the previous player.
|
||||||
|
int playbackState = previousPlayer.getPlaybackState();
|
||||||
|
if (playbackState != Player.STATE_ENDED) {
|
||||||
|
playbackPositionMs = previousPlayer.getCurrentPosition();
|
||||||
|
playWhenReady = previousPlayer.getPlayWhenReady();
|
||||||
|
}
|
||||||
|
previousPlayer.stop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentPlayer = currentPlayer;
|
||||||
|
|
||||||
|
// Media queue management.
|
||||||
|
/*if (currentPlayer == exoPlayer) {
|
||||||
|
exoPlayer.prepare(concatenatingMediaSource);
|
||||||
|
}*/
|
||||||
|
currentPlayer.seekTo(playbackPositionMs);
|
||||||
|
currentPlayer.setPlayWhenReady(true);
|
||||||
|
}
|
||||||
|
|
||||||
private void resetViewCount() {
|
private void resetViewCount() {
|
||||||
TextView textViewCount = findViewById(R.id.file_view_view_count);
|
TextView textViewCount = findViewById(R.id.file_view_view_count);
|
||||||
Helper.setViewText(textViewCount, null);
|
Helper.setViewText(textViewCount, null);
|
||||||
|
@ -1179,7 +1257,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
if (claim.getName().startsWith("@")) {
|
if (claim.getName().startsWith("@")) {
|
||||||
// opening a channel
|
// opening a channel
|
||||||
Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
|
Intent intent = new Intent(MainActivity.ACTION_OPEN_CHANNEL_URL);
|
||||||
intent.putExtra("url", !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
|
intent.putExtra("url", claim.getPermanentUrl());
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
bringMainTaskToFront();
|
bringMainTaskToFront();
|
||||||
finish();
|
finish();
|
||||||
|
@ -1409,6 +1487,18 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
Helper.setViewText(findViewById(R.id.player_duration_total), Helper.formatDuration(Double.valueOf(totalDuration / 1000.0).longValue()));
|
Helper.setViewText(findViewById(R.id.player_duration_total), Helper.formatDuration(Double.valueOf(totalDuration / 1000.0).longValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndScheduleDurations() {
|
||||||
|
if (MainActivity.appPlayer != null) {
|
||||||
|
if (totalDuration == 0) {
|
||||||
|
elapsedDuration = MainActivity.appPlayer.getCurrentPosition();
|
||||||
|
totalDuration = MainActivity.appPlayer.getDuration();
|
||||||
|
}
|
||||||
|
renderElapsedDuration();
|
||||||
|
renderTotalDuration();
|
||||||
|
scheduleElapsedPlayback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void logPlay(String url, long startTimeMillis) {
|
private void logPlay(String url, long startTimeMillis) {
|
||||||
long timeToStartMillis = startTimeMillis > 0 ? System.currentTimeMillis() - startTimeMillis : 0;
|
long timeToStartMillis = startTimeMillis > 0 ? System.currentTimeMillis() - startTimeMillis : 0;
|
||||||
|
|
||||||
|
@ -1554,6 +1644,19 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
|
findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void toggleCast() {
|
||||||
|
if (!MainActivity.castPlayer.isCastSessionAvailable()) {
|
||||||
|
showError(getString(R.string.no_cast_session_available));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPlayer == MainActivity.appPlayer) {
|
||||||
|
setCurrentPlayer(MainActivity.castPlayer);
|
||||||
|
} else {
|
||||||
|
setCurrentPlayer(MainActivity.appPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onDownloadAborted() {
|
private void onDownloadAborted() {
|
||||||
downloadInProgress = false;
|
downloadInProgress = false;
|
||||||
|
|
||||||
|
@ -1598,6 +1701,7 @@ public class FileViewActivity extends AppCompatActivity {
|
||||||
final Set<String> categories = baseIntent.getCategories();
|
final Set<String> categories = baseIntent.getCategories();
|
||||||
if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
|
if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
|
||||||
task.moveToFront();
|
task.moveToFront();
|
||||||
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,9 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
|
import com.google.android.exoplayer2.ext.cast.CastPlayer;
|
||||||
import com.google.android.exoplayer2.ui.PlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
|
import com.google.android.gms.cast.framework.CastContext;
|
||||||
import com.google.android.gms.tasks.OnCompleteListener;
|
import com.google.android.gms.tasks.OnCompleteListener;
|
||||||
import com.google.android.gms.tasks.Task;
|
import com.google.android.gms.tasks.Task;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
@ -105,6 +107,7 @@ import io.lbry.browser.tasks.lbryinc.FetchRewardsTask;
|
||||||
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
|
import io.lbry.browser.tasks.LighthouseAutoCompleteTask;
|
||||||
import io.lbry.browser.tasks.MergeSubscriptionsTask;
|
import io.lbry.browser.tasks.MergeSubscriptionsTask;
|
||||||
import io.lbry.browser.tasks.claim.ResolveTask;
|
import io.lbry.browser.tasks.claim.ResolveTask;
|
||||||
|
import io.lbry.browser.tasks.localdata.FetchRecentUrlHistoryTask;
|
||||||
import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler;
|
import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler;
|
||||||
import io.lbry.browser.tasks.wallet.LoadSharedUserStateTask;
|
import io.lbry.browser.tasks.wallet.LoadSharedUserStateTask;
|
||||||
import io.lbry.browser.tasks.wallet.SaveSharedUserStateTask;
|
import io.lbry.browser.tasks.wallet.SaveSharedUserStateTask;
|
||||||
|
@ -140,6 +143,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
private Map<String, Class> specialRouteFragmentClassMap;
|
private Map<String, Class> specialRouteFragmentClassMap;
|
||||||
private boolean inPictureInPictureMode;
|
private boolean inPictureInPictureMode;
|
||||||
public static SimpleExoPlayer appPlayer;
|
public static SimpleExoPlayer appPlayer;
|
||||||
|
public static CastContext castContext;
|
||||||
|
public static CastPlayer castPlayer;
|
||||||
public static Claim nowPlayingClaim;
|
public static Claim nowPlayingClaim;
|
||||||
public static boolean startingFilePickerActivity = false;
|
public static boolean startingFilePickerActivity = false;
|
||||||
public static boolean startingShareActivity = false;
|
public static boolean startingShareActivity = false;
|
||||||
|
@ -225,7 +230,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
|
|
||||||
private NavigationMenuAdapter navMenuAdapter;
|
private NavigationMenuAdapter navMenuAdapter;
|
||||||
private UrlSuggestionListAdapter urlSuggestionListAdapter;
|
private UrlSuggestionListAdapter urlSuggestionListAdapter;
|
||||||
private List<UrlSuggestion> recentHistory;
|
private List<UrlSuggestion> recentUrlHistory;
|
||||||
private boolean hasLoadedFirstBalance;
|
private boolean hasLoadedFirstBalance;
|
||||||
|
|
||||||
// broadcast receivers
|
// broadcast receivers
|
||||||
|
@ -295,7 +300,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
initKeyStore();
|
initKeyStore();
|
||||||
loadAuthToken();
|
loadAuthToken();
|
||||||
|
|
||||||
dbHelper = new DatabaseHelper(this);
|
|
||||||
if (!isDarkMode()) {
|
if (!isDarkMode()) {
|
||||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||||
}
|
}
|
||||||
|
@ -315,6 +319,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
});
|
});
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
castContext = CastContext.getSharedInstance(this);
|
||||||
|
dbHelper = new DatabaseHelper(this);
|
||||||
checkNotificationOpenIntent(getIntent());
|
checkNotificationOpenIntent(getIntent());
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
@ -542,9 +548,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
|
|
||||||
private Claim getCachedClaimForUrl(String url) {
|
private Claim getCachedClaimForUrl(String url) {
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setCanonicalUrl(url);
|
key.setUrl(url);
|
||||||
key.setPermanentUrl(url);
|
|
||||||
key.setShortUrl(url);
|
|
||||||
return Lbry.claimCache.containsKey(key) ? Lbry.claimCache.get(key) : null;
|
return Lbry.claimCache.containsKey(key) ? Lbry.claimCache.get(key) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,19 +885,25 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
for (int i = 0; i < claims.size(); i++) {
|
for (int i = 0; i < claims.size(); i++) {
|
||||||
// build a simple url from the claim for matching
|
// build a simple url from the claim for matching
|
||||||
Claim claim = claims.get(i);
|
Claim claim = claims.get(i);
|
||||||
|
Claim actualClaim = claim;
|
||||||
|
boolean isRepost = false;
|
||||||
|
if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType())) {
|
||||||
|
actualClaim = claim.getRepostedClaim();
|
||||||
|
isRepost = true;
|
||||||
|
}
|
||||||
if (Helper.isNullOrEmpty(claim.getName())) {
|
if (Helper.isNullOrEmpty(claim.getName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LbryUri simpleUrl = new LbryUri();
|
LbryUri simpleUrl = new LbryUri();
|
||||||
if (claim.getName().startsWith("@")) {
|
if (actualClaim.getName().startsWith("@") && !isRepost) {
|
||||||
// channel
|
// channel
|
||||||
simpleUrl.setChannelName(claim.getName());
|
simpleUrl.setChannelName(actualClaim.getName());
|
||||||
} else {
|
} else {
|
||||||
simpleUrl.setStreamName(claim.getName());
|
simpleUrl.setStreamName(claim.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
urlSuggestionListAdapter.setClaimForUrl(simpleUrl, claim);
|
urlSuggestionListAdapter.setClaimForUrl(simpleUrl, actualClaim);
|
||||||
}
|
}
|
||||||
urlSuggestionListAdapter.notifyDataSetChanged();
|
urlSuggestionListAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
@ -909,10 +919,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
|
|
||||||
private void displayUrlSuggestionsForNoInput() {
|
private void displayUrlSuggestionsForNoInput() {
|
||||||
urlSuggestionListAdapter.clear();
|
urlSuggestionListAdapter.clear();
|
||||||
List<UrlSuggestion> blankSuggestions = buildDefaultSuggestionsForBlankUrl();
|
loadDefaultSuggestionsForBlankUrl();
|
||||||
urlSuggestionListAdapter.addUrlSuggestions(blankSuggestions);
|
|
||||||
List<String> urls = urlSuggestionListAdapter.getItemUrls();
|
|
||||||
resolveUrlSuggestions(urls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleUriInputChanged(String text) {
|
private void handleUriInputChanged(String text) {
|
||||||
|
@ -948,25 +955,48 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<UrlSuggestion> buildDefaultSuggestionsForBlankUrl() {
|
private void loadDefaultSuggestionsForBlankUrl() {
|
||||||
List<UrlSuggestion> suggestions = new ArrayList<>();
|
if (recentUrlHistory != null && recentUrlHistory.size() > 0) {
|
||||||
if (recentHistory != null && recentHistory.size() > 0) {
|
urlSuggestionListAdapter.addUrlSuggestions(recentUrlHistory);
|
||||||
// show recent history if avaiable
|
}
|
||||||
suggestions = new ArrayList<>(recentHistory);
|
|
||||||
} else {
|
FetchRecentUrlHistoryTask task = new FetchRecentUrlHistoryTask(DatabaseHelper.getInstance(), new FetchRecentUrlHistoryTask.FetchRecentUrlHistoryHandler() {
|
||||||
try {
|
@Override
|
||||||
suggestions.add(new UrlSuggestion(
|
public void onSuccess(List<UrlSuggestion> recentHistory) {
|
||||||
UrlSuggestion.TYPE_FILE, "What is LBRY?", LbryUri.parse("lbry://what#19b9c243bea0c45175e6a6027911abbad53e983e")));
|
List<UrlSuggestion> suggestions = new ArrayList<>(recentHistory);
|
||||||
suggestions.add(new UrlSuggestion(
|
List<UrlSuggestion> lbrySuggestions = buildLbryUrlSuggestions();
|
||||||
UrlSuggestion.TYPE_CHANNEL, "LBRYCast", LbryUri.parse("lbry://@lbrycast#4c29f8b013adea4d5cca1861fb2161d5089613ea")));
|
if (suggestions.size() < 10) {
|
||||||
suggestions.add(new UrlSuggestion(
|
for (int i = suggestions.size(), j = 0; i < 10 && j < lbrySuggestions.size(); i++, j++) {
|
||||||
UrlSuggestion.TYPE_CHANNEL, "The LBRY Channel", LbryUri.parse("lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a")));
|
suggestions.add(lbrySuggestions.get(j));
|
||||||
|
}
|
||||||
|
} else if (suggestions.size() == 0) {
|
||||||
|
suggestions.addAll(lbrySuggestions);
|
||||||
|
}
|
||||||
|
|
||||||
for (UrlSuggestion suggestion : suggestions) {
|
for (UrlSuggestion suggestion : suggestions) {
|
||||||
suggestion.setUseTextAsDescription(true);
|
suggestion.setUseTextAsDescription(true);
|
||||||
}
|
}
|
||||||
} catch (LbryUriException ex) {
|
|
||||||
// pass
|
recentUrlHistory = new ArrayList<>(suggestions);
|
||||||
|
urlSuggestionListAdapter.clear();
|
||||||
|
urlSuggestionListAdapter.addUrlSuggestions(recentUrlHistory);
|
||||||
|
List<String> urls = urlSuggestionListAdapter.getItemUrls();
|
||||||
|
resolveUrlSuggestions(urls);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<UrlSuggestion> buildLbryUrlSuggestions() {
|
||||||
|
List<UrlSuggestion> suggestions = new ArrayList<>();
|
||||||
|
suggestions.add(new UrlSuggestion(
|
||||||
|
UrlSuggestion.TYPE_FILE, "What is LBRY?", LbryUri.tryParse("lbry://what#19b9c243bea0c45175e6a6027911abbad53e983e")));
|
||||||
|
suggestions.add(new UrlSuggestion(
|
||||||
|
UrlSuggestion.TYPE_CHANNEL, "LBRYCast", LbryUri.tryParse("lbry://@lbrycast#4c29f8b013adea4d5cca1861fb2161d5089613ea")));
|
||||||
|
suggestions.add(new UrlSuggestion(
|
||||||
|
UrlSuggestion.TYPE_CHANNEL, "The LBRY Channel", LbryUri.tryParse("lbry://@lbry#3fda836a92faaceedfe398225fb9b2ee2ed1f01a")));
|
||||||
|
for (UrlSuggestion suggestion : suggestions) {
|
||||||
|
suggestion.setUseTextAsDescription(true);
|
||||||
}
|
}
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}
|
}
|
||||||
|
@ -975,7 +1005,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
||||||
List<UrlSuggestion> suggestions = new ArrayList<UrlSuggestion>();
|
List<UrlSuggestion> suggestions = new ArrayList<UrlSuggestion>();
|
||||||
|
|
||||||
if (LbryUri.PROTO_DEFAULT.equalsIgnoreCase(text)) {
|
if (LbryUri.PROTO_DEFAULT.equalsIgnoreCase(text)) {
|
||||||
return buildDefaultSuggestionsForBlankUrl();
|
loadDefaultSuggestionsForBlankUrl();
|
||||||
|
return recentUrlHistory != null ? recentUrlHistory : new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// First item is always search
|
// First item is always search
|
||||||
|
|
|
@ -16,6 +16,7 @@ import io.lbry.browser.exceptions.LbryUriException;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
import io.lbry.browser.model.UrlSuggestion;
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
import io.lbry.browser.ui.controls.SolidIconView;
|
import io.lbry.browser.ui.controls.SolidIconView;
|
||||||
|
import io.lbry.browser.utils.Helper;
|
||||||
import io.lbry.browser.utils.LbryUri;
|
import io.lbry.browser.utils.LbryUri;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@ public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestion
|
||||||
iconStringId = R.string.fa_at;
|
iconStringId = R.string.fa_at;
|
||||||
fullTitle = item.getTitle();
|
fullTitle = item.getTitle();
|
||||||
desc = item.getClaim() != null ? item.getClaim().getTitle() :
|
desc = item.getClaim() != null ? item.getClaim().getTitle() :
|
||||||
(item.isUseTextAsDescription() ? item.getText() : String.format(context.getString(R.string.view_channel_url_desc), item.getText()));
|
((item.isUseTextAsDescription() && !Helper.isNullOrEmpty(item.getText())) ? item.getText() : String.format(context.getString(R.string.view_channel_url_desc), item.getText()));
|
||||||
break;
|
break;
|
||||||
case UrlSuggestion.TYPE_TAG:
|
case UrlSuggestion.TYPE_TAG:
|
||||||
iconStringId = R.string.fa_hashtag;
|
iconStringId = R.string.fa_hashtag;
|
||||||
|
@ -113,7 +114,7 @@ public class UrlSuggestionListAdapter extends RecyclerView.Adapter<UrlSuggestion
|
||||||
iconStringId = R.string.fa_file;
|
iconStringId = R.string.fa_file;
|
||||||
fullTitle = item.getTitle();
|
fullTitle = item.getTitle();
|
||||||
desc = item.getClaim() != null ? item.getClaim().getTitle() :
|
desc = item.getClaim() != null ? item.getClaim().getTitle() :
|
||||||
(item.isUseTextAsDescription() ? item.getText() : String.format(context.getString(R.string.view_file_url_desc), item.getText()));
|
((item.isUseTextAsDescription() && !Helper.isNullOrEmpty(item.getText())) ? item.getText() : String.format(context.getString(R.string.view_file_url_desc), item.getText()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.lbry.browser.utils.LbryUri;
|
||||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
public static final int DATABASE_VERSION = 1;
|
public static final int DATABASE_VERSION = 1;
|
||||||
public static final String DATABASE_NAME = "LbryApp.db";
|
public static final String DATABASE_NAME = "LbryApp.db";
|
||||||
|
private static DatabaseHelper instance;
|
||||||
|
|
||||||
private static final String[] SQL_CREATE_TABLES = {
|
private static final String[] SQL_CREATE_TABLES = {
|
||||||
// local subscription store
|
// local subscription store
|
||||||
|
@ -58,7 +59,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
|
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
|
||||||
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions";
|
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions";
|
||||||
|
|
||||||
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?)";
|
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)";
|
||||||
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
|
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
|
||||||
private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?";
|
private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?";
|
||||||
private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10";
|
private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10";
|
||||||
|
@ -77,6 +78,10 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public DatabaseHelper(Context context) {
|
public DatabaseHelper(Context context) {
|
||||||
super(context, String.format("%s/%s", context.getFilesDir().getAbsolutePath(), DATABASE_NAME), null, DATABASE_VERSION);
|
super(context, String.format("%s/%s", context.getFilesDir().getAbsolutePath(), DATABASE_NAME), null, DATABASE_VERSION);
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
public static DatabaseHelper getInstance() {
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
for (String sql : SQL_CREATE_TABLES) {
|
for (String sql : SQL_CREATE_TABLES) {
|
||||||
|
@ -113,13 +118,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
UrlSuggestion suggestion = new UrlSuggestion();
|
UrlSuggestion suggestion = new UrlSuggestion();
|
||||||
suggestion.setText(cursor.getString(0));
|
suggestion.setText(cursor.getString(0));
|
||||||
|
suggestion.setUri(cursor.isNull(1) ? null : LbryUri.tryParse(cursor.getString(1)));
|
||||||
suggestion.setType(cursor.getInt(2));
|
suggestion.setType(cursor.getInt(2));
|
||||||
|
suggestion.setTitleUrlOnly(true);
|
||||||
try {
|
|
||||||
suggestion.setUri(cursor.isNull(1) ? null : LbryUri.parse(cursor.getString(1)));
|
|
||||||
} catch (LbryUriException ex) {
|
|
||||||
// don't fail if the LbryUri is invalid
|
|
||||||
}
|
|
||||||
suggestions.add(suggestion);
|
suggestions.add(suggestion);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -372,9 +372,10 @@ public class Claim {
|
||||||
Claim signingChannel = new Claim();
|
Claim signingChannel = new Claim();
|
||||||
signingChannel.setClaimId(searchResultObject.getString("channel_claim_id"));
|
signingChannel.setClaimId(searchResultObject.getString("channel_claim_id"));
|
||||||
signingChannel.setName(searchResultObject.getString("channel"));
|
signingChannel.setName(searchResultObject.getString("channel"));
|
||||||
|
LbryUri channelUri = new LbryUri();
|
||||||
claimUri.setChannelClaimId(signingChannel.getClaimId());
|
channelUri.setChannelClaimId(signingChannel.getClaimId());
|
||||||
claimUri.setChannelName(signingChannel.getName());
|
channelUri.setChannelName(signingChannel.getName());
|
||||||
|
signingChannel.setPermanentUrl(channelUri.toString());
|
||||||
|
|
||||||
claim.setSigningChannel(signingChannel);
|
claim.setSigningChannel(signingChannel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,34 +5,36 @@ import androidx.annotation.Nullable;
|
||||||
import io.lbry.browser.utils.Helper;
|
import io.lbry.browser.utils.Helper;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to represent a key to check equality with another object
|
* Class to represent a key to check equality with another object
|
||||||
*/
|
*/
|
||||||
|
@ToString
|
||||||
public class ClaimCacheKey {
|
public class ClaimCacheKey {
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private String claimId;
|
private String claimId;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private String canonicalUrl;
|
private String url;
|
||||||
@Getter
|
|
||||||
@Setter
|
public static ClaimCacheKey fromClaimShortUrl(Claim claim) {
|
||||||
private String permanentUrl;
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
@Getter
|
key.setUrl(claim.getShortUrl());
|
||||||
@Setter
|
return key;
|
||||||
private String shortUrl;
|
}
|
||||||
@Getter
|
|
||||||
@Setter
|
public static ClaimCacheKey fromClaimPermanentUrl(Claim claim) {
|
||||||
private String vanityUrl;
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
|
key.setUrl(claim.getPermanentUrl());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
public static ClaimCacheKey fromClaim(Claim claim) {
|
public static ClaimCacheKey fromClaim(Claim claim) {
|
||||||
ClaimCacheKey key = new ClaimCacheKey();
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setClaimId(claim.getClaimId());
|
key.setClaimId(claim.getClaimId());
|
||||||
key.setCanonicalUrl(claim.getCanonicalUrl());
|
key.setUrl(!Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
|
||||||
key.setPermanentUrl(claim.getPermanentUrl());
|
|
||||||
key.setShortUrl(claim.getShortUrl());
|
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,44 +43,24 @@ public class ClaimCacheKey {
|
||||||
if (obj == null || !(obj instanceof ClaimCacheKey)) {
|
if (obj == null || !(obj instanceof ClaimCacheKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClaimCacheKey key = (ClaimCacheKey) obj;
|
ClaimCacheKey key = (ClaimCacheKey) obj;
|
||||||
if (!Helper.isNullOrEmpty(claimId) && !Helper.isNullOrEmpty(key.getClaimId())) {
|
if (!Helper.isNullOrEmpty(claimId) && !Helper.isNullOrEmpty(key.getClaimId())) {
|
||||||
return claimId.equalsIgnoreCase(key.getClaimId());
|
return claimId.equalsIgnoreCase(key.getClaimId());
|
||||||
}
|
}
|
||||||
if (!Helper.isNullOrEmpty(permanentUrl) && !Helper.isNullOrEmpty(key.getPermanentUrl())) {
|
if (!Helper.isNullOrEmpty(url) && !Helper.isNullOrEmpty(key.getUrl())) {
|
||||||
return permanentUrl.equalsIgnoreCase(key.getPermanentUrl());
|
return url.equalsIgnoreCase(key.getUrl());
|
||||||
}
|
}
|
||||||
if (!Helper.isNullOrEmpty(canonicalUrl) && !Helper.isNullOrEmpty(key.getCanonicalUrl())) {
|
|
||||||
return canonicalUrl.equalsIgnoreCase(key.getCanonicalUrl());
|
|
||||||
}
|
|
||||||
if (!Helper.isNullOrEmpty(shortUrl) && !Helper.isNullOrEmpty(key.getShortUrl())) {
|
|
||||||
return shortUrl.equalsIgnoreCase(key.getShortUrl());
|
|
||||||
}
|
|
||||||
if (!Helper.isNullOrEmpty(vanityUrl) && !Helper.isNullOrEmpty(key.getVanityUrl())) {
|
|
||||||
return vanityUrl.equalsIgnoreCase(key.getVanityUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
if (!Helper.isNullOrEmpty(url)) {
|
||||||
|
return url.hashCode();
|
||||||
|
}
|
||||||
if (!Helper.isNullOrEmpty(claimId)) {
|
if (!Helper.isNullOrEmpty(claimId)) {
|
||||||
return claimId.hashCode();
|
return claimId.hashCode();
|
||||||
}
|
}
|
||||||
if (!Helper.isNullOrEmpty(permanentUrl)) {
|
|
||||||
return permanentUrl.hashCode();
|
|
||||||
}
|
|
||||||
if (!Helper.isNullOrEmpty(canonicalUrl)) {
|
|
||||||
return canonicalUrl.hashCode();
|
|
||||||
}
|
|
||||||
if (!Helper.isNullOrEmpty(shortUrl)) {
|
|
||||||
return shortUrl.hashCode();
|
|
||||||
}
|
|
||||||
if (!Helper.isNullOrEmpty(vanityUrl)) {
|
|
||||||
return vanityUrl.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.hashCode();
|
return super.hashCode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ public class UrlSuggestion {
|
||||||
private LbryUri uri;
|
private LbryUri uri;
|
||||||
private Claim claim; // associated claim if resolved
|
private Claim claim; // associated claim if resolved
|
||||||
private boolean titleTextOnly;
|
private boolean titleTextOnly;
|
||||||
|
private boolean titleUrlOnly;
|
||||||
private boolean useTextAsDescription;
|
private boolean useTextAsDescription;
|
||||||
|
|
||||||
public UrlSuggestion() {
|
public UrlSuggestion() {
|
||||||
|
@ -34,6 +35,10 @@ public class UrlSuggestion {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
|
if (titleUrlOnly && (type == TYPE_CHANNEL || type == TYPE_FILE)) {
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (!titleTextOnly) {
|
if (!titleTextOnly) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_CHANNEL:
|
case TYPE_CHANNEL:
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class ClaimSearchTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
}
|
}
|
||||||
protected List<Claim> doInBackground(Void... params) {
|
protected List<Claim> doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
return Lbry.claimSearch(options, connectionString);
|
return Helper.filterInvalidReposts(Lbry.claimSearch(options, connectionString));
|
||||||
} catch (ApiCallException ex) {
|
} catch (ApiCallException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class ResolveTask extends AsyncTask<Void, Void, List<Claim>> {
|
||||||
}
|
}
|
||||||
protected List<Claim> doInBackground(Void... params) {
|
protected List<Claim> doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
return Lbry.resolve(urls, connectionString);
|
return Helper.filterInvalidReposts(Lbry.resolve(urls, connectionString));
|
||||||
} catch (ApiCallException ex) {
|
} catch (ApiCallException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package io.lbry.browser.tasks.localdata;
|
||||||
|
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteException;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
|
|
||||||
|
public class FetchRecentUrlHistoryTask extends AsyncTask<Void, Void, List<UrlSuggestion>> {
|
||||||
|
private DatabaseHelper dbHelper;
|
||||||
|
private FetchRecentUrlHistoryHandler handler;
|
||||||
|
public FetchRecentUrlHistoryTask(DatabaseHelper dbHelper, FetchRecentUrlHistoryHandler handler) {
|
||||||
|
this.dbHelper = dbHelper;
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
protected List<UrlSuggestion> doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||||
|
return DatabaseHelper.getRecentHistory(db);
|
||||||
|
} catch (SQLiteException ex) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void onPostExecute(List<UrlSuggestion> recentHistory) {
|
||||||
|
if (handler != null) {
|
||||||
|
handler.onSuccess(recentHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface FetchRecentUrlHistoryHandler {
|
||||||
|
void onSuccess(List<UrlSuggestion> recentHistory);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,21 +9,21 @@ import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.model.UrlSuggestion;
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||||
|
|
||||||
public class CreateUrlHistoryTask extends AsyncTask<Void, Void, Boolean> {
|
public class SaveUrlHistoryTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
private Context context;
|
private DatabaseHelper dbHelper;
|
||||||
private UrlSuggestion suggestion;
|
private UrlSuggestion suggestion;
|
||||||
private GenericTaskHandler handler;
|
private SaveUrlHistoryHandler handler;
|
||||||
private Exception error;
|
private Exception error;
|
||||||
|
|
||||||
public CreateUrlHistoryTask(UrlSuggestion suggestion, Context context, GenericTaskHandler handler) {
|
public SaveUrlHistoryTask(UrlSuggestion suggestion, DatabaseHelper dbHelper, SaveUrlHistoryHandler handler) {
|
||||||
this.suggestion = suggestion;
|
this.suggestion = suggestion;
|
||||||
this.context = context;
|
this.dbHelper = dbHelper;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
||||||
}
|
}
|
||||||
protected Boolean doInBackground(Void... params) {
|
protected Boolean doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
SQLiteDatabase db = ((MainActivity) context).getDbHelper().getWritableDatabase();
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
DatabaseHelper.createOrUpdateUrlHistoryItem(suggestion.getText(), suggestion.getUri().toString(), suggestion.getType(), db);
|
DatabaseHelper.createOrUpdateUrlHistoryItem(suggestion.getText(), suggestion.getUri().toString(), suggestion.getType(), db);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
|
@ -35,10 +35,15 @@ public class CreateUrlHistoryTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
protected void onPostExecute(Boolean result) {
|
protected void onPostExecute(Boolean result) {
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (result) {
|
if (result) {
|
||||||
handler.onSuccess();
|
handler.onSuccess(suggestion);
|
||||||
} else {
|
} else {
|
||||||
handler.onError(error);
|
handler.onError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface SaveUrlHistoryHandler {
|
||||||
|
void onSuccess(UrlSuggestion item);
|
||||||
|
void onError(Exception error);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package io.lbry.browser.tasks.localdata;
|
||||||
|
|
||||||
|
public class SaveViewHistoryTask {
|
||||||
|
}
|
|
@ -31,10 +31,13 @@ import java.util.Map;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
import io.lbry.browser.MainActivity;
|
||||||
import io.lbry.browser.R;
|
import io.lbry.browser.R;
|
||||||
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.dialog.SendTipDialogFragment;
|
import io.lbry.browser.dialog.SendTipDialogFragment;
|
||||||
import io.lbry.browser.exceptions.LbryUriException;
|
import io.lbry.browser.exceptions.LbryUriException;
|
||||||
import io.lbry.browser.listener.FetchChannelsListener;
|
import io.lbry.browser.listener.FetchChannelsListener;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
|
import io.lbry.browser.model.ClaimCacheKey;
|
||||||
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
import io.lbry.browser.model.lbryinc.Subscription;
|
import io.lbry.browser.model.lbryinc.Subscription;
|
||||||
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
|
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
|
||||||
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
import io.lbry.browser.tasks.claim.ClaimListResultHandler;
|
||||||
|
@ -296,13 +299,24 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
|
||||||
if (updateRequired) {
|
if (updateRequired) {
|
||||||
resetSubCount();
|
resetSubCount();
|
||||||
if (!Helper.isNullOrEmpty(url)) {
|
if (!Helper.isNullOrEmpty(url)) {
|
||||||
|
// check if the claim is already cached
|
||||||
|
ClaimCacheKey key = new ClaimCacheKey();
|
||||||
|
key.setUrl(url);
|
||||||
|
if (Lbry.claimCache.containsKey(key)) {
|
||||||
|
claim = Lbry.claimCache.get(key);
|
||||||
|
} else {
|
||||||
resolveUrl();
|
resolveUrl();
|
||||||
|
}
|
||||||
} else if (claim == null) {
|
} else if (claim == null) {
|
||||||
// nothing at this location
|
// nothing at this location
|
||||||
renderNothingAtLocation();
|
renderNothingAtLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Helper.isNullOrEmpty(url)) {
|
||||||
|
Helper.saveUrlHistory(url, claim != null ? claim.getTitle() : null, UrlSuggestion.TYPE_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
if (claim != null) {
|
if (claim != null) {
|
||||||
renderClaim();
|
renderClaim();
|
||||||
}
|
}
|
||||||
|
@ -315,6 +329,10 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
|
||||||
public void onSuccess(List<Claim> claims) {
|
public void onSuccess(List<Claim> claims) {
|
||||||
if (claims.size() > 0 && !Helper.isNullOrEmpty(claims.get(0).getClaimId())) {
|
if (claims.size() > 0 && !Helper.isNullOrEmpty(claims.get(0).getClaimId())) {
|
||||||
claim = claims.get(0);
|
claim = claims.get(0);
|
||||||
|
if (!Helper.isNullOrEmpty(url)) {
|
||||||
|
Helper.saveUrlHistory(url, claim.getTitle(), UrlSuggestion.TYPE_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
renderClaim();
|
renderClaim();
|
||||||
checkOwnChannel();
|
checkOwnChannel();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class SearchFragment extends BaseFragment implements
|
||||||
|
|
||||||
private void resolveFeaturedItem(String vanityUrl) {
|
private void resolveFeaturedItem(String vanityUrl) {
|
||||||
final ClaimCacheKey key = new ClaimCacheKey();
|
final ClaimCacheKey key = new ClaimCacheKey();
|
||||||
key.setVanityUrl(vanityUrl);
|
key.setUrl(vanityUrl);
|
||||||
if (Lbry.claimCache.containsKey(key)) {
|
if (Lbry.claimCache.containsKey(key)) {
|
||||||
Claim cachedClaim = Lbry.claimCache.get(key);
|
Claim cachedClaim = Lbry.claimCache.get(key);
|
||||||
updateFeaturedItemFromResolvedClaim(cachedClaim);
|
updateFeaturedItemFromResolvedClaim(cachedClaim);
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.GradientDrawable;
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
|
@ -40,10 +41,13 @@ import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import io.lbry.browser.MainActivity;
|
import io.lbry.browser.MainActivity;
|
||||||
|
import io.lbry.browser.data.DatabaseHelper;
|
||||||
import io.lbry.browser.dialog.ContentFromDialogFragment;
|
import io.lbry.browser.dialog.ContentFromDialogFragment;
|
||||||
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
import io.lbry.browser.dialog.ContentSortDialogFragment;
|
||||||
import io.lbry.browser.model.Claim;
|
import io.lbry.browser.model.Claim;
|
||||||
import io.lbry.browser.model.Tag;
|
import io.lbry.browser.model.Tag;
|
||||||
|
import io.lbry.browser.model.UrlSuggestion;
|
||||||
|
import io.lbry.browser.tasks.localdata.SaveUrlHistoryTask;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
|
|
||||||
public final class Helper {
|
public final class Helper {
|
||||||
|
@ -555,4 +559,26 @@ public final class Helper {
|
||||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
textView.setText(HtmlCompat.fromHtml(textView.getText().toString(), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
textView.setText(HtmlCompat.fromHtml(textView.getText().toString(), HtmlCompat.FROM_HTML_MODE_LEGACY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Claim> filterInvalidReposts(List<Claim> claims) {
|
||||||
|
List<Claim> filtered = new ArrayList<>();
|
||||||
|
for (Claim claim : claims) {
|
||||||
|
if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType()) && claim.getRepostedClaim() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filtered.add(claim);
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveUrlHistory(String url, String title, int type) {
|
||||||
|
DatabaseHelper dbHelper = DatabaseHelper.getInstance();
|
||||||
|
if (dbHelper != null) {
|
||||||
|
UrlSuggestion suggestion = new UrlSuggestion();
|
||||||
|
suggestion.setUri(LbryUri.tryParse(url));
|
||||||
|
suggestion.setType(type);
|
||||||
|
suggestion.setText(Helper.isNull(title) ? "" : title);
|
||||||
|
new SaveUrlHistoryTask(suggestion, dbHelper, null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,9 +250,7 @@ public final class Lbry {
|
||||||
Claim claim = Claim.fromJSONObject(result.getJSONObject(keys.next()));
|
Claim claim = Claim.fromJSONObject(result.getJSONObject(keys.next()));
|
||||||
claims.add(claim);
|
claims.add(claim);
|
||||||
|
|
||||||
// TODO: Add/remove/prune entries claim cache management
|
addClaimToCache(claim);
|
||||||
ClaimCacheKey key = ClaimCacheKey.fromClaim(claim);
|
|
||||||
claimCache.put(key, claim);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (LbryRequestException | LbryResponseException | JSONException ex) {
|
} catch (LbryRequestException | LbryResponseException | JSONException ex) {
|
||||||
|
@ -396,8 +394,7 @@ public final class Lbry {
|
||||||
Claim claim = Claim.fromJSONObject(items.getJSONObject(i));
|
Claim claim = Claim.fromJSONObject(items.getJSONObject(i));
|
||||||
claims.add(claim);
|
claims.add(claim);
|
||||||
|
|
||||||
ClaimCacheKey key = ClaimCacheKey.fromClaim(claim);
|
addClaimToCache(claim);
|
||||||
claimCache.put(key, claim);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,4 +449,15 @@ public final class Lbry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addClaimToCache(Claim claim) {
|
||||||
|
ClaimCacheKey fullKey = ClaimCacheKey.fromClaim(claim);
|
||||||
|
ClaimCacheKey shortUrlKey = ClaimCacheKey.fromClaimShortUrl(claim);
|
||||||
|
ClaimCacheKey permanentUrlKey = ClaimCacheKey.fromClaimPermanentUrl(claim);
|
||||||
|
claimCache.put(fullKey, claim);
|
||||||
|
claimCache.put(permanentUrlKey, claim);
|
||||||
|
if (!Helper.isNullOrEmpty(shortUrlKey.getUrl())) {
|
||||||
|
claimCache.put(shortUrlKey, claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
app/src/main/res/drawable-anydpi/ic_cast.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="#FFFFFF"
|
||||||
|
android:alpha="0.8">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"/>
|
||||||
|
</vector>
|
11
app/src/main/res/drawable-anydpi/ic_cast_connected.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="#FFFFFF"
|
||||||
|
android:alpha="0.8">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM19,7L5,7v1.63c3.96,1.28 7.09,4.41 8.37,8.37L19,17L19,7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||||
|
</vector>
|
BIN
app/src/main/res/drawable-hdpi/ic_cast.png
Normal file
After Width: | Height: | Size: 410 B |
BIN
app/src/main/res/drawable-hdpi/ic_cast_connected.png
Normal file
After Width: | Height: | Size: 477 B |
BIN
app/src/main/res/drawable-mdpi/ic_cast.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
app/src/main/res/drawable-mdpi/ic_cast_connected.png
Normal file
After Width: | Height: | Size: 318 B |
BIN
app/src/main/res/drawable-xhdpi/ic_cast.png
Normal file
After Width: | Height: | Size: 497 B |
BIN
app/src/main/res/drawable-xhdpi/ic_cast_connected.png
Normal file
After Width: | Height: | Size: 563 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_cast.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_cast_connected.png
Normal file
After Width: | Height: | Size: 867 B |
|
@ -162,9 +162,15 @@
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.PlayerControlView android:id="@+id/file_view_cast_control_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:repeat_toggle_modes="all|one"
|
||||||
|
app:show_timeout="-1"/>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/file_view_scroll_view"
|
android:id="@+id/file_view_scroll_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</androidx.appcompat.widget.Toolbar>
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<include layout="@layout/content_main" />
|
<include layout="@layout/content_main" />
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
android:id="@+id/url_suggestions_container"
|
android:id="@+id/url_suggestions_container"
|
||||||
android:background="@color/pageBackground"
|
android:background="@color/pageBackground"
|
||||||
android:elevation="6dp"
|
android:elevation="6dp"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:visibility="gone">
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/url_suggestions"
|
android:id="@+id/url_suggestions"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -21,7 +21,25 @@
|
||||||
style="@style/ExoMediaButton.Pause" />
|
style="@style/ExoMediaButton.Pause" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/player_toggle_full_screen"
|
android:id="@+id/player_toggle_cast"
|
||||||
|
android:clickable="true"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:visibility="gone">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/player_image_cast_toggle"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:src="@drawable/ic_cast"
|
||||||
|
android:tint="@color/white" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/player_toggle_fullscreen"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
|
@ -41,7 +59,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_toLeftOf="@id/player_toggle_full_screen"
|
android:layout_toLeftOf="@id/player_toggle_fullscreen"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="4dp">
|
android:paddingRight="4dp">
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
<string name="delete_file">Delete file</string>
|
<string name="delete_file">Delete file</string>
|
||||||
<string name="confirm_delete_file_message">Are you sure you want to remove this file from your device?</string>
|
<string name="confirm_delete_file_message">Are you sure you want to remove this file from your device?</string>
|
||||||
<string name="unable_to_view_url">Failed to load %1$s. Please try again later.</string>
|
<string name="unable_to_view_url">Failed to load %1$s. Please try again later.</string>
|
||||||
|
<string name="no_cast_session_available">There is no cast session available at this time.</string>
|
||||||
<plurals name="view_count">
|
<plurals name="view_count">
|
||||||
<item quantity="one">%1$s view</item>
|
<item quantity="one">%1$s view</item>
|
||||||
<item quantity="other">%1$s views</item>
|
<item quantity="other">%1$s views</item>
|
||||||
|
|