diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java index f9b6c945..61bbb09c 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java @@ -13,7 +13,9 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.text.format.DateUtils; +import android.view.ContextMenu; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -37,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.github.chrisbanes.photoview.PhotoView; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.database.ExoDatabaseProvider; @@ -125,6 +128,8 @@ import io.lbry.lbrysdk.Utils; public class FileViewFragment extends BaseFragment implements MainActivity.BackPressInterceptor, DownloadActionListener, FetchClaimsListener, SdkStatusListener, StoragePermissionListener { private static final int RELATED_CONTENT_SIZE = 16; + private static final String DEFAULT_PLAYBACK_SPEED = "1x"; + private PlayerControlView castControlView; private Player currentPlayer; private boolean loadingNewClaim; @@ -791,7 +796,28 @@ public class FileViewFragment extends BaseFragment implements } }); - root.findViewById(R.id.player_toggle_fullscreen).setOnClickListener(new View.OnClickListener() { + PlayerView playerView = root.findViewById(R.id.file_view_exoplayer_view); + View playbackSpeedContainer = playerView.findViewById(R.id.player_playback_speed); + TextView textPlaybackSpeed = playerView.findViewById(R.id.player_playback_speed_label); + textPlaybackSpeed.setText(DEFAULT_PLAYBACK_SPEED); + + playbackSpeedContainer.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() { + @Override + public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) { + Helper.buildPlaybackSpeedMenu(contextMenu); + } + }); + playbackSpeedContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Context context = getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).openContextMenu(playbackSpeedContainer); + } + } + }); + + playerView.findViewById(R.id.player_toggle_fullscreen).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // check full screen mode @@ -802,6 +828,22 @@ public class FileViewFragment extends BaseFragment implements } } }); + playerView.findViewById(R.id.player_skip_back_10).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (MainActivity.appPlayer != null) { + MainActivity.appPlayer.seekTo(Math.max(0, MainActivity.appPlayer.getCurrentPosition() - 10000)); + } + } + }); + playerView.findViewById(R.id.player_skip_forward_10).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (MainActivity.appPlayer != null) { + MainActivity.appPlayer.seekTo(MainActivity.appPlayer.getCurrentPosition() + 10000); + } + } + }); root.findViewById(R.id.file_view_publisher_name).setOnClickListener(new View.OnClickListener() { @Override @@ -1667,8 +1709,10 @@ public class FileViewFragment extends BaseFragment implements ((ViewGroup) exoplayerContainer.getParent()).removeView(exoplayerContainer); globalLayout.addView(exoplayerContainer); + View playerView = root.findViewById(R.id.file_view_exoplayer_view); + ((ImageView) playerView.findViewById(R.id.player_image_full_screen_toggle)).setImageResource(R.drawable.ic_fullscreen_exit); + root.findViewById(R.id.player_image_full_screen_toggle).setVisibility(View.GONE); - root.findViewById(R.id.player_image_full_screen_exit_toggle).setVisibility(View.VISIBLE); MainActivity activity = (MainActivity) context; activity.enterFullScreenMode(); @@ -1691,8 +1735,8 @@ public class FileViewFragment extends BaseFragment implements ((ViewGroup) exoplayerContainer.getParent()).removeView(exoplayerContainer); mediaContainer.addView(exoplayerContainer); - root.findViewById(R.id.player_image_full_screen_toggle).setVisibility(View.VISIBLE); - root.findViewById(R.id.player_image_full_screen_exit_toggle).setVisibility(View.GONE); + View playerView = root.findViewById(R.id.file_view_exoplayer_view); + ((ImageView) playerView.findViewById(R.id.player_image_full_screen_toggle)).setImageResource(R.drawable.ic_fullscreen); exoplayerContainer.setPadding(0, 0, 0, 0); activity.exitFullScreenMode(); @@ -1750,6 +1794,8 @@ public class FileViewFragment extends BaseFragment implements if (MainActivity.appPlayer != null) { MainActivity.appPlayer.removeListener(fileViewPlayerListener); + PlaybackParameters params = new PlaybackParameters(1.0f); + MainActivity.appPlayer.setPlaybackParameters(params); } } @@ -2021,6 +2067,23 @@ public class FileViewFragment extends BaseFragment implements } } + @Override + public boolean onContextItemSelected(MenuItem item) { + View root = getView(); + if (root != null) { + float speed = item.getItemId() / 100.0f; + String speedString = String.format("%sx", new DecimalFormat("0.##").format(speed)); + PlayerView playerView = root.findViewById(R.id.file_view_exoplayer_view); + ((TextView) playerView.findViewById(R.id.player_playback_speed_label)).setText(speedString); + + if (MainActivity.appPlayer != null) { + PlaybackParameters params = new PlaybackParameters(speed); + MainActivity.appPlayer.setPlaybackParameters(params); + } + } + return true; + } + @Override public boolean shouldHideGlobalPlayer() { return true; diff --git a/app/src/main/java/io/lbry/browser/ui/library/LibraryFragment.java b/app/src/main/java/io/lbry/browser/ui/library/LibraryFragment.java index 22a11a9e..49377b2a 100644 --- a/app/src/main/java/io/lbry/browser/ui/library/LibraryFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/library/LibraryFragment.java @@ -26,12 +26,10 @@ import com.google.android.material.snackbar.Snackbar; import org.json.JSONException; import org.json.JSONObject; -import java.nio.channels.AsynchronousChannel; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import io.lbry.browser.MainActivity; import io.lbry.browser.R; @@ -42,20 +40,16 @@ import io.lbry.browser.listener.SdkStatusListener; import io.lbry.browser.listener.SelectionModeListener; import io.lbry.browser.model.Claim; import io.lbry.browser.model.LbryFile; -import io.lbry.browser.model.NavMenuItem; import io.lbry.browser.model.ViewHistory; -import io.lbry.browser.tasks.claim.AbandonChannelTask; -import io.lbry.browser.tasks.claim.AbandonHandler; import io.lbry.browser.tasks.claim.ClaimListResultHandler; +import io.lbry.browser.tasks.claim.ClaimListTask; import io.lbry.browser.tasks.claim.ClaimSearchResultHandler; import io.lbry.browser.tasks.claim.PurchaseListTask; import io.lbry.browser.tasks.claim.ResolveTask; import io.lbry.browser.tasks.file.BulkDeleteFilesTask; -import io.lbry.browser.tasks.file.DeleteFileTask; import io.lbry.browser.tasks.file.FileListTask; import io.lbry.browser.tasks.localdata.FetchViewHistoryTask; import io.lbry.browser.ui.BaseFragment; -import io.lbry.browser.ui.channel.ChannelFormFragment; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.LbryAnalytics; @@ -85,6 +79,7 @@ public class LibraryFragment extends BaseFragment implements private Date lastDate; private boolean listReachedEnd; private boolean contentListLoading; + private boolean initialOwnClaimsFetched; private CardView cardStats; private TextView linkStats; @@ -252,6 +247,8 @@ public class LibraryFragment extends BaseFragment implements showDownloads(); } else if (currentFilter == FILTER_HISTORY) { showHistory(); + } else if (currentFilter == FILTER_PURCHASES) { + showPurchases(); } } @@ -271,10 +268,42 @@ public class LibraryFragment extends BaseFragment implements layoutSdkInitializing.setVisibility(Lbry.SDK_READY ? View.GONE : View.VISIBLE); currentPage = 1; if (Lbry.SDK_READY) { - fetchDownloads(); + if (!initialOwnClaimsFetched) { + fetchOwnClaimsAndShowDownloads(); + } else { + fetchDownloads(); + } } } + private void fetchOwnClaimsAndShowDownloads() { + if (Lbry.ownClaims != null && Lbry.ownClaims.size() > 0) { + initialOwnClaimsFetched = true; + fetchDownloads(); + return; + } + + linkStats.setVisibility(View.INVISIBLE); + ClaimListTask task = new ClaimListTask(Arrays.asList(Claim.TYPE_STREAM, Claim.TYPE_REPOST), listLoading, new ClaimListResultHandler() { + @Override + public void onSuccess(List claims) { + Lbry.ownClaims = Helper.filterDeletedClaims(new ArrayList<>(claims)); + initialOwnClaimsFetched = true; + if (currentFilter == FILTER_DOWNLOADS) { + fetchDownloads(); + } + checkStatsLink(); + } + + @Override + public void onError(Exception error) { + initialOwnClaimsFetched = true; + checkStatsLink(); + } + }); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + private void showPurchases() { currentFilter = FILTER_PURCHASES; linkFilterDownloads.setTypeface(null, Typeface.NORMAL); diff --git a/app/src/main/java/io/lbry/browser/utils/Helper.java b/app/src/main/java/io/lbry/browser/utils/Helper.java index 69821752..108d287c 100644 --- a/app/src/main/java/io/lbry/browser/utils/Helper.java +++ b/app/src/main/java/io/lbry/browser/utils/Helper.java @@ -18,6 +18,7 @@ import android.os.Environment; import android.provider.DocumentsContract; import android.provider.MediaStore; import android.text.method.LinkMovementMethod; +import android.view.ContextMenu; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; @@ -77,6 +78,8 @@ public final class Helper { public static final SimpleDateFormat FILESTAMP_FORMAT = new SimpleDateFormat("yyyyMMdd_HHmmss"); public static final String EXPLORER_TX_PREFIX = "https://explorer.lbry.com/tx"; + public static final List PLAYBACK_SPEEDS = Arrays.asList(0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0); + public static boolean isNull(String value) { return value == null; } @@ -84,6 +87,14 @@ public final class Helper { return value == null || value.trim().length() == 0; } + public static void buildPlaybackSpeedMenu(ContextMenu menu) { + int order = 0; + DecimalFormat formatter = new DecimalFormat("0.##"); + for (Double speed : PLAYBACK_SPEEDS) { + menu.add(0, Double.valueOf(speed * 100).intValue(), ++order, String.format("%sx", formatter.format(speed))); + } + } + public static String capitalize(String value) { StringBuilder sb = new StringBuilder(); boolean capitalizeNext = true; diff --git a/app/src/main/res/drawable-anydpi/ic_forward_10.xml b/app/src/main/res/drawable-anydpi/ic_forward_10.xml new file mode 100644 index 00000000..55e7a754 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_forward_10.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_replay_10.xml b/app/src/main/res/drawable-anydpi/ic_replay_10.xml new file mode 100644 index 00000000..a238e2d5 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_replay_10.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_forward_10.png b/app/src/main/res/drawable-hdpi/ic_forward_10.png new file mode 100644 index 00000000..d8763537 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_forward_10.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_replay_10.png b/app/src/main/res/drawable-hdpi/ic_replay_10.png new file mode 100644 index 00000000..7a487849 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_replay_10.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_forward_10.png b/app/src/main/res/drawable-mdpi/ic_forward_10.png new file mode 100644 index 00000000..751934c3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_forward_10.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_replay_10.png b/app/src/main/res/drawable-mdpi/ic_replay_10.png new file mode 100644 index 00000000..d1a44f69 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_replay_10.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_forward_10.png b/app/src/main/res/drawable-xhdpi/ic_forward_10.png new file mode 100644 index 00000000..c5acd34f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_forward_10.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_replay_10.png b/app/src/main/res/drawable-xhdpi/ic_replay_10.png new file mode 100644 index 00000000..14819ffa Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_replay_10.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_forward_10.png b/app/src/main/res/drawable-xxhdpi/ic_forward_10.png new file mode 100644 index 00000000..ac59544c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_forward_10.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_replay_10.png b/app/src/main/res/drawable-xxhdpi/ic_replay_10.png new file mode 100644 index 00000000..7a43cc57 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_replay_10.png differ 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 97f6a581..ec3e9d63 100644 --- a/app/src/main/res/layout/exo_playback_control_view.xml +++ b/app/src/main/res/layout/exo_playback_control_view.xml @@ -6,19 +6,56 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + + + + + + + + + + + + + + + + + - @@ -99,6 +150,7 @@ android:layout_alignParentRight="true" android:gravity="end" android:fontFamily="@font/inter" + android:singleLine="true" android:text="@string/zero_duration" android:textColor="@color/white" android:textSize="14sp" />