diff --git a/README.md b/README.md
index b154fad58..715e25b1e 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,22 @@
-
+
NewPipe
A free lightweight YouTube frontend for Android.
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
Screenshots • Description • Features • Contribution • Donate • License
Website • Blog • Press
-
-WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
+
+
+WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR TERMS OF CONDITIONS.
## Screenshots
@@ -29,6 +30,8 @@ WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR
[](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
[](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
[](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
+[](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_11.png)
+[](fastlane/metadata/android/en-US/images/tenInchScreenshots/shot_12.png)
## Description
@@ -61,11 +64,11 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
* Queuing videos
* Local playlists
* Subtitles
-* Multi-service support (eg. SoundCloud in NewPipe Beta)
+* Multi-service support (eg. SoundCloud \[beta\])
+* Livestream support
### Coming Features
-* Livestream support
* Cast to UPnP and Cast
* Show comments
* ... and many more
@@ -81,22 +84,27 @@ If you like NewPipe we'd be happy about a donation. You can either donate via Bi
- |
- |
+ |
+ |
16A9J59ahMRqkLSZjhYj33n9j3fMztFxnh |
- |
- |
- |
+ |
+ |
+ |
- |
- |
- |
+ |
+ |
+ |
+## Privacy Policy
+
+The NewPipe project aims to provide a private, anonymous experience for using media web services.
+Therefore, the app does not collect any data without your consent. NewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report or leave a comment at our blog. You can find the document [here](https://newpipe.schabi.org/legal/privacy/).
+
## License
[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 2ca4fd78d..9ab40e81c 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -33,12 +33,14 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
+import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@@ -64,19 +66,17 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment;
-import org.schabi.newpipe.local.history.HistoryRecordManager;
-import org.schabi.newpipe.report.ErrorActivity;
-import org.schabi.newpipe.util.StreamItemAdapter;
-import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
-import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog;
+import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
+import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
+import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper;
@@ -87,6 +87,8 @@ import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.PermissionHelper;
+import org.schabi.newpipe.util.StreamItemAdapter;
+import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable;
@@ -154,6 +156,7 @@ public class VideoDetailFragment
private View videoTitleRoot;
private TextView videoTitleTextView;
+ @Nullable
private ImageView videoTitleToggleArrow;
private TextView videoCountView;
@@ -415,14 +418,16 @@ public class VideoDetailFragment
}
private void toggleTitleAndDescription() {
- if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
- videoTitleTextView.setMaxLines(1);
- videoDescriptionRootLayout.setVisibility(View.GONE);
- videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
- } else {
- videoTitleTextView.setMaxLines(10);
- videoDescriptionRootLayout.setVisibility(View.VISIBLE);
- videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
+ if (videoTitleToggleArrow != null) { //it is null for tablets
+ if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
+ videoTitleTextView.setMaxLines(1);
+ videoDescriptionRootLayout.setVisibility(View.GONE);
+ videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
+ } else {
+ videoTitleTextView.setMaxLines(10);
+ videoDescriptionRootLayout.setVisibility(View.VISIBLE);
+ videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
+ }
}
}
@@ -622,8 +627,11 @@ public class VideoDetailFragment
relatedStreamsView.addView(
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
relatedStreamsView.addView(getSeparatorView());
- relatedStreamRootLayout.setVisibility(View.VISIBLE);
- } else nextStreamTitle.setVisibility(View.GONE);
+ setRelatedStreamsVisibility(View.VISIBLE);
+ } else {
+ nextStreamTitle.setVisibility(View.GONE);
+ setRelatedStreamsVisibility(View.GONE);
+ }
if (info.getRelatedStreams() != null
&& !info.getRelatedStreams().isEmpty() && showRelatedStreams) {
@@ -639,13 +647,13 @@ public class VideoDetailFragment
}
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
- relatedStreamRootLayout.setVisibility(View.VISIBLE);
+ setRelatedStreamsVisibility(View.VISIBLE);
relatedStreamExpandButton.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
} else {
- if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
+ if (info.getNextVideo() == null) setRelatedStreamsVisibility(View.GONE);
relatedStreamExpandButton.setVisibility(View.GONE);
}
}
@@ -1114,8 +1122,16 @@ public class VideoDetailFragment
animateView(videoTitleTextView, true, 0);
videoDescriptionRootLayout.setVisibility(View.GONE);
- videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
- videoTitleToggleArrow.setVisibility(View.GONE);
+ if (videoTitleToggleArrow != null) { //phone
+ videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
+ videoTitleToggleArrow.setVisibility(View.GONE);
+ } else { //tablet
+ final View related = (View) relatedStreamRootLayout.getParent();
+ //don`t need to hide it if related streams are disabled
+ if (related.getVisibility() == View.VISIBLE) {
+ related.setVisibility(View.INVISIBLE);
+ }
+ }
videoTitleRoot.setClickable(false);
imageLoader.cancelDisplayTask(thumbnailImageView);
@@ -1190,11 +1206,15 @@ public class VideoDetailFragment
detailDurationView.setVisibility(View.GONE);
}
- videoTitleRoot.setClickable(true);
- videoTitleToggleArrow.setVisibility(View.VISIBLE);
- videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
videoDescriptionView.setVisibility(View.GONE);
- videoDescriptionRootLayout.setVisibility(View.GONE);
+ if (videoTitleToggleArrow != null) {
+ videoTitleRoot.setClickable(true);
+ videoTitleToggleArrow.setVisibility(View.VISIBLE);
+ videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
+ videoDescriptionRootLayout.setVisibility(View.GONE);
+ } else {
+ videoDescriptionRootLayout.setVisibility(View.VISIBLE);
+ }
if (!TextUtils.isEmpty(info.getUploadDate())) {
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
}
@@ -1242,6 +1262,11 @@ public class VideoDetailFragment
// Only auto play in the first open
autoPlayEnabled = false;
}
+
+ final ViewParent related = relatedStreamRootLayout.getParent();
+ if (related instanceof ScrollView) {
+ ((ScrollView) related).scrollTo(0, 0);
+ }
}
@@ -1299,4 +1324,13 @@ public class VideoDetailFragment
showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema);
}
+
+ private void setRelatedStreamsVisibility(int visibility) {
+ final ViewParent parent = relatedStreamRootLayout.getParent();
+ if (parent instanceof ScrollView) {
+ ((ScrollView) parent).setVisibility(visibility);
+ } else {
+ relatedStreamRootLayout.setVisibility(visibility);
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
index c70ea2b19..0816334ea 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java
@@ -3,10 +3,15 @@ package org.schabi.newpipe.fragments.list;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -21,9 +26,9 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
-import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.info_list.InfoListAdapter;
+import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.NavigationHelper;
@@ -36,7 +41,7 @@ import java.util.Queue;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
-public abstract class BaseListFragment extends BaseStateFragment implements ListViewContract, StateSaver.WriteRead {
+public abstract class BaseListFragment extends BaseStateFragment implements ListViewContract, StateSaver.WriteRead, SharedPreferences.OnSharedPreferenceChangeListener {
/*//////////////////////////////////////////////////////////////////////////
// Views
@@ -44,6 +49,9 @@ public abstract class BaseListFragment extends BaseStateFragment implem
protected InfoListAdapter infoListAdapter;
protected RecyclerView itemsList;
+ private int updateFlags = 0;
+
+ private static final int LIST_MODE_UPDATE_FLAG = 0x32;
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
@@ -59,12 +67,31 @@ public abstract class BaseListFragment extends BaseStateFragment implem
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ PreferenceManager.getDefaultSharedPreferences(activity)
+ .registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
StateSaver.onDestroy(savedState);
+ PreferenceManager.getDefaultSharedPreferences(activity)
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (updateFlags != 0) {
+ if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
+ final boolean useGrid = isGridLayout();
+ itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
+ infoListAdapter.setGridItemVariants(useGrid);
+ infoListAdapter.notifyDataSetChanged();
+ }
+ updateFlags = 0;
+ }
}
/*//////////////////////////////////////////////////////////////////////////
@@ -119,13 +146,25 @@ public abstract class BaseListFragment extends BaseStateFragment implem
return new LinearLayoutManager(activity);
}
+ protected RecyclerView.LayoutManager getGridLayoutManager() {
+ final Resources resources = activity.getResources();
+ int width = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width);
+ width += (24 * resources.getDisplayMetrics().density);
+ final int spanCount = (int) Math.floor(resources.getDisplayMetrics().widthPixels / (double)width);
+ final GridLayoutManager lm = new GridLayoutManager(activity, spanCount);
+ lm.setSpanSizeLookup(infoListAdapter.getSpanSizeLookup(spanCount));
+ return lm;
+ }
+
@Override
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
+ final boolean useGrid = isGridLayout();
itemsList = rootView.findViewById(R.id.items_list);
- itemsList.setLayoutManager(getListLayoutManager());
+ itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
+ infoListAdapter.setGridItemVariants(useGrid);
infoListAdapter.setFooter(getListFooter());
infoListAdapter.setHeader(getListHeader());
@@ -308,4 +347,22 @@ public abstract class BaseListFragment extends BaseStateFragment implem
public void handleNextItems(N result) {
isLoading.set(false);
}
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(getString(R.string.list_view_mode_key))) {
+ updateFlags |= LIST_MODE_UPDATE_FLAG;
+ }
+ }
+
+ protected boolean isGridLayout() {
+ final String list_mode = PreferenceManager.getDefaultSharedPreferences(activity).getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value));
+ if ("auto".equals(list_mode)) {
+ final Configuration configuration = getResources().getConfiguration();
+ return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
+ && configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
+ } else {
+ return "grid".equals(list_mode);
+ }
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
index cf12deb6f..15fdcad05 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
@@ -1,6 +1,7 @@
package org.schabi.newpipe.info_list;
import android.app.Activity;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
@@ -12,9 +13,12 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
+import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
+import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
+import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
@@ -52,14 +56,18 @@ public class InfoListAdapter extends RecyclerView.Adapter infoItemList;
private boolean useMiniVariant = false;
+ private boolean useGridVariant = false;
private boolean showFooter = false;
private View header = null;
private View footer = null;
@@ -94,6 +102,10 @@ public class InfoListAdapter extends RecyclerView.Adapter data) {
if (data != null) {
if (DEBUG) {
@@ -206,11 +218,11 @@ public class InfoListAdapter extends RecyclerView.Adapter {
+ if (itemBuilder.getOnChannelSelectedListener() != null) {
+ itemBuilder.getOnChannelSelectedListener().held(item);
+ }
+ return true;
+ });
}
protected String getDetailLine(final ChannelInfoItem item) {
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistGridInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistGridInfoItemHolder.java
new file mode 100644
index 000000000..96b9c90a7
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/PlaylistGridInfoItemHolder.java
@@ -0,0 +1,13 @@
+package org.schabi.newpipe.info_list.holder;
+
+import android.view.ViewGroup;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.info_list.InfoItemBuilder;
+
+public class PlaylistGridInfoItemHolder extends PlaylistMiniInfoItemHolder {
+
+ public PlaylistGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
+ super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamGridInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamGridInfoItemHolder.java
new file mode 100644
index 000000000..a2e585857
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/StreamGridInfoItemHolder.java
@@ -0,0 +1,13 @@
+package org.schabi.newpipe.info_list.holder;
+
+import android.view.ViewGroup;
+
+import org.schabi.newpipe.R;
+import org.schabi.newpipe.info_list.InfoItemBuilder;
+
+public class StreamGridInfoItemHolder extends StreamMiniInfoItemHolder {
+
+ public StreamGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
+ super(infoItemBuilder, R.layout.list_stream_grid_item, parent);
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java b/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
index 5192aa2ab..abdf82353 100644
--- a/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/BaseLocalListFragment.java
@@ -1,8 +1,13 @@
package org.schabi.newpipe.local;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -25,7 +30,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
* called and is memory efficient when in backstack.
* */
public abstract class BaseLocalListFragment extends BaseStateFragment
- implements ListViewContract {
+ implements ListViewContract, SharedPreferences.OnSharedPreferenceChangeListener {
/*//////////////////////////////////////////////////////////////////////////
// Views
@@ -36,6 +41,9 @@ public abstract class BaseLocalListFragment extends BaseStateFragment
protected LocalItemListAdapter itemListAdapter;
protected RecyclerView itemsList;
+ private int updateFlags = 0;
+
+ private static final int LIST_MODE_UPDATE_FLAG = 0x32;
/*//////////////////////////////////////////////////////////////////////////
// Lifecycle - Creation
@@ -45,6 +53,29 @@ public abstract class BaseLocalListFragment extends BaseStateFragment
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ PreferenceManager.getDefaultSharedPreferences(activity)
+ .registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ PreferenceManager.getDefaultSharedPreferences(activity)
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (updateFlags != 0) {
+ if ((updateFlags & LIST_MODE_UPDATE_FLAG) != 0) {
+ final boolean useGrid = isGridLayout();
+ itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
+ itemListAdapter.setGridItemVariants(useGrid);
+ itemListAdapter.notifyDataSetChanged();
+ }
+ updateFlags = 0;
+ }
}
/*//////////////////////////////////////////////////////////////////////////
@@ -59,6 +90,16 @@ public abstract class BaseLocalListFragment extends BaseStateFragment
return activity.getLayoutInflater().inflate(R.layout.pignate_footer, itemsList, false);
}
+ protected RecyclerView.LayoutManager getGridLayoutManager() {
+ final Resources resources = activity.getResources();
+ int width = resources.getDimensionPixelSize(R.dimen.video_item_grid_thumbnail_image_width);
+ width += (24 * resources.getDisplayMetrics().density);
+ final int spanCount = (int) Math.floor(resources.getDisplayMetrics().widthPixels / (double)width);
+ final GridLayoutManager lm = new GridLayoutManager(activity, spanCount);
+ lm.setSpanSizeLookup(itemListAdapter.getSpanSizeLookup(spanCount));
+ return lm;
+ }
+
protected RecyclerView.LayoutManager getListLayoutManager() {
return new LinearLayoutManager(activity);
}
@@ -67,10 +108,13 @@ public abstract class BaseLocalListFragment extends BaseStateFragment
protected void initViews(View rootView, Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
- itemsList = rootView.findViewById(R.id.items_list);
- itemsList.setLayoutManager(getListLayoutManager());
-
itemListAdapter = new LocalItemListAdapter(activity);
+
+ final boolean useGrid = isGridLayout();
+ itemsList = rootView.findViewById(R.id.items_list);
+ itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
+
+ itemListAdapter.setGridItemVariants(useGrid);
itemListAdapter.setHeader(headerRootView = getListHeader());
itemListAdapter.setFooter(footerRootView = getListFooter());
@@ -174,4 +218,22 @@ public abstract class BaseLocalListFragment extends BaseStateFragment
resetFragment();
return super.onError(exception);
}
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(getString(R.string.list_view_mode_key))) {
+ updateFlags |= LIST_MODE_UPDATE_FLAG;
+ }
+ }
+
+ protected boolean isGridLayout() {
+ final String list_mode = PreferenceManager.getDefaultSharedPreferences(activity).getString(getString(R.string.list_view_mode_key), getString(R.string.list_view_mode_value));
+ if ("auto".equals(list_mode)) {
+ final Configuration configuration = getResources().getConfiguration();
+ return configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
+ && configuration.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
+ } else {
+ return "grid".equals(list_mode);
+ }
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java b/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
index 99937b58c..e298dedd3 100644
--- a/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/local/LocalItemListAdapter.java
@@ -1,18 +1,21 @@
package org.schabi.newpipe.local;
import android.app.Activity;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.database.LocalItem;
-import org.schabi.newpipe.local.HeaderFooterHolder;
-import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.holder.LocalItemHolder;
+import org.schabi.newpipe.local.holder.LocalPlaylistGridItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
+import org.schabi.newpipe.local.holder.LocalPlaylistStreamGridItemHolder;
import org.schabi.newpipe.local.holder.LocalPlaylistStreamItemHolder;
+import org.schabi.newpipe.local.holder.LocalStatisticStreamGridItemHolder;
import org.schabi.newpipe.local.holder.LocalStatisticStreamItemHolder;
+import org.schabi.newpipe.local.holder.RemotePlaylistGridItemHolder;
import org.schabi.newpipe.local.holder.RemotePlaylistItemHolder;
import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.Localization;
@@ -52,14 +55,19 @@ public class LocalItemListAdapter extends RecyclerView.Adapter localItems;
private final DateFormat dateFormat;
private boolean showFooter = false;
+ private boolean useGridVariant = false;
private View header = null;
private View footer = null;
@@ -134,6 +142,10 @@ public class LocalItemListAdapter extends RecyclerView.Adapter> {
+public class SubscriptionFragment extends BaseStateFragment> implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final int REQUEST_EXPORT_CODE = 666;
private static final int REQUEST_IMPORT_CODE = 667;
@@ -78,6 +89,9 @@ public class SubscriptionFragment extends BaseStateFragment() {
- @Override
+
public void selected(ChannelInfoItem selectedItem) {
final FragmentManager fragmentManager = getFM();
NavigationHelper.openChannelFragment(fragmentManager,
@@ -326,6 +369,11 @@ public class SubscriptionFragment extends BaseStateFragment importExportOptions.switchState());
}
+ private void showLongTapDialog(ChannelInfoItem selectedItem) {
+ final Context context = getContext();
+ final Activity activity = getActivity();
+ if (context == null || context.getResources() == null || getActivity() == null) return;
+
+ final String[] commands = new String[]{
+ context.getResources().getString(R.string.share),
+ context.getResources().getString(R.string.unsubscribe)
+ };
+
+ final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
+ switch (i) {
+ case 0:
+ shareChannel(selectedItem);
+ break;
+ case 1:
+ deleteChannel(selectedItem);
+ break;
+ default:
+ break;
+ }
+ };
+
+ final View bannerView = View.inflate(activity, R.layout.dialog_title, null);
+ bannerView.setSelected(true);
+
+ TextView titleView = bannerView.findViewById(R.id.itemTitleView);
+ titleView.setText(selectedItem.getName());
+
+ TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
+ detailsView.setVisibility(View.GONE);
+
+ new AlertDialog.Builder(activity)
+ .setCustomTitle(bannerView)
+ .setItems(commands, actions)
+ .create()
+ .show();
+
+ }
+
+ private void shareChannel (ChannelInfoItem selectedItem) {
+ shareUrl(selectedItem.getName(), selectedItem.getUrl());
+ }
+
+ @SuppressLint("CheckResult")
+ private void deleteChannel (ChannelInfoItem selectedItem) {
+ subscriptionService.subscriptionTable()
+ .getSubscription(selectedItem.getServiceId(), selectedItem.getUrl())
+ .toObservable()
+ .observeOn(Schedulers.io())
+ .subscribe(getDeleteObserver());
+
+ Toast.makeText(activity, getString(R.string.channel_unsubscribed), Toast.LENGTH_SHORT).show();
+ }
+
+
+
+ private Observer> getDeleteObserver(){
+ return new Observer>() {
+ @Override
+ public void onSubscribe(Disposable d) {
+ disposables.add(d);
+ }
+
+ @Override
+ public void onNext(List subscriptionEntities) {
+ subscriptionService.subscriptionTable().delete(subscriptionEntities);
+ }
+
+ @Override
+ public void onError(Throwable exception) {
+ SubscriptionFragment.this.onError(exception);
+ }
+
+ @Override
+ public void onComplete() { }
+ };
+ }
+
private void resetFragment() {
if (disposables != null) disposables.clear();
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
@@ -445,4 +572,22 @@ public class SubscriptionFragment extends BaseStateFragment playerImpl.getRootView().getWidth() / 2) {
+ boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
+ boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
+ boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
+
+ if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
@@ -1052,7 +1058,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
}
- } else {
+ } else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
float currentProgressPercent =
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 05afe2859..16dffc3de 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -169,8 +169,12 @@ public class PlayerHelper {
return isResumeAfterAudioFocusGain(context, false);
}
- public static boolean isPlayerGestureEnabled(@NonNull final Context context) {
- return isPlayerGestureEnabled(context, true);
+ public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
+ return isVolumeGestureEnabled(context, true);
+ }
+
+ public static boolean isBrightnessGestureEnabled(@NonNull final Context context) {
+ return isBrightnessGestureEnabled(context, true);
}
public static boolean isUsingOldPlayer(@NonNull final Context context) {
@@ -306,8 +310,12 @@ public class PlayerHelper {
return getPreferences(context).getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), b);
}
- private static boolean isPlayerGestureEnabled(@NonNull final Context context, final boolean b) {
- return getPreferences(context).getBoolean(context.getString(R.string.player_gesture_controls_key), b);
+ private static boolean isVolumeGestureEnabled(@NonNull final Context context, final boolean b) {
+ return getPreferences(context).getBoolean(context.getString(R.string.volume_gesture_control_key), b);
+ }
+
+ private static boolean isBrightnessGestureEnabled(@NonNull final Context context, final boolean b) {
+ return getPreferences(context).getBoolean(context.getString(R.string.brightness_gesture_control_key), b);
}
private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) {
diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
index 49ee357ad..e04c1e8d0 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java
@@ -32,6 +32,7 @@ import org.schabi.newpipe.extractor.Info;
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
+import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
new file mode 100644
index 000000000..7d7e1230e
--- /dev/null
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -0,0 +1,581 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout-large-land/fragment_video_detail.xml b/app/src/main/res/layout-large-land/fragment_video_detail.xml
new file mode 100644
index 000000000..73939d60a
--- /dev/null
+++ b/app/src/main/res/layout-large-land/fragment_video_detail.xml
@@ -0,0 +1,491 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_subscription.xml b/app/src/main/res/layout/fragment_subscription.xml
index a40059455..f2137074e 100644
--- a/app/src/main/res/layout/fragment_subscription.xml
+++ b/app/src/main/res/layout/fragment_subscription.xml
@@ -11,7 +11,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
- app:layoutManager="LinearLayoutManager"
android:visibility="gone"
tools:listitem="@layout/list_channel_item"
tools:visibility="visible"/>
diff --git a/app/src/main/res/layout/list_channel_grid_item.xml b/app/src/main/res/layout/list_channel_grid_item.xml
new file mode 100644
index 000000000..3fe642974
--- /dev/null
+++ b/app/src/main/res/layout/list_channel_grid_item.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_playlist_grid_item.xml b/app/src/main/res/layout/list_playlist_grid_item.xml
new file mode 100644
index 000000000..949b1159b
--- /dev/null
+++ b/app/src/main/res/layout/list_playlist_grid_item.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_stream_grid_item.xml b/app/src/main/res/layout/list_stream_grid_item.xml
new file mode 100644
index 000000000..cf73bf9b1
--- /dev/null
+++ b/app/src/main/res/layout/list_stream_grid_item.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_stream_playlist_grid_item.xml b/app/src/main/res/layout/list_stream_playlist_grid_item.xml
new file mode 100644
index 000000000..4b31a452e
--- /dev/null
+++ b/app/src/main/res/layout/list_stream_playlist_grid_item.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 5e3e180b4..851262a73 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -490,6 +490,7 @@
Предел разрешения в мобильной сети
Каналы
Плейлисты
+ Видео
Дорожки
Пользователи
Проматывать тишину
@@ -502,4 +503,9 @@
Фоновый плеер
Плеер в окне
+ Вид списка
+ Список
+ Сетка
+ Автоматически
+
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index dd9431b46..1f95d2fbb 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -483,8 +483,12 @@
До тлового програвача
Зменшити до віконного програвачу
-Канали
+ Канали
Плейлисти
Стежки
Користувачі
-
+
+ Вигляд списку
+ Список
+ Сiтка
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index e7af3231e..229c00533 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -12,6 +12,8 @@
124dp
70dp
+ 164dp
+ 92dp
94dp
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index 2c45fa02d..54cc8b45b 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -19,7 +19,8 @@
autoplay_through_intent
use_oldplayer
- player_gesture_controls
+ volume_gesture_control
+ brightness_gesture_control
resume_on_audio_focus_gain
popup_remember_size_pos_key
use_inexact_seek_key
@@ -880,5 +881,18 @@
- 144p
+ list_view_mode
+ auto
-
\ No newline at end of file
+
+ - auto
+ - list
+ - grid
+
+
+ - @string/auto
+ - @string/list
+ - @string/grid
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 169d0b693..9fa90f47d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,7 +5,7 @@
%1$s views
Published on %1$s
No stream player found. Do you want to install VLC?
- No stream player found (you can install VLC to play it)
+ No stream player found (you can install VLC to play it).
Install
Cancel
https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc
@@ -13,23 +13,24 @@
Open in popup mode
Share
Download
- Download stream file.
+ Download stream file
Search
Settings
- Did you mean: %1$s ?
+ Did you mean: %1$s?
Share with
Choose browser
rotation
Use external video player
- Some resolutions will NOT have audio when this option is enabled
+ Removes audio at SOME resolutions
Use external audio player
NewPipe popup mode
RSS
Subscribe
Subscribed
+ Unsubscribe
Channel unsubscribed
- Unable to change subscription
- Unable to update subscription
+ Could not change subscription
+ Could not update subscription
Show info
Main
@@ -48,8 +49,8 @@
Path to store downloaded videos in
Enter download path for videos
- Audio download path
- Path to store downloaded audio in
+ Audio download folder
+ Downloaded audio is stored here
Enter download path for audio files
Autoplay
@@ -75,15 +76,17 @@
Use fast inexact seek
Inexact seek allows the player to seek to positions faster with reduced precision
Load thumbnails
- Disable to stop all thumbnails from loading and save on data and memory usage. Changing this will clear both in-memory and on-disk image cache.
+ When off no thumbnails load, saving data and memory usage. Changes clear both in-memory and on-disk image cache.
Image cache wiped
Wipe cached metadata
Remove all cached webpage data
Metadata cache wiped
Auto-queue next stream
Auto-append a related stream when playing the last stream in a non-repeating queue.
- Player gesture controls
- Use gestures to control the brightness and volume of the player
+ Volume gesture control
+ Use gestures to control the volume of the player
+ Brightness gesture control
+ Use gestures to control the brightness of the player
Search suggestions
Show suggestions when searching
Search history
@@ -93,18 +96,18 @@
Resume on focus gain
Continue playing after interruptions (e.g. phone calls)
Download
- Next video
- Show \'next\' and \'similar\' videos
- Show \"hold to append\" tip
+ Next
+ Show \'Next\' and \'Similar\' videos
+ Show \"Hold to append\" tip
Show tip when background or popup button is pressed on video details page
- URL not supported
+ Unsupported URL
Default content country
Service
Default content language
Player
Behavior
- Video & Audio
- History & Cache
+ Video & audio
+ History & cache
Popup
Appearance
Other
@@ -116,8 +119,8 @@
https://www.c3s.cc/
Play
Content
- Show age restricted content
- Age Restricted Video. Allowing such material is possible from Settings.
+ Age restricted content
+ Show age Restricted Video. Allowing such material is possible from \"Settings\".
live
LIVE
Downloads
@@ -147,7 +150,7 @@
newpipe
NewPipe Notification
- Notifications for NewPipe Background and Popup Players
+ Notifications for NewPipe background and popup players
[Unknown]
@@ -158,29 +161,29 @@
Import database
Export database
- Will override your current history and subscriptions
- Export history, subscriptions and playlists.
+ Overrides your current history and subscriptions
+ Export history, subscriptions and playlists
Clear watch history
- Deletes the history of played streams.
- Delete whole watch history.
+ Deletes the history of played streams
+ Delete entire watch history?
Watch history deleted.
Clear search history
- Deletes history of search keywords.
- Delete whole search history.
+ Deletes history of search keywords
+ Delete entire search history?
Search history deleted.
Error
- External storage not available.
- Download to external SD Card is not possible yet. Should the download place be reset?
+ External storage unavailable
+ Download to external SD card is not possible yet. Reset download folder location?
Network error
Could not load all thumbnails
Could not decrypt video URL signature
Could not parse website
Could not parse website completely
- Content not available
+ Content unavailable
Blocked by GEMA
Could not set up download menu
- This is a LIVE STREAM, which is not yet supported.
+ Live streams are not supported yet
Could not get any stream
Could not load image
App/UI crashed
@@ -191,10 +194,10 @@
Invalid URL
No video streams found
No audio streams found
- Invalid directory
- Invalid file/content source
- File doesn\'t exist or insufficient permission to read or write to it
- File name cannot be empty
+ No such folder
+ No such file/content source
+ The file doesn\'t exist or permission to read or write to it is lacking
+ Filename cannot be empty
An error occurred: %1$s
No streams available to download
Using default tabs, error while reading saved tabs
@@ -226,7 +229,7 @@
User report
No results
@string/no_videos
- Nothing Here But Crickets
+ Nothing here but crickets
Drag to reorder
Cannot create download directory \'%1$s\'
@@ -283,7 +286,7 @@
Filename
Threads
Error
- Server unsupported
+ Unsupported server
File already exists
Malformed URL or Internet not available
NewPipe Downloading
@@ -298,8 +301,8 @@
MD5
SHA-1
reCAPTCHA
- reCAPTCHA Challenge
- reCAPTCHA Challenge requested
+ reCAPTCHA challenge
+ reCAPTCHA challenge requested
@@ -344,7 +347,7 @@
https://newpipe.schabi.org/legal/privacy/
Read privacy policy
NewPipe\'s License
- NewPipe is copyleft libre software: You can use, study share and improve it at your will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ NewPipe is copyleft libre software: You can use, study share and improve it at will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Read license
@@ -352,7 +355,7 @@
History
Searched
Watched
- History is disabled
+ History is turned off
History
The history is empty
History cleared
@@ -373,10 +376,10 @@
Feed Page
Channel Page
Select a channel
- No channel subscribed yet
+ No channel subscriptions yet
Select a kiosk
- Export complete
- Import complete
+ Exported
+ Imported
No valid ZIP file
Warning: Could not import all files.
This will override your current setup.
@@ -390,17 +393,17 @@
%1$s/%2$s
- Background Player
- Popup Player
+ Background player
+ Popup player
Remove
Details
Audio Settings
- Hold To Enqueue
- Enqueue on Background
- Enqueue on Popup
- Start Playing Here
- Start Here on Background
- Start Here on Popup
+ Hold To enqueue
+ Enqueue when backgrounded
+ Enqueue on new popup
+ Start playing here
+ Start here when backgrounded
+ Start here on new popup
Open Drawer
@@ -424,9 +427,9 @@
"Loading requested content"
- Create New Playlist
- Delete Playlist
- Rename Playlist
+ New Playlist
+ Delete
+ Rename
Name
Add To Playlist
Set as Playlist Thumbnail
@@ -434,11 +437,11 @@
Bookmark Playlist
Remove Bookmark
- Do you want to delete this playlist?
+ Delete this playlist?
Playlist created
- Added to playlist
- Playlist thumbnail changed
- Could not delete playlist
+ Playlisted
+ Playlist thumbnail changed.
+ Could not delete playlist.
No Captions
@@ -457,11 +460,11 @@
Enable LeakCanary
Memory leak monitoring may cause the app to become unresponsive when heap dumping
- Report Out-of-lifecycle Errors
+ Report out-of-lifecycle errors
Force reporting of undeliverable Rx exceptions outside of fragment or activity lifecycle after disposal
- Import/Export
+ Import/export
Import
Import from
Export to
@@ -512,11 +515,14 @@
- Minimize on application switch
- Action when switching to other application from main video player — %s
+ Minimize on app switch
+ Action when switching to other app from main video player — %s
None
Minimize to background player
Minimize to popup player
+ List view mode
+ List
+ Grid
+ Auto
Switch View
-
diff --git a/app/src/main/res/xml/appearance_settings.xml b/app/src/main/res/xml/appearance_settings.xml
index 1f711b510..437736ab0 100644
--- a/app/src/main/res/xml/appearance_settings.xml
+++ b/app/src/main/res/xml/appearance_settings.xml
@@ -22,6 +22,14 @@
android:title="@string/show_hold_to_append_title"
android:summary="@string/show_hold_to_append_summary"/>
+
+
+ android:key="@string/volume_gesture_control_key"
+ android:summary="@string/volume_gesture_control_summary"
+ android:title="@string/volume_gesture_control_title"/>
+
+