mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 08:30:44 +00:00
Merge branch 'dev' into separate-gesture-options
This commit is contained in:
commit
046740f10b
@ -15,7 +15,7 @@
|
|||||||
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#description">Description</a> • <a href="#features">Features</a> • <a href="#contribution">Contribution</a> • <a href="#donate">Donate</a> • <a href="#license">License</a></p>
|
<p align="center"><a href="#screenshots">Screenshots</a> • <a href="#description">Description</a> • <a href="#features">Features</a> • <a href="#contribution">Contribution</a> • <a href="#donate">Donate</a> • <a href="#license">License</a></p>
|
||||||
<p align="center"><a href="https://newpipe.schabi.org">Website</a> • <a href="https://newpipe.schabi.org/blog/">Blog</a> • <a href="https://newpipe.schabi.org/press/">Press</a></p>
|
<p align="center"><a href="https://newpipe.schabi.org">Website</a> • <a href="https://newpipe.schabi.org/blog/">Blog</a> • <a href="https://newpipe.schabi.org/press/">Press</a></p>
|
||||||
<hr />
|
<hr />
|
||||||
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
|
## Screenshots
|
||||||
|
|
||||||
@ -29,6 +29,8 @@ WARNING: PUTTING NEWPIPE OR ANY FORK OF IT INTO GOOGLE PLAYSTORE VIOLATES THEIR
|
|||||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
|
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_8.png)
|
||||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
|
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_9.png)
|
||||||
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png" width=160>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_10.png)
|
||||||
|
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_11.png" width=405>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_11.png)
|
||||||
|
[<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/shot_12.png" width=405>](fastlane/metadata/android/en-US/images/phoneScreenshots/shot_12.png)
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@ -61,11 +63,11 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only
|
|||||||
* Queuing videos
|
* Queuing videos
|
||||||
* Local playlists
|
* Local playlists
|
||||||
* Subtitles
|
* Subtitles
|
||||||
* Multi-service support (eg. SoundCloud in NewPipe Beta)
|
* Multi-service support (eg. SoundCloud \[beta\])
|
||||||
|
* Livestream support
|
||||||
|
|
||||||
### Coming Features
|
### Coming Features
|
||||||
|
|
||||||
* Livestream support
|
|
||||||
* Cast to UPnP and Cast
|
* Cast to UPnP and Cast
|
||||||
* Show comments
|
* Show comments
|
||||||
* ... and many more
|
* ... and many more
|
||||||
|
@ -106,7 +106,7 @@ public class App extends Application {
|
|||||||
// https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
|
// https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling
|
||||||
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
|
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
|
||||||
@Override
|
@Override
|
||||||
public void accept(@NonNull Throwable throwable) throws Exception {
|
public void accept(@NonNull Throwable throwable) {
|
||||||
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " +
|
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " +
|
||||||
"throwable = [" + throwable.getClass().getName() + "]");
|
"throwable = [" + throwable.getClass().getName() + "]");
|
||||||
|
|
||||||
|
@ -12,14 +12,12 @@ import android.view.View;
|
|||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
import com.squareup.leakcanary.RefWatcher;
|
import com.squareup.leakcanary.RefWatcher;
|
||||||
|
|
||||||
import org.schabi.newpipe.report.UserAction;
|
|
||||||
|
|
||||||
import icepick.Icepick;
|
import icepick.Icepick;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
|
|
||||||
public abstract class BaseFragment extends Fragment {
|
public abstract class BaseFragment extends Fragment {
|
||||||
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||||
protected boolean DEBUG = MainActivity.DEBUG;
|
protected final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
protected AppCompatActivity activity;
|
protected AppCompatActivity activity;
|
||||||
public static final ImageLoader imageLoader = ImageLoader.getInstance();
|
public static final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
|
@ -43,7 +43,7 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||||||
|
|
||||||
private static Downloader instance;
|
private static Downloader instance;
|
||||||
private String mCookies;
|
private String mCookies;
|
||||||
private OkHttpClient client;
|
private final OkHttpClient client;
|
||||||
|
|
||||||
private Downloader(OkHttpClient.Builder builder) {
|
private Downloader(OkHttpClient.Builder builder) {
|
||||||
this.client = builder
|
this.client = builder
|
||||||
|
@ -23,7 +23,6 @@ package org.schabi.newpipe;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -66,8 +65,6 @@ import org.schabi.newpipe.util.ServiceHelper;
|
|||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.InfoItem.InfoType.PLAYLIST;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
|
@ -85,7 +85,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ReCaptchaWebViewClient extends WebViewClient {
|
private class ReCaptchaWebViewClient extends WebViewClient {
|
||||||
private Activity context;
|
private final Activity context;
|
||||||
private String mCookies;
|
private String mCookies;
|
||||||
|
|
||||||
ReCaptchaWebViewClient(Activity ctx) {
|
ReCaptchaWebViewClient(Activity ctx) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.FragmentManager;
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@ -13,7 +12,6 @@ import android.preference.PreferenceManager;
|
|||||||
import android.support.annotation.DrawableRes;
|
import android.support.annotation.DrawableRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
@ -38,7 +36,6 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
|
||||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
@ -51,14 +48,12 @@ import org.schabi.newpipe.util.NavigationHelper;
|
|||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observer;
|
|
||||||
|
|
||||||
import icepick.Icepick;
|
import icepick.Icepick;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
@ -86,7 +81,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
protected int selectedPreviously = -1;
|
protected int selectedPreviously = -1;
|
||||||
|
|
||||||
protected String currentUrl;
|
protected String currentUrl;
|
||||||
protected CompositeDisposable disposables = new CompositeDisposable();
|
protected final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private boolean selectionIsDownload = false;
|
private boolean selectionIsDownload = false;
|
||||||
|
|
||||||
@ -184,12 +179,16 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
if (selectedChoiceKey.equals(alwaysAskKey)) {
|
if (selectedChoiceKey.equals(alwaysAskKey)) {
|
||||||
final List<AdapterChoiceItem> choices = getChoicesForService(currentService, currentLinkType);
|
final List<AdapterChoiceItem> choices = getChoicesForService(currentService, currentLinkType);
|
||||||
|
|
||||||
if (choices.size() == 1) {
|
switch (choices.size()) {
|
||||||
handleChoice(choices.get(0).key);
|
case 1:
|
||||||
} else if (choices.size() == 0) {
|
handleChoice(choices.get(0).key);
|
||||||
handleChoice(showInfoKey);
|
break;
|
||||||
} else {
|
case 0:
|
||||||
showDialog(choices);
|
handleChoice(showInfoKey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
showDialog(choices);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (selectedChoiceKey.equals(showInfoKey)) {
|
} else if (selectedChoiceKey.equals(showInfoKey)) {
|
||||||
handleChoice(showInfoKey);
|
handleChoice(showInfoKey);
|
||||||
|
@ -4,7 +4,6 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
@ -17,7 +16,7 @@ import java.lang.ref.WeakReference;
|
|||||||
|
|
||||||
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
||||||
|
|
||||||
WeakReference<Activity> weakReference;
|
final WeakReference<Activity> weakReference;
|
||||||
private License license;
|
private License license;
|
||||||
|
|
||||||
public LicenseFragmentHelper(@Nullable Activity activity) {
|
public LicenseFragmentHelper(@Nullable Activity activity) {
|
||||||
@ -78,18 +77,18 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
|||||||
throw new NullPointerException("license is null");
|
throw new NullPointerException("license is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
String licenseContent = "";
|
StringBuilder licenseContent = new StringBuilder();
|
||||||
String webViewData;
|
String webViewData;
|
||||||
try {
|
try {
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(context.getAssets().open(license.getFilename()), "UTF-8"));
|
BufferedReader in = new BufferedReader(new InputStreamReader(context.getAssets().open(license.getFilename()), "UTF-8"));
|
||||||
String str;
|
String str;
|
||||||
while ((str = in.readLine()) != null) {
|
while ((str = in.readLine()) != null) {
|
||||||
licenseContent += str;
|
licenseContent.append(str);
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
// split the HTML file and insert the stylesheet into the HEAD of the file
|
// split the HTML file and insert the stylesheet into the HEAD of the file
|
||||||
String[] insert = licenseContent.split("</head>");
|
String[] insert = licenseContent.toString().split("</head>");
|
||||||
webViewData = insert[0] + "<style type=\"text/css\">"
|
webViewData = insert[0] + "<style type=\"text/css\">"
|
||||||
+ getLicenseStylesheet(context) + "</style></head>"
|
+ getLicenseStylesheet(context) + "</style></head>"
|
||||||
+ insert[1];
|
+ insert[1];
|
||||||
|
@ -30,7 +30,7 @@ public interface BasicDAO<Entity> {
|
|||||||
|
|
||||||
/* Deletes */
|
/* Deletes */
|
||||||
@Delete
|
@Delete
|
||||||
int delete(final Entity entity);
|
void delete(final Entity entity);
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
int delete(final Collection<Entity> entities);
|
int delete(final Collection<Entity> entities);
|
||||||
@ -42,5 +42,5 @@ public interface BasicDAO<Entity> {
|
|||||||
int update(final Entity entity);
|
int update(final Entity entity);
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
int update(final Collection<Entity> entities);
|
void update(final Collection<Entity> entities);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import android.arch.persistence.room.Dao;
|
|||||||
import android.arch.persistence.room.Query;
|
import android.arch.persistence.room.Query;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
|
||||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -5,7 +5,6 @@ import android.arch.persistence.room.Dao;
|
|||||||
import android.arch.persistence.room.Query;
|
import android.arch.persistence.room.Query;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
|
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
||||||
|
@ -2,7 +2,6 @@ package org.schabi.newpipe.database.playlist.dao;
|
|||||||
|
|
||||||
import android.arch.persistence.room.Dao;
|
import android.arch.persistence.room.Dao;
|
||||||
import android.arch.persistence.room.Query;
|
import android.arch.persistence.room.Query;
|
||||||
import android.arch.persistence.room.Transaction;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
import org.schabi.newpipe.database.BasicDAO;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
|
||||||
@ -12,7 +11,6 @@ import java.util.List;
|
|||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
|
@ -8,7 +8,6 @@ import org.schabi.newpipe.database.BasicDAO;
|
|||||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@ import android.arch.persistence.room.Entity;
|
|||||||
import android.arch.persistence.room.Index;
|
import android.arch.persistence.room.Index;
|
||||||
import android.arch.persistence.room.PrimaryKey;
|
import android.arch.persistence.room.PrimaryKey;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import android.arch.persistence.room.Ignore;
|
|||||||
import android.arch.persistence.room.Index;
|
import android.arch.persistence.room.Index;
|
||||||
import android.arch.persistence.room.PrimaryKey;
|
import android.arch.persistence.room.PrimaryKey;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
@ -10,7 +10,6 @@ import org.schabi.newpipe.database.BasicDAO;
|
|||||||
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -23,7 +22,6 @@ import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_SERVI
|
|||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
|
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
|
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
|
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public abstract class StreamDAO implements BasicDAO<StreamEntity> {
|
public abstract class StreamDAO implements BasicDAO<StreamEntity> {
|
||||||
|
@ -28,11 +28,11 @@ public class DeleteDownloadManager {
|
|||||||
|
|
||||||
private static final String KEY_STATE = "delete_manager_state";
|
private static final String KEY_STATE = "delete_manager_state";
|
||||||
|
|
||||||
private View mView;
|
private final View mView;
|
||||||
private HashSet<String> mPendingMap;
|
private final HashSet<String> mPendingMap;
|
||||||
private List<Disposable> mDisposableList;
|
private final List<Disposable> mDisposableList;
|
||||||
private DownloadManager mDownloadManager;
|
private DownloadManager mDownloadManager;
|
||||||
private PublishSubject<DownloadMission> publishSubject = PublishSubject.create();
|
private final PublishSubject<DownloadMission> publishSubject = PublishSubject.create();
|
||||||
|
|
||||||
DeleteDownloadManager(Activity activity) {
|
DeleteDownloadManager(Activity activity) {
|
||||||
mPendingMap = new HashSet<>();
|
mPendingMap = new HashSet<>();
|
||||||
|
@ -55,7 +55,7 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||||||
private StreamItemAdapter<AudioStream> audioStreamsAdapter;
|
private StreamItemAdapter<AudioStream> audioStreamsAdapter;
|
||||||
private StreamItemAdapter<VideoStream> videoStreamsAdapter;
|
private StreamItemAdapter<VideoStream> videoStreamsAdapter;
|
||||||
|
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private EditText nameEditText;
|
private EditText nameEditText;
|
||||||
private Spinner streamsSpinner;
|
private Spinner streamsSpinner;
|
||||||
|
@ -32,7 +32,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package org.schabi.newpipe.fragments;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -3,9 +3,9 @@ package org.schabi.newpipe.fragments.detail;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
class StackItem implements Serializable {
|
class StackItem implements Serializable {
|
||||||
private int serviceId;
|
private final int serviceId;
|
||||||
private String title;
|
private String title;
|
||||||
private String url;
|
private final String url;
|
||||||
|
|
||||||
StackItem(int serviceId, String url, String title) {
|
StackItem(int serviceId, String url, String title) {
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
|
@ -33,12 +33,14 @@ import android.view.MenuItem;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.fragments.BackPressable;
|
import org.schabi.newpipe.fragments.BackPressable;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
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.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
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.MainVideoPlayer;
|
||||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
import org.schabi.newpipe.player.PopupVideoPlayer;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
import org.schabi.newpipe.player.old.PlayVideoActivity;
|
import org.schabi.newpipe.player.old.PlayVideoActivity;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
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.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
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 org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -154,6 +156,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
private View videoTitleRoot;
|
private View videoTitleRoot;
|
||||||
private TextView videoTitleTextView;
|
private TextView videoTitleTextView;
|
||||||
|
@Nullable
|
||||||
private ImageView videoTitleToggleArrow;
|
private ImageView videoTitleToggleArrow;
|
||||||
private TextView videoCountView;
|
private TextView videoCountView;
|
||||||
|
|
||||||
@ -415,14 +418,16 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void toggleTitleAndDescription() {
|
private void toggleTitleAndDescription() {
|
||||||
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
if (videoTitleToggleArrow != null) { //it is null for tablets
|
||||||
videoTitleTextView.setMaxLines(1);
|
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
||||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
videoTitleTextView.setMaxLines(1);
|
||||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||||
} else {
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||||
videoTitleTextView.setMaxLines(10);
|
} else {
|
||||||
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
videoTitleTextView.setMaxLines(10);
|
||||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
|
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
||||||
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,8 +627,11 @@ public class VideoDetailFragment
|
|||||||
relatedStreamsView.addView(
|
relatedStreamsView.addView(
|
||||||
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
|
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
|
||||||
relatedStreamsView.addView(getSeparatorView());
|
relatedStreamsView.addView(getSeparatorView());
|
||||||
relatedStreamRootLayout.setVisibility(View.VISIBLE);
|
setRelatedStreamsVisibility(View.VISIBLE);
|
||||||
} else nextStreamTitle.setVisibility(View.GONE);
|
} else {
|
||||||
|
nextStreamTitle.setVisibility(View.GONE);
|
||||||
|
setRelatedStreamsVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
if (info.getRelatedStreams() != null
|
if (info.getRelatedStreams() != null
|
||||||
&& !info.getRelatedStreams().isEmpty() && showRelatedStreams) {
|
&& !info.getRelatedStreams().isEmpty() && showRelatedStreams) {
|
||||||
@ -639,13 +647,13 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
|
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
|
||||||
|
|
||||||
relatedStreamRootLayout.setVisibility(View.VISIBLE);
|
setRelatedStreamsVisibility(View.VISIBLE);
|
||||||
relatedStreamExpandButton.setVisibility(View.VISIBLE);
|
relatedStreamExpandButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
|
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
|
||||||
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
|
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
|
||||||
} else {
|
} else {
|
||||||
if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
|
if (info.getNextVideo() == null) setRelatedStreamsVisibility(View.GONE);
|
||||||
relatedStreamExpandButton.setVisibility(View.GONE);
|
relatedStreamExpandButton.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -760,7 +768,7 @@ public class VideoDetailFragment
|
|||||||
* Stack that contains the "navigation history".<br>
|
* Stack that contains the "navigation history".<br>
|
||||||
* The peek is the current video.
|
* The peek is the current video.
|
||||||
*/
|
*/
|
||||||
protected LinkedList<StackItem> stack = new LinkedList<>();
|
protected final LinkedList<StackItem> stack = new LinkedList<>();
|
||||||
|
|
||||||
public void clearHistory() {
|
public void clearHistory() {
|
||||||
stack.clear();
|
stack.clear();
|
||||||
@ -1114,8 +1122,16 @@ public class VideoDetailFragment
|
|||||||
animateView(videoTitleTextView, true, 0);
|
animateView(videoTitleTextView, true, 0);
|
||||||
|
|
||||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
if (videoTitleToggleArrow != null) { //phone
|
||||||
videoTitleToggleArrow.setVisibility(View.GONE);
|
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);
|
videoTitleRoot.setClickable(false);
|
||||||
|
|
||||||
imageLoader.cancelDisplayTask(thumbnailImageView);
|
imageLoader.cancelDisplayTask(thumbnailImageView);
|
||||||
@ -1190,11 +1206,15 @@ public class VideoDetailFragment
|
|||||||
detailDurationView.setVisibility(View.GONE);
|
detailDurationView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
videoTitleRoot.setClickable(true);
|
|
||||||
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
|
||||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
|
||||||
videoDescriptionView.setVisibility(View.GONE);
|
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())) {
|
if (!TextUtils.isEmpty(info.getUploadDate())) {
|
||||||
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
|
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
|
||||||
}
|
}
|
||||||
@ -1242,6 +1262,11 @@ public class VideoDetailFragment
|
|||||||
// Only auto play in the first open
|
// Only auto play in the first open
|
||||||
autoPlayEnabled = false;
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,10 +3,15 @@ package org.schabi.newpipe.fragments.list;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
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.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
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.InfoItemDialog;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
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.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
@ -36,7 +41,7 @@ import java.util.Queue;
|
|||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implements ListViewContract<I, N>, StateSaver.WriteRead {
|
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implements ListViewContract<I, N>, StateSaver.WriteRead, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
@ -44,6 +49,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||||||
|
|
||||||
protected InfoListAdapter infoListAdapter;
|
protected InfoListAdapter infoListAdapter;
|
||||||
protected RecyclerView itemsList;
|
protected RecyclerView itemsList;
|
||||||
|
private int updateFlags = 0;
|
||||||
|
|
||||||
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
@ -59,12 +67,31 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
StateSaver.onDestroy(savedState);
|
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<I, N> extends BaseStateFragment<I> implem
|
|||||||
return new LinearLayoutManager(activity);
|
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
|
@Override
|
||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
|
||||||
|
final boolean useGrid = isGridLayout();
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
itemsList = rootView.findViewById(R.id.items_list);
|
||||||
itemsList.setLayoutManager(getListLayoutManager());
|
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
|
||||||
|
|
||||||
|
infoListAdapter.setGridItemVariants(useGrid);
|
||||||
infoListAdapter.setFooter(getListFooter());
|
infoListAdapter.setFooter(getListFooter());
|
||||||
infoListAdapter.setHeader(getListHeader());
|
infoListAdapter.setHeader(getListHeader());
|
||||||
|
|
||||||
@ -308,4 +347,22 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||||||
public void handleNextItems(N result) {
|
public void handleNextItems(N result) {
|
||||||
isLoading.set(false);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,6 @@ import android.view.View;
|
|||||||
|
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.ListInfo;
|
import org.schabi.newpipe.extractor.ListInfo;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
|
||||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
@ -19,7 +16,6 @@ import icepick.State;
|
|||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public abstract class BaseListInfoFragment<I extends ListInfo>
|
public abstract class BaseListInfoFragment<I extends ListInfo>
|
||||||
|
@ -68,7 +68,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|||||||
|
|
||||||
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||||
|
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
private Disposable subscribeButtonMonitor;
|
private Disposable subscribeButtonMonitor;
|
||||||
private SubscriptionService subscriptionService;
|
private SubscriptionService subscriptionService;
|
||||||
|
|
||||||
@ -90,8 +90,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
|
|
||||||
private MenuItem menuRssButton;
|
private MenuItem menuRssButton;
|
||||||
|
|
||||||
private boolean mIsVisibleToUser = false;
|
|
||||||
|
|
||||||
public static ChannelFragment getInstance(int serviceId, String url, String name) {
|
public static ChannelFragment getInstance(int serviceId, String url, String name) {
|
||||||
ChannelFragment instance = new ChannelFragment();
|
ChannelFragment instance = new ChannelFragment();
|
||||||
instance.setInitialData(serviceId, url, name);
|
instance.setInitialData(serviceId, url, name);
|
||||||
@ -105,7 +103,6 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
@Override
|
@Override
|
||||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||||
super.setUserVisibleHint(isVisibleToUser);
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
mIsVisibleToUser = isVisibleToUser;
|
|
||||||
if(activity != null
|
if(activity != null
|
||||||
&& useAsFrontPage
|
&& useAsFrontPage
|
||||||
&& isVisibleToUser) {
|
&& isVisibleToUser) {
|
||||||
|
@ -5,7 +5,6 @@ import android.preference.PreferenceManager;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -19,8 +18,6 @@ import org.schabi.newpipe.extractor.StreamingService;
|
|||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
|
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
|
||||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
|
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
|
@ -20,7 +20,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
import org.schabi.newpipe.App;
|
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||||
@ -30,7 +29,6 @@ import org.schabi.newpipe.extractor.NewPipe;
|
|||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||||
|
@ -122,12 +122,11 @@ public class SearchFragment
|
|||||||
private String nextPageUrl;
|
private String nextPageUrl;
|
||||||
private String contentCountry;
|
private String contentCountry;
|
||||||
private boolean isSuggestionsEnabled = true;
|
private boolean isSuggestionsEnabled = true;
|
||||||
private boolean isSearchHistoryEnabled = true;
|
|
||||||
|
|
||||||
private PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
||||||
private Disposable searchDisposable;
|
private Disposable searchDisposable;
|
||||||
private Disposable suggestionDisposable;
|
private Disposable suggestionDisposable;
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private SuggestionListAdapter suggestionListAdapter;
|
private SuggestionListAdapter suggestionListAdapter;
|
||||||
private HistoryRecordManager historyRecordManager;
|
private HistoryRecordManager historyRecordManager;
|
||||||
@ -173,7 +172,7 @@ public class SearchFragment
|
|||||||
|
|
||||||
suggestionListAdapter = new SuggestionListAdapter(activity);
|
suggestionListAdapter = new SuggestionListAdapter(activity);
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
|
boolean isSearchHistoryEnabled = preferences.getBoolean(getString(R.string.enable_search_history_key), true);
|
||||||
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
||||||
|
|
||||||
historyRecordManager = new HistoryRecordManager(context);
|
historyRecordManager = new HistoryRecordManager(context);
|
||||||
|
@ -45,7 +45,7 @@ public class InfoItemBuilder {
|
|||||||
private static final String TAG = InfoItemBuilder.class.toString();
|
private static final String TAG = InfoItemBuilder.class.toString();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
private final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
|
|
||||||
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
|
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
|
||||||
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
|
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
|
||||||
|
@ -5,7 +5,6 @@ import android.app.AlertDialog;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.schabi.newpipe.info_list;
|
package org.schabi.newpipe.info_list;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
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.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
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.InfoItemHolder;
|
||||||
|
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
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.StreamInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.util.FallbackViewHolder;
|
import org.schabi.newpipe.util.FallbackViewHolder;
|
||||||
@ -52,14 +56,18 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
|
|
||||||
private static final int MINI_STREAM_HOLDER_TYPE = 0x100;
|
private static final int MINI_STREAM_HOLDER_TYPE = 0x100;
|
||||||
private static final int STREAM_HOLDER_TYPE = 0x101;
|
private static final int STREAM_HOLDER_TYPE = 0x101;
|
||||||
|
private static final int GRID_STREAM_HOLDER_TYPE = 0x102;
|
||||||
private static final int MINI_CHANNEL_HOLDER_TYPE = 0x200;
|
private static final int MINI_CHANNEL_HOLDER_TYPE = 0x200;
|
||||||
private static final int CHANNEL_HOLDER_TYPE = 0x201;
|
private static final int CHANNEL_HOLDER_TYPE = 0x201;
|
||||||
|
private static final int GRID_CHANNEL_HOLDER_TYPE = 0x202;
|
||||||
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
|
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
|
||||||
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
|
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
|
||||||
|
private static final int GRID_PLAYLIST_HOLDER_TYPE = 0x302;
|
||||||
|
|
||||||
private final InfoItemBuilder infoItemBuilder;
|
private final InfoItemBuilder infoItemBuilder;
|
||||||
private final ArrayList<InfoItem> infoItemList;
|
private final ArrayList<InfoItem> infoItemList;
|
||||||
private boolean useMiniVariant = false;
|
private boolean useMiniVariant = false;
|
||||||
|
private boolean useGridVariant = false;
|
||||||
private boolean showFooter = false;
|
private boolean showFooter = false;
|
||||||
private View header = null;
|
private View header = null;
|
||||||
private View footer = null;
|
private View footer = null;
|
||||||
@ -94,6 +102,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
this.useMiniVariant = useMiniVariant;
|
this.useMiniVariant = useMiniVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGridItemVariants(boolean useGridVariant) {
|
||||||
|
this.useGridVariant = useGridVariant;
|
||||||
|
}
|
||||||
|
|
||||||
public void addInfoItemList(List<InfoItem> data) {
|
public void addInfoItemList(List<InfoItem> data) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -206,11 +218,11 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
final InfoItem item = infoItemList.get(position);
|
final InfoItem item = infoItemList.get(position);
|
||||||
switch (item.getInfoType()) {
|
switch (item.getInfoType()) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
return useMiniVariant ? MINI_STREAM_HOLDER_TYPE : STREAM_HOLDER_TYPE;
|
return useGridVariant ? GRID_STREAM_HOLDER_TYPE : useMiniVariant ? MINI_STREAM_HOLDER_TYPE : STREAM_HOLDER_TYPE;
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
return useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
|
return useGridVariant ? GRID_CHANNEL_HOLDER_TYPE : useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
|
||||||
case PLAYLIST:
|
case PLAYLIST:
|
||||||
return useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
|
return useGridVariant ? GRID_PLAYLIST_HOLDER_TYPE : useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
Log.e(TAG, "Trollolo");
|
||||||
return -1;
|
return -1;
|
||||||
@ -229,14 +241,20 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
return new StreamMiniInfoItemHolder(infoItemBuilder, parent);
|
return new StreamMiniInfoItemHolder(infoItemBuilder, parent);
|
||||||
case STREAM_HOLDER_TYPE:
|
case STREAM_HOLDER_TYPE:
|
||||||
return new StreamInfoItemHolder(infoItemBuilder, parent);
|
return new StreamInfoItemHolder(infoItemBuilder, parent);
|
||||||
|
case GRID_STREAM_HOLDER_TYPE:
|
||||||
|
return new StreamGridInfoItemHolder(infoItemBuilder, parent);
|
||||||
case MINI_CHANNEL_HOLDER_TYPE:
|
case MINI_CHANNEL_HOLDER_TYPE:
|
||||||
return new ChannelMiniInfoItemHolder(infoItemBuilder, parent);
|
return new ChannelMiniInfoItemHolder(infoItemBuilder, parent);
|
||||||
case CHANNEL_HOLDER_TYPE:
|
case CHANNEL_HOLDER_TYPE:
|
||||||
return new ChannelInfoItemHolder(infoItemBuilder, parent);
|
return new ChannelInfoItemHolder(infoItemBuilder, parent);
|
||||||
|
case GRID_CHANNEL_HOLDER_TYPE:
|
||||||
|
return new ChannelGridInfoItemHolder(infoItemBuilder, parent);
|
||||||
case MINI_PLAYLIST_HOLDER_TYPE:
|
case MINI_PLAYLIST_HOLDER_TYPE:
|
||||||
return new PlaylistMiniInfoItemHolder(infoItemBuilder, parent);
|
return new PlaylistMiniInfoItemHolder(infoItemBuilder, parent);
|
||||||
case PLAYLIST_HOLDER_TYPE:
|
case PLAYLIST_HOLDER_TYPE:
|
||||||
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
|
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
|
||||||
|
case GRID_PLAYLIST_HOLDER_TYPE:
|
||||||
|
return new PlaylistGridInfoItemHolder(infoItemBuilder, parent);
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
Log.e(TAG, "Trollolo");
|
||||||
return new FallbackViewHolder(new View(parent.getContext()));
|
return new FallbackViewHolder(new View(parent.getContext()));
|
||||||
@ -257,4 +275,14 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
((HFHolder) holder).view = footer;
|
((HFHolder) holder).view = footer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
|
||||||
|
return new GridLayoutManager.SpanSizeLookup() {
|
||||||
|
@Override
|
||||||
|
public int getSpanSize(int position) {
|
||||||
|
final int type = getItemViewType(position);
|
||||||
|
return type == HEADER_TYPE || type == FOOTER_TYPE ? spanCount : 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 ChannelGridInfoItemHolder extends ChannelMiniInfoItemHolder {
|
||||||
|
|
||||||
|
public ChannelGridInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, R.layout.list_channel_grid_item, parent);
|
||||||
|
}
|
||||||
|
}
|
@ -47,6 +47,13 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
itemBuilder.getOnChannelSelectedListener().selected(item);
|
itemBuilder.getOnChannelSelectedListener().selected(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itemView.setOnLongClickListener(view -> {
|
||||||
|
if (itemBuilder.getOnChannelSelectedListener() != null) {
|
||||||
|
itemBuilder.getOnChannelSelectedListener().held(item);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getDetailLine(final ChannelInfoItem item) {
|
protected String getDetailLine(final ChannelInfoItem item) {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,13 @@
|
|||||||
package org.schabi.newpipe.local;
|
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.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -25,7 +30,7 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|||||||
* called and is memory efficient when in backstack.
|
* called and is memory efficient when in backstack.
|
||||||
* */
|
* */
|
||||||
public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
implements ListViewContract<I, N> {
|
implements ListViewContract<I, N>, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
@ -36,6 +41,9 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
|
|
||||||
protected LocalItemListAdapter itemListAdapter;
|
protected LocalItemListAdapter itemListAdapter;
|
||||||
protected RecyclerView itemsList;
|
protected RecyclerView itemsList;
|
||||||
|
private int updateFlags = 0;
|
||||||
|
|
||||||
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Lifecycle - Creation
|
// Lifecycle - Creation
|
||||||
@ -45,6 +53,29 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
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<I, N> extends BaseStateFragment<I>
|
|||||||
return activity.getLayoutInflater().inflate(R.layout.pignate_footer, itemsList, false);
|
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() {
|
protected RecyclerView.LayoutManager getListLayoutManager() {
|
||||||
return new LinearLayoutManager(activity);
|
return new LinearLayoutManager(activity);
|
||||||
}
|
}
|
||||||
@ -67,10 +108,13 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
|
||||||
itemsList.setLayoutManager(getListLayoutManager());
|
|
||||||
|
|
||||||
itemListAdapter = new LocalItemListAdapter(activity);
|
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.setHeader(headerRootView = getListHeader());
|
||||||
itemListAdapter.setFooter(footerRootView = getListFooter());
|
itemListAdapter.setFooter(footerRootView = getListFooter());
|
||||||
|
|
||||||
@ -174,4 +218,22 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
resetFragment();
|
resetFragment();
|
||||||
return super.onError(exception);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public class LocalItemBuilder {
|
|||||||
private static final String TAG = LocalItemBuilder.class.toString();
|
private static final String TAG = LocalItemBuilder.class.toString();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
private final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
|
|
||||||
private OnClickGesture<LocalItem> onSelectedListener;
|
private OnClickGesture<LocalItem> onSelectedListener;
|
||||||
|
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
package org.schabi.newpipe.local;
|
package org.schabi.newpipe.local;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
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.LocalItemHolder;
|
||||||
|
import org.schabi.newpipe.local.holder.LocalPlaylistGridItemHolder;
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
|
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.LocalPlaylistStreamItemHolder;
|
||||||
|
import org.schabi.newpipe.local.holder.LocalStatisticStreamGridItemHolder;
|
||||||
import org.schabi.newpipe.local.holder.LocalStatisticStreamItemHolder;
|
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.local.holder.RemotePlaylistItemHolder;
|
||||||
import org.schabi.newpipe.util.FallbackViewHolder;
|
import org.schabi.newpipe.util.FallbackViewHolder;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
@ -52,14 +55,19 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
|
|
||||||
private static final int STREAM_STATISTICS_HOLDER_TYPE = 0x1000;
|
private static final int STREAM_STATISTICS_HOLDER_TYPE = 0x1000;
|
||||||
private static final int STREAM_PLAYLIST_HOLDER_TYPE = 0x1001;
|
private static final int STREAM_PLAYLIST_HOLDER_TYPE = 0x1001;
|
||||||
|
private static final int STREAM_STATISTICS_GRID_HOLDER_TYPE = 0x1002;
|
||||||
|
private static final int STREAM_PLAYLIST_GRID_HOLDER_TYPE = 0x1004;
|
||||||
private static final int LOCAL_PLAYLIST_HOLDER_TYPE = 0x2000;
|
private static final int LOCAL_PLAYLIST_HOLDER_TYPE = 0x2000;
|
||||||
private static final int REMOTE_PLAYLIST_HOLDER_TYPE = 0x2001;
|
private static final int REMOTE_PLAYLIST_HOLDER_TYPE = 0x2001;
|
||||||
|
private static final int LOCAL_PLAYLIST_GRID_HOLDER_TYPE = 0x2002;
|
||||||
|
private static final int REMOTE_PLAYLIST_GRID_HOLDER_TYPE = 0x2004;
|
||||||
|
|
||||||
private final LocalItemBuilder localItemBuilder;
|
private final LocalItemBuilder localItemBuilder;
|
||||||
private final ArrayList<LocalItem> localItems;
|
private final ArrayList<LocalItem> localItems;
|
||||||
private final DateFormat dateFormat;
|
private final DateFormat dateFormat;
|
||||||
|
|
||||||
private boolean showFooter = false;
|
private boolean showFooter = false;
|
||||||
|
private boolean useGridVariant = false;
|
||||||
private View header = null;
|
private View header = null;
|
||||||
private View footer = null;
|
private View footer = null;
|
||||||
|
|
||||||
@ -134,6 +142,10 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGridItemVariants(boolean useGridVariant) {
|
||||||
|
this.useGridVariant = useGridVariant;
|
||||||
|
}
|
||||||
|
|
||||||
public void setHeader(View header) {
|
public void setHeader(View header) {
|
||||||
boolean changed = header != this.header;
|
boolean changed = header != this.header;
|
||||||
this.header = header;
|
this.header = header;
|
||||||
@ -195,11 +207,11 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
final LocalItem item = localItems.get(position);
|
final LocalItem item = localItems.get(position);
|
||||||
|
|
||||||
switch (item.getLocalItemType()) {
|
switch (item.getLocalItemType()) {
|
||||||
case PLAYLIST_LOCAL_ITEM: return LOCAL_PLAYLIST_HOLDER_TYPE;
|
case PLAYLIST_LOCAL_ITEM: return useGridVariant ? LOCAL_PLAYLIST_GRID_HOLDER_TYPE : LOCAL_PLAYLIST_HOLDER_TYPE;
|
||||||
case PLAYLIST_REMOTE_ITEM: return REMOTE_PLAYLIST_HOLDER_TYPE;
|
case PLAYLIST_REMOTE_ITEM: return useGridVariant ? REMOTE_PLAYLIST_GRID_HOLDER_TYPE : REMOTE_PLAYLIST_HOLDER_TYPE;
|
||||||
|
|
||||||
case PLAYLIST_STREAM_ITEM: return STREAM_PLAYLIST_HOLDER_TYPE;
|
case PLAYLIST_STREAM_ITEM: return useGridVariant ? STREAM_PLAYLIST_GRID_HOLDER_TYPE : STREAM_PLAYLIST_HOLDER_TYPE;
|
||||||
case STATISTIC_STREAM_ITEM: return STREAM_STATISTICS_HOLDER_TYPE;
|
case STATISTIC_STREAM_ITEM: return useGridVariant ? STREAM_STATISTICS_GRID_HOLDER_TYPE : STREAM_STATISTICS_HOLDER_TYPE;
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "No holder type has been considered for item: [" +
|
Log.e(TAG, "No holder type has been considered for item: [" +
|
||||||
item.getLocalItemType() + "]");
|
item.getLocalItemType() + "]");
|
||||||
@ -218,12 +230,20 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
return new HeaderFooterHolder(footer);
|
return new HeaderFooterHolder(footer);
|
||||||
case LOCAL_PLAYLIST_HOLDER_TYPE:
|
case LOCAL_PLAYLIST_HOLDER_TYPE:
|
||||||
return new LocalPlaylistItemHolder(localItemBuilder, parent);
|
return new LocalPlaylistItemHolder(localItemBuilder, parent);
|
||||||
|
case LOCAL_PLAYLIST_GRID_HOLDER_TYPE:
|
||||||
|
return new LocalPlaylistGridItemHolder(localItemBuilder, parent);
|
||||||
case REMOTE_PLAYLIST_HOLDER_TYPE:
|
case REMOTE_PLAYLIST_HOLDER_TYPE:
|
||||||
return new RemotePlaylistItemHolder(localItemBuilder, parent);
|
return new RemotePlaylistItemHolder(localItemBuilder, parent);
|
||||||
|
case REMOTE_PLAYLIST_GRID_HOLDER_TYPE:
|
||||||
|
return new RemotePlaylistGridItemHolder(localItemBuilder, parent);
|
||||||
case STREAM_PLAYLIST_HOLDER_TYPE:
|
case STREAM_PLAYLIST_HOLDER_TYPE:
|
||||||
return new LocalPlaylistStreamItemHolder(localItemBuilder, parent);
|
return new LocalPlaylistStreamItemHolder(localItemBuilder, parent);
|
||||||
|
case STREAM_PLAYLIST_GRID_HOLDER_TYPE:
|
||||||
|
return new LocalPlaylistStreamGridItemHolder(localItemBuilder, parent);
|
||||||
case STREAM_STATISTICS_HOLDER_TYPE:
|
case STREAM_STATISTICS_HOLDER_TYPE:
|
||||||
return new LocalStatisticStreamItemHolder(localItemBuilder, parent);
|
return new LocalStatisticStreamItemHolder(localItemBuilder, parent);
|
||||||
|
case STREAM_STATISTICS_GRID_HOLDER_TYPE:
|
||||||
|
return new LocalStatisticStreamGridItemHolder(localItemBuilder, parent);
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "No view type has been considered for holder: [" + type + "]");
|
Log.e(TAG, "No view type has been considered for holder: [" + type + "]");
|
||||||
return new FallbackViewHolder(new View(parent.getContext()));
|
return new FallbackViewHolder(new View(parent.getContext()));
|
||||||
@ -247,4 +267,14 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
((HeaderFooterHolder) holder).view = footer;
|
((HeaderFooterHolder) holder).view = footer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int spanCount) {
|
||||||
|
return new GridLayoutManager.SpanSizeLookup() {
|
||||||
|
@Override
|
||||||
|
public int getSpanSize(int position) {
|
||||||
|
final int type = getItemViewType(position);
|
||||||
|
return type == HEADER_TYPE || type == FOOTER_TYPE ? spanCount : 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package org.schabi.newpipe.local.dialog;
|
package org.schabi.newpipe.local.dialog;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.view.Window;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
@ -41,6 +43,18 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
|
|||||||
StateSaver.onDestroy(savedState);
|
StateSaver.onDestroy(savedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||||
|
//remove title
|
||||||
|
final Window window = dialog.getWindow();
|
||||||
|
if (window != null) {
|
||||||
|
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
}
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// State Saving
|
// State Saving
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
@ -58,7 +72,7 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
public void readFrom(@NonNull Queue<Object> savedObjects) {
|
||||||
streamEntities = (List<StreamEntity>) savedObjects.poll();
|
streamEntities = (List<StreamEntity>) savedObjects.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,6 @@ import io.reactivex.MaybeObserver;
|
|||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.functions.Consumer;
|
|
||||||
import io.reactivex.functions.Predicate;
|
|
||||||
|
|
||||||
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {
|
public class FeedFragment extends BaseListFragment<List<SubscriptionEntity>, Void> {
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe.local.history;
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
@ -45,7 +45,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.Scheduler;
|
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ import org.schabi.newpipe.R;
|
|||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
|
||||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
@ -57,7 +56,7 @@ public class StatisticsPlaylistFragment
|
|||||||
/* Used for independent events */
|
/* Used for independent events */
|
||||||
private Subscription databaseSubscription;
|
private Subscription databaseSubscription;
|
||||||
private HistoryRecordManager recordManager;
|
private HistoryRecordManager recordManager;
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private enum StatisticSortMode {
|
private enum StatisticSortMode {
|
||||||
LAST_PLAYED,
|
LAST_PLAYED,
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
public class LocalPlaylistGridItemHolder extends LocalPlaylistItemHolder {
|
||||||
|
|
||||||
|
public LocalPlaylistGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,10 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
|
|||||||
super(infoItemBuilder, parent);
|
super(infoItemBuilder, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalPlaylistItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, layoutId, parent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
|
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
|
||||||
if (!(localItem instanceof PlaylistMetadataEntry)) return;
|
if (!(localItem instanceof PlaylistMetadataEntry)) return;
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
public class LocalPlaylistStreamGridItemHolder extends LocalPlaylistStreamItemHolder {
|
||||||
|
|
||||||
|
public LocalPlaylistStreamGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, R.layout.list_stream_playlist_grid_item, parent); //TODO
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
public class LocalStatisticStreamGridItemHolder extends LocalStatisticStreamItemHolder {
|
||||||
|
|
||||||
|
public LocalStatisticStreamGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, R.layout.list_stream_grid_item, parent);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -42,10 +43,15 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
|||||||
public final TextView itemVideoTitleView;
|
public final TextView itemVideoTitleView;
|
||||||
public final TextView itemUploaderView;
|
public final TextView itemUploaderView;
|
||||||
public final TextView itemDurationView;
|
public final TextView itemDurationView;
|
||||||
|
@Nullable
|
||||||
public final TextView itemAdditionalDetails;
|
public final TextView itemAdditionalDetails;
|
||||||
|
|
||||||
public LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
|
public LocalStatisticStreamItemHolder(LocalItemBuilder itemBuilder, ViewGroup parent) {
|
||||||
super(infoItemBuilder, R.layout.list_stream_item, parent);
|
this(itemBuilder, R.layout.list_stream_item, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalStatisticStreamItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, layoutId, parent);
|
||||||
|
|
||||||
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
|
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
|
||||||
itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView);
|
itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView);
|
||||||
@ -80,7 +86,9 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
|||||||
itemDurationView.setVisibility(View.GONE);
|
itemDurationView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat));
|
if (itemAdditionalDetails != null) {
|
||||||
|
itemAdditionalDetails.setText(getStreamInfoDetailLine(item, dateFormat));
|
||||||
|
}
|
||||||
|
|
||||||
// Default thumbnail is shown on error, while loading and if the url is empty
|
// Default thumbnail is shown on error, while loading and if the url is empty
|
||||||
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,
|
itemBuilder.displayImage(item.thumbnailUrl, itemThumbnailView,
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
public class RemotePlaylistGridItemHolder extends RemotePlaylistItemHolder {
|
||||||
|
|
||||||
|
public RemotePlaylistGridItemHolder(LocalItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, R.layout.list_playlist_grid_item, parent);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,10 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
|
|||||||
super(infoItemBuilder, parent);
|
super(infoItemBuilder, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemotePlaylistItemHolder(LocalItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
||||||
|
super(infoItemBuilder, layoutId, parent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
|
public void updateFromItem(final LocalItem localItem, final DateFormat dateFormat) {
|
||||||
if (!(localItem instanceof PlaylistRemoteEntity)) return;
|
if (!(localItem instanceof PlaylistRemoteEntity)) return;
|
||||||
|
@ -459,7 +459,11 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
|
|
||||||
|
|
||||||
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
||||||
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
int directions = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||||
|
if (isGridLayout()) {
|
||||||
|
directions |= ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||||
|
}
|
||||||
|
return new ItemTouchHelper.SimpleCallback(directions,
|
||||||
ItemTouchHelper.ACTION_STATE_IDLE) {
|
ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||||
@Override
|
@Override
|
||||||
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,
|
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
package org.schabi.newpipe.local.subscription;
|
package org.schabi.newpipe.local.subscription;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.DrawableRes;
|
import android.support.annotation.DrawableRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
@ -17,6 +24,7 @@ import android.support.v4.app.FragmentManager;
|
|||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.GridLayoutManager;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -40,10 +48,11 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||||||
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
|
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
|
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
|
||||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
|
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
@ -72,7 +81,7 @@ import static org.schabi.newpipe.local.subscription.services.SubscriptionsImport
|
|||||||
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEntity>> {
|
public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEntity>> implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
private static final int REQUEST_EXPORT_CODE = 666;
|
private static final int REQUEST_EXPORT_CODE = 666;
|
||||||
private static final int REQUEST_IMPORT_CODE = 667;
|
private static final int REQUEST_IMPORT_CODE = 667;
|
||||||
|
|
||||||
@ -80,8 +89,10 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
@State
|
@State
|
||||||
protected Parcelable itemsListState;
|
protected Parcelable itemsListState;
|
||||||
private InfoListAdapter infoListAdapter;
|
private InfoListAdapter infoListAdapter;
|
||||||
|
private int updateFlags = 0;
|
||||||
|
|
||||||
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
|
|
||||||
private View headerRootLayout;
|
|
||||||
private View whatsNewItemListHeader;
|
private View whatsNewItemListHeader;
|
||||||
private View importExportListHeader;
|
private View importExportListHeader;
|
||||||
|
|
||||||
@ -100,6 +111,8 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,6 +140,15 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
setupBroadcastReceiver();
|
setupBroadcastReceiver();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -153,9 +175,25 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
disposables = null;
|
disposables = null;
|
||||||
subscriptionService = null;
|
subscriptionService = null;
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected RecyclerView.LayoutManager getListLayoutManager() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*/////////////////////////////////////////////////////////////////////////
|
/*/////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Menu
|
||||||
/////////////////////////////////////////////////////////////////////////*/
|
/////////////////////////////////////////////////////////////////////////*/
|
||||||
@ -287,16 +325,19 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
|
||||||
|
final boolean useGrid = isGridLayout();
|
||||||
infoListAdapter = new InfoListAdapter(getActivity());
|
infoListAdapter = new InfoListAdapter(getActivity());
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
itemsList = rootView.findViewById(R.id.items_list);
|
||||||
itemsList.setLayoutManager(new LinearLayoutManager(activity));
|
itemsList.setLayoutManager(useGrid ? getGridLayoutManager() : getListLayoutManager());
|
||||||
|
|
||||||
|
View headerRootLayout;
|
||||||
infoListAdapter.setHeader(headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, itemsList, false));
|
infoListAdapter.setHeader(headerRootLayout = activity.getLayoutInflater().inflate(R.layout.subscription_header, itemsList, false));
|
||||||
whatsNewItemListHeader = headerRootLayout.findViewById(R.id.whats_new);
|
whatsNewItemListHeader = headerRootLayout.findViewById(R.id.whats_new);
|
||||||
importExportListHeader = headerRootLayout.findViewById(R.id.import_export);
|
importExportListHeader = headerRootLayout.findViewById(R.id.import_export);
|
||||||
importExportOptions = headerRootLayout.findViewById(R.id.import_export_options);
|
importExportOptions = headerRootLayout.findViewById(R.id.import_export_options);
|
||||||
|
|
||||||
infoListAdapter.useMiniItemVariants(true);
|
infoListAdapter.useMiniItemVariants(true);
|
||||||
|
infoListAdapter.setGridItemVariants(useGrid);
|
||||||
itemsList.setAdapter(infoListAdapter);
|
itemsList.setAdapter(infoListAdapter);
|
||||||
|
|
||||||
setupImportFromItems(headerRootLayout.findViewById(R.id.import_from_options));
|
setupImportFromItems(headerRootLayout.findViewById(R.id.import_from_options));
|
||||||
@ -320,7 +361,7 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
super.initListeners();
|
super.initListeners();
|
||||||
|
|
||||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||||
@Override
|
|
||||||
public void selected(ChannelInfoItem selectedItem) {
|
public void selected(ChannelInfoItem selectedItem) {
|
||||||
final FragmentManager fragmentManager = getFM();
|
final FragmentManager fragmentManager = getFM();
|
||||||
NavigationHelper.openChannelFragment(fragmentManager,
|
NavigationHelper.openChannelFragment(fragmentManager,
|
||||||
@ -328,6 +369,11 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
selectedItem.getUrl(),
|
selectedItem.getUrl(),
|
||||||
selectedItem.getName());
|
selectedItem.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void held(ChannelInfoItem selectedItem) {
|
||||||
|
showLongTapDialog(selectedItem);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
@ -338,6 +384,85 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
importExportListHeader.setOnClickListener(v -> importExportOptions.switchState());
|
importExportListHeader.setOnClickListener(v -> 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<List<SubscriptionEntity>> getDeleteObserver(){
|
||||||
|
return new Observer<List<SubscriptionEntity>>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(Disposable d) {
|
||||||
|
disposables.add(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(List<SubscriptionEntity> subscriptionEntities) {
|
||||||
|
subscriptionService.subscriptionTable().delete(subscriptionEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable exception) {
|
||||||
|
SubscriptionFragment.this.onError(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void resetFragment() {
|
private void resetFragment() {
|
||||||
if (disposables != null) disposables.clear();
|
if (disposables != null) disposables.clear();
|
||||||
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
|
if (infoListAdapter != null) infoListAdapter.clearStreamItemList();
|
||||||
@ -447,4 +572,22 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
R.string.general_error);
|
R.string.general_error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,10 @@ public class SubscriptionService {
|
|||||||
private static final int SUBSCRIPTION_DEBOUNCE_INTERVAL = 500;
|
private static final int SUBSCRIPTION_DEBOUNCE_INTERVAL = 500;
|
||||||
private static final int SUBSCRIPTION_THREAD_POOL_SIZE = 4;
|
private static final int SUBSCRIPTION_THREAD_POOL_SIZE = 4;
|
||||||
|
|
||||||
private AppDatabase db;
|
private final AppDatabase db;
|
||||||
private Flowable<List<SubscriptionEntity>> subscription;
|
private final Flowable<List<SubscriptionEntity>> subscription;
|
||||||
|
|
||||||
private Scheduler subscriptionScheduler;
|
private final Scheduler subscriptionScheduler;
|
||||||
|
|
||||||
private SubscriptionService(Context context) {
|
private SubscriptionService(Context context) {
|
||||||
db = NewPipeDatabase.getInstance(context.getApplicationContext());
|
db = NewPipeDatabase.getInstance(context.getApplicationContext());
|
||||||
@ -116,7 +116,7 @@ public class SubscriptionService {
|
|||||||
public Completable updateChannelInfo(final ChannelInfo info) {
|
public Completable updateChannelInfo(final ChannelInfo info) {
|
||||||
final Function<List<SubscriptionEntity>, CompletableSource> update = new Function<List<SubscriptionEntity>, CompletableSource>() {
|
final Function<List<SubscriptionEntity>, CompletableSource> update = new Function<List<SubscriptionEntity>, CompletableSource>() {
|
||||||
@Override
|
@Override
|
||||||
public CompletableSource apply(@NonNull List<SubscriptionEntity> subscriptionEntities) throws Exception {
|
public CompletableSource apply(@NonNull List<SubscriptionEntity> subscriptionEntities) {
|
||||||
if (DEBUG) Log.d(TAG, "updateChannelInfo() called with: subscriptionEntities = [" + subscriptionEntities + "]");
|
if (DEBUG) Log.d(TAG, "updateChannelInfo() called with: subscriptionEntities = [" + subscriptionEntities + "]");
|
||||||
if (subscriptionEntities.size() == 1) {
|
if (subscriptionEntities.size() == 1) {
|
||||||
SubscriptionEntity subscription = subscriptionEntities.get(0);
|
SubscriptionEntity subscription = subscriptionEntities.get(0);
|
||||||
|
@ -58,8 +58,8 @@ public abstract class BaseImportExportService extends Service {
|
|||||||
protected NotificationCompat.Builder notificationBuilder;
|
protected NotificationCompat.Builder notificationBuilder;
|
||||||
|
|
||||||
protected SubscriptionService subscriptionService;
|
protected SubscriptionService subscriptionService;
|
||||||
protected CompositeDisposable disposables = new CompositeDisposable();
|
protected final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
protected PublishProcessor<String> notificationUpdater = PublishProcessor.create();
|
protected final PublishProcessor<String> notificationUpdater = PublishProcessor.create();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@ -90,9 +90,9 @@ public abstract class BaseImportExportService extends Service {
|
|||||||
|
|
||||||
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
|
private static final int NOTIFICATION_SAMPLING_PERIOD = 2500;
|
||||||
|
|
||||||
protected AtomicInteger currentProgress = new AtomicInteger(-1);
|
protected final AtomicInteger currentProgress = new AtomicInteger(-1);
|
||||||
protected AtomicInteger maxProgress = new AtomicInteger(-1);
|
protected final AtomicInteger maxProgress = new AtomicInteger(-1);
|
||||||
protected ImportExportEventListener eventListener = new ImportExportEventListener() {
|
protected final ImportExportEventListener eventListener = new ImportExportEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSizeReceived(int size) {
|
public void onSizeReceived(int size) {
|
||||||
maxProgress.set(size);
|
maxProgress.set(size);
|
||||||
@ -187,13 +187,13 @@ public abstract class BaseImportExportService extends Service {
|
|||||||
protected Toast toast;
|
protected Toast toast;
|
||||||
|
|
||||||
protected void showToast(@StringRes int message) {
|
protected void showToast(@StringRes int message) {
|
||||||
showToast(getString(message), Toast.LENGTH_SHORT);
|
showToast(getString(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showToast(String message, int duration) {
|
protected void showToast(String message) {
|
||||||
if (toast != null) toast.cancel();
|
if (toast != null) toast.cancel();
|
||||||
|
|
||||||
toast = Toast.makeText(this, message, duration);
|
toast = Toast.makeText(this, message, Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,12 +144,16 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
|||||||
showToast(R.string.import_ongoing);
|
showToast(R.string.import_ongoing);
|
||||||
|
|
||||||
Flowable<List<SubscriptionItem>> flowable = null;
|
Flowable<List<SubscriptionItem>> flowable = null;
|
||||||
if (currentMode == CHANNEL_URL_MODE) {
|
switch (currentMode) {
|
||||||
flowable = importFromChannelUrl();
|
case CHANNEL_URL_MODE:
|
||||||
} else if (currentMode == INPUT_STREAM_MODE) {
|
flowable = importFromChannelUrl();
|
||||||
flowable = importFromInputStream();
|
break;
|
||||||
} else if (currentMode == PREVIOUS_EXPORT_MODE) {
|
case INPUT_STREAM_MODE:
|
||||||
flowable = importFromPreviousExport();
|
flowable = importFromInputStream();
|
||||||
|
break;
|
||||||
|
case PREVIOUS_EXPORT_MODE:
|
||||||
|
flowable = importFromPreviousExport();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flowable == null) {
|
if (flowable == null) {
|
||||||
|
@ -230,7 +230,8 @@ public abstract class BasePlayer implements
|
|||||||
int sizeBeforeAppend = playQueue.size();
|
int sizeBeforeAppend = playQueue.size();
|
||||||
playQueue.append(queue.getStreams());
|
playQueue.append(queue.getStreams());
|
||||||
|
|
||||||
if (intent.getBooleanExtra(SELECT_ON_APPEND, false) &&
|
if ((intent.getBooleanExtra(SELECT_ON_APPEND, false) ||
|
||||||
|
getCurrentState() == STATE_COMPLETED) &&
|
||||||
queue.getStreams().size() > 0) {
|
queue.getStreams().size() > 0) {
|
||||||
playQueue.setIndex(sizeBeforeAppend);
|
playQueue.setIndex(sizeBeforeAppend);
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,10 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
setLandscape(lastOrientationWasLandscape);
|
setLandscape(lastOrientationWasLandscape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int lastResizeMode = defaultPreferences.getInt(
|
||||||
|
getString(R.string.last_resize_mode), AspectRatioFrameLayout.RESIZE_MODE_FIT);
|
||||||
|
playerImpl.setResizeMode(lastResizeMode);
|
||||||
|
|
||||||
// Upon going in or out of multiwindow mode, isInMultiWindow will always be false,
|
// Upon going in or out of multiwindow mode, isInMultiWindow will always be false,
|
||||||
// since the first onResume needs to restore the player.
|
// since the first onResume needs to restore the player.
|
||||||
// Subsequent onResume calls while multiwindow mode remains the same and the player is
|
// Subsequent onResume calls while multiwindow mode remains the same and the player is
|
||||||
@ -705,14 +709,27 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int nextResizeMode(int currentResizeMode) {
|
protected int nextResizeMode(int currentResizeMode) {
|
||||||
|
final int newResizeMode;
|
||||||
switch (currentResizeMode) {
|
switch (currentResizeMode) {
|
||||||
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
|
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
|
||||||
return AspectRatioFrameLayout.RESIZE_MODE_FILL;
|
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL;
|
||||||
|
break;
|
||||||
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
|
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
|
||||||
return AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storeResizeMode(newResizeMode);
|
||||||
|
return newResizeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeResizeMode(@AspectRatioFrameLayout.ResizeMode int resizeMode) {
|
||||||
|
defaultPreferences.edit()
|
||||||
|
.putInt(getString(R.string.last_resize_mode), resizeMode)
|
||||||
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,7 +114,6 @@ public final class PopupVideoPlayer extends Service {
|
|||||||
|
|
||||||
private View closeOverlayView;
|
private View closeOverlayView;
|
||||||
private FloatingActionButton closeOverlayButton;
|
private FloatingActionButton closeOverlayButton;
|
||||||
private WindowManager.LayoutParams closeOverlayLayoutParams;
|
|
||||||
|
|
||||||
private int tossFlingVelocity;
|
private int tossFlingVelocity;
|
||||||
|
|
||||||
@ -248,7 +247,7 @@ public final class PopupVideoPlayer extends Service {
|
|||||||
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|
final int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
|
||||||
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
|
||||||
|
|
||||||
closeOverlayLayoutParams = new WindowManager.LayoutParams(
|
WindowManager.LayoutParams closeOverlayLayoutParams = new WindowManager.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
layoutParamType,
|
layoutParamType,
|
||||||
flags,
|
flags,
|
||||||
|
@ -137,16 +137,16 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
private TextView captionTextView;
|
private TextView captionTextView;
|
||||||
|
|
||||||
private ValueAnimator controlViewAnimator;
|
private ValueAnimator controlViewAnimator;
|
||||||
private Handler controlsVisibilityHandler = new Handler();
|
private final Handler controlsVisibilityHandler = new Handler();
|
||||||
|
|
||||||
boolean isSomePopupMenuVisible = false;
|
boolean isSomePopupMenuVisible = false;
|
||||||
private int qualityPopupMenuGroupId = 69;
|
private final int qualityPopupMenuGroupId = 69;
|
||||||
private PopupMenu qualityPopupMenu;
|
private PopupMenu qualityPopupMenu;
|
||||||
|
|
||||||
private int playbackSpeedPopupMenuGroupId = 79;
|
private final int playbackSpeedPopupMenuGroupId = 79;
|
||||||
private PopupMenu playbackSpeedPopupMenu;
|
private PopupMenu playbackSpeedPopupMenu;
|
||||||
|
|
||||||
private int captionPopupMenuGroupId = 89;
|
private final int captionPopupMenuGroupId = 89;
|
||||||
private PopupMenu captionPopupMenu;
|
private PopupMenu captionPopupMenu;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -683,12 +683,17 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
if (getAspectRatioFrameLayout() != null) {
|
if (getAspectRatioFrameLayout() != null) {
|
||||||
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
|
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
|
||||||
final int newResizeMode = nextResizeMode(currentResizeMode);
|
final int newResizeMode = nextResizeMode(currentResizeMode);
|
||||||
getAspectRatioFrameLayout().setResizeMode(newResizeMode);
|
setResizeMode(newResizeMode);
|
||||||
getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode) {
|
||||||
|
getAspectRatioFrameLayout().setResizeMode(resizeMode);
|
||||||
|
getResizeView().setText(PlayerHelper.resizeTypeOf(context, resizeMode));
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode);
|
protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode);
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// SeekBar Listener
|
// SeekBar Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -116,7 +116,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
|
|||||||
private void onAudioFocusGain() {
|
private void onAudioFocusGain() {
|
||||||
Log.d(TAG, "onAudioFocusGain() called");
|
Log.d(TAG, "onAudioFocusGain() called");
|
||||||
player.setVolume(DUCK_AUDIO_TO);
|
player.setVolume(DUCK_AUDIO_TO);
|
||||||
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
|
animateAudio(DUCK_AUDIO_TO, 1f);
|
||||||
|
|
||||||
if (PlayerHelper.isResumeAfterAudioFocusGain(context)) {
|
if (PlayerHelper.isResumeAfterAudioFocusGain(context)) {
|
||||||
player.setPlayWhenReady(true);
|
player.setPlayWhenReady(true);
|
||||||
@ -131,13 +131,13 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
|
|||||||
private void onAudioFocusLossCanDuck() {
|
private void onAudioFocusLossCanDuck() {
|
||||||
Log.d(TAG, "onAudioFocusLossCanDuck() called");
|
Log.d(TAG, "onAudioFocusLossCanDuck() called");
|
||||||
// Set the volume to 1/10 on ducking
|
// Set the volume to 1/10 on ducking
|
||||||
animateAudio(player.getVolume(), DUCK_AUDIO_TO, DUCK_DURATION);
|
animateAudio(player.getVolume(), DUCK_AUDIO_TO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animateAudio(final float from, final float to, int duration) {
|
private void animateAudio(final float from, final float to) {
|
||||||
ValueAnimator valueAnimator = new ValueAnimator();
|
ValueAnimator valueAnimator = new ValueAnimator();
|
||||||
valueAnimator.setFloatValues(from, to);
|
valueAnimator.setFloatValues(from, to);
|
||||||
valueAnimator.setDuration(duration);
|
valueAnimator.setDuration(AudioReactor.DUCK_DURATION);
|
||||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(Animator animation) {
|
public void onAnimationStart(Animator animation) {
|
||||||
|
@ -4,12 +4,9 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
|
|
||||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
||||||
@ -17,8 +14,6 @@ import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
|
|
||||||
import org.schabi.newpipe.Downloader;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/* package-private */ class CacheFactory implements DataSource.Factory {
|
/* package-private */ class CacheFactory implements DataSource.Factory {
|
||||||
|
@ -66,25 +66,15 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
private double stepSize = DEFAULT_STEP;
|
private double stepSize = DEFAULT_STEP;
|
||||||
|
|
||||||
@Nullable private SeekBar tempoSlider;
|
@Nullable private SeekBar tempoSlider;
|
||||||
@Nullable private TextView tempoMinimumText;
|
|
||||||
@Nullable private TextView tempoMaximumText;
|
|
||||||
@Nullable private TextView tempoCurrentText;
|
@Nullable private TextView tempoCurrentText;
|
||||||
@Nullable private TextView tempoStepDownText;
|
@Nullable private TextView tempoStepDownText;
|
||||||
@Nullable private TextView tempoStepUpText;
|
@Nullable private TextView tempoStepUpText;
|
||||||
|
|
||||||
@Nullable private SeekBar pitchSlider;
|
@Nullable private SeekBar pitchSlider;
|
||||||
@Nullable private TextView pitchMinimumText;
|
|
||||||
@Nullable private TextView pitchMaximumText;
|
|
||||||
@Nullable private TextView pitchCurrentText;
|
@Nullable private TextView pitchCurrentText;
|
||||||
@Nullable private TextView pitchStepDownText;
|
@Nullable private TextView pitchStepDownText;
|
||||||
@Nullable private TextView pitchStepUpText;
|
@Nullable private TextView pitchStepUpText;
|
||||||
|
|
||||||
@Nullable private TextView stepSizeOnePercentText;
|
|
||||||
@Nullable private TextView stepSizeFivePercentText;
|
|
||||||
@Nullable private TextView stepSizeTenPercentText;
|
|
||||||
@Nullable private TextView stepSizeTwentyFivePercentText;
|
|
||||||
@Nullable private TextView stepSizeOneHundredPercentText;
|
|
||||||
|
|
||||||
@Nullable private CheckBox unhookingCheckbox;
|
@Nullable private CheckBox unhookingCheckbox;
|
||||||
@Nullable private CheckBox skipSilenceCheckbox;
|
@Nullable private CheckBox skipSilenceCheckbox;
|
||||||
|
|
||||||
@ -181,8 +171,8 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
|
|
||||||
private void setupTempoControl(@NonNull View rootView) {
|
private void setupTempoControl(@NonNull View rootView) {
|
||||||
tempoSlider = rootView.findViewById(R.id.tempoSeekbar);
|
tempoSlider = rootView.findViewById(R.id.tempoSeekbar);
|
||||||
tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
|
TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
|
||||||
tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
|
TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
|
||||||
tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText);
|
tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText);
|
||||||
tempoStepUpText = rootView.findViewById(R.id.tempoStepUp);
|
tempoStepUpText = rootView.findViewById(R.id.tempoStepUp);
|
||||||
tempoStepDownText = rootView.findViewById(R.id.tempoStepDown);
|
tempoStepDownText = rootView.findViewById(R.id.tempoStepDown);
|
||||||
@ -203,8 +193,8 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
|
|
||||||
private void setupPitchControl(@NonNull View rootView) {
|
private void setupPitchControl(@NonNull View rootView) {
|
||||||
pitchSlider = rootView.findViewById(R.id.pitchSeekbar);
|
pitchSlider = rootView.findViewById(R.id.pitchSeekbar);
|
||||||
pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
|
TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
|
||||||
pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
|
TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
|
||||||
pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText);
|
pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText);
|
||||||
pitchStepDownText = rootView.findViewById(R.id.pitchStepDown);
|
pitchStepDownText = rootView.findViewById(R.id.pitchStepDown);
|
||||||
pitchStepUpText = rootView.findViewById(R.id.pitchStepUp);
|
pitchStepUpText = rootView.findViewById(R.id.pitchStepUp);
|
||||||
@ -247,11 +237,11 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupStepSizeSelector(@NonNull final View rootView) {
|
private void setupStepSizeSelector(@NonNull final View rootView) {
|
||||||
stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
||||||
stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
||||||
stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
|
TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
|
||||||
stepSizeTwentyFivePercentText = rootView.findViewById(R.id.stepSizeTwentyFivePercent);
|
TextView stepSizeTwentyFivePercentText = rootView.findViewById(R.id.stepSizeTwentyFivePercent);
|
||||||
stepSizeOneHundredPercentText = rootView.findViewById(R.id.stepSizeOneHundredPercent);
|
TextView stepSizeOneHundredPercentText = rootView.findViewById(R.id.stepSizeOneHundredPercent);
|
||||||
|
|
||||||
if (stepSizeOnePercentText != null) {
|
if (stepSizeOnePercentText != null) {
|
||||||
stepSizeOnePercentText.setText(getPercentString(STEP_ONE_PERCENT_VALUE));
|
stepSizeOnePercentText.setText(getPercentString(STEP_ONE_PERCENT_VALUE));
|
||||||
|
@ -207,7 +207,7 @@ public class PlayerHelper {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static SeekParameters getSeekParameters(@NonNull final Context context) {
|
public static SeekParameters getSeekParameters(@NonNull final Context context) {
|
||||||
return isUsingInexactSeek(context, false) ?
|
return isUsingInexactSeek(context) ?
|
||||||
SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
|
SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,8 +326,8 @@ public class PlayerHelper {
|
|||||||
return getPreferences(context).getBoolean(context.getString(R.string.popup_remember_size_pos_key), b);
|
return getPreferences(context).getBoolean(context.getString(R.string.popup_remember_size_pos_key), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUsingInexactSeek(@NonNull final Context context, final boolean b) {
|
private static boolean isUsingInexactSeek(@NonNull final Context context) {
|
||||||
return getPreferences(context).getBoolean(context.getString(R.string.use_inexact_seek_key), b);
|
return getPreferences(context).getBoolean(context.getString(R.string.use_inexact_seek_key), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAutoQueueEnabled(@NonNull final Context context, final boolean b) {
|
private static boolean isAutoQueueEnabled(@NonNull final Context context, final boolean b) {
|
||||||
|
@ -79,7 +79,7 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
|
|||||||
|
|
||||||
private void publishFloatingQueueWindow() {
|
private void publishFloatingQueueWindow() {
|
||||||
if (callback.getQueueSize() == 0) {
|
if (callback.getQueueSize() == 0) {
|
||||||
mediaSession.setQueue(Collections.<MediaSessionCompat.QueueItem>emptyList());
|
mediaSession.setQueue(Collections.emptyList());
|
||||||
activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
|
activeQueueItemId = MediaSessionCompat.QueueItem.UNKNOWN_ID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
|
|||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
|
|
||||||
public class BasePlayerMediaSession implements MediaSessionCallback {
|
public class BasePlayerMediaSession implements MediaSessionCallback {
|
||||||
private BasePlayer player;
|
private final BasePlayer player;
|
||||||
|
|
||||||
public BasePlayerMediaSession(final BasePlayer player) {
|
public BasePlayerMediaSession(final BasePlayer player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
@ -4,7 +4,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
@ -12,7 +11,6 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
|||||||
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class allows irregular text language labels for use when selecting text captions and
|
* This class allows irregular text language labels for use when selecting text captions and
|
||||||
@ -55,7 +53,7 @@ public class CustomTrackSelector extends DefaultTrackSelector {
|
|||||||
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
|
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
|
||||||
@Override
|
@Override
|
||||||
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
|
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
|
||||||
Parameters params) throws ExoPlaybackException {
|
Parameters params) {
|
||||||
TrackGroup selectedGroup = null;
|
TrackGroup selectedGroup = null;
|
||||||
int selectedTrackIndex = 0;
|
int selectedTrackIndex = 0;
|
||||||
int selectedTrackScore = 0;
|
int selectedTrackScore = 0;
|
||||||
|
@ -335,7 +335,7 @@ public class MediaSourceManager {
|
|||||||
|
|
||||||
private void loadImmediate() {
|
private void loadImmediate() {
|
||||||
if (DEBUG) Log.d(TAG, "MediaSource - loadImmediate() called");
|
if (DEBUG) Log.d(TAG, "MediaSource - loadImmediate() called");
|
||||||
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue, WINDOW_SIZE);
|
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue);
|
||||||
if (itemsToLoad == null) return;
|
if (itemsToLoad == null) return;
|
||||||
|
|
||||||
// Evict the previous items being loaded to free up memory, before start loading new ones
|
// Evict the previous items being loaded to free up memory, before start loading new ones
|
||||||
@ -472,8 +472,7 @@ public class MediaSourceManager {
|
|||||||
// Manager Helpers
|
// Manager Helpers
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue,
|
private static ItemsToLoad getItemsToLoad(@NonNull final PlayQueue playQueue) {
|
||||||
final int windowSize) {
|
|
||||||
// The current item has higher priority
|
// The current item has higher priority
|
||||||
final int currentIndex = playQueue.getIndex();
|
final int currentIndex = playQueue.getIndex();
|
||||||
final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
|
final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
|
||||||
@ -482,8 +481,8 @@ public class MediaSourceManager {
|
|||||||
// The rest are just for seamless playback
|
// The rest are just for seamless playback
|
||||||
// Although timeline is not updated prior to the current index, these sources are still
|
// Although timeline is not updated prior to the current index, these sources are still
|
||||||
// loaded into the cache for faster retrieval at a potentially later time.
|
// loaded into the cache for faster retrieval at a potentially later time.
|
||||||
final int leftBound = Math.max(0, currentIndex - windowSize);
|
final int leftBound = Math.max(0, currentIndex - MediaSourceManager.WINDOW_SIZE);
|
||||||
final int rightLimit = currentIndex + windowSize + 1;
|
final int rightLimit = currentIndex + MediaSourceManager.WINDOW_SIZE + 1;
|
||||||
final int rightBound = Math.min(playQueue.size(), rightLimit);
|
final int rightBound = Math.min(playQueue.size(), rightLimit);
|
||||||
final Set<PlayQueueItem> neighbors = new ArraySet<>(
|
final Set<PlayQueueItem> neighbors = new ArraySet<>(
|
||||||
playQueue.getStreams().subList(leftBound,rightBound));
|
playQueue.getStreams().subList(leftBound,rightBound));
|
||||||
|
@ -8,8 +8,6 @@ import com.google.android.exoplayer2.source.MediaSource;
|
|||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface PlaybackListener {
|
public interface PlaybackListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,14 +19,14 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
|
|||||||
boolean isInitial;
|
boolean isInitial;
|
||||||
boolean isComplete;
|
boolean isComplete;
|
||||||
|
|
||||||
int serviceId;
|
final int serviceId;
|
||||||
String baseUrl;
|
final String baseUrl;
|
||||||
String nextUrl;
|
String nextUrl;
|
||||||
|
|
||||||
transient Disposable fetchReactor;
|
transient Disposable fetchReactor;
|
||||||
|
|
||||||
AbstractInfoPlayQueue(final U item) {
|
AbstractInfoPlayQueue(final U item) {
|
||||||
this(item.getServiceId(), item.getUrl(), null, Collections.<StreamInfoItem>emptyList(), 0);
|
this(item.getServiceId(), item.getUrl(), null, Collections.emptyList(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractInfoPlayQueue(final int serviceId,
|
AbstractInfoPlayQueue(final int serviceId,
|
||||||
|
@ -5,10 +5,8 @@ import android.text.TextUtils;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
@ -6,8 +6,6 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 01.08.16.
|
* Created by Christian Schabesberger on 01.08.16.
|
||||||
|
@ -5,7 +5,6 @@ import android.support.annotation.NonNull;
|
|||||||
|
|
||||||
import org.acra.collector.CrashReportData;
|
import org.acra.collector.CrashReportData;
|
||||||
import org.acra.sender.ReportSender;
|
import org.acra.sender.ReportSender;
|
||||||
import org.acra.sender.ReportSenderException;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -31,7 +30,7 @@ import org.schabi.newpipe.R;
|
|||||||
public class AcraReportSender implements ReportSender {
|
public class AcraReportSender implements ReportSender {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(@NonNull Context context, @NonNull CrashReportData report) throws ReportSenderException {
|
public void send(@NonNull Context context, @NonNull CrashReportData report) {
|
||||||
ErrorActivity.reportError(context, report,
|
ErrorActivity.reportError(context, report,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,"none",
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,"none",
|
||||||
"App crash, UI failure", R.string.app_ui_crash));
|
"App crash, UI failure", R.string.app_ui_crash));
|
||||||
|
@ -3,7 +3,6 @@ package org.schabi.newpipe.report;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -46,7 +45,6 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 24.10.15.
|
* Created by Christian Schabesberger on 24.10.15.
|
||||||
@ -81,12 +79,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
private ErrorInfo errorInfo;
|
private ErrorInfo errorInfo;
|
||||||
private Class returnActivity;
|
private Class returnActivity;
|
||||||
private String currentTimeStamp;
|
private String currentTimeStamp;
|
||||||
// views
|
|
||||||
private TextView errorView;
|
|
||||||
private EditText userCommentBox;
|
private EditText userCommentBox;
|
||||||
private Button reportButton;
|
|
||||||
private TextView infoView;
|
|
||||||
private TextView errorMessageView;
|
|
||||||
|
|
||||||
public static void reportUiError(final AppCompatActivity activity, final Throwable el) {
|
public static void reportUiError(final AppCompatActivity activity, final Throwable el) {
|
||||||
reportError(activity, el, activity.getClass(), null,
|
reportError(activity, el, activity.getClass(), null,
|
||||||
@ -194,11 +187,11 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
actionBar.setDisplayShowTitleEnabled(true);
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
reportButton = findViewById(R.id.errorReportButton);
|
Button reportButton = findViewById(R.id.errorReportButton);
|
||||||
userCommentBox = findViewById(R.id.errorCommentBox);
|
userCommentBox = findViewById(R.id.errorCommentBox);
|
||||||
errorView = findViewById(R.id.errorView);
|
TextView errorView = findViewById(R.id.errorView);
|
||||||
infoView = findViewById(R.id.errorInfosView);
|
TextView infoView = findViewById(R.id.errorInfosView);
|
||||||
errorMessageView = findViewById(R.id.errorMessageView);
|
TextView errorMessageView = findViewById(R.id.errorMessageView);
|
||||||
|
|
||||||
ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
||||||
returnActivity = ac.returnActivity;
|
returnActivity = ac.returnActivity;
|
||||||
@ -281,15 +274,14 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String formErrorText(String[] el) {
|
private String formErrorText(String[] el) {
|
||||||
String text = "";
|
StringBuilder text = new StringBuilder();
|
||||||
if (el != null) {
|
if (el != null) {
|
||||||
for (String e : el) {
|
for (String e : el) {
|
||||||
text += "-------------------------------------\n"
|
text.append("-------------------------------------\n").append(e);
|
||||||
+ e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text += "-------------------------------------";
|
text.append("-------------------------------------");
|
||||||
return text;
|
return text.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,6 @@ import android.os.Bundle;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
@ -49,7 +48,7 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment {
|
|||||||
return super.onPreferenceTreeClick(preference);
|
return super.onPreferenceTreeClick(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Preference.OnPreferenceChangeListener themePreferenceChange = new Preference.OnPreferenceChangeListener() {
|
private final Preference.OnPreferenceChangeListener themePreferenceChange = new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
defaultPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, true).apply();
|
defaultPreferences.edit().putBoolean(Constants.KEY_THEME_CHANGE, true).apply();
|
||||||
|
@ -13,7 +13,7 @@ import org.schabi.newpipe.MainActivity;
|
|||||||
|
|
||||||
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
|
public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
|
||||||
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||||
protected boolean DEBUG = MainActivity.DEBUG;
|
protected final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
protected SharedPreferences defaultPreferences;
|
protected SharedPreferences defaultPreferences;
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ import android.os.Bundle;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v7.preference.ListPreference;
|
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -19,12 +17,9 @@ import com.nononsenseapps.filepicker.Utils;
|
|||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
|
||||||
import org.schabi.newpipe.util.ZipHelper;
|
import org.schabi.newpipe.util.ZipHelper;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
@ -47,7 +42,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
private static final int REQUEST_IMPORT_PATH = 8945;
|
private static final int REQUEST_IMPORT_PATH = 8945;
|
||||||
private static final int REQUEST_EXPORT_PATH = 30945;
|
private static final int REQUEST_EXPORT_PATH = 30945;
|
||||||
|
|
||||||
private String homeDir;
|
|
||||||
private File databasesDir;
|
private File databasesDir;
|
||||||
private File newpipe_db;
|
private File newpipe_db;
|
||||||
private File newpipe_db_journal;
|
private File newpipe_db_journal;
|
||||||
@ -81,7 +75,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
|
||||||
homeDir = getActivity().getApplicationInfo().dataDir;
|
String homeDir = getActivity().getApplicationInfo().dataDir;
|
||||||
databasesDir = new File(homeDir + "/databases");
|
databasesDir = new File(homeDir + "/databases");
|
||||||
newpipe_db = new File(homeDir + "/databases/newpipe.db");
|
newpipe_db = new File(homeDir + "/databases/newpipe.db");
|
||||||
newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal");
|
newpipe_db_journal = new File(homeDir + "/databases/newpipe.db-journal");
|
||||||
@ -193,7 +187,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
zipFile.close();
|
zipFile.close();
|
||||||
} catch (Exception e){}
|
} catch (Exception ignored){}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -254,17 +248,17 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
|
|
||||||
if (v instanceof Boolean)
|
if (v instanceof Boolean)
|
||||||
prefEdit.putBoolean(key, ((Boolean) v).booleanValue());
|
prefEdit.putBoolean(key, (Boolean) v);
|
||||||
else if (v instanceof Float)
|
else if (v instanceof Float)
|
||||||
prefEdit.putFloat(key, ((Float) v).floatValue());
|
prefEdit.putFloat(key, (Float) v);
|
||||||
else if (v instanceof Integer)
|
else if (v instanceof Integer)
|
||||||
prefEdit.putInt(key, ((Integer) v).intValue());
|
prefEdit.putInt(key, (Integer) v);
|
||||||
else if (v instanceof Long)
|
else if (v instanceof Long)
|
||||||
prefEdit.putLong(key, ((Long) v).longValue());
|
prefEdit.putLong(key, (Long) v);
|
||||||
else if (v instanceof String)
|
else if (v instanceof String)
|
||||||
prefEdit.putString(key, ((String) v));
|
prefEdit.putString(key, ((String) v));
|
||||||
}
|
}
|
||||||
prefEdit.commit();
|
prefEdit.apply();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -286,13 +280,12 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
// Error
|
// Error
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected boolean onError(Throwable e) {
|
protected void onError(Throwable e) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
ErrorActivity.reportError(activity, e,
|
ErrorActivity.reportError(activity, e,
|
||||||
activity.getClass(),
|
activity.getClass(),
|
||||||
null,
|
null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||||
"none", "", R.string.app_ui_crash));
|
"none", "", R.string.app_ui_crash));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,20 @@
|
|||||||
package org.schabi.newpipe.settings;
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.InfoCache;
|
import org.schabi.newpipe.util.InfoCache;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.disposables.Disposables;
|
|
||||||
|
|
||||||
public class HistorySettingsFragment extends BasePreferenceFragment {
|
public class HistorySettingsFragment extends BasePreferenceFragment {
|
||||||
private String cacheWipeKey;
|
private String cacheWipeKey;
|
||||||
|
@ -51,9 +51,7 @@ import io.reactivex.schedulers.Schedulers;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class SelectChannelFragment extends DialogFragment {
|
public class SelectChannelFragment extends DialogFragment {
|
||||||
private SelectChannelAdapter channelAdapter;
|
private final ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
private SubscriptionService subscriptionService;
|
|
||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
|
||||||
|
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private TextView emptyView;
|
private TextView emptyView;
|
||||||
@ -89,9 +87,9 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
|
View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
|
||||||
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
|
recyclerView = v.findViewById(R.id.items_list);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
channelAdapter = new SelectChannelAdapter();
|
SelectChannelAdapter channelAdapter = new SelectChannelAdapter();
|
||||||
recyclerView.setAdapter(channelAdapter);
|
recyclerView.setAdapter(channelAdapter);
|
||||||
|
|
||||||
progressBar = v.findViewById(R.id.progressBar);
|
progressBar = v.findViewById(R.id.progressBar);
|
||||||
@ -101,7 +99,7 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
emptyView.setVisibility(View.GONE);
|
emptyView.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
|
||||||
subscriptionService = SubscriptionService.getInstance(getContext());
|
SubscriptionService subscriptionService = SubscriptionService.getInstance(getContext());
|
||||||
subscriptionService.getSubscription().toObservable()
|
subscriptionService.getSubscription().toObservable()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -203,9 +201,9 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
thumbnailView = v.findViewById(R.id.itemThumbnailView);
|
thumbnailView = v.findViewById(R.id.itemThumbnailView);
|
||||||
titleView = v.findViewById(R.id.itemTitleView);
|
titleView = v.findViewById(R.id.itemTitleView);
|
||||||
}
|
}
|
||||||
public View view;
|
public final View view;
|
||||||
public CircleImageView thumbnailView;
|
public final CircleImageView thumbnailView;
|
||||||
public TextView titleView;
|
public final TextView titleView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,14 +211,13 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
// Error
|
// Error
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected boolean onError(Throwable e) {
|
protected void onError(Throwable e) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
ErrorActivity.reportError(activity, e,
|
ErrorActivity.reportError(activity, e,
|
||||||
activity.getClass(),
|
activity.getClass(),
|
||||||
null,
|
null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||||
"none", "", R.string.app_ui_crash));
|
"none", "", R.string.app_ui_crash));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
|
View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
|
||||||
recyclerView = (RecyclerView) v.findViewById(R.id.items_list);
|
recyclerView = v.findViewById(R.id.items_list);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
try {
|
try {
|
||||||
selectKioskAdapter = new SelectKioskAdapter();
|
selectKioskAdapter = new SelectKioskAdapter();
|
||||||
@ -112,13 +112,13 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
public Entry (int i, int si, String ki, String kn){
|
public Entry (int i, int si, String ki, String kn){
|
||||||
icon = i; serviceId=si; kioskId=ki; kioskName = kn;
|
icon = i; serviceId=si; kioskId=ki; kioskName = kn;
|
||||||
}
|
}
|
||||||
int icon;
|
final int icon;
|
||||||
int serviceId;
|
final int serviceId;
|
||||||
String kioskId;
|
final String kioskId;
|
||||||
String kioskName;
|
final String kioskName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Entry> kioskList = new Vector<>();
|
private final List<Entry> kioskList = new Vector<>();
|
||||||
|
|
||||||
public SelectKioskAdapter()
|
public SelectKioskAdapter()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -157,9 +157,9 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
thumbnailView = v.findViewById(R.id.itemThumbnailView);
|
thumbnailView = v.findViewById(R.id.itemThumbnailView);
|
||||||
titleView = v.findViewById(R.id.itemTitleView);
|
titleView = v.findViewById(R.id.itemTitleView);
|
||||||
}
|
}
|
||||||
public View view;
|
public final View view;
|
||||||
public ImageView thumbnailView;
|
public final ImageView thumbnailView;
|
||||||
public TextView titleView;
|
public final TextView titleView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBindViewHolder(SelectKioskItemHolder holder, final int position) {
|
public void onBindViewHolder(SelectKioskItemHolder holder, final int position) {
|
||||||
@ -179,13 +179,12 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
// Error
|
// Error
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected boolean onError(Throwable e) {
|
protected void onError(Throwable e) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
ErrorActivity.reportError(activity, e,
|
ErrorActivity.reportError(activity, e,
|
||||||
activity.getClass(),
|
activity.getClass(),
|
||||||
null,
|
null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||||
"none", "", R.string.app_ui_crash));
|
"none", "", R.string.app_ui_crash));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import org.schabi.newpipe.extractor.Info;
|
|||||||
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
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.ContentNotAvailableException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
@ -183,7 +184,7 @@ public final class ExtractorHelper {
|
|||||||
cache.removeInfo(serviceId, url);
|
cache.removeInfo(serviceId, url);
|
||||||
load = loadFromNetwork;
|
load = loadFromNetwork;
|
||||||
} else {
|
} else {
|
||||||
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url),
|
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url),
|
||||||
loadFromNetwork.toMaybe())
|
loadFromNetwork.toMaybe())
|
||||||
.firstElement() //Take the first valid
|
.firstElement() //Take the first valid
|
||||||
.toSingle();
|
.toSingle();
|
||||||
|
@ -28,9 +28,6 @@ import org.schabi.newpipe.MainActivity;
|
|||||||
import org.schabi.newpipe.extractor.Info;
|
import org.schabi.newpipe.extractor.Info;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.SoundCloud;
|
|
||||||
|
|
||||||
|
|
||||||
public final class InfoCache {
|
public final class InfoCache {
|
||||||
@ -58,7 +55,7 @@ public final class InfoCache {
|
|||||||
public Info getFromKey(int serviceId, @NonNull String url) {
|
public Info getFromKey(int serviceId, @NonNull String url) {
|
||||||
if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
|
if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
|
||||||
synchronized (lruCache) {
|
synchronized (lruCache) {
|
||||||
return getInfo(lruCache, keyOf(serviceId, url));
|
return getInfo(keyOf(serviceId, url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +86,7 @@ public final class InfoCache {
|
|||||||
public void trimCache() {
|
public void trimCache() {
|
||||||
if (DEBUG) Log.d(TAG, "trimCache() called");
|
if (DEBUG) Log.d(TAG, "trimCache() called");
|
||||||
synchronized (lruCache) {
|
synchronized (lruCache) {
|
||||||
removeStaleCache(lruCache);
|
removeStaleCache();
|
||||||
lruCache.trimToSize(TRIM_CACHE_TO);
|
lruCache.trimToSize(TRIM_CACHE_TO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,23 +102,22 @@ public final class InfoCache {
|
|||||||
return serviceId + url;
|
return serviceId + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeStaleCache(@NonNull final LruCache<String, CacheData> cache) {
|
private static void removeStaleCache() {
|
||||||
for (Map.Entry<String, CacheData> entry : cache.snapshot().entrySet()) {
|
for (Map.Entry<String, CacheData> entry : InfoCache.lruCache.snapshot().entrySet()) {
|
||||||
final CacheData data = entry.getValue();
|
final CacheData data = entry.getValue();
|
||||||
if (data != null && data.isExpired()) {
|
if (data != null && data.isExpired()) {
|
||||||
cache.remove(entry.getKey());
|
InfoCache.lruCache.remove(entry.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static Info getInfo(@NonNull final LruCache<String, CacheData> cache,
|
private static Info getInfo(@NonNull final String key) {
|
||||||
@NonNull final String key) {
|
final CacheData data = InfoCache.lruCache.get(key);
|
||||||
final CacheData data = cache.get(key);
|
|
||||||
if (data == null) return null;
|
if (data == null) return null;
|
||||||
|
|
||||||
if (data.isExpired()) {
|
if (data.isExpired()) {
|
||||||
cache.remove(key);
|
InfoCache.lruCache.remove(key);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ public final class ListHelper {
|
|||||||
*/
|
*/
|
||||||
private static void sortStreamList(List<VideoStream> videoStreams, final boolean ascendingOrder) {
|
private static void sortStreamList(List<VideoStream> videoStreams, final boolean ascendingOrder) {
|
||||||
Collections.sort(videoStreams, (o1, o2) -> {
|
Collections.sort(videoStreams, (o1, o2) -> {
|
||||||
int result = compareVideoStreamResolution(o1, o2, VIDEO_FORMAT_QUALITY_RANKING);
|
int result = compareVideoStreamResolution(o1, o2);
|
||||||
return result == 0 ? 0 : (ascendingOrder ? result : -result);
|
return result == 0 ? 0 : (ascendingOrder ? result : -result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -399,8 +399,7 @@ public final class ListHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compares the quality of two video streams.
|
// Compares the quality of two video streams.
|
||||||
private static int compareVideoStreamResolution(VideoStream streamA, VideoStream streamB,
|
private static int compareVideoStreamResolution(VideoStream streamA, VideoStream streamB) {
|
||||||
List<MediaFormat> formatRanking) {
|
|
||||||
if (streamA == null) {
|
if (streamA == null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -414,7 +413,7 @@ public final class ListHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Same bitrate and format
|
// Same bitrate and format
|
||||||
return formatRanking.indexOf(streamA.getFormat()) - formatRanking.indexOf(streamB.getFormat());
|
return ListHelper.VIDEO_FORMAT_QUALITY_RANKING.indexOf(streamA.getFormat()) - ListHelper.VIDEO_FORMAT_QUALITY_RANKING.indexOf(streamB.getFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ import org.schabi.newpipe.download.DownloadActivity;
|
|||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
import org.schabi.newpipe.extractor.stream.Stream;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
|
@ -21,7 +21,6 @@ package org.schabi.newpipe.util;
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
@ -31,7 +31,7 @@ import us.shandian.giga.util.Utility;
|
|||||||
public class StreamItemAdapter<T extends Stream> extends BaseAdapter {
|
public class StreamItemAdapter<T extends Stream> extends BaseAdapter {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
private StreamSizeWrapper<T> streamsWrapper;
|
private final StreamSizeWrapper<T> streamsWrapper;
|
||||||
private final boolean showIconNoAudio;
|
private final boolean showIconNoAudio;
|
||||||
|
|
||||||
public StreamItemAdapter(Context context, StreamSizeWrapper<T> streamsWrapper, boolean showIconNoAudio) {
|
public StreamItemAdapter(Context context, StreamSizeWrapper<T> streamsWrapper, boolean showIconNoAudio) {
|
||||||
@ -124,7 +124,7 @@ public class StreamItemAdapter<T extends Stream> extends BaseAdapter {
|
|||||||
public static class StreamSizeWrapper<T extends Stream> implements Serializable {
|
public static class StreamSizeWrapper<T extends Stream> implements Serializable {
|
||||||
private static final StreamSizeWrapper<Stream> EMPTY = new StreamSizeWrapper<>(Collections.emptyList());
|
private static final StreamSizeWrapper<Stream> EMPTY = new StreamSizeWrapper<>(Collections.emptyList());
|
||||||
private final List<T> streamsList;
|
private final List<T> streamsList;
|
||||||
private long[] streamSizes;
|
private final long[] streamSizes;
|
||||||
|
|
||||||
public StreamSizeWrapper(List<T> streamsList) {
|
public StreamSizeWrapper(List<T> streamsList) {
|
||||||
this.streamsList = streamsList;
|
this.streamsList = streamsList;
|
||||||
|
@ -56,7 +56,6 @@ public class ZipHelper {
|
|||||||
/**
|
/**
|
||||||
* This will extract data from Zipfiles.
|
* This will extract data from Zipfiles.
|
||||||
* Caution this will override the original file.
|
* Caution this will override the original file.
|
||||||
* @param inZip The ZipOutputStream where the data is stored in
|
|
||||||
* @param file The path of the file on the disk where the data should be extracted to.
|
* @param file The path of the file on the disk where the data should be extracted to.
|
||||||
* @param name The path of the file inside the zip.
|
* @param name The path of the file inside the zip.
|
||||||
* @return will return true if the file was found within the zip file
|
* @return will return true if the file was found within the zip file
|
||||||
|
@ -81,7 +81,7 @@ public class CollapsibleView extends LinearLayout {
|
|||||||
|
|
||||||
private int targetHeight = -1;
|
private int targetHeight = -1;
|
||||||
private ValueAnimator currentAnimator;
|
private ValueAnimator currentAnimator;
|
||||||
private List<StateListener> listeners = new ArrayList<>();
|
private final List<StateListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method recalculates the height of this view so it <b>must</b> be called when
|
* This method recalculates the height of this view so it <b>must</b> be called when
|
||||||
|
@ -123,7 +123,7 @@ public class DownloadManagerImpl implements DownloadManager {
|
|||||||
Collections.sort(missions, new Comparator<DownloadMission>() {
|
Collections.sort(missions, new Comparator<DownloadMission>() {
|
||||||
@Override
|
@Override
|
||||||
public int compare(DownloadMission o1, DownloadMission o2) {
|
public int compare(DownloadMission o1, DownloadMission o2) {
|
||||||
return Long.valueOf(o1.timestamp).compareTo(o2.timestamp);
|
return Long.compare(o1.timestamp, o2.timestamp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,8 @@ public class DownloadMission implements Serializable {
|
|||||||
public long done;
|
public long done;
|
||||||
public int threadCount = 3;
|
public int threadCount = 3;
|
||||||
public int finishCount;
|
public int finishCount;
|
||||||
private List<Long> threadPositions = new ArrayList<Long>();
|
private final List<Long> threadPositions = new ArrayList<>();
|
||||||
public final Map<Long, Boolean> blockState = new HashMap<Long, Boolean>();
|
public final Map<Long, Boolean> blockState = new HashMap<>();
|
||||||
public boolean running;
|
public boolean running;
|
||||||
public boolean finished;
|
public boolean finished;
|
||||||
public boolean fallback;
|
public boolean fallback;
|
||||||
@ -77,7 +77,7 @@ public class DownloadMission implements Serializable {
|
|||||||
|
|
||||||
public transient boolean recovered;
|
public transient boolean recovered;
|
||||||
|
|
||||||
private transient ArrayList<WeakReference<MissionListener>> mListeners = new ArrayList<WeakReference<MissionListener>>();
|
private transient ArrayList<WeakReference<MissionListener>> mListeners = new ArrayList<>();
|
||||||
private transient boolean mWritingToFile;
|
private transient boolean mWritingToFile;
|
||||||
|
|
||||||
private static final int NO_IDENTIFIER = -1;
|
private static final int NO_IDENTIFIER = -1;
|
||||||
@ -232,7 +232,7 @@ public class DownloadMission implements Serializable {
|
|||||||
public synchronized void addListener(MissionListener listener) {
|
public synchronized void addListener(MissionListener listener) {
|
||||||
Handler handler = new Handler(Looper.getMainLooper());
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
MissionListener.handlerStore.put(listener, handler);
|
MissionListener.handlerStore.put(listener, handler);
|
||||||
mListeners.add(new WeakReference<MissionListener>(listener));
|
mListeners.add(new WeakReference<>(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void removeListener(MissionListener listener) {
|
public synchronized void removeListener(MissionListener listener) {
|
||||||
|
@ -92,7 +92,7 @@ public class DownloadRunnable implements Runnable {
|
|||||||
// A server may be ignoring the range request
|
// A server may be ignoring the range request
|
||||||
if (conn.getResponseCode() != 206) {
|
if (conn.getResponseCode() != 206) {
|
||||||
mMission.errCode = DownloadMission.ERROR_SERVER_UNSUPPORTED;
|
mMission.errCode = DownloadMission.ERROR_SERVER_UNSUPPORTED;
|
||||||
notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED);
|
notifyError();
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.e(TAG, mId + ":Unsupported " + conn.getResponseCode());
|
Log.e(TAG, mId + ":Unsupported " + conn.getResponseCode());
|
||||||
@ -161,9 +161,9 @@ public class DownloadRunnable implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyError(final int err) {
|
private void notifyError() {
|
||||||
synchronized (mMission) {
|
synchronized (mMission) {
|
||||||
mMission.notifyError(err);
|
mMission.notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED);
|
||||||
mMission.pause();
|
mMission.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ public class DownloadManagerService extends Service {
|
|||||||
private DownloadDataSource mDataSource;
|
private DownloadDataSource mDataSource;
|
||||||
|
|
||||||
|
|
||||||
private MissionListener missionListener = new MissionListener();
|
private final MissionListener missionListener = new MissionListener();
|
||||||
|
|
||||||
|
|
||||||
private void notifyMediaScanner(DownloadMission mission) {
|
private void notifyMediaScanner(DownloadMission mission) {
|
||||||
|
@ -306,12 +306,12 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
|
|||||||
public DownloadMission mission;
|
public DownloadMission mission;
|
||||||
public int position;
|
public int position;
|
||||||
|
|
||||||
public TextView status;
|
public final TextView status;
|
||||||
public ImageView icon;
|
public final ImageView icon;
|
||||||
public TextView name;
|
public final TextView name;
|
||||||
public TextView size;
|
public final TextView size;
|
||||||
public View bkg;
|
public final View bkg;
|
||||||
public ImageView menu;
|
public final ImageView menu;
|
||||||
public ProgressDrawable progress;
|
public ProgressDrawable progress;
|
||||||
public MissionObserver observer;
|
public MissionObserver observer;
|
||||||
|
|
||||||
@ -332,8 +332,8 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class MissionObserver implements DownloadMission.MissionListener {
|
static class MissionObserver implements DownloadMission.MissionListener {
|
||||||
private MissionAdapter mAdapter;
|
private final MissionAdapter mAdapter;
|
||||||
private ViewHolder mHolder;
|
private final ViewHolder mHolder;
|
||||||
|
|
||||||
public MissionObserver(MissionAdapter adapter, ViewHolder holder) {
|
public MissionObserver(MissionAdapter adapter, ViewHolder holder) {
|
||||||
mAdapter = adapter;
|
mAdapter = adapter;
|
||||||
@ -365,7 +365,7 @@ public class MissionAdapter extends RecyclerView.Adapter<MissionAdapter.ViewHold
|
|||||||
|
|
||||||
private static class ChecksumTask extends AsyncTask<String, Void, String> {
|
private static class ChecksumTask extends AsyncTask<String, Void, String> {
|
||||||
ProgressDialog prog;
|
ProgressDialog prog;
|
||||||
WeakReference<Activity> weakReference;
|
final WeakReference<Activity> weakReference;
|
||||||
|
|
||||||
ChecksumTask(@NonNull Activity activity) {
|
ChecksumTask(@NonNull Activity activity) {
|
||||||
weakReference = new WeakReference<>(activity);
|
weakReference = new WeakReference<>(activity);
|
||||||
|
@ -12,7 +12,8 @@ import android.support.v4.content.ContextCompat;
|
|||||||
|
|
||||||
public class ProgressDrawable extends Drawable {
|
public class ProgressDrawable extends Drawable {
|
||||||
private float mProgress;
|
private float mProgress;
|
||||||
private int mBackgroundColor, mForegroundColor;
|
private final int mBackgroundColor;
|
||||||
|
private final int mForegroundColor;
|
||||||
|
|
||||||
public ProgressDrawable(Context context, @ColorRes int background, @ColorRes int foreground) {
|
public ProgressDrawable(Context context, @ColorRes int background, @ColorRes int foreground) {
|
||||||
this(ContextCompat.getColor(context, background), ContextCompat.getColor(context, foreground));
|
this(ContextCompat.getColor(context, background), ContextCompat.getColor(context, foreground));
|
||||||
|
@ -16,6 +16,8 @@ import android.support.v7.widget.GridLayoutManager;
|
|||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -44,7 +46,7 @@ public abstract class MissionsFragment extends Fragment {
|
|||||||
private DeleteDownloadManager mDeleteDownloadManager;
|
private DeleteDownloadManager mDeleteDownloadManager;
|
||||||
private Disposable mDeleteDisposable;
|
private Disposable mDeleteDisposable;
|
||||||
|
|
||||||
private ServiceConnection mConnection = new ServiceConnection() {
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||||
@ -144,17 +146,21 @@ public abstract class MissionsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public void onPrepareOptionsMenu(Menu menu) {
|
||||||
return super.onOptionsItemSelected(item);
|
mSwitch = menu.findItem(R.id.switch_mode);
|
||||||
|
super.onPrepareOptionsMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
/*switch (item.getItemId()) {
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
case R.id.switch_mode:
|
case R.id.switch_mode:
|
||||||
mLinear = !mLinear;
|
mLinear = !mLinear;
|
||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyChange() {
|
public void notifyChange() {
|
||||||
|
@ -11,9 +11,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@ -198,7 +196,7 @@ public class Utility {
|
|||||||
while ((len = i.read(buf)) != -1) {
|
while ((len = i.read(buf)) != -1) {
|
||||||
md.update(buf, 0, len);
|
md.update(buf, 0, len);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
581
app/src/main/res/layout-large-land/activity_main_player.xml
Normal file
581
app/src/main/res/layout-large-land/activity_main_player.xml
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
|
android:id="@+id/aspectRatioLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<SurfaceView
|
||||||
|
android:id="@+id/surfaceView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/surfaceForeground"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@android:color/black"/>
|
||||||
|
|
||||||
|
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout>
|
||||||
|
|
||||||
|
<com.google.android.exoplayer2.ui.SubtitleView
|
||||||
|
android:id="@+id/subtitleView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/endScreen"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:background="@android:color/white"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/playQueuePanel"
|
||||||
|
android:layout_width="380dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:background="?attr/queue_background_color"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:id="@+id/playQueueControl">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playQueueClose"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginRight="40dp"
|
||||||
|
android:layout_marginEnd="40dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
android:src="@drawable/ic_close_white_24dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/repeatButton"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_marginLeft="40dp"
|
||||||
|
android:layout_marginStart="40dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
android:src="@drawable/exo_controls_repeat_off"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/shuffleButton"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@id/repeatButton"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
android:src="@drawable/ic_shuffle_white_24dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/playQueue"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/playQueueControl"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
app:layoutManager="LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/play_queue_item"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/playbackControlRoot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/video_overlay_color"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/playbackWindowRoot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/topControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:background="@drawable/player_top_controls_bg"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/metadataView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_toLeftOf="@+id/qualityTextView"
|
||||||
|
android:gravity="top"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/titleTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="The Video Title LONG very LONG"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/channelTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
tools:text="The Video Artist LONG very LONG very Long"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/qualityTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_toLeftOf="@+id/playbackSpeed"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:text="720p"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="HardcodedText,RtlHardcoded"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackSpeed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_toLeftOf="@+id/queueButton"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minHeight="35dp"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
|
tools:text="1x" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/queueButton"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_toLeftOf="@+id/moreOptionsButton"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/list"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/moreOptionsButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_expand_more_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/secondaryControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/topControls"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingLeft="5dp"
|
||||||
|
android:paddingRight="5dp"
|
||||||
|
android:visibility="invisible"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizeTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="35dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="50dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="HardcodedText,RtlHardcoded"
|
||||||
|
tools:text="FIT"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/captionTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_toLeftOf="@id/switchBackground"
|
||||||
|
android:layout_toRightOf="@id/resizeTextView"
|
||||||
|
android:gravity="center|left"
|
||||||
|
android:minHeight="35dp"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:paddingLeft="2dp"
|
||||||
|
android:paddingRight="2dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
|
tools:text="English" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/toggleOrientation"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_screen_rotation_white"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/toggle_orientation"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/switchPopup"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:layout_toLeftOf="@id/toggleOrientation"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_fullscreen_exit_white"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/switch_to_popup"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/switchBackground"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:layout_toLeftOf="@id/switchPopup"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_headset_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/switch_to_background"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bottomControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="@drawable/player_controls_bg"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackCurrentTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minHeight="40dp"
|
||||||
|
android:text="-:--:--"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
tools:text="1:06:29"/>
|
||||||
|
|
||||||
|
|
||||||
|
<android.support.v7.widget.AppCompatSeekBar
|
||||||
|
android:id="@+id/playbackSeekBar"
|
||||||
|
style="@style/Widget.AppCompat.SeekBar"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
tools:progress="25"
|
||||||
|
tools:secondaryProgress="50"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackEndTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="-:--:--"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
tools:ignore="HardcodedText"
|
||||||
|
tools:text="1:23:49"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playbackLiveSync"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingLeft="4dp"
|
||||||
|
android:paddingRight="4dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/duration_live_button"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:maxLength="4"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="HardcodedText,RtlHardcoded,RtlSymmetry" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playPauseButton"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_pause_white"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playPreviousButton"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginRight="30dp"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_toLeftOf="@id/playPauseButton"
|
||||||
|
android:layout_toStartOf="@id/playPauseButton"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/exo_controls_previous"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playNextButton"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginLeft="30dp"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_toRightOf="@id/playPauseButton"
|
||||||
|
android:layout_toEndOf="@id/playPauseButton"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/exo_controls_next"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/controlAnimationView"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:background="@drawable/background_oval_black_transparent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:src="@drawable/ic_action_av_fast_rewind"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/loading_panel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarLoadingPanel"
|
||||||
|
style="?android:attr/progressBarStyleLargeInverse"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:indeterminate="true"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_toEndOf="@+id/loading_panel"
|
||||||
|
android:layout_toRightOf="@+id/loading_panel"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/volumeRelativeLayout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:background="@drawable/background_oval_black_transparent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/volumeProgressBar"
|
||||||
|
style="?android:progressBarStyleHorizontal"
|
||||||
|
android:layout_width="128dp"
|
||||||
|
android:layout_height="128dp"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:progressDrawable="@drawable/progress_circular_white" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/volumeImageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:src="@drawable/ic_volume_up_white_72dp" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/brightnessRelativeLayout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:background="@drawable/background_oval_black_transparent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/brightnessProgressBar"
|
||||||
|
style="?android:progressBarStyleHorizontal"
|
||||||
|
android:layout_width="128dp"
|
||||||
|
android:layout_height="128dp"
|
||||||
|
android:indeterminate="false"
|
||||||
|
android:progressDrawable="@drawable/progress_circular_white" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/brightnessImageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:src="@drawable/ic_brightness_high_white_72dp" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currentDisplaySeek"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginBottom="58dp"
|
||||||
|
android:background="#64000000"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingLeft="30dp"
|
||||||
|
android:paddingRight="30dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="26sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="1:06:29"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
491
app/src/main/res/layout-large-land/fragment_video_detail.xml
Normal file
491
app/src/main/res/layout-large-land/fragment_video_detail.xml
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/video_item_detail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.nirhart.parallaxscroll.views.ParallaxScrollView
|
||||||
|
android:id="@+id/detail_main_content"
|
||||||
|
app:parallax_factor="1.9"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="5">
|
||||||
|
|
||||||
|
<!--WRAPPER-->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- THUMBNAIL -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/detail_thumbnail_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/detail_thumbnail_image_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:contentDescription="@string/detail_thumbnail_view_description"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:layout_height="200dp"
|
||||||
|
tools:src="@drawable/dummy_thumbnail" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/detail_thumbnail_play_button"
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:src="@drawable/new_play_arrow"
|
||||||
|
android:visibility="invisible"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/touch_append_detail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="#64000000"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingLeft="30dp"
|
||||||
|
android:paddingRight="30dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:text="@string/hold_to_append"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_duration_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|right"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:alpha=".6"
|
||||||
|
android:background="#23000000"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="2dp"
|
||||||
|
android:paddingLeft="6dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
|
android:paddingTop="2dp"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="12:38"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- CONTENT -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/detail_content_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:windowBackground">
|
||||||
|
|
||||||
|
<!-- TITLE -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/detail_title_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_video_title_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_detail_title_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero." />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- LOADING INDICATOR-->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/loading_progress_bar"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/detail_title_root_layout"
|
||||||
|
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<!--ERROR PANEL-->
|
||||||
|
<include
|
||||||
|
android:id="@+id/error_panel"
|
||||||
|
layout="@layout/error_retry"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/detail_title_root_layout"
|
||||||
|
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<!--HIDING ROOT-->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_content_root_hiding"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@+id/detail_title_root_layout"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<!--DETAIL-->
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/detail_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<!--UPLOADER-->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_uploader_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_toLeftOf="@id/details_panel"
|
||||||
|
android:layout_toStartOf="@id/details_panel"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="6dp">
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/detail_uploader_thumbnail_view"
|
||||||
|
android:layout_width="@dimen/video_item_detail_uploader_image_size"
|
||||||
|
android:layout_height="@dimen/video_item_detail_uploader_image_size"
|
||||||
|
android:contentDescription="@string/detail_uploader_thumbnail_view_description"
|
||||||
|
android:src="@drawable/buddy"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_uploader_text_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="15dp"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_detail_uploader_text_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="Uploader" />
|
||||||
|
|
||||||
|
<!--<Button
|
||||||
|
android:id="@+id/detail_uploader_subscribe"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|right"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:text="@string/rss_button_title"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:theme="@style/RedButton"
|
||||||
|
android:drawableLeft="@drawable/ic_rss_feed_white_24dp"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
android:visibility="gone"/>-->
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- VIEW & THUMBS -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/details_panel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:paddingLeft="6dp"
|
||||||
|
android:paddingRight="6dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_view_count_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_detail_views_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="2,816,821,505 views" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/detail_thumbs_up_img_view"
|
||||||
|
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||||
|
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||||
|
android:layout_below="@id/detail_view_count_view"
|
||||||
|
android:contentDescription="@string/detail_likes_img_view_description"
|
||||||
|
android:src="?attr/thumbs_up" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_thumbs_up_count_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||||
|
android:layout_below="@id/detail_view_count_view"
|
||||||
|
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||||
|
android:layout_toRightOf="@id/detail_thumbs_up_img_view"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="12M" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/detail_thumbs_down_img_view"
|
||||||
|
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||||
|
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||||
|
android:layout_below="@id/detail_view_count_view"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||||
|
android:contentDescription="@string/detail_dislikes_img_view_description"
|
||||||
|
android:src="?attr/thumbs_down"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_thumbs_down_count_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||||
|
android:layout_below="@id/detail_view_count_view"
|
||||||
|
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||||
|
android:layout_toRightOf="@id/detail_thumbs_down_img_view"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="10K" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_thumbs_disabled_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||||
|
android:layout_below="@id/detail_view_count_view"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_toRightOf="@id/detail_thumbs_down_img_view"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/disabled"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_control_panel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="6dp">
|
||||||
|
|
||||||
|
<!-- CONTROLS -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_controls_playlist_append"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/append_playlist"
|
||||||
|
android:drawableTop="?attr/ic_playlist_add"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:text="@string/controls_add_to_playlist_title"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_controls_background"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/play_audio"
|
||||||
|
android:drawableTop="?attr/audio"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:text="@string/controls_background_title"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_controls_popup"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/open_in_popup_mode"
|
||||||
|
android:drawableTop="?attr/popup"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:text="@string/controls_popup_title"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_controls_download"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="55dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/controls_download_desc"
|
||||||
|
android:drawableTop="?attr/download"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:text="@string/download"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:background="?attr/separator_color" />
|
||||||
|
|
||||||
|
<!--DESCRIPTIONS-->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_description_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_upload_date_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textSize="@dimen/video_item_detail_upload_date_text_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Published on Oct 2, 2009" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_description_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="@dimen/video_item_detail_description_text_size"
|
||||||
|
tools:text="Description Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum." />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:background="?attr/separator_color" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.nirhart.parallaxscroll.views.ParallaxScrollView>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="3">
|
||||||
|
|
||||||
|
<!--NEXT AND RELATED VIDEOS-->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_related_streams_root_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/detail_next_stream_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:text="@string/next_video_title"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textSize="@dimen/video_item_detail_next_text_size"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/detail_related_streams_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:minHeight="50dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/detail_related_streams_expand"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:src="?attr/expand"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
@ -16,7 +16,8 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:src="@drawable/background_header" />
|
android:src="@drawable/background_header"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/drawer_header_np_nude_view"
|
android:id="@+id/drawer_header_np_nude_view"
|
||||||
@ -26,7 +27,8 @@
|
|||||||
|
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_marginTop="30dp"
|
android:layout_marginTop="30dp"
|
||||||
android:src="@drawable/np_logo_nude_shadow" />
|
android:src="@drawable/np_logo_nude_shadow"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/drawer_header_np_text_view"
|
android:id="@+id/drawer_header_np_text_view"
|
||||||
@ -38,7 +40,7 @@
|
|||||||
android:layout_toRightOf="@id/drawer_header_np_nude_view"
|
android:layout_toRightOf="@id/drawer_header_np_nude_view"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
android:textSize="30dp"
|
android:textSize="30sp"
|
||||||
android:textColor="@color/drawer_header_font_color"
|
android:textColor="@color/drawer_header_font_color"
|
||||||
android:textStyle="bold|italic" />
|
android:textStyle="bold|italic" />
|
||||||
|
|
||||||
@ -50,7 +52,7 @@
|
|||||||
android:layout_alignStart="@id/drawer_header_np_text_view"
|
android:layout_alignStart="@id/drawer_header_np_text_view"
|
||||||
android:layout_below="@id/drawer_header_np_text_view"
|
android:layout_below="@id/drawer_header_np_text_view"
|
||||||
android:text="YouTube"
|
android:text="YouTube"
|
||||||
android:textSize="18dp"
|
android:textSize="18sp"
|
||||||
android:textColor="@color/drawer_header_font_color"
|
android:textColor="@color/drawer_header_font_color"
|
||||||
android:textStyle="italic" />
|
android:textStyle="italic" />
|
||||||
|
|
||||||
@ -66,6 +68,7 @@
|
|||||||
android:paddingBottom="20dp"
|
android:paddingBottom="20dp"
|
||||||
android:paddingEnd="20dp"
|
android:paddingEnd="20dp"
|
||||||
android:paddingRight="20dp"
|
android:paddingRight="20dp"
|
||||||
android:src="@drawable/ic_arrow_down_white" />
|
android:src="@drawable/ic_arrow_down_white"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -114,7 +114,8 @@
|
|||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/errorCommentBox"
|
android:id="@+id/errorCommentBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/errorReportButton"
|
android:id="@+id/errorReportButton"
|
||||||
|
@ -16,7 +16,8 @@ android:focusable="true">
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
android:src="@drawable/background_header"
|
android:src="@drawable/background_header"
|
||||||
android:scaleType="centerCrop"/>
|
android:scaleType="centerCrop"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/drawer_header_np_nude_view"
|
android:id="@+id/drawer_header_np_nude_view"
|
||||||
@ -26,7 +27,8 @@ android:focusable="true">
|
|||||||
|
|
||||||
android:layout_width="70dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="70dp"
|
android:layout_height="70dp"
|
||||||
android:src="@drawable/np_logo_nude_shadow"/>
|
android:src="@drawable/np_logo_nude_shadow"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/drawer_header_np_text_view"
|
android:id="@+id/drawer_header_np_text_view"
|
||||||
@ -38,7 +40,7 @@ android:focusable="true">
|
|||||||
android:layout_alignTop="@id/drawer_header_np_nude_view"
|
android:layout_alignTop="@id/drawer_header_np_nude_view"
|
||||||
android:layout_alignBottom="@id/drawer_header_np_nude_view"
|
android:layout_alignBottom="@id/drawer_header_np_nude_view"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textSize="30dp"
|
android:textSize="30sp"
|
||||||
android:textColor="@color/drawer_header_font_color"
|
android:textColor="@color/drawer_header_font_color"
|
||||||
android:textStyle="bold|italic"/>
|
android:textStyle="bold|italic"/>
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ android:focusable="true">
|
|||||||
android:layout_below="@id/drawer_header_np_text_view"
|
android:layout_below="@id/drawer_header_np_text_view"
|
||||||
android:layout_alignLeft="@id/drawer_header_np_text_view"
|
android:layout_alignLeft="@id/drawer_header_np_text_view"
|
||||||
android:layout_alignStart="@id/drawer_header_np_text_view"
|
android:layout_alignStart="@id/drawer_header_np_text_view"
|
||||||
android:textSize="18dp"
|
android:textSize="18sp"
|
||||||
android:textColor="@color/drawer_header_font_color"
|
android:textColor="@color/drawer_header_font_color"
|
||||||
android:textStyle="italic"/>
|
android:textStyle="italic"/>
|
||||||
|
|
||||||
@ -66,6 +68,7 @@ android:focusable="true">
|
|||||||
android:paddingBottom="20dp"
|
android:paddingBottom="20dp"
|
||||||
android:paddingRight="20dp"
|
android:paddingRight="20dp"
|
||||||
android:src="@drawable/ic_arrow_down_white"
|
android:src="@drawable/ic_arrow_down_white"
|
||||||
android:paddingEnd="20dp" />
|
android:paddingEnd="20dp"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user