mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-11 01:40:59 +00:00
Merge branch 'dev' into LongTapInSubs
This commit is contained in:
commit
d107fe19f7
@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 27
|
targetSdkVersion 27
|
||||||
versionCode 66
|
versionCode 68
|
||||||
versionName "0.13.7"
|
versionName "0.14.1"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
@ -55,7 +55,7 @@ dependencies {
|
|||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:fef71aeccc37'
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:217d13b1028'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
testImplementation 'org.mockito:mockito-core:2.8.9'
|
||||||
|
@ -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()) {
|
||||||
|
case 1:
|
||||||
handleChoice(choices.get(0).key);
|
handleChoice(choices.get(0).key);
|
||||||
} else if (choices.size() == 0) {
|
break;
|
||||||
|
case 0:
|
||||||
handleChoice(showInfoKey);
|
handleChoice(showInfoKey);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
showDialog(choices);
|
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;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package org.schabi.newpipe.fragments;
|
package org.schabi.newpipe.fragments;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
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;
|
||||||
@ -12,7 +10,6 @@ import android.support.v4.app.FragmentPagerAdapter;
|
|||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
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.preference.PreferenceManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@ -23,42 +20,26 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
|
||||||
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
|
|
||||||
import org.schabi.newpipe.local.feed.FeedFragment;
|
|
||||||
import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
|
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
|
||||||
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.KioskTranslator;
|
import org.schabi.newpipe.settings.tabs.Tab;
|
||||||
|
import org.schabi.newpipe.settings.tabs.TabsManager;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
||||||
|
|
||||||
public int currentServiceId = -1;
|
|
||||||
private ViewPager viewPager;
|
private ViewPager viewPager;
|
||||||
private List<String> tabs = new ArrayList<>();
|
private SelectedTabsPagerAdapter pagerAdapter;
|
||||||
static PagerAdapter adapter;
|
private TabLayout tabLayout;
|
||||||
TabLayout tabLayout;
|
|
||||||
private SharedPreferences prefs;
|
|
||||||
private Bundle savedInstanceStateBundle;
|
|
||||||
|
|
||||||
private static final String TAB_NUMBER_BLANK = "0";
|
private List<Tab> tabsList = new ArrayList<>();
|
||||||
private static final String TAB_NUMBER_KIOSK = "1";
|
private TabsManager tabsManager;
|
||||||
private static final String TAB_NUMBER_SUBSCIRPTIONS = "2";
|
|
||||||
private static final String TAB_NUMBER_FEED = "3";
|
|
||||||
private static final String TAB_NUMBER_BOOKMARKS = "4";
|
|
||||||
private static final String TAB_NUMBER_HISTORY = "5";
|
|
||||||
private static final String TAB_NUMBER_CHANNEL = "6";
|
|
||||||
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener listener;
|
private boolean hasTabsChanged = false;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment's LifeCycle
|
// Fragment's LifeCycle
|
||||||
@ -66,23 +47,24 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
savedInstanceStateBundle = savedInstanceState;
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
listener = (prefs, key) -> {
|
|
||||||
if(key.equals("saveUsedTabs")) {
|
tabsManager = TabsManager.getManager(activity);
|
||||||
mainPageChanged();
|
tabsManager.setSavedTabsListener(() -> {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "TabsManager.SavedTabsChangeListener: onTabsChanged called, isResumed = " + isResumed());
|
||||||
}
|
}
|
||||||
};
|
if (isResumed()) {
|
||||||
|
updateTabs();
|
||||||
|
} else {
|
||||||
|
hasTabsChanged = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
currentServiceId = ServiceHelper.getSelectedServiceId(activity);
|
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
|
||||||
prefs.registerOnSharedPreferenceChangeListener(listener);
|
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_main, container, false);
|
return inflater.inflate(R.layout.fragment_main, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,110 +76,28 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
viewPager = rootView.findViewById(R.id.pager);
|
viewPager = rootView.findViewById(R.id.pager);
|
||||||
|
|
||||||
/* Nested fragment, use child fragment here to maintain backstack in view pager. */
|
/* Nested fragment, use child fragment here to maintain backstack in view pager. */
|
||||||
adapter = new PagerAdapter(getChildFragmentManager());
|
pagerAdapter = new SelectedTabsPagerAdapter(getChildFragmentManager());
|
||||||
viewPager.setAdapter(adapter);
|
viewPager.setAdapter(pagerAdapter);
|
||||||
|
|
||||||
tabLayout.setupWithViewPager(viewPager);
|
tabLayout.setupWithViewPager(viewPager);
|
||||||
|
tabLayout.addOnTabSelectedListener(this);
|
||||||
mainPageChanged();
|
updateTabs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
public void mainPageChanged() {
|
if (hasTabsChanged) {
|
||||||
getTabOrder();
|
hasTabsChanged = false;
|
||||||
adapter.notifyDataSetChanged();
|
updateTabs();
|
||||||
viewPager.setOffscreenPageLimit(adapter.getCount());
|
|
||||||
setIcons();
|
|
||||||
setFirstTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setFirstTitle() {
|
|
||||||
if((tabs.size() > 0)
|
|
||||||
&& activity != null) {
|
|
||||||
String tabInformation = tabs.get(0);
|
|
||||||
if (tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
|
||||||
String kiosk[] = tabInformation.split("\t");
|
|
||||||
if (kiosk.length == 3) {
|
|
||||||
setTitle(kiosk[1]);
|
|
||||||
}
|
|
||||||
} else if (tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
|
||||||
|
|
||||||
String channelInfo[] = tabInformation.split("\t");
|
|
||||||
if(channelInfo.length==4) {
|
|
||||||
setTitle(channelInfo[2]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (tabInformation) {
|
|
||||||
case TAB_NUMBER_BLANK:
|
|
||||||
setTitle(getString(R.string.app_name));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
|
||||||
setTitle(getString(R.string.tab_subscriptions));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_FEED:
|
|
||||||
setTitle(getString(R.string.fragment_whats_new));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_BOOKMARKS:
|
|
||||||
setTitle(getString(R.string.tab_bookmarks));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_HISTORY:
|
|
||||||
setTitle(getString(R.string.title_activity_history));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
}
|
public void onDestroy() {
|
||||||
}
|
super.onDestroy();
|
||||||
|
tabsManager.unsetSavedTabsListener();
|
||||||
private void setIcons() {
|
|
||||||
for (int i = 0; i < tabs.size(); i++) {
|
|
||||||
String tabInformation = tabs.get(i);
|
|
||||||
|
|
||||||
TabLayout.Tab tabToSet = tabLayout.getTabAt(i);
|
|
||||||
Context c = getContext();
|
|
||||||
|
|
||||||
if (tabToSet != null && c != null) {
|
|
||||||
|
|
||||||
if (tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
|
||||||
String kiosk[] = tabInformation.split("\t");
|
|
||||||
if (kiosk.length == 3) {
|
|
||||||
tabToSet.setIcon(KioskTranslator.getKioskIcons(kiosk[1], getContext()));
|
|
||||||
}
|
|
||||||
} else if (tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_channel));
|
|
||||||
} else {
|
|
||||||
switch (tabInformation) {
|
|
||||||
case TAB_NUMBER_BLANK:
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_hot));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_channel));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_FEED:
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.rss));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_BOOKMARKS:
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.ic_bookmark));
|
|
||||||
break;
|
|
||||||
case TAB_NUMBER_HISTORY:
|
|
||||||
tabToSet.setIcon(ThemeHelper.resolveResourceIdFromAttr(getContext(), R.attr.history));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void getTabOrder() {
|
|
||||||
tabs.clear();
|
|
||||||
|
|
||||||
String save = prefs.getString("saveUsedTabs", "1\tTrending\t0\n2\n4\n");
|
|
||||||
String tabsArray[] = save.trim().split("\n");
|
|
||||||
|
|
||||||
Collections.addAll(tabs, tabsArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
@ -237,9 +137,33 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
// Tabs
|
// Tabs
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public void updateTabs() {
|
||||||
|
tabsList.clear();
|
||||||
|
tabsList.addAll(tabsManager.getTabs());
|
||||||
|
pagerAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
viewPager.setOffscreenPageLimit(pagerAdapter.getCount());
|
||||||
|
updateTabsIcon();
|
||||||
|
updateCurrentTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTabsIcon() {
|
||||||
|
for (int i = 0; i < tabsList.size(); i++) {
|
||||||
|
final TabLayout.Tab tabToSet = tabLayout.getTabAt(i);
|
||||||
|
if (tabToSet != null) {
|
||||||
|
tabToSet.setIcon(tabsList.get(i).getTabIconRes(activity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCurrentTitle() {
|
||||||
|
setTitle(tabsList.get(viewPager.getCurrentItem()).getTabName(requireContext()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabSelected(TabLayout.Tab tab) {
|
public void onTabSelected(TabLayout.Tab selectedTab) {
|
||||||
viewPager.setCurrentItem(tab.getPosition());
|
if (DEBUG) Log.d(TAG, "onTabSelected() called with: selectedTab = [" + selectedTab + "]");
|
||||||
|
updateCurrentTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -248,68 +172,40 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabReselected(TabLayout.Tab tab) {
|
public void onTabReselected(TabLayout.Tab tab) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onTabReselected() called with: tab = [" + tab + "]");
|
||||||
|
updateCurrentTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PagerAdapter extends FragmentPagerAdapter {
|
private class SelectedTabsPagerAdapter extends FragmentPagerAdapter {
|
||||||
PagerAdapter(FragmentManager fm) {
|
private SelectedTabsPagerAdapter(FragmentManager fragmentManager) {
|
||||||
super(fm);
|
super(fragmentManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Fragment getItem(int position) {
|
public Fragment getItem(int position) {
|
||||||
String tabInformation = tabs.get(position);
|
final Tab tab = tabsList.get(position);
|
||||||
|
|
||||||
if(tabInformation.startsWith(TAB_NUMBER_KIOSK + "\t")) {
|
Throwable throwable = null;
|
||||||
String kiosk[] = tabInformation.split("\t");
|
Fragment fragment = null;
|
||||||
if(kiosk.length==3) {
|
|
||||||
KioskFragment fragment = null;
|
|
||||||
try {
|
try {
|
||||||
fragment = KioskFragment.getInstance(Integer.parseInt(kiosk[2]), kiosk[1]);
|
fragment = tab.getFragment();
|
||||||
fragment.useAsFrontPage(true);
|
} catch (ExtractionException e) {
|
||||||
return fragment;
|
throwable = e;
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportError(activity, e,
|
|
||||||
activity.getClass(),
|
|
||||||
null,
|
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
|
||||||
"none", "", R.string.app_ui_crash));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if(tabInformation.startsWith(TAB_NUMBER_CHANNEL + "\t")) {
|
|
||||||
String channelInfo[] = tabInformation.split("\t");
|
|
||||||
if(channelInfo.length==4) {
|
|
||||||
ChannelFragment fragment = ChannelFragment.getInstance(Integer.parseInt(channelInfo[3]), channelInfo[1], channelInfo[2]);
|
|
||||||
fragment.useAsFrontPage(true);
|
|
||||||
return fragment;
|
|
||||||
} else {
|
|
||||||
return new BlankFragment();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (tabInformation) {
|
|
||||||
case TAB_NUMBER_BLANK:
|
|
||||||
return new BlankFragment();
|
|
||||||
case TAB_NUMBER_SUBSCIRPTIONS:
|
|
||||||
SubscriptionFragment sFragment = new SubscriptionFragment();
|
|
||||||
sFragment.useAsFrontPage(true);
|
|
||||||
return sFragment;
|
|
||||||
case TAB_NUMBER_FEED:
|
|
||||||
FeedFragment fFragment = new FeedFragment();
|
|
||||||
fFragment.useAsFrontPage(true);
|
|
||||||
return fFragment;
|
|
||||||
case TAB_NUMBER_BOOKMARKS:
|
|
||||||
BookmarkFragment bFragment = new BookmarkFragment();
|
|
||||||
bFragment.useAsFrontPage(true);
|
|
||||||
return bFragment;
|
|
||||||
case TAB_NUMBER_HISTORY:
|
|
||||||
StatisticsPlaylistFragment cFragment = new StatisticsPlaylistFragment();
|
|
||||||
cFragment.useAsFrontPage(true);
|
|
||||||
return cFragment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (throwable != null) {
|
||||||
|
ErrorActivity.reportError(activity, throwable, activity.getClass(), null,
|
||||||
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash));
|
||||||
return new BlankFragment();
|
return new BlankFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fragment instanceof BaseFragment) {
|
||||||
|
((BaseFragment) fragment).useAsFrontPage(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemPosition(Object object) {
|
public int getItemPosition(Object object) {
|
||||||
// Causes adapter to reload all Fragments when
|
// Causes adapter to reload all Fragments when
|
||||||
@ -319,12 +215,12 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return tabs.size();
|
return tabsList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||||
getFragmentManager()
|
getChildFragmentManager()
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.remove((Fragment) object)
|
.remove((Fragment) object)
|
||||||
.commitNowAllowingStateLoss();
|
.commitNowAllowingStateLoss();
|
||||||
|
@ -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;
|
||||||
|
@ -760,7 +760,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();
|
||||||
|
@ -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>
|
||||||
|
@ -33,15 +33,14 @@ 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.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
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.dialog.PlaylistAppendDialog;
|
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||||
|
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
||||||
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;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionService;
|
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
@ -69,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;
|
||||||
|
|
||||||
@ -91,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);
|
||||||
@ -106,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) {
|
||||||
@ -422,10 +418,12 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
|||||||
imageLoader.displayImage(result.getAvatarUrl(), headerAvatarView,
|
imageLoader.displayImage(result.getAvatarUrl(), headerAvatarView,
|
||||||
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
|
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
|
||||||
|
|
||||||
if (result.getSubscriberCount() != -1) {
|
|
||||||
headerSubscribersTextView.setText(Localization.localizeSubscribersCount(activity, result.getSubscriberCount()));
|
|
||||||
headerSubscribersTextView.setVisibility(View.VISIBLE);
|
headerSubscribersTextView.setVisibility(View.VISIBLE);
|
||||||
} else headerSubscribersTextView.setVisibility(View.GONE);
|
if (result.getSubscriberCount() >= 0) {
|
||||||
|
headerSubscribersTextView.setText(Localization.localizeSubscribersCount(activity, result.getSubscriberCount()));
|
||||||
|
} else {
|
||||||
|
headerSubscribersTextView.setText(R.string.subscribers_count_not_available);
|
||||||
|
}
|
||||||
|
|
||||||
if (menuRssButton != null) menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl()));
|
if (menuRssButton != null) menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl()));
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -58,7 +58,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,
|
||||||
|
@ -19,7 +19,6 @@ import android.support.annotation.Nullable;
|
|||||||
import android.support.v4.app.FragmentManager;
|
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.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;
|
||||||
@ -43,6 +42,7 @@ 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.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.ErrorActivity;
|
||||||
@ -84,7 +84,6 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
protected Parcelable itemsListState;
|
protected Parcelable itemsListState;
|
||||||
private InfoListAdapter infoListAdapter;
|
private InfoListAdapter infoListAdapter;
|
||||||
|
|
||||||
private View headerRootLayout;
|
|
||||||
private View whatsNewItemListHeader;
|
private View whatsNewItemListHeader;
|
||||||
private View importExportListHeader;
|
private View importExportListHeader;
|
||||||
|
|
||||||
@ -294,6 +293,7 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
|||||||
itemsList = rootView.findViewById(R.id.items_list);
|
itemsList = rootView.findViewById(R.id.items_list);
|
||||||
itemsList.setLayoutManager(new LinearLayoutManager(activity));
|
itemsList.setLayoutManager(new LinearLayoutManager(activity));
|
||||||
|
|
||||||
|
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);
|
||||||
|
@ -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) {
|
||||||
|
case CHANNEL_URL_MODE:
|
||||||
flowable = importFromChannelUrl();
|
flowable = importFromChannelUrl();
|
||||||
} else if (currentMode == INPUT_STREAM_MODE) {
|
break;
|
||||||
|
case INPUT_STREAM_MODE:
|
||||||
flowable = importFromInputStream();
|
flowable = importFromInputStream();
|
||||||
} else if (currentMode == PREVIOUS_EXPORT_MODE) {
|
break;
|
||||||
|
case PREVIOUS_EXPORT_MODE:
|
||||||
flowable = importFromPreviousExport();
|
flowable = importFromPreviousExport();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flowable == null) {
|
if (flowable == null) {
|
||||||
|
@ -70,7 +70,6 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
|
|||||||
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.SerializedCache;
|
import org.schabi.newpipe.util.SerializedCache;
|
||||||
|
|
||||||
@ -88,7 +87,6 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL
|
|||||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION;
|
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION;
|
||||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK;
|
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK;
|
||||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT;
|
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT;
|
||||||
import static org.schabi.newpipe.report.UserAction.PLAY_STREAM;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for the players, joining the common properties
|
* Base for the players, joining the common properties
|
||||||
@ -175,7 +173,6 @@ public abstract class BasePlayer implements
|
|||||||
};
|
};
|
||||||
this.intentFilter = new IntentFilter();
|
this.intentFilter = new IntentFilter();
|
||||||
setupBroadcastReceiver(intentFilter);
|
setupBroadcastReceiver(intentFilter);
|
||||||
context.registerReceiver(broadcastReceiver, intentFilter);
|
|
||||||
|
|
||||||
this.recordManager = new HistoryRecordManager(context);
|
this.recordManager = new HistoryRecordManager(context);
|
||||||
|
|
||||||
@ -212,6 +209,8 @@ public abstract class BasePlayer implements
|
|||||||
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
||||||
mediaSessionManager = new MediaSessionManager(context, simpleExoPlayer,
|
mediaSessionManager = new MediaSessionManager(context, simpleExoPlayer,
|
||||||
new BasePlayerMediaSession(this));
|
new BasePlayerMediaSession(this));
|
||||||
|
|
||||||
|
registerBroadcastReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initListeners() {}
|
public void initListeners() {}
|
||||||
@ -231,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);
|
||||||
}
|
}
|
||||||
@ -362,14 +362,17 @@ public abstract class BasePlayer implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterBroadcastReceiver() {
|
protected void registerBroadcastReceiver() {
|
||||||
|
// Try to unregister current first
|
||||||
|
unregisterBroadcastReceiver();
|
||||||
|
context.registerReceiver(broadcastReceiver, intentFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unregisterBroadcastReceiver() {
|
||||||
try {
|
try {
|
||||||
context.unregisterReceiver(broadcastReceiver);
|
context.unregisterReceiver(broadcastReceiver);
|
||||||
} catch (final IllegalArgumentException unregisteredException) {
|
} catch (final IllegalArgumentException unregisteredException) {
|
||||||
ErrorActivity.reportError(context, unregisteredException, null, null,
|
Log.w(TAG, "Broadcast receiver already unregistered (" + unregisteredException.getMessage() + ")");
|
||||||
ErrorActivity.ErrorInfo.make(PLAY_STREAM,
|
|
||||||
"none",
|
|
||||||
"play stream", R.string.general_error));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -460,7 +464,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
public void initListeners() {
|
public void initListeners() {
|
||||||
super.initListeners();
|
super.initListeners();
|
||||||
|
|
||||||
MySimpleOnGestureListener listener = new MySimpleOnGestureListener();
|
PlayerGestureListener listener = new PlayerGestureListener();
|
||||||
gestureDetector = new GestureDetector(context, listener);
|
gestureDetector = new GestureDetector(context, listener);
|
||||||
gestureDetector.setIsLongpressEnabled(false);
|
gestureDetector.setIsLongpressEnabled(false);
|
||||||
getRootView().setOnTouchListener(listener);
|
getRootView().setOnTouchListener(listener);
|
||||||
@ -489,6 +493,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
|
|
||||||
volumeProgressBar.setMax(maxGestureLength);
|
volumeProgressBar.setMax(maxGestureLength);
|
||||||
brightnessProgressBar.setMax(maxGestureLength);
|
brightnessProgressBar.setMax(maxGestureLength);
|
||||||
|
|
||||||
|
setInitialGestureValues();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -703,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
|
||||||
@ -799,6 +818,13 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void setInitialGestureValues() {
|
||||||
|
if (getAudioReactor() != null) {
|
||||||
|
final float currentVolumeNormalized = (float) getAudioReactor().getVolume() / getAudioReactor().getMaxVolume();
|
||||||
|
volumeProgressBar.setProgress((int) (volumeProgressBar.getMax() * currentVolumeNormalized));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showControlsThenHide() {
|
public void showControlsThenHide() {
|
||||||
if (queueVisible) return;
|
if (queueVisible) return;
|
||||||
@ -939,7 +965,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
private class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||||
private boolean isMoving;
|
private boolean isMoving;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -978,31 +1004,30 @@ public final class MainVideoPlayer extends AppCompatActivity
|
|||||||
return super.onDown(e);
|
return super.onDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
|
private static final int MOVEMENT_THRESHOLD = 40;
|
||||||
|
|
||||||
|
private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
|
||||||
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
private final int maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||||
|
|
||||||
private final int MOVEMENT_THRESHOLD = 40;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
|
||||||
if (!isPlayerGestureEnabled) return false;
|
if (!isPlayerGestureEnabled) return false;
|
||||||
|
|
||||||
//noinspection PointlessBooleanExpression
|
//noinspection PointlessBooleanExpression
|
||||||
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
||||||
", e1.getRaw = [" + e1.getRawX() + ", " + e1.getRawY() + "]" +
|
", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" +
|
||||||
", e2.getRaw = [" + e2.getRawX() + ", " + e2.getRawY() + "]" +
|
", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" +
|
||||||
", distanceXy = [" + distanceX + ", " + distanceY + "]");
|
", distanceXy = [" + distanceX + ", " + distanceY + "]");
|
||||||
|
|
||||||
if (!isMoving && (
|
final boolean insideThreshold = Math.abs(movingEvent.getY() - initialEvent.getY()) <= MOVEMENT_THRESHOLD;
|
||||||
Math.abs(e2.getY() - e1.getY()) <= MOVEMENT_THRESHOLD
|
if (!isMoving && (insideThreshold || Math.abs(distanceX) > Math.abs(distanceY))
|
||||||
|| Math.abs(distanceX) > Math.abs(distanceY)
|
|| playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
|
||||||
) || playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
isMoving = true;
|
isMoving = true;
|
||||||
|
|
||||||
if (e1.getX() > playerImpl.getRootView().getWidth() / 2) {
|
if (initialEvent.getX() > playerImpl.getRootView().getWidth() / 2) {
|
||||||
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
|
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
|
||||||
float currentProgressPercent =
|
float currentProgressPercent =
|
||||||
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
||||||
|
@ -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));
|
||||||
|
@ -203,7 +203,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,8 +318,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
package org.schabi.newpipe.settings;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
|
||||||
|
|
||||||
public class AddTabsDialog {
|
|
||||||
private final AlertDialog dialog;
|
|
||||||
|
|
||||||
public AddTabsDialog(@NonNull final Context context,
|
|
||||||
@NonNull final String title,
|
|
||||||
@NonNull final String[] commands,
|
|
||||||
@NonNull final DialogInterface.OnClickListener actions) {
|
|
||||||
|
|
||||||
final View bannerView = View.inflate(context, R.layout.dialog_title, null);
|
|
||||||
bannerView.setSelected(true);
|
|
||||||
|
|
||||||
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
|
|
||||||
titleView.setText(title);
|
|
||||||
|
|
||||||
TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
|
|
||||||
detailsView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
dialog = new AlertDialog.Builder(context)
|
|
||||||
.setCustomTitle(bannerView)
|
|
||||||
.setItems(commands, actions)
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void show() {
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -1,291 +0,0 @@
|
|||||||
package org.schabi.newpipe.settings;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.CardView;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ChoseTabsFragment extends Fragment {
|
|
||||||
|
|
||||||
public ChoseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
|
|
||||||
|
|
||||||
RecyclerView selectedTabsView;
|
|
||||||
|
|
||||||
List<String> selectedTabs = new ArrayList<>();
|
|
||||||
private String saveString;
|
|
||||||
public String[] availableTabs = new String[7];
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
((AppCompatActivity)getContext()).getSupportActionBar().setTitle(R.string.main_page_content);
|
|
||||||
return inflater.inflate(R.layout.fragment_chose_tabs, container, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View rootView, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(rootView, savedInstanceState);
|
|
||||||
|
|
||||||
tabNames();
|
|
||||||
initUsedTabs();
|
|
||||||
initButton(rootView);
|
|
||||||
|
|
||||||
selectedTabsView = rootView.findViewById(R.id.usedTabs);
|
|
||||||
selectedTabsView.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
selectedTabsAdapter = new ChoseTabsFragment.SelectedTabsAdapter();
|
|
||||||
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
|
||||||
itemTouchHelper.attachToRecyclerView(selectedTabsView);
|
|
||||||
selectedTabsAdapter.setOnItemSelectedListener(itemTouchHelper);
|
|
||||||
|
|
||||||
selectedTabsView.setAdapter(selectedTabsAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveChanges() {
|
|
||||||
StringBuilder save = new StringBuilder();
|
|
||||||
if(selectedTabs.size()==0) {
|
|
||||||
save = new StringBuilder("0");
|
|
||||||
} else {
|
|
||||||
for(String s: selectedTabs) {
|
|
||||||
save.append(s);
|
|
||||||
save.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveString = save.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
saveChanges();
|
|
||||||
SharedPreferences sharedPreferences = android.preference.PreferenceManager.getDefaultSharedPreferences(getContext());
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.putString("saveUsedTabs", saveString);
|
|
||||||
editor.commit();
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initUsedTabs() {
|
|
||||||
String save = android.preference.PreferenceManager.getDefaultSharedPreferences(getContext()).getString("saveUsedTabs", "1\tTrending\t0\n2\n4\n");
|
|
||||||
String tabs[] = save.trim().split("\n");
|
|
||||||
selectedTabs.addAll(Arrays.asList(tabs));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tabNames() {
|
|
||||||
availableTabs[0] = getString(R.string.blank_page_summary);
|
|
||||||
availableTabs[1] = getString(R.string.kiosk_page_summary);
|
|
||||||
availableTabs[2] = getString(R.string.subscription_page_summary);
|
|
||||||
availableTabs[3] = getString(R.string.feed_page_summary);
|
|
||||||
availableTabs[4] = getString(R.string.tab_bookmarks);
|
|
||||||
availableTabs[5] = getString(R.string.title_activity_history);
|
|
||||||
availableTabs[6] = getString(R.string.channel_page_summary);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initButton(View rootView) {
|
|
||||||
FloatingActionButton fab = rootView.findViewById(R.id.floatingActionButton);
|
|
||||||
fab.setImageResource(ThemeHelper.getIconByAttr(R.attr.ic_add, getContext()));
|
|
||||||
fab.setOnClickListener(v -> {
|
|
||||||
Dialog.OnClickListener onClickListener = (dialog, which) -> addTab(which);
|
|
||||||
|
|
||||||
new AddTabsDialog(getContext(),
|
|
||||||
getString(R.string.tab_chose),
|
|
||||||
availableTabs,
|
|
||||||
onClickListener)
|
|
||||||
.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
TypedValue typedValue = new TypedValue();
|
|
||||||
getActivity().getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
|
|
||||||
int color = typedValue.data;
|
|
||||||
fab.setBackgroundTintList(ColorStateList.valueOf(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void addTab(int position) {
|
|
||||||
if(position==6) {
|
|
||||||
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
|
|
||||||
selectChannelFragment.setOnSelectedLisener((String url, String name, int service) -> {
|
|
||||||
selectedTabs.add(position+"\t"+url+"\t"+name+"\t"+service);
|
|
||||||
selectedTabsAdapter.notifyDataSetChanged();
|
|
||||||
saveChanges();
|
|
||||||
});
|
|
||||||
selectChannelFragment.show(getFragmentManager(), "select_channel");
|
|
||||||
} else if(position==1) {
|
|
||||||
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
|
|
||||||
selectKioskFragment.setOnSelectedLisener((String kioskId, int service_id) -> {
|
|
||||||
selectedTabs.add(position+"\t"+kioskId+"\t"+service_id);
|
|
||||||
selectedTabsAdapter.notifyDataSetChanged();
|
|
||||||
saveChanges();
|
|
||||||
});
|
|
||||||
selectKioskFragment.show(getFragmentManager(), "select_kiosk");
|
|
||||||
} else {
|
|
||||||
selectedTabs.add(String.valueOf(position));
|
|
||||||
selectedTabsAdapter.notifyDataSetChanged();
|
|
||||||
saveChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SelectedTabsAdapter extends RecyclerView.Adapter<ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder>{
|
|
||||||
private ItemTouchHelper itemTouchHelper;
|
|
||||||
|
|
||||||
public void setOnItemSelectedListener(ItemTouchHelper mItemTouchHelper) {
|
|
||||||
itemTouchHelper = mItemTouchHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void swapItems(int fromPosition, int toPosition) {
|
|
||||||
String temp = selectedTabs.get(fromPosition);
|
|
||||||
selectedTabs.set(fromPosition, selectedTabs.get(toPosition));
|
|
||||||
selectedTabs.set(toPosition, temp);
|
|
||||||
notifyItemMoved(fromPosition, toPosition);
|
|
||||||
saveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
|
||||||
View view = inflater.inflate(R.layout.viewholder_chose_tabs, parent, false);
|
|
||||||
return new ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ChoseTabsFragment.SelectedTabsAdapter.TabViewHolder holder, int position) {
|
|
||||||
holder.bind(position, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return selectedTabs.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
class TabViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
TextView text;
|
|
||||||
View view;
|
|
||||||
CardView cardView;
|
|
||||||
ImageView handle;
|
|
||||||
|
|
||||||
public TabViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
|
|
||||||
text = itemView.findViewById(R.id.tabName);
|
|
||||||
cardView = itemView.findViewById(R.id.layoutCard);
|
|
||||||
handle = itemView.findViewById(R.id.handle);
|
|
||||||
view = itemView;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bind(int position, TabViewHolder holder) {
|
|
||||||
handle.setImageResource(ThemeHelper.getIconByAttr(R.attr.drag_handle, getContext()));
|
|
||||||
handle.setOnTouchListener(getOnTouchListener(holder));
|
|
||||||
|
|
||||||
view.setOnLongClickListener(getOnLongClickListener(holder));
|
|
||||||
|
|
||||||
if(selectedTabs.get(position).startsWith("6\t")) {
|
|
||||||
String channelInfo[] = selectedTabs.get(position).split("\t");
|
|
||||||
String channelName = "";
|
|
||||||
if (channelInfo.length == 4) channelName = channelInfo[2];
|
|
||||||
String textToSet = availableTabs[6] + ": " + channelName;
|
|
||||||
text.setText(textToSet);
|
|
||||||
} else if(selectedTabs.get(position).startsWith("1\t")) {
|
|
||||||
String kioskInfo[] = selectedTabs.get(position).split("\t");
|
|
||||||
String kioskName = "";
|
|
||||||
if (kioskInfo.length == 3) kioskName = kioskInfo[1];
|
|
||||||
String textToSet = availableTabs[1] + ": " + kioskName;
|
|
||||||
text.setText(textToSet);
|
|
||||||
} else {
|
|
||||||
text.setText(availableTabs[Integer.parseInt(selectedTabs.get(position))]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private View.OnTouchListener getOnTouchListener(final RecyclerView.ViewHolder item) {
|
|
||||||
return (view, motionEvent) -> {
|
|
||||||
view.performClick();
|
|
||||||
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
||||||
if(itemTouchHelper != null) itemTouchHelper.startDrag(item);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private View.OnLongClickListener getOnLongClickListener(TabViewHolder holder) {
|
|
||||||
return (view) -> {
|
|
||||||
if(itemTouchHelper != null) itemTouchHelper.startSwipe(holder);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
|
||||||
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
|
||||||
ItemTouchHelper.START | ItemTouchHelper.END) {
|
|
||||||
@Override
|
|
||||||
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,
|
|
||||||
int viewSizeOutOfBounds, int totalSize,
|
|
||||||
long msSinceStartScroll) {
|
|
||||||
final int standardSpeed = super.interpolateOutOfBoundsScroll(recyclerView, viewSize,
|
|
||||||
viewSizeOutOfBounds, totalSize, msSinceStartScroll);
|
|
||||||
final int minimumAbsVelocity = Math.max(12,
|
|
||||||
Math.abs(standardSpeed));
|
|
||||||
return minimumAbsVelocity * (int) Math.signum(viewSizeOutOfBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source,
|
|
||||||
RecyclerView.ViewHolder target) {
|
|
||||||
if (source.getItemViewType() != target.getItemViewType() ||
|
|
||||||
selectedTabsAdapter == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int sourceIndex = source.getAdapterPosition();
|
|
||||||
final int targetIndex = target.getAdapterPosition();
|
|
||||||
selectedTabsAdapter.swapItems(sourceIndex, targetIndex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLongPressDragEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isItemViewSwipeEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
|
|
||||||
int position = viewHolder.getAdapterPosition();
|
|
||||||
selectedTabs.remove(position);
|
|
||||||
selectedTabsAdapter.notifyItemRemoved(position);
|
|
||||||
saveChanges();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
@ -66,7 +64,7 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public interface OnSelectedLisener {
|
public interface OnSelectedLisener {
|
||||||
void onChannelSelected(String url, String name, int service);
|
void onChannelSelected(int serviceId, String url, String name);
|
||||||
}
|
}
|
||||||
OnSelectedLisener onSelectedLisener = null;
|
OnSelectedLisener onSelectedLisener = null;
|
||||||
public void setOnSelectedLisener(OnSelectedLisener listener) {
|
public void setOnSelectedLisener(OnSelectedLisener listener) {
|
||||||
@ -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())
|
||||||
@ -126,7 +124,7 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
private void clickedItem(int position) {
|
private void clickedItem(int position) {
|
||||||
if(onSelectedLisener != null) {
|
if(onSelectedLisener != null) {
|
||||||
SubscriptionEntity entry = subscriptions.get(position);
|
SubscriptionEntity entry = subscriptions.get(position);
|
||||||
onSelectedLisener.onChannelSelected(entry.getUrl(), entry.getName(), entry.getServiceId());
|
onSelectedLisener.onChannelSelected(entry.getServiceId(), entry.getUrl(), entry.getName());
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public interface OnSelectedLisener {
|
public interface OnSelectedLisener {
|
||||||
void onKioskSelected(String kioskId, int service_id);
|
void onKioskSelected(int serviceId, String kioskId, String kioskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnSelectedLisener onSelectedLisener = null;
|
OnSelectedLisener onSelectedLisener = null;
|
||||||
@ -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();
|
||||||
@ -101,7 +101,7 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
|
|
||||||
private void clickedItem(SelectKioskAdapter.Entry entry) {
|
private void clickedItem(SelectKioskAdapter.Entry entry) {
|
||||||
if(onSelectedLisener != null) {
|
if(onSelectedLisener != null) {
|
||||||
onSelectedLisener.onKioskSelected(entry.kioskId, entry.serviceId);
|
onSelectedLisener.onKioskSelected(entry.serviceId, entry.kioskId, entry.kioskName);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,8 @@ public class SettingsActivity extends AppCompatActivity implements BasePreferenc
|
|||||||
finish();
|
finish();
|
||||||
} else getSupportFragmentManager().popBackStack();
|
} else getSupportFragmentManager().popBackStack();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package org.schabi.newpipe.settings.tabs;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.widget.AppCompatImageView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
public class AddTabDialog {
|
||||||
|
private final AlertDialog dialog;
|
||||||
|
|
||||||
|
AddTabDialog(@NonNull final Context context,
|
||||||
|
@NonNull final ChooseTabListItem[] items,
|
||||||
|
@NonNull final DialogInterface.OnClickListener actions) {
|
||||||
|
|
||||||
|
dialog = new AlertDialog.Builder(context)
|
||||||
|
.setTitle(context.getString(R.string.tab_choose))
|
||||||
|
.setAdapter(new DialogListAdapter(context, items), actions)
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ChooseTabListItem {
|
||||||
|
final int tabId;
|
||||||
|
final String itemName;
|
||||||
|
@DrawableRes final int itemIcon;
|
||||||
|
|
||||||
|
ChooseTabListItem(Context context, Tab tab) {
|
||||||
|
this(tab.getTabId(), tab.getTabName(context), tab.getTabIconRes(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
ChooseTabListItem(int tabId, String itemName, @DrawableRes int itemIcon) {
|
||||||
|
this.tabId = tabId;
|
||||||
|
this.itemName = itemName;
|
||||||
|
this.itemIcon = itemIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DialogListAdapter extends BaseAdapter {
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
private final ChooseTabListItem[] items;
|
||||||
|
|
||||||
|
@DrawableRes private final int fallbackIcon;
|
||||||
|
|
||||||
|
private DialogListAdapter(Context context, ChooseTabListItem[] items) {
|
||||||
|
this.inflater = LayoutInflater.from(context);
|
||||||
|
this.items = items;
|
||||||
|
this.fallbackIcon = ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_hot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return items.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChooseTabListItem getItem(int position) {
|
||||||
|
return items[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return getItem(position).tabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = inflater.inflate(R.layout.list_choose_tabs_dialog, parent, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ChooseTabListItem item = getItem(position);
|
||||||
|
final AppCompatImageView tabIconView = convertView.findViewById(R.id.tabIcon);
|
||||||
|
final TextView tabNameView = convertView.findViewById(R.id.tabName);
|
||||||
|
|
||||||
|
tabIconView.setImageResource(item.itemIcon > 0 ? item.itemIcon : fallbackIcon);
|
||||||
|
tabNameView.setText(item.itemName);
|
||||||
|
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,386 @@
|
|||||||
|
package org.schabi.newpipe.settings.tabs;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.content.res.AppCompatResources;
|
||||||
|
import android.support.v7.widget.AppCompatImageView;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.report.UserAction;
|
||||||
|
import org.schabi.newpipe.settings.SelectChannelFragment;
|
||||||
|
import org.schabi.newpipe.settings.SelectKioskFragment;
|
||||||
|
import org.schabi.newpipe.settings.tabs.AddTabDialog.ChooseTabListItem;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.settings.tabs.Tab.typeFrom;
|
||||||
|
|
||||||
|
public class ChooseTabsFragment extends Fragment {
|
||||||
|
|
||||||
|
private TabsManager tabsManager;
|
||||||
|
private List<Tab> tabList = new ArrayList<>();
|
||||||
|
public ChooseTabsFragment.SelectedTabsAdapter selectedTabsAdapter;
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lifecycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
tabsManager = TabsManager.getManager(requireContext());
|
||||||
|
updateTabList();
|
||||||
|
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.fragment_choose_tabs, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View rootView, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(rootView, savedInstanceState);
|
||||||
|
|
||||||
|
initButton(rootView);
|
||||||
|
|
||||||
|
RecyclerView listSelectedTabs = rootView.findViewById(R.id.selectedTabs);
|
||||||
|
listSelectedTabs.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||||
|
|
||||||
|
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
||||||
|
itemTouchHelper.attachToRecyclerView(listSelectedTabs);
|
||||||
|
|
||||||
|
selectedTabsAdapter = new SelectedTabsAdapter(requireContext(), itemTouchHelper);
|
||||||
|
listSelectedTabs.setAdapter(selectedTabsAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
updateTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
saveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Menu
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private final int MENU_ITEM_RESTORE_ID = 123456;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
|
final MenuItem restoreItem = menu.add(Menu.NONE, MENU_ITEM_RESTORE_ID, Menu.NONE, R.string.restore_defaults);
|
||||||
|
restoreItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||||
|
|
||||||
|
final int restoreIcon = ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_restore_defaults);
|
||||||
|
restoreItem.setIcon(AppCompatResources.getDrawable(requireContext(), restoreIcon));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == MENU_ITEM_RESTORE_ID) {
|
||||||
|
restoreDefaults();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void updateTabList() {
|
||||||
|
tabList.clear();
|
||||||
|
tabList.addAll(tabsManager.getTabs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTitle() {
|
||||||
|
if (getActivity() instanceof AppCompatActivity) {
|
||||||
|
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||||
|
if (actionBar != null) actionBar.setTitle(R.string.main_page_content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveChanges() {
|
||||||
|
tabsManager.saveTabs(tabList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreDefaults() {
|
||||||
|
new AlertDialog.Builder(requireContext(), ThemeHelper.getDialogTheme(requireContext()))
|
||||||
|
.setTitle(R.string.restore_defaults)
|
||||||
|
.setMessage(R.string.restore_defaults_confirmation)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
|
tabsManager.resetTabs();
|
||||||
|
updateTabList();
|
||||||
|
selectedTabsAdapter.notifyDataSetChanged();
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initButton(View rootView) {
|
||||||
|
final FloatingActionButton fab = rootView.findViewById(R.id.addTabsButton);
|
||||||
|
fab.setOnClickListener(v -> {
|
||||||
|
final ChooseTabListItem[] availableTabs = getAvailableTabs(requireContext());
|
||||||
|
|
||||||
|
if (availableTabs.length == 0) {
|
||||||
|
//Toast.makeText(requireContext(), "No available tabs", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog.OnClickListener actionListener = (dialog, which) -> {
|
||||||
|
final ChooseTabListItem selected = availableTabs[which];
|
||||||
|
addTab(selected.tabId);
|
||||||
|
};
|
||||||
|
|
||||||
|
new AddTabDialog(requireContext(), availableTabs, actionListener)
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTab(final Tab tab) {
|
||||||
|
tabList.add(tab);
|
||||||
|
selectedTabsAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTab(int tabId) {
|
||||||
|
final Tab.Type type = typeFrom(tabId);
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
ErrorActivity.reportError(requireContext(), new IllegalStateException("Tab id not found: " + tabId), null, null,
|
||||||
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none", "Choosing tabs on settings", 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case KIOSK: {
|
||||||
|
SelectKioskFragment selectFragment = new SelectKioskFragment();
|
||||||
|
selectFragment.setOnSelectedLisener((serviceId, kioskId, kioskName) ->
|
||||||
|
addTab(new Tab.KioskTab(serviceId, kioskId)));
|
||||||
|
selectFragment.show(requireFragmentManager(), "select_kiosk");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case CHANNEL: {
|
||||||
|
SelectChannelFragment selectFragment = new SelectChannelFragment();
|
||||||
|
selectFragment.setOnSelectedLisener((serviceId, url, name) ->
|
||||||
|
addTab(new Tab.ChannelTab(serviceId, url, name)));
|
||||||
|
selectFragment.show(requireFragmentManager(), "select_channel");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
addTab(type.getTab());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChooseTabListItem[] getAvailableTabs(Context context) {
|
||||||
|
final ArrayList<ChooseTabListItem> returnList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Tab.Type type : Tab.Type.values()) {
|
||||||
|
final Tab tab = type.getTab();
|
||||||
|
switch (type) {
|
||||||
|
case BLANK:
|
||||||
|
if (!tabList.contains(tab)) {
|
||||||
|
returnList.add(new ChooseTabListItem(tab.getTabId(), getString(R.string.blank_page_summary),
|
||||||
|
tab.getTabIconRes(context)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KIOSK:
|
||||||
|
returnList.add(new ChooseTabListItem(tab.getTabId(), getString(R.string.kiosk_page_summary),
|
||||||
|
ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_hot)));
|
||||||
|
break;
|
||||||
|
case CHANNEL:
|
||||||
|
returnList.add(new ChooseTabListItem(tab.getTabId(), getString(R.string.channel_page_summary),
|
||||||
|
tab.getTabIconRes(context)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!tabList.contains(tab)) {
|
||||||
|
returnList.add(new ChooseTabListItem(context, tab));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnList.toArray(new ChooseTabListItem[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// List Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private class SelectedTabsAdapter extends RecyclerView.Adapter<ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder> {
|
||||||
|
private ItemTouchHelper itemTouchHelper;
|
||||||
|
private final LayoutInflater inflater;
|
||||||
|
|
||||||
|
SelectedTabsAdapter(Context context, ItemTouchHelper itemTouchHelper) {
|
||||||
|
this.itemTouchHelper = itemTouchHelper;
|
||||||
|
this.inflater = LayoutInflater.from(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swapItems(int fromPosition, int toPosition) {
|
||||||
|
Collections.swap(tabList, fromPosition, toPosition);
|
||||||
|
notifyItemMoved(fromPosition, toPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = inflater.inflate(R.layout.list_choose_tabs, parent, false);
|
||||||
|
return new ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ChooseTabsFragment.SelectedTabsAdapter.TabViewHolder holder, int position) {
|
||||||
|
holder.bind(position, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return tabList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TabViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private AppCompatImageView tabIconView;
|
||||||
|
private TextView tabNameView;
|
||||||
|
private ImageView handle;
|
||||||
|
|
||||||
|
TabViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
|
||||||
|
tabNameView = itemView.findViewById(R.id.tabName);
|
||||||
|
tabIconView = itemView.findViewById(R.id.tabIcon);
|
||||||
|
handle = itemView.findViewById(R.id.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
void bind(int position, TabViewHolder holder) {
|
||||||
|
handle.setOnTouchListener(getOnTouchListener(holder));
|
||||||
|
|
||||||
|
final Tab tab = tabList.get(position);
|
||||||
|
final Tab.Type type = Tab.typeFrom(tab.getTabId());
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String tabName = tab.getTabName(requireContext());
|
||||||
|
switch (type) {
|
||||||
|
case BLANK:
|
||||||
|
tabName = requireContext().getString(R.string.blank_page_summary);
|
||||||
|
break;
|
||||||
|
case KIOSK:
|
||||||
|
tabName = NewPipe.getNameOfService(((Tab.KioskTab) tab).getKioskServiceId()) + "/" + tabName;
|
||||||
|
break;
|
||||||
|
case CHANNEL:
|
||||||
|
tabName = NewPipe.getNameOfService(((Tab.ChannelTab) tab).getChannelServiceId()) + "/" + tabName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tabNameView.setText(tabName);
|
||||||
|
tabIconView.setImageResource(tab.getTabIconRes(requireContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
private View.OnTouchListener getOnTouchListener(final RecyclerView.ViewHolder item) {
|
||||||
|
return (view, motionEvent) -> {
|
||||||
|
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (itemTouchHelper != null && getItemCount() > 1) {
|
||||||
|
itemTouchHelper.startDrag(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemTouchHelper.SimpleCallback getItemTouchCallback() {
|
||||||
|
return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
|
||||||
|
ItemTouchHelper.START | ItemTouchHelper.END) {
|
||||||
|
@Override
|
||||||
|
public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize,
|
||||||
|
int viewSizeOutOfBounds, int totalSize,
|
||||||
|
long msSinceStartScroll) {
|
||||||
|
final int standardSpeed = super.interpolateOutOfBoundsScroll(recyclerView, viewSize,
|
||||||
|
viewSizeOutOfBounds, totalSize, msSinceStartScroll);
|
||||||
|
final int minimumAbsVelocity = Math.max(12,
|
||||||
|
Math.abs(standardSpeed));
|
||||||
|
return minimumAbsVelocity * (int) Math.signum(viewSizeOutOfBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source,
|
||||||
|
RecyclerView.ViewHolder target) {
|
||||||
|
if (source.getItemViewType() != target.getItemViewType() ||
|
||||||
|
selectedTabsAdapter == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int sourceIndex = source.getAdapterPosition();
|
||||||
|
final int targetIndex = target.getAdapterPosition();
|
||||||
|
selectedTabsAdapter.swapItems(sourceIndex, targetIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLongPressDragEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isItemViewSwipeEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
|
||||||
|
int position = viewHolder.getAdapterPosition();
|
||||||
|
tabList.remove(position);
|
||||||
|
selectedTabsAdapter.notifyItemRemoved(position);
|
||||||
|
|
||||||
|
if (tabList.isEmpty()) {
|
||||||
|
tabList.add(Tab.Type.BLANK.getTab());
|
||||||
|
selectedTabsAdapter.notifyItemInserted(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
416
app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java
Normal file
416
app/src/main/java/org/schabi/newpipe/settings/tabs/Tab.java
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
package org.schabi.newpipe.settings.tabs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
|
import com.grack.nanojson.JsonObject;
|
||||||
|
import com.grack.nanojson.JsonSink;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.fragments.BlankFragment;
|
||||||
|
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||||
|
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||||
|
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
|
||||||
|
import org.schabi.newpipe.local.feed.FeedFragment;
|
||||||
|
import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
|
||||||
|
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||||
|
import org.schabi.newpipe.util.KioskTranslator;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
public abstract class Tab {
|
||||||
|
Tab() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab(@NonNull JsonObject jsonObject) {
|
||||||
|
readDataFromJson(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getTabId();
|
||||||
|
public abstract String getTabName(Context context);
|
||||||
|
@DrawableRes public abstract int getTabIconRes(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a instance of the fragment that this tab represent.
|
||||||
|
*/
|
||||||
|
public abstract Fragment getFragment() throws ExtractionException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof Tab && obj.getClass().equals(this.getClass())
|
||||||
|
&& ((Tab) obj).getTabId() == this.getTabId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// JSON Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private static final String JSON_TAB_ID_KEY = "tab_id";
|
||||||
|
|
||||||
|
public void writeJsonOn(JsonSink jsonSink) {
|
||||||
|
jsonSink.object();
|
||||||
|
|
||||||
|
jsonSink.value(JSON_TAB_ID_KEY, getTabId());
|
||||||
|
writeDataToJson(jsonSink);
|
||||||
|
|
||||||
|
jsonSink.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeDataToJson(JsonSink writerSink) {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readDataFromJson(JsonObject jsonObject) {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tab Handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Tab from(@NonNull JsonObject jsonObject) {
|
||||||
|
final int tabId = jsonObject.getInt(Tab.JSON_TAB_ID_KEY, -1);
|
||||||
|
|
||||||
|
if (tabId == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return from(tabId, jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Tab from(final int tabId) {
|
||||||
|
return from(tabId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Type typeFrom(int tabId) {
|
||||||
|
for (Type available : Type.values()) {
|
||||||
|
if (available.getTabId() == tabId) {
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Tab from(final int tabId, @Nullable JsonObject jsonObject) {
|
||||||
|
final Type type = typeFrom(tabId);
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonObject != null) {
|
||||||
|
switch (type) {
|
||||||
|
case KIOSK:
|
||||||
|
return new KioskTab(jsonObject);
|
||||||
|
case CHANNEL:
|
||||||
|
return new ChannelTab(jsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.getTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Implementations
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
BLANK(new BlankTab()),
|
||||||
|
SUBSCRIPTIONS(new SubscriptionsTab()),
|
||||||
|
FEED(new FeedTab()),
|
||||||
|
BOOKMARKS(new BookmarksTab()),
|
||||||
|
HISTORY(new HistoryTab()),
|
||||||
|
KIOSK(new KioskTab()),
|
||||||
|
CHANNEL(new ChannelTab());
|
||||||
|
|
||||||
|
private Tab tab;
|
||||||
|
|
||||||
|
Type(Tab tab) {
|
||||||
|
this.tab = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTabId() {
|
||||||
|
return tab.getTabId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tab getTab() {
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BlankTab extends Tab {
|
||||||
|
public static final int ID = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return "NewPipe"; //context.getString(R.string.blank_page_summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_blank_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlankFragment getFragment() {
|
||||||
|
return new BlankFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SubscriptionsTab extends Tab {
|
||||||
|
public static final int ID = 1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return context.getString(R.string.tab_subscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubscriptionFragment getFragment() {
|
||||||
|
return new SubscriptionFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FeedTab extends Tab {
|
||||||
|
public static final int ID = 2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return context.getString(R.string.fragment_whats_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.rss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FeedFragment getFragment() {
|
||||||
|
return new FeedFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BookmarksTab extends Tab {
|
||||||
|
public static final int ID = 3;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return context.getString(R.string.tab_bookmarks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_bookmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BookmarkFragment getFragment() {
|
||||||
|
return new BookmarkFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HistoryTab extends Tab {
|
||||||
|
public static final int ID = 4;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return context.getString(R.string.title_activity_history);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.history);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StatisticsPlaylistFragment getFragment() {
|
||||||
|
return new StatisticsPlaylistFragment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KioskTab extends Tab {
|
||||||
|
public static final int ID = 5;
|
||||||
|
|
||||||
|
private int kioskServiceId;
|
||||||
|
private String kioskId;
|
||||||
|
|
||||||
|
private static final String JSON_KIOSK_SERVICE_ID_KEY = "service_id";
|
||||||
|
private static final String JSON_KIOSK_ID_KEY = "kiosk_id";
|
||||||
|
|
||||||
|
private KioskTab() {
|
||||||
|
this(-1, "<no-id>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public KioskTab(int kioskServiceId, String kioskId) {
|
||||||
|
this.kioskServiceId = kioskServiceId;
|
||||||
|
this.kioskId = kioskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KioskTab(JsonObject jsonObject) {
|
||||||
|
super(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return KioskTranslator.getTranslatedKioskName(kioskId, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
final int kioskIcon = KioskTranslator.getKioskIcons(kioskId, context);
|
||||||
|
|
||||||
|
if (kioskIcon <= 0) {
|
||||||
|
throw new IllegalStateException("Kiosk ID is not valid: \"" + kioskId + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return kioskIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KioskFragment getFragment() throws ExtractionException {
|
||||||
|
return KioskFragment.getInstance(kioskServiceId, kioskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeDataToJson(JsonSink writerSink) {
|
||||||
|
writerSink.value(JSON_KIOSK_SERVICE_ID_KEY, kioskServiceId)
|
||||||
|
.value(JSON_KIOSK_ID_KEY, kioskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readDataFromJson(JsonObject jsonObject) {
|
||||||
|
kioskServiceId = jsonObject.getInt(JSON_KIOSK_SERVICE_ID_KEY, -1);
|
||||||
|
kioskId = jsonObject.getString(JSON_KIOSK_ID_KEY, "<no-id>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKioskServiceId() {
|
||||||
|
return kioskServiceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKioskId() {
|
||||||
|
return kioskId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ChannelTab extends Tab {
|
||||||
|
public static final int ID = 6;
|
||||||
|
|
||||||
|
private int channelServiceId;
|
||||||
|
private String channelUrl;
|
||||||
|
private String channelName;
|
||||||
|
|
||||||
|
private static final String JSON_CHANNEL_SERVICE_ID_KEY = "channel_service_id";
|
||||||
|
private static final String JSON_CHANNEL_URL_KEY = "channel_url";
|
||||||
|
private static final String JSON_CHANNEL_NAME_KEY = "channel_name";
|
||||||
|
|
||||||
|
private ChannelTab() {
|
||||||
|
this(-1, "<no-url>", "<no-name>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelTab(int channelServiceId, String channelUrl, String channelName) {
|
||||||
|
this.channelServiceId = channelServiceId;
|
||||||
|
this.channelUrl = channelUrl;
|
||||||
|
this.channelName = channelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelTab(JsonObject jsonObject) {
|
||||||
|
super(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTabId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTabName(Context context) {
|
||||||
|
return channelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
@Override
|
||||||
|
public int getTabIconRes(Context context) {
|
||||||
|
return ThemeHelper.resolveResourceIdFromAttr(context, R.attr.ic_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFragment getFragment() {
|
||||||
|
return ChannelFragment.getInstance(channelServiceId, channelUrl, channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeDataToJson(JsonSink writerSink) {
|
||||||
|
writerSink.value(JSON_CHANNEL_SERVICE_ID_KEY, channelServiceId)
|
||||||
|
.value(JSON_CHANNEL_URL_KEY, channelUrl)
|
||||||
|
.value(JSON_CHANNEL_NAME_KEY, channelName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readDataFromJson(JsonObject jsonObject) {
|
||||||
|
channelServiceId = jsonObject.getInt(JSON_CHANNEL_SERVICE_ID_KEY, -1);
|
||||||
|
channelUrl = jsonObject.getString(JSON_CHANNEL_URL_KEY, "<no-url>");
|
||||||
|
channelName = jsonObject.getString(JSON_CHANNEL_NAME_KEY, "<no-name>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChannelServiceId() {
|
||||||
|
return channelServiceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChannelUrl() {
|
||||||
|
return channelUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChannelName() {
|
||||||
|
return channelName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package org.schabi.newpipe.settings.tabs;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.grack.nanojson.JsonArray;
|
||||||
|
import com.grack.nanojson.JsonObject;
|
||||||
|
import com.grack.nanojson.JsonParser;
|
||||||
|
import com.grack.nanojson.JsonParserException;
|
||||||
|
import com.grack.nanojson.JsonStringWriter;
|
||||||
|
import com.grack.nanojson.JsonWriter;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.settings.tabs.Tab.Type;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to get a JSON representation of a list of tabs, and the other way around.
|
||||||
|
*/
|
||||||
|
public class TabsJsonHelper {
|
||||||
|
private static final String JSON_TABS_ARRAY_KEY = "tabs";
|
||||||
|
|
||||||
|
protected static final List<Tab> FALLBACK_INITIAL_TABS_LIST = Collections.unmodifiableList(Arrays.asList(
|
||||||
|
new Tab.KioskTab(YouTube.getServiceId(), "Trending"),
|
||||||
|
Type.SUBSCRIPTIONS.getTab(),
|
||||||
|
Type.BOOKMARKS.getTab()
|
||||||
|
));
|
||||||
|
|
||||||
|
public static class InvalidJsonException extends Exception {
|
||||||
|
private InvalidJsonException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
private InvalidJsonException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InvalidJsonException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to reads the passed JSON and returns the list of tabs if no error were encountered.
|
||||||
|
* <p>
|
||||||
|
* If the JSON is null or empty, or the list of tabs that it represents is empty, the
|
||||||
|
* {@link #FALLBACK_INITIAL_TABS_LIST fallback list} will be returned.
|
||||||
|
* <p>
|
||||||
|
* Tabs with invalid ids (i.e. not in the {@link Tab.Type} enum) will be ignored.
|
||||||
|
*
|
||||||
|
* @param tabsJson a JSON string got from {@link #getJsonToSave(List)}.
|
||||||
|
* @return a list of {@link Tab tabs}.
|
||||||
|
* @throws InvalidJsonException if the JSON string is not valid
|
||||||
|
*/
|
||||||
|
public static List<Tab> getTabsFromJson(@Nullable String tabsJson) throws InvalidJsonException {
|
||||||
|
if (tabsJson == null || tabsJson.isEmpty()) {
|
||||||
|
return FALLBACK_INITIAL_TABS_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Tab> returnTabs = new ArrayList<>();
|
||||||
|
|
||||||
|
final JsonObject outerJsonObject;
|
||||||
|
try {
|
||||||
|
outerJsonObject = JsonParser.object().from(tabsJson);
|
||||||
|
final JsonArray tabsArray = outerJsonObject.getArray(JSON_TABS_ARRAY_KEY);
|
||||||
|
|
||||||
|
if (tabsArray == null) {
|
||||||
|
throw new InvalidJsonException("JSON doesn't contain \"" + JSON_TABS_ARRAY_KEY + "\" array");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object o : tabsArray) {
|
||||||
|
if (!(o instanceof JsonObject)) continue;
|
||||||
|
|
||||||
|
final Tab tab = Tab.from((JsonObject) o);
|
||||||
|
|
||||||
|
if (tab != null) {
|
||||||
|
returnTabs.add(tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JsonParserException e) {
|
||||||
|
throw new InvalidJsonException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnTabs.isEmpty()) {
|
||||||
|
return FALLBACK_INITIAL_TABS_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a JSON representation from a list of tabs.
|
||||||
|
*
|
||||||
|
* @param tabList a list of {@link Tab tabs}.
|
||||||
|
* @return a JSON string representing the list of tabs
|
||||||
|
*/
|
||||||
|
public static String getJsonToSave(@Nullable List<Tab> tabList) {
|
||||||
|
final JsonStringWriter jsonWriter = JsonWriter.string();
|
||||||
|
jsonWriter.object();
|
||||||
|
|
||||||
|
jsonWriter.array(JSON_TABS_ARRAY_KEY);
|
||||||
|
if (tabList != null) for (Tab tab : tabList) {
|
||||||
|
tab.writeJsonOn(jsonWriter);
|
||||||
|
}
|
||||||
|
jsonWriter.end();
|
||||||
|
|
||||||
|
jsonWriter.end();
|
||||||
|
return jsonWriter.done();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package org.schabi.newpipe.settings.tabs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TabsManager {
|
||||||
|
private final SharedPreferences sharedPreferences;
|
||||||
|
private final String savedTabsKey;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public static TabsManager getManager(Context context) {
|
||||||
|
return new TabsManager(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TabsManager(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
this.savedTabsKey = context.getString(R.string.saved_tabs_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tab> getTabs() {
|
||||||
|
final String savedJson = sharedPreferences.getString(savedTabsKey, null);
|
||||||
|
try {
|
||||||
|
return TabsJsonHelper.getTabsFromJson(savedJson);
|
||||||
|
} catch (TabsJsonHelper.InvalidJsonException e) {
|
||||||
|
Toast.makeText(context, R.string.saved_tabs_invalid_json, Toast.LENGTH_SHORT).show();
|
||||||
|
return getDefaultTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveTabs(List<Tab> tabList) {
|
||||||
|
final String jsonToSave = TabsJsonHelper.getJsonToSave(tabList);
|
||||||
|
sharedPreferences.edit().putString(savedTabsKey, jsonToSave).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTabs() {
|
||||||
|
sharedPreferences.edit().remove(savedTabsKey).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tab> getDefaultTabs() {
|
||||||
|
return TabsJsonHelper.FALLBACK_INITIAL_TABS_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public interface SavedTabsChangeListener {
|
||||||
|
void onTabsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SavedTabsChangeListener savedTabsChangeListener;
|
||||||
|
private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
|
||||||
|
|
||||||
|
public void setSavedTabsListener(SavedTabsChangeListener listener) {
|
||||||
|
if (preferenceChangeListener != null) {
|
||||||
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
|
||||||
|
}
|
||||||
|
savedTabsChangeListener = listener;
|
||||||
|
preferenceChangeListener = getPreferenceChangeListener();
|
||||||
|
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsetSavedTabsListener() {
|
||||||
|
if (preferenceChangeListener != null) {
|
||||||
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
|
||||||
|
}
|
||||||
|
preferenceChangeListener = null;
|
||||||
|
savedTabsChangeListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SharedPreferences.OnSharedPreferenceChangeListener getPreferenceChangeListener() {
|
||||||
|
return (sharedPreferences, key) -> {
|
||||||
|
if (key.equals(savedTabsKey)) {
|
||||||
|
if (savedTabsChangeListener != null) savedTabsChangeListener.onTabsChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -184,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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
app/src/main/res/drawable/ic_blank_page_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_blank_page_black_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M17,3L7,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,5c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_blank_page_white_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_blank_page_white_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M17,3L7,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,5c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14z"/>
|
||||||
|
</vector>
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
|
||||||
|
</vector>
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
|
||||||
|
</vector>
|
@ -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,8 @@
|
|||||||
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:textStyle="bold|italic" />
|
android:textStyle="bold|italic" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -49,7 +52,8 @@
|
|||||||
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:textStyle="italic" />
|
android:textStyle="italic" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -64,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"
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
android:layout_below="@+id/channel_title_view"
|
android:layout_below="@+id/channel_title_view"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:gravity="left|center"
|
android:gravity="left|center"
|
||||||
android:lines="1"
|
android:maxLines="2"
|
||||||
android:textSize="@dimen/channel_subscribers_text_size"
|
android:textSize="@dimen/channel_subscribers_text_size"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:ignore="RtlHardcoded"
|
tools:ignore="RtlHardcoded"
|
||||||
|
@ -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,8 @@ 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:textStyle="bold|italic"/>
|
android:textStyle="bold|italic"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -49,7 +52,8 @@ 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:textStyle="italic"/>
|
android:textStyle="italic"/>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -64,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>
|
@ -21,7 +21,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:srcCompat="@mipmap/ic_launcher" />
|
app:srcCompat="@mipmap/ic_launcher"
|
||||||
|
android:contentDescription="TODO" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_name"
|
android:id="@+id/app_name"
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/relLay"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/usedTabs"
|
android:id="@+id/selectedTabs"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="0dp"
|
tools:listitem="@layout/list_choose_tabs"/>
|
||||||
android:paddingBottom="0dp"
|
|
||||||
android:paddingTop="0dp" >
|
|
||||||
|
|
||||||
</android.support.v7.widget.RecyclerView>
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/floatingActionButton"
|
android:id="@+id/addTabsButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:clickable="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
android:focusable="true" />
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
|
app:fabSize="auto"
|
||||||
|
app:srcCompat="?attr/ic_add"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -10,7 +10,8 @@
|
|||||||
android:paddingBottom="8dp"
|
android:paddingBottom="8dp"
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
android:paddingTop="8dp">
|
android:paddingTop="8dp"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/info"
|
android:id="@+id/info"
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true">
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/name"
|
android:id="@+id/name"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user